NeoMutt  2024-10-02-37-gfa9146
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
lib.h File Reference

Auto-completion. More...

#include <stdbool.h>
#include <stddef.h>
#include "compapi.h"
#include "data.h"
+ Include dependency graph for lib.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

int mutt_command_complete (struct CompletionData *cd, struct Buffer *buf, int pos, int numtabs)
 Complete a command name.
 
int mutt_complete (struct CompletionData *cd, struct Buffer *buf)
 Attempt to complete a partial pathname.
 
int mutt_label_complete (struct CompletionData *cd, struct Buffer *buf, int numtabs)
 Complete a label name.
 
bool mutt_nm_query_complete (struct CompletionData *cd, struct Buffer *buf, int numtabs)
 Complete to the nearest notmuch tag.
 
bool mutt_nm_tag_complete (struct CompletionData *cd, struct Buffer *buf, int numtabs)
 Complete to the nearest notmuch tag.
 
int mutt_var_value_complete (struct CompletionData *cd, struct Buffer *buf, int pos)
 Complete a variable/value.
 
void matches_ensure_morespace (struct CompletionData *cd, int new_size)
 Allocate more space for auto-completion.
 
bool candidate (struct CompletionData *cd, char *user, const char *src, char *dest, size_t dlen)
 Helper function for completion.
 

Variables

const struct CompleteOps CompleteCommandOps
 Auto-Completion of Commands.
 
const struct CompleteOps CompleteLabelOps
 Auto-Completion of Labels.
 

Detailed Description

Auto-completion.

Authors
  • Richard Russon
  • Anna Figueiredo Gomes

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file lib.h.

Function Documentation

◆ mutt_command_complete()

int mutt_command_complete ( struct CompletionData cd,
struct Buffer buf,
int  pos,
int  numtabs 
)

Complete a command name.

Parameters
cdCompletion Data
bufBuffer for the result
posCursor position in the buffer
numtabsNumber of times the user has hit 'tab'
Return values
1Success, a match
0Error, no match

Definition at line 112 of file helpers.c.

113{
114 char *pt = buf->data;
115 int spaces; /* keep track of the number of leading spaces on the line */
116
117 SKIPWS(pt);
118 spaces = pt - buf->data;
119
120 pt = buf->data + pos - spaces;
121 while ((pt > buf->data) && !isspace((unsigned char) *pt))
122 pt--;
123
124 if (pt == buf->data) /* complete cmd */
125 {
126 /* first TAB. Collect all the matches */
127 if (numtabs == 1)
128 {
129 cd->num_matched = 0;
130 mutt_str_copy(cd->user_typed, pt, sizeof(cd->user_typed));
131 memset(cd->match_list, 0, cd->match_list_len);
132 memset(cd->completed, 0, sizeof(cd->completed));
133
134 struct Command *c = NULL;
135 for (size_t num = 0, size = commands_array(&c); num < size; num++)
136 candidate(cd, cd->user_typed, c[num].name, cd->completed, sizeof(cd->completed));
138 cd->match_list[cd->num_matched++] = cd->user_typed;
139
140 /* All matches are stored. Longest non-ambiguous string is ""
141 * i.e. don't change 'buf'. Fake successful return this time */
142 if (cd->user_typed[0] == '\0')
143 return 1;
144 }
145
146 if ((cd->completed[0] == '\0') && (cd->user_typed[0] != '\0'))
147 return 0;
148
149 /* cd->num_matched will _always_ be at least 1 since the initial
150 * user-typed string is always stored */
151 if ((numtabs == 1) && (cd->num_matched == 2))
152 {
153 snprintf(cd->completed, sizeof(cd->completed), "%s", cd->match_list[0]);
154 }
155 else if ((numtabs > 1) && (cd->num_matched > 2))
156 {
157 /* cycle through all the matches */
158 snprintf(cd->completed, sizeof(cd->completed), "%s",
159 cd->match_list[(numtabs - 2) % cd->num_matched]);
160 }
161
162 /* return the completed command */
163 buf_strcpy(buf, cd->completed);
164 }
165 else if (buf_startswith(buf, "set") || buf_startswith(buf, "unset") ||
166 buf_startswith(buf, "reset") || buf_startswith(buf, "toggle"))
167 { /* complete variables */
168 static const char *const prefixes[] = { "no", "inv", "?", "&", 0 };
169
170 pt++;
171 /* loop through all the possible prefixes (no, inv, ...) */
172 if (buf_startswith(buf, "set"))
173 {
174 for (int num = 0; prefixes[num]; num++)
175 {
176 if (mutt_str_startswith(pt, prefixes[num]))
177 {
178 pt += mutt_str_len(prefixes[num]);
179 break;
180 }
181 }
182 }
183
184 /* first TAB. Collect all the matches */
185 if (numtabs == 1)
186 {
187 cd->num_matched = 0;
188 mutt_str_copy(cd->user_typed, pt, sizeof(cd->user_typed));
189 memset(cd->match_list, 0, cd->match_list_len);
190 memset(cd->completed, 0, sizeof(cd->completed));
191
192 struct HashElem *he = NULL;
193 struct HashElem **he_list = get_elem_list(NeoMutt->sub->cs);
194 for (size_t i = 0; he_list[i]; i++)
195 {
196 he = he_list[i];
197 const int type = DTYPE(he->type);
198
200 continue;
201
202 candidate(cd, cd->user_typed, he->key.strkey, cd->completed, sizeof(cd->completed));
203 }
204 FREE(&he_list);
205
207 cd->match_list[cd->num_matched++] = cd->user_typed;
208
209 /* All matches are stored. Longest non-ambiguous string is ""
210 * i.e. don't change 'buf'. Fake successful return this time */
211 if (cd->user_typed[0] == '\0')
212 return 1;
213 }
214
215 if ((cd->completed[0] == 0) && cd->user_typed[0])
216 return 0;
217
218 /* cd->num_matched will _always_ be at least 1 since the initial
219 * user-typed string is always stored */
220 if ((numtabs == 1) && (cd->num_matched == 2))
221 {
222 snprintf(cd->completed, sizeof(cd->completed), "%s", cd->match_list[0]);
223 }
224 else if ((numtabs > 1) && (cd->num_matched > 2))
225 {
226 /* cycle through all the matches */
227 snprintf(cd->completed, sizeof(cd->completed), "%s",
228 cd->match_list[(numtabs - 2) % cd->num_matched]);
229 }
230
231 strncpy(pt, cd->completed, buf->data + buf->dsize - pt - spaces);
232 buf_fix_dptr(buf);
233 }
234 else if (buf_startswith(buf, "exec"))
235 {
236 const enum MenuType mtype = menu_get_current_type();
237 const struct MenuFuncOp *funcs = km_get_table(mtype);
238 if (!funcs && (mtype != MENU_PAGER))
239 funcs = OpGeneric;
240
241 pt++;
242 /* first TAB. Collect all the matches */
243 if (numtabs == 1)
244 {
245 cd->num_matched = 0;
246 mutt_str_copy(cd->user_typed, pt, sizeof(cd->user_typed));
247 memset(cd->match_list, 0, cd->match_list_len);
248 memset(cd->completed, 0, sizeof(cd->completed));
249 for (int num = 0; funcs[num].name; num++)
250 candidate(cd, cd->user_typed, funcs[num].name, cd->completed, sizeof(cd->completed));
251 /* try the generic menu */
252 if ((mtype != MENU_PAGER) && (mtype != MENU_GENERIC))
253 {
254 funcs = OpGeneric;
255 for (int num = 0; funcs[num].name; num++)
256 candidate(cd, cd->user_typed, funcs[num].name, cd->completed,
257 sizeof(cd->completed));
258 }
260 cd->match_list[cd->num_matched++] = cd->user_typed;
261
262 /* All matches are stored. Longest non-ambiguous string is ""
263 * i.e. don't change 'buf'. Fake successful return this time */
264 if (cd->user_typed[0] == '\0')
265 return 1;
266 }
267
268 if ((cd->completed[0] == '\0') && (cd->user_typed[0] != '\0'))
269 return 0;
270
271 /* cd->num_matched will _always_ be at least 1 since the initial
272 * user-typed string is always stored */
273 if ((numtabs == 1) && (cd->num_matched == 2))
274 {
275 snprintf(cd->completed, sizeof(cd->completed), "%s", cd->match_list[0]);
276 }
277 else if ((numtabs > 1) && (cd->num_matched > 2))
278 {
279 /* cycle through all the matches */
280 snprintf(cd->completed, sizeof(cd->completed), "%s",
281 cd->match_list[(numtabs - 2) % cd->num_matched]);
282 }
283
284 strncpy(pt, cd->completed, buf->data + buf->dsize - pt - spaces);
285 buf_fix_dptr(buf);
286 }
287 else
288 {
289 return 0;
290 }
291
292 return 1;
293}
void buf_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition: buffer.c:182
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:395
size_t buf_startswith(const struct Buffer *buf, const char *prefix)
Check whether a buffer starts with a prefix.
Definition: buffer.c:709
void matches_ensure_morespace(struct CompletionData *cd, int new_size)
Allocate more space for auto-completion.
Definition: helpers.c:54
bool candidate(struct CompletionData *cd, char *user, const char *src, char *dest, size_t dlen)
Helper function for completion.
Definition: helpers.c:78
size_t commands_array(struct Command **first)
Get Commands array.
Definition: command.c:75
const struct MenuFuncOp OpGeneric[]
Functions for the Generic Menu.
Definition: functions.c:68
const struct MenuFuncOp * km_get_table(enum MenuType mtype)
Lookup a Menu's functions.
Definition: lib.c:525
#define FREE(x)
Definition: memory.h:45
enum MenuType menu_get_current_type(void)
Get the type of the current Window.
Definition: menu.c:89
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:230
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:496
size_t mutt_str_copy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:581
#define SKIPWS(ch)
Definition: string2.h:45
size_t dsize
Length of data.
Definition: buffer.h:39
char * data
Pointer to data.
Definition: buffer.h:37
int match_list_len
Enough space for all of the config items.
Definition: data.h:38
char user_typed[1024]
Initial string that starts completion.
Definition: data.h:34
char completed[256]
Completed string (command or variable)
Definition: data.h:36
int num_matched
Number of matches for completion.
Definition: data.h:35
const char ** match_list
Matching strings.
Definition: data.h:37
struct ConfigSet * cs
Parent ConfigSet.
Definition: subset.h:51
The item stored in a Hash Table.
Definition: hash.h:43
union HashKey key
Key representing the data.
Definition: hash.h:45
int type
Type of data stored in Hash Table, e.g. DT_STRING.
Definition: hash.h:44
Mapping between a function and an operation.
Definition: lib.h:101
const char * name
Name of the function.
Definition: lib.h:102
Container for Accounts, Notifications.
Definition: neomutt.h:42
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:46
struct HashElem ** get_elem_list(struct ConfigSet *cs)
Create a sorted list of all config items.
Definition: subset.c:79
MenuType
Types of GUI selections.
Definition: type.h:36
@ MENU_GENERIC
Generic selection list.
Definition: type.h:46
@ MENU_PAGER
Pager pager (email viewer)
Definition: type.h:52
#define DTYPE(t)
Definition: types.h:50
#define D_INTERNAL_DEPRECATED
Config item shouldn't be used any more.
Definition: types.h:88
@ DT_SYNONYM
synonym for another variable
Definition: types.h:46
const char * strkey
String key.
Definition: hash.h:35
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_complete()

int mutt_complete ( struct CompletionData cd,
struct Buffer buf 
)

Attempt to complete a partial pathname.

Parameters
cdCompletion Data
bufBuffer containing pathname
Return values
0Ok
-1No matches

Given a partial pathname, fill in as much of the rest of the path as is unique.

Definition at line 57 of file complete.c.

58{
59 const char *p = NULL;
60 DIR *dir = NULL;
61 struct dirent *de = NULL;
62 int init = 0;
63 size_t len;
64 struct Buffer *dirpart = NULL;
65 struct Buffer *exp_dirpart = NULL;
66 struct Buffer *filepart = NULL;
67 struct Buffer *tmp = NULL;
68 struct Buffer *imap_path = NULL;
69 int rc;
70
71 mutt_debug(LL_DEBUG2, "completing %s\n", buf_string(buf));
72
73 if (OptNews)
74 return nntp_complete(buf);
75
76 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
77 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
78
79 imap_path = buf_pool_get();
80 /* we can use '/' as a delimiter, imap_complete rewrites it */
81 char ch = buf_at(buf, 0);
82 if ((ch == '=') || (ch == '+') || (ch == '!'))
83 {
84 if (ch == '!')
85 p = NONULL(c_spool_file);
86 else
87 p = NONULL(c_folder);
88
89 buf_concat_path(imap_path, p, buf_string(buf) + 1);
90 }
91 else
92 {
93 buf_copy(imap_path, buf);
94 }
95
96 if (imap_path_probe(buf_string(imap_path), NULL) == MUTT_IMAP)
97 {
98 rc = imap_complete(buf, buf_string(imap_path));
99 buf_pool_release(&imap_path);
100 return rc;
101 }
102
103 buf_pool_release(&imap_path);
104
105 dirpart = buf_pool_get();
106 exp_dirpart = buf_pool_get();
107 filepart = buf_pool_get();
108 tmp = buf_pool_get();
109
110 ch = buf_at(buf, 0);
111 if ((ch == '=') || (ch == '+') || (ch == '!'))
112 {
113 buf_addch(dirpart, ch);
114 if (ch == '!')
115 buf_strcpy(exp_dirpart, c_spool_file);
116 else
117 buf_strcpy(exp_dirpart, c_folder);
118 p = strrchr(buf_string(buf), '/');
119 if (p)
120 {
121 buf_concatn_path(tmp, buf_string(exp_dirpart), buf_len(exp_dirpart),
122 buf_string(buf) + 1, (size_t) (p - buf_string(buf) - 1));
123 buf_copy(exp_dirpart, tmp);
124 buf_substrcpy(dirpart, buf_string(buf), p + 1);
125 buf_strcpy(filepart, p + 1);
126 }
127 else
128 {
129 buf_strcpy(filepart, buf_string(buf) + 1);
130 }
132 }
133 else
134 {
135 p = strrchr(buf_string(buf), '/');
136 if (p)
137 {
138 if (p == buf_string(buf)) /* absolute path */
139 {
140 p = buf_string(buf) + 1;
141 buf_strcpy(dirpart, "/");
142 buf_strcpy(filepart, p);
144 }
145 else
146 {
147 buf_substrcpy(dirpart, buf_string(buf), p);
148 buf_strcpy(filepart, p + 1);
149 buf_copy(exp_dirpart, dirpart);
150 buf_expand_path(exp_dirpart);
152 }
153 }
154 else
155 {
156 /* no directory name, so assume current directory. */
157 buf_strcpy(filepart, buf_string(buf));
159 }
160 }
161
162 if (!dir)
163 {
164 mutt_debug(LL_DEBUG1, "%s: %s (errno %d)\n", buf_string(exp_dirpart),
165 strerror(errno), errno);
166 goto cleanup;
167 }
168
169 /* special case to handle when there is no filepart yet. find the first
170 * file/directory which is not "." or ".." */
171 len = buf_len(filepart);
172 if (len == 0)
173 {
174 while ((de = readdir(dir)))
175 {
176 if (!mutt_str_equal(".", de->d_name) && !mutt_str_equal("..", de->d_name))
177 {
178 buf_strcpy(filepart, de->d_name);
179 init++;
180 break;
181 }
182 }
183 }
184
185 while ((de = readdir(dir)))
186 {
187 if (mutt_strn_equal(de->d_name, buf_string(filepart), len))
188 {
189 if (init)
190 {
191 char *cp = filepart->data;
192
193 for (int i = 0; (*cp != '\0') && (de->d_name[i] != '\0'); i++, cp++)
194 {
195 if (*cp != de->d_name[i])
196 break;
197 }
198 *cp = '\0';
199 buf_fix_dptr(filepart);
200 }
201 else
202 {
203 struct stat st = { 0 };
204
205 buf_strcpy(filepart, de->d_name);
206
207 /* check to see if it is a directory */
208 if (buf_is_empty(dirpart))
209 {
210 buf_reset(tmp);
211 }
212 else
213 {
214 buf_copy(tmp, exp_dirpart);
215 buf_addch(tmp, '/');
216 }
217 buf_addstr(tmp, buf_string(filepart));
218 if ((stat(buf_string(tmp), &st) != -1) && (st.st_mode & S_IFDIR))
219 buf_addch(filepart, '/');
220 init = 1;
221 }
222 }
223 }
224 closedir(dir);
225
226 if (buf_is_empty(dirpart))
227 {
228 buf_copy(buf, filepart);
229 }
230 else
231 {
232 buf_copy(buf, dirpart);
233 if (!mutt_str_equal("/", buf_string(dirpart)) &&
234 (buf_string(dirpart)[0] != '=') && (buf_string(dirpart)[0] != '+'))
235 {
236 buf_addstr(buf, "/");
237 }
238 buf_addstr(buf, buf_string(filepart));
239 }
240
241cleanup:
242 buf_pool_release(&dirpart);
243 buf_pool_release(&exp_dirpart);
244 buf_pool_release(&filepart);
245 buf_pool_release(&tmp);
246
247 return init ? 0 : -1;
248}
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:491
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:76
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:291
char buf_at(const struct Buffer *buf, size_t offset)
Return the character at the given offset.
Definition: buffer.c:670
size_t buf_concatn_path(struct Buffer *buf, const char *dir, size_t dirlen, const char *fname, size_t fnamelen)
Join a directory name and a filename.
Definition: buffer.c:546
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:241
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:226
size_t buf_copy(struct Buffer *dst, const struct Buffer *src)
Copy a Buffer's contents to another Buffer.
Definition: buffer.c:601
size_t buf_concat_path(struct Buffer *buf, const char *dir, const char *fname)
Join a directory name and a filename.
Definition: buffer.c:509
size_t buf_substrcpy(struct Buffer *buf, const char *beg, const char *end)
Copy a partial string into a Buffer.
Definition: buffer.c:471
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:291
@ MUTT_IMAP
'IMAP' Mailbox type
Definition: mailbox.h:50
DIR * mutt_file_opendir(const char *path, enum MuttOpenDirMode mode)
Open a directory.
Definition: file.c:642
@ MUTT_OPENDIR_NONE
Plain opendir()
Definition: file.h:63
bool OptNews
(pseudo) used to change reader mode
Definition: globals.c:67
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox? - Implements MxOps::path_probe() -.
Definition: imap.c:2345
int imap_complete(struct Buffer *buf, const char *path)
Try to complete an IMAP folder path.
Definition: imap.c:1275
@ LL_DEBUG2
Log at debug level 2.
Definition: logging2.h:44
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:660
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:425
void buf_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:315
int nntp_complete(struct Buffer *buf)
Auto-complete NNTP newsgroups.
Definition: complete.c:46
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:81
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:94
#define NONULL(x)
Definition: string2.h:37
String manipulation buffer.
Definition: buffer.h:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_label_complete()

int mutt_label_complete ( struct CompletionData cd,
struct Buffer buf,
int  numtabs 
)

Complete a label name.

Parameters
cdCompletion Data
bufBuffer for the result
numtabsNumber of times the user has hit 'tab'
Return values
1Success, a match
0Error, no match

Definition at line 311 of file helpers.c.

312{
313 char *pt = buf->data;
314
315 struct Mailbox *m_cur = get_current_mailbox();
316 if (!m_cur || !m_cur->label_hash)
317 return 0;
318
319 SKIPWS(pt);
320
321 /* first TAB. Collect all the matches */
322 if (numtabs == 1)
323 {
324 struct HashElem *he = NULL;
325 struct HashWalkState hws = { 0 };
326
327 cd->num_matched = 0;
328 mutt_str_copy(cd->user_typed, buf_string(buf), sizeof(cd->user_typed));
329 memset(cd->match_list, 0, cd->match_list_len);
330 memset(cd->completed, 0, sizeof(cd->completed));
331 while ((he = mutt_hash_walk(m_cur->label_hash, &hws)))
332 candidate(cd, cd->user_typed, he->key.strkey, cd->completed, sizeof(cd->completed));
334 mutt_qsort_r(cd->match_list, cd->num_matched, sizeof(char *), label_sort, NULL);
335 cd->match_list[cd->num_matched++] = cd->user_typed;
336
337 /* All matches are stored. Longest non-ambiguous string is ""
338 * i.e. don't change 'buf'. Fake successful return this time */
339 if (cd->user_typed[0] == '\0')
340 return 1;
341 }
342
343 if ((cd->completed[0] == '\0') && (cd->user_typed[0] != '\0'))
344 return 0;
345
346 /* cd->num_matched will _always_ be at least 1 since the initial
347 * user-typed string is always stored */
348 if ((numtabs == 1) && (cd->num_matched == 2))
349 {
350 snprintf(cd->completed, sizeof(cd->completed), "%s", cd->match_list[0]);
351 }
352 else if ((numtabs > 1) && (cd->num_matched > 2))
353 {
354 /* cycle through all the matches */
355 snprintf(cd->completed, sizeof(cd->completed), "%s",
356 cd->match_list[(numtabs - 2) % cd->num_matched]);
357 }
358
359 /* return the completed label */
360 buf_strcpy(buf, cd->completed);
361
362 return 1;
363}
static int label_sort(const void *a, const void *b, void *sdata)
Compare two label strings - Implements sort_t -.
Definition: helpers.c:298
struct HashElem * mutt_hash_walk(const struct HashTable *table, struct HashWalkState *state)
Iterate through all the HashElem's in a Hash Table.
Definition: hash.c:489
struct Mailbox * get_current_mailbox(void)
Get the current Mailbox.
Definition: index.c:715
void mutt_qsort_r(void *base, size_t nmemb, size_t size, sort_t compar, void *sdata)
Sort an array, where the comparator has access to opaque data rather than requiring global variables.
Definition: qsort_r.c:67
Cursor to iterate through a Hash Table.
Definition: hash.h:132
A mailbox.
Definition: mailbox.h:79
struct HashTable * label_hash
Hash Table: "x-labels" -> Email.
Definition: mailbox.h:125
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_nm_query_complete()

bool mutt_nm_query_complete ( struct CompletionData cd,
struct Buffer buf,
int  numtabs 
)

Complete to the nearest notmuch tag.

Parameters
cdCompletion Data
bufBuffer for the result
numtabsNumber of times the user has hit 'tab'
Return values
trueSuccess, a match
falseError, no match

Complete the last "tag:"-prefixed string.

Definition at line 101 of file complete.c.

102{
103 char *pt = buf->data;
104 int spaces;
105
106 SKIPWS(pt);
107 spaces = pt - buf->data;
108
109 pt = (char *) buf_rfind(buf, "tag:");
110 if (pt)
111 {
112 pt += 4;
113 if (numtabs == 1)
114 {
115 /* First TAB. Collect all the matches */
116 complete_all_nm_tags(cd, pt);
117
118 /* All matches are stored. Longest non-ambiguous string is ""
119 * i.e. don't change 'buf'. Fake successful return this time. */
120 if (cd->user_typed[0] == '\0')
121 return true;
122 }
123
124 if ((cd->completed[0] == '\0') && (cd->user_typed[0] != '\0'))
125 return false;
126
127 /* cd->num_matched will _always_ be at least 1 since the initial
128 * user-typed string is always stored */
129 if ((numtabs == 1) && (cd->num_matched == 2))
130 {
131 snprintf(cd->completed, sizeof(cd->completed), "%s", cd->match_list[0]);
132 }
133 else if ((numtabs > 1) && (cd->num_matched > 2))
134 {
135 /* cycle through all the matches */
136 snprintf(cd->completed, sizeof(cd->completed), "%s",
137 cd->match_list[(numtabs - 2) % cd->num_matched]);
138 }
139
140 /* return the completed query */
141 strncpy(pt, cd->completed, buf->data + buf->dsize - pt - spaces);
142 }
143 else
144 {
145 return false;
146 }
147
148 return true;
149}
const char * buf_rfind(const struct Buffer *buf, const char *str)
Find last instance of a substring.
Definition: buffer.c:797
int complete_all_nm_tags(struct CompletionData *cd, const char *pt)
Pass a list of Notmuch tags to the completion code.
Definition: complete.c:48
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_nm_tag_complete()

bool mutt_nm_tag_complete ( struct CompletionData cd,
struct Buffer buf,
int  numtabs 
)

Complete to the nearest notmuch tag.

Parameters
cdCompletion Data
bufBuffer for the result
numtabsNumber of times the user has hit 'tab'
Return values
trueSuccess, a match
falseError, no match

Complete the nearest "+" or "-" -prefixed string previous to pos.

Definition at line 161 of file complete.c.

162{
163 if (!buf)
164 return false;
165
166 char *pt = buf->data;
167
168 /* Only examine the last token */
169 char *last_space = strrchr(buf->data, ' ');
170 if (last_space)
171 pt = (last_space + 1);
172
173 /* Skip the +/- */
174 if ((pt[0] == '+') || (pt[0] == '-'))
175 pt++;
176
177 if (numtabs == 1)
178 {
179 /* First TAB. Collect all the matches */
180 complete_all_nm_tags(cd, pt);
181
182 /* All matches are stored. Longest non-ambiguous string is ""
183 * i.e. don't change 'buf'. Fake successful return this time. */
184 if (cd->user_typed[0] == '\0')
185 return true;
186 }
187
188 if ((cd->completed[0] == '\0') && (cd->user_typed[0] != '\0'))
189 return false;
190
191 /* cd->num_matched will _always_ be at least 1 since the initial
192 * user-typed string is always stored */
193 if ((numtabs == 1) && (cd->num_matched == 2))
194 {
195 snprintf(cd->completed, sizeof(cd->completed), "%s", cd->match_list[0]);
196 }
197 else if ((numtabs > 1) && (cd->num_matched > 2))
198 {
199 /* cycle through all the matches */
200 snprintf(cd->completed, sizeof(cd->completed), "%s",
201 cd->match_list[(numtabs - 2) % cd->num_matched]);
202 }
203
204 /* return the completed query */
205 strncpy(pt, cd->completed, buf->data + buf->dsize - pt);
206
207 return true;
208}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_var_value_complete()

int mutt_var_value_complete ( struct CompletionData cd,
struct Buffer buf,
int  pos 
)

Complete a variable/value.

Parameters
cdCompletion Data
bufBuffer for the result
posCursor position in the buffer
Return values
1Success
0Failure

Definition at line 373 of file helpers.c.

374{
375 char *pt = buf->data;
376
377 if (pt[0] == '\0')
378 return 0;
379
380 SKIPWS(pt);
381 const int spaces = pt - buf->data;
382
383 pt = buf->data + pos - spaces;
384 while ((pt > buf->data) && !isspace((unsigned char) *pt))
385 pt--;
386 pt++; /* move past the space */
387 if (*pt == '=') /* abort if no var before the '=' */
388 return 0;
389
390 if (buf_startswith(buf, "set"))
391 {
392 char var[256] = { 0 };
393 mutt_str_copy(var, pt, sizeof(var));
394 /* ignore the trailing '=' when comparing */
395 int vlen = mutt_str_len(var);
396 if (vlen == 0)
397 return 0;
398
399 var[vlen - 1] = '\0';
400
401 struct HashElem *he = cs_subset_lookup(NeoMutt->sub, var);
402 if (!he)
403 return 0; /* no such variable. */
404
405 struct Buffer *value = buf_pool_get();
406 struct Buffer *pretty = buf_pool_get();
407 int rc = cs_subset_he_string_get(NeoMutt->sub, he, value);
408 if (CSR_RESULT(rc) == CSR_SUCCESS)
409 {
410 pretty_var(value->data, pretty);
411 snprintf(pt, buf->dsize - (pt - buf->data), "%s=%s", var, pretty->data);
412 buf_pool_release(&value);
413 buf_pool_release(&pretty);
414 return 0;
415 }
416 buf_pool_release(&value);
417 buf_pool_release(&pretty);
418 return 1;
419 }
420 return 0;
421}
size_t pretty_var(const char *str, struct Buffer *buf)
Escape and stringify a config item value.
Definition: dump.c:85
#define CSR_RESULT(x)
Definition: set.h:52
#define CSR_SUCCESS
Action completed successfully.
Definition: set.h:35
int cs_subset_he_string_get(const struct ConfigSubset *sub, struct HashElem *he, struct Buffer *result)
Get a config item as a string.
Definition: subset.c:332
struct HashElem * cs_subset_lookup(const struct ConfigSubset *sub, const char *name)
Find an inherited config item.
Definition: subset.c:187
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ matches_ensure_morespace()

void matches_ensure_morespace ( struct CompletionData cd,
int  new_size 
)

Allocate more space for auto-completion.

Parameters
cdCompletion Data
new_sizeSpace required

Definition at line 54 of file helpers.c.

55{
56 if (new_size <= (cd->match_list_len - 2))
57 return;
58
59 new_size = ROUND_UP(new_size + 2, 512);
60
61 mutt_mem_realloc(&cd->match_list, new_size * sizeof(char *));
62 memset(&cd->match_list[cd->match_list_len], 0, new_size - cd->match_list_len);
63
64 cd->match_list_len = new_size;
65}
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:115
#define ROUND_UP(NUM, STEP)
Definition: memory.h:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ candidate()

bool candidate ( struct CompletionData cd,
char *  user,
const char *  src,
char *  dest,
size_t  dlen 
)

Helper function for completion.

Parameters
cdCompletion Data
userUser entered data for completion
srcCandidate for completion
destCompletion result gets here
dlenLength of dest buffer
Return values
trueIf candidate string matches

Changes the dest buffer if necessary/possible to aid completion.

Definition at line 78 of file helpers.c.

79{
80 if (!dest || !user || !src)
81 return false;
82
83 if (strstr(src, user) != src)
84 return false;
85
87 cd->match_list[cd->num_matched++] = src;
88 if (dest[0] == '\0')
89 {
90 mutt_str_copy(dest, src, dlen);
91 }
92 else
93 {
94 int l;
95 for (l = 0; (src[l] != '\0') && (src[l] == dest[l]); l++)
96 ; // do nothing
97
98 dest[l] = '\0';
99 }
100 return true;
101}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Variable Documentation

◆ CompleteCommandOps

const struct CompleteOps CompleteCommandOps
extern

Auto-Completion of Commands.

Definition at line 477 of file helpers.c.

◆ CompleteLabelOps

const struct CompleteOps CompleteLabelOps
extern

Auto-Completion of Labels.

Definition at line 484 of file helpers.c.