NeoMutt  2025-12-11-694-ga89709
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, void *cdata)
 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,
void * cdata )

Complete a command name.

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

Definition at line 125 of file helpers.c.

127{
128 char *pt = buf->data;
129 int spaces; /* keep track of the number of leading spaces on the line */
130
131 SKIPWS(pt);
132 spaces = pt - buf->data;
133
134 pt = buf->data + pos - spaces;
135 while ((pt > buf->data) && !mutt_isspace(*pt))
136 pt--;
137
138 if (pt == buf->data) /* complete cmd */
139 {
140 /* first TAB. Collect all the matches */
141 if (numtabs == 1)
142 {
143 cd->num_matched = 0;
144 mutt_str_copy(cd->user_typed, pt, sizeof(cd->user_typed));
145 memset(cd->match_list, 0, cd->match_list_len * sizeof(const char *));
146 memset(cd->completed, 0, sizeof(cd->completed));
147
148 const struct Command **cp = NULL;
150 {
151 const struct Command *cmd = *cp;
152
153 // For synonyms, match against the synonym name but complete to the real command name
154 if ((cmd->flags & CF_SYNONYM) && cmd->help)
155 {
156 // Check if user-typed matches the beginning of the synonym name
157 if (strstr(cmd->name, cd->user_typed) == cmd->name)
158 {
159 // Use the real command name for completion
160 const char *real_name = cmd->help;
161
162 // Manually add the real command name to the match list
164 cd->match_list[cd->num_matched++] = real_name;
165
166 // Update the completion result
167 if (cd->completed[0] == '\0')
168 {
169 mutt_str_copy(cd->completed, real_name, sizeof(cd->completed));
170 }
171 else
172 {
173 int l;
174 for (l = 0; (real_name[l] != '\0') && (real_name[l] == cd->completed[l]); l++)
175 ; // do nothing
176 cd->completed[l] = '\0';
177 }
178 }
179 }
180 else
181 {
182 candidate(cd, cd->user_typed, cmd->name, cd->completed, sizeof(cd->completed));
183 }
184 }
185
187 cd->match_list[cd->num_matched++] = cd->user_typed;
188
189 /* All matches are stored. Longest non-ambiguous string is ""
190 * i.e. don't change 'buf'. Fake successful return this time */
191 if (cd->user_typed[0] == '\0')
192 return 1;
193 }
194
195 if ((cd->completed[0] == '\0') && (cd->user_typed[0] != '\0'))
196 return 0;
197
198 /* cd->num_matched will _always_ be at least 1 since the initial
199 * user-typed string is always stored */
200 if ((numtabs == 1) && (cd->num_matched == 2))
201 {
202 snprintf(cd->completed, sizeof(cd->completed), "%s", cd->match_list[0]);
203 }
204 else if ((numtabs > 1) && (cd->num_matched > 2))
205 {
206 /* cycle through all the matches */
207 snprintf(cd->completed, sizeof(cd->completed), "%s",
208 cd->match_list[(numtabs - 2) % cd->num_matched]);
209 }
210
211 /* return the completed command */
212 buf_strcpy(buf, cd->completed);
213 }
214 else if (buf_startswith(buf, "set") || buf_startswith(buf, "unset") ||
215 buf_startswith(buf, "reset") || buf_startswith(buf, "toggle"))
216 { /* complete variables */
217 static const char *const prefixes[] = { "no", "inv", "?", "&", 0 };
218
219 pt++;
220 /* loop through all the possible prefixes (no, inv, ...) */
221 if (buf_startswith(buf, "set"))
222 {
223 for (int num = 0; prefixes[num]; num++)
224 {
225 if (mutt_str_startswith(pt, prefixes[num]))
226 {
227 pt += mutt_str_len(prefixes[num]);
228 break;
229 }
230 }
231 }
232
233 /* first TAB. Collect all the matches */
234 if (numtabs == 1)
235 {
236 cd->num_matched = 0;
237 mutt_str_copy(cd->user_typed, pt, sizeof(cd->user_typed));
238 memset(cd->match_list, 0, cd->match_list_len * sizeof(const char *));
239 memset(cd->completed, 0, sizeof(cd->completed));
240
241 struct HashElemArray hea = get_elem_list(NeoMutt->sub->cs, GEL_ALL_CONFIG);
242 struct HashElem **hep = NULL;
243 ARRAY_FOREACH(hep, &hea)
244 {
245 candidate(cd, cd->user_typed, (*hep)->key.strkey, cd->completed,
246 sizeof(cd->completed));
247 }
248 ARRAY_FREE(&hea);
249
251 cd->match_list[cd->num_matched++] = cd->user_typed;
252
253 /* All matches are stored. Longest non-ambiguous string is ""
254 * i.e. don't change 'buf'. Fake successful return this time */
255 if (cd->user_typed[0] == '\0')
256 return 1;
257 }
258
259 if ((cd->completed[0] == 0) && cd->user_typed[0])
260 return 0;
261
262 /* cd->num_matched will _always_ be at least 1 since the initial
263 * user-typed string is always stored */
264 if ((numtabs == 1) && (cd->num_matched == 2))
265 {
266 snprintf(cd->completed, sizeof(cd->completed), "%s", cd->match_list[0]);
267 }
268 else if ((numtabs > 1) && (cd->num_matched > 2))
269 {
270 /* cycle through all the matches */
271 snprintf(cd->completed, sizeof(cd->completed), "%s",
272 cd->match_list[(numtabs - 2) % cd->num_matched]);
273 }
274
275 mutt_str_copy(pt, cd->completed, buf->data + buf->dsize - pt - spaces);
276 buf_fix_dptr(buf);
277 }
278 else if (buf_startswith(buf, "exec"))
279 {
280 pt++;
281 /* first TAB. Collect all the matches */
282 if (numtabs == 1)
283 {
284 cd->num_matched = 0;
285 mutt_str_copy(cd->user_typed, pt, sizeof(cd->user_typed));
286 memset(cd->match_list, 0, cd->match_list_len * sizeof(const char *));
287 memset(cd->completed, 0, sizeof(cd->completed));
288
289 enum MenuType mtype = MENU_GENERIC;
290 if (cdata)
291 {
292 struct FileCompletionData *fcd = cdata;
293 struct MuttWindow *win = fcd->win;
294 if (win && (win->type == WT_MENU) && win->wdata)
295 {
296 struct Menu *menu = win->wdata;
297 mtype = menu->md->id;
298 }
299 }
300 else
301 {
302 mtype = menu_get_current_type();
303 }
304
305 const struct MenuDefinition *md = menu_find(mtype);
306 struct StringArray fna = km_get_func_array(md);
307
309 const char **strp = NULL;
310 ARRAY_FOREACH(strp, &fna)
311 {
312 candidate(cd, cd->user_typed, *strp, cd->completed, sizeof(cd->completed));
313 }
314 ARRAY_FREE(&fna);
315
317 cd->match_list[cd->num_matched++] = cd->user_typed;
318
319 /* All matches are stored. Longest non-ambiguous string is ""
320 * i.e. don't change 'buf'. Fake successful return this time */
321 if (cd->user_typed[0] == '\0')
322 return 1;
323 }
324
325 if ((cd->completed[0] == '\0') && (cd->user_typed[0] != '\0'))
326 return 0;
327
328 /* cd->num_matched will _always_ be at least 1 since the initial
329 * user-typed string is always stored */
330 if ((numtabs == 1) && (cd->num_matched == 2))
331 {
332 snprintf(cd->completed, sizeof(cd->completed), "%s", cd->match_list[0]);
333 }
334 else if ((numtabs > 1) && (cd->num_matched > 2))
335 {
336 /* cycle through all the matches */
337 snprintf(cd->completed, sizeof(cd->completed), "%s",
338 cd->match_list[(numtabs - 2) % cd->num_matched]);
339 }
340
341 mutt_str_copy(pt, cd->completed, buf->data + buf->dsize - pt - spaces);
342 buf_fix_dptr(buf);
343 }
344 else
345 {
346 return 0;
347 }
348
349 return 1;
350}
#define ARRAY_SORT(head, fn, sdata)
Sort an array.
Definition array.h:373
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:223
#define ARRAY_FREE(head)
Release all memory.
Definition array.h:209
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:707
#define CF_SYNONYM
Command is a synonym for another command.
Definition command.h:49
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:79
bool mutt_isspace(int arg)
Wrapper for isspace(3)
Definition ctype.c:96
static int complete_sort_strings(const void *a, const void *b, void *sdata)
Compare two strings - Implements sort_t -.
Definition helpers.c:107
struct StringArray km_get_func_array(const struct MenuDefinition *md)
Get array of function names for a Menu.
Definition dump.c:475
struct MenuDefinition * menu_find(int menu)
Find a Menu Definition by Menu type.
Definition menu.c:245
enum MenuType menu_get_current_type(void)
Get the type of the current Window.
Definition menu.c:91
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition string.c:234
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
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:586
@ WT_MENU
An Window containing a Menu.
Definition mutt_window.h:97
#define SKIPWS(ch)
Definition string2.h:52
size_t dsize
Length of data.
Definition buffer.h:39
char * data
Pointer to data.
Definition buffer.h:37
CommandFlags flags
Command flags, e.g. CF_SYNONYM.
Definition command.h:184
const char * help
One-line description of the Command.
Definition command.h:180
const char * name
Name of the Command.
Definition command.h:159
int match_list_len
Enough space for all of the config items.
Definition data.h:37
char user_typed[1024]
Initial string that starts completion.
Definition data.h:33
char completed[256]
Completed string (command or variable)
Definition data.h:35
int num_matched
Number of matches for completion.
Definition data.h:34
const char ** match_list
Matching strings.
Definition data.h:36
struct ConfigSet * cs
Parent ConfigSet.
Definition subset.h:50
Input for the file completion function.
Definition curs_lib.h:39
struct MuttWindow * win
Current Focused Window.
Definition curs_lib.h:44
The item stored in a Hash Table.
Definition hash.h:44
Functions for a Dialog or Window.
Definition menu.h:80
int id
Menu ID, e.g. MENU_ALIAS.
Definition menu.h:81
Definition lib.h:80
struct MuttWindow * win
Window holding the Menu.
Definition lib.h:88
const struct MenuDefinition * md
Menu definition for keymap entries.
Definition lib.h:84
void * wdata
Private data.
enum WindowType type
Window type, e.g. WT_SIDEBAR.
Container for Accounts, Notifications.
Definition neomutt.h:41
struct CommandArray commands
NeoMutt commands.
Definition neomutt.h:53
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
struct HashElemArray get_elem_list(struct ConfigSet *cs, enum GetElemListFlags flags)
Create a sorted list of all config items.
Definition subset.c:81
@ GEL_ALL_CONFIG
All the normal config (no synonyms or deprecated)
Definition subset.h:81
MenuType
Types of GUI selections.
Definition type.h:33
@ MENU_GENERIC
Generic selection list.
Definition type.h:43
+ 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 58 of file complete.c.

59{
60 const char *p = NULL;
61 DIR *dir = NULL;
62 struct dirent *de = NULL;
63 int init = 0;
64 size_t len;
65 struct Buffer *dirpart = NULL;
66 struct Buffer *exp_dirpart = NULL;
67 struct Buffer *filepart = NULL;
68 struct Buffer *tmp = NULL;
69 struct Buffer *imap_path = NULL;
70 int rc;
71
72 mutt_debug(LL_DEBUG2, "completing %s\n", buf_string(buf));
73
74 if (OptNews)
75 return nntp_complete(buf);
76
77 const char *const c_spool_file = cs_subset_string(NeoMutt->sub, "spool_file");
78 const char *const c_folder = cs_subset_string(NeoMutt->sub, "folder");
79
80 imap_path = buf_pool_get();
81 /* we can use '/' as a delimiter, imap_complete rewrites it */
82 char ch = buf_at(buf, 0);
83 if ((ch == '=') || (ch == '+') || (ch == '!'))
84 {
85 if (ch == '!')
86 p = NONULL(c_spool_file);
87 else
88 p = NONULL(c_folder);
89
90 buf_concat_path(imap_path, p, buf_string(buf) + 1);
91 }
92 else
93 {
94 buf_copy(imap_path, buf);
95 }
96
97 if (imap_path_probe(buf_string(imap_path), NULL) == MUTT_IMAP)
98 {
99 rc = imap_complete(buf, buf_string(imap_path));
100 buf_pool_release(&imap_path);
101 return rc;
102 }
103
104 buf_pool_release(&imap_path);
105
106 dirpart = buf_pool_get();
107 exp_dirpart = buf_pool_get();
108 filepart = buf_pool_get();
109 tmp = buf_pool_get();
110
111 ch = buf_at(buf, 0);
112 if ((ch == '=') || (ch == '+') || (ch == '!'))
113 {
114 buf_addch(dirpart, ch);
115 if (ch == '!')
116 buf_strcpy(exp_dirpart, c_spool_file);
117 else
118 buf_strcpy(exp_dirpart, c_folder);
119 p = strrchr(buf_string(buf), '/');
120 if (p)
121 {
122 buf_concatn_path(tmp, buf_string(exp_dirpart), buf_len(exp_dirpart),
123 buf_string(buf) + 1, (size_t) (p - buf_string(buf) - 1));
124 buf_copy(exp_dirpart, tmp);
125 buf_substrcpy(dirpart, buf_string(buf), p + 1);
126 buf_strcpy(filepart, p + 1);
127 }
128 else
129 {
130 buf_strcpy(filepart, buf_string(buf) + 1);
131 }
133 }
134 else
135 {
136 p = strrchr(buf_string(buf), '/');
137 if (p)
138 {
139 if (p == buf_string(buf)) /* absolute path */
140 {
141 p = buf_string(buf) + 1;
142 buf_strcpy(dirpart, "/");
143 buf_strcpy(filepart, p);
145 }
146 else
147 {
148 buf_substrcpy(dirpart, buf_string(buf), p);
149 buf_strcpy(filepart, p + 1);
150 buf_copy(exp_dirpart, dirpart);
151 expand_path(exp_dirpart, false);
153 }
154 }
155 else
156 {
157 /* no directory name, so assume current directory. */
158 buf_strcpy(filepart, buf_string(buf));
160 }
161 }
162
163 if (!dir)
164 {
165 mutt_debug(LL_DEBUG1, "%s: %s (errno %d)\n", buf_string(exp_dirpart),
166 strerror(errno), errno);
167 goto cleanup;
168 }
169
170 /* special case to handle when there is no filepart yet. find the first
171 * file/directory which is not "." or ".." */
172 len = buf_len(filepart);
173 if (len == 0)
174 {
175 while ((de = readdir(dir)))
176 {
177 if (!mutt_str_equal(".", de->d_name) && !mutt_str_equal("..", de->d_name))
178 {
179 buf_strcpy(filepart, de->d_name);
180 init++;
181 break;
182 }
183 }
184 }
185
186 while ((de = readdir(dir)))
187 {
188 if (mutt_strn_equal(de->d_name, buf_string(filepart), len))
189 {
190 if (init)
191 {
192 char *cp = filepart->data;
193
194 for (int i = 0; (*cp != '\0') && (de->d_name[i] != '\0'); i++, cp++)
195 {
196 if (*cp != de->d_name[i])
197 break;
198 }
199 *cp = '\0';
200 buf_fix_dptr(filepart);
201 }
202 else
203 {
204 struct stat st = { 0 };
205
206 buf_strcpy(filepart, de->d_name);
207
208 /* check to see if it is a directory */
209 if (buf_is_empty(dirpart))
210 {
211 buf_reset(tmp);
212 }
213 else
214 {
215 buf_copy(tmp, exp_dirpart);
216 buf_addch(tmp, '/');
217 }
218 buf_addstr(tmp, buf_string(filepart));
219 if ((stat(buf_string(tmp), &st) != -1) && (st.st_mode & S_IFDIR))
220 buf_addch(filepart, '/');
221 init = 1;
222 }
223 }
224 }
225 closedir(dir);
226
227 if (buf_is_empty(dirpart))
228 {
229 buf_copy(buf, filepart);
230 }
231 else
232 {
233 buf_copy(buf, dirpart);
234 if (!mutt_str_equal("/", buf_string(dirpart)) &&
235 (buf_string(dirpart)[0] != '=') && (buf_string(dirpart)[0] != '+'))
236 {
237 buf_addstr(buf, "/");
238 }
239 buf_addstr(buf, buf_string(filepart));
240 }
241
242cleanup:
243 buf_pool_release(&dirpart);
244 buf_pool_release(&exp_dirpart);
245 buf_pool_release(&filepart);
246 buf_pool_release(&tmp);
247
248 return init ? 0 : -1;
249}
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:668
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:49
DIR * mutt_file_opendir(const char *path, enum MuttOpenDirMode mode)
Open a directory.
Definition file.c:535
@ MUTT_OPENDIR_NONE
Plain opendir()
Definition file.h:63
bool OptNews
(pseudo) used to change reader mode
Definition globals.c:53
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
enum MailboxType imap_path_probe(const char *path, const struct stat *st)
Is this an IMAP Mailbox?
Definition imap.c:2546
int imap_complete(struct Buffer *buf, const char *path)
Try to complete an IMAP folder path.
Definition imap.c:1462
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:46
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:665
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:429
void expand_path(struct Buffer *buf, bool regex)
Create the canonical path.
Definition muttlib.c:122
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:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
#define NONULL(x)
Definition string2.h:44
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 368 of file helpers.c.

369{
370 char *pt = buf->data;
371
372 struct Mailbox *m_cur = get_current_mailbox();
373 if (!m_cur || !m_cur->label_hash)
374 return 0;
375
376 SKIPWS(pt);
377
378 /* first TAB. Collect all the matches */
379 if (numtabs == 1)
380 {
381 struct HashElem *he = NULL;
382 struct HashWalkState hws = { 0 };
383
384 cd->num_matched = 0;
385 mutt_str_copy(cd->user_typed, buf_string(buf), sizeof(cd->user_typed));
386 memset(cd->match_list, 0, cd->match_list_len * sizeof(const char *));
387 memset(cd->completed, 0, sizeof(cd->completed));
388 while ((he = mutt_hash_walk(m_cur->label_hash, &hws)))
389 candidate(cd, cd->user_typed, he->key.strkey, cd->completed, sizeof(cd->completed));
391 mutt_qsort_r(cd->match_list, cd->num_matched, sizeof(char *), label_sort, NULL);
392 cd->match_list[cd->num_matched++] = cd->user_typed;
393
394 /* All matches are stored. Longest non-ambiguous string is ""
395 * i.e. don't change 'buf'. Fake successful return this time */
396 if (cd->user_typed[0] == '\0')
397 return 1;
398 }
399
400 if ((cd->completed[0] == '\0') && (cd->user_typed[0] != '\0'))
401 return 0;
402
403 /* cd->num_matched will _always_ be at least 1 since the initial
404 * user-typed string is always stored */
405 if ((numtabs == 1) && (cd->num_matched == 2))
406 {
407 snprintf(cd->completed, sizeof(cd->completed), "%s", cd->match_list[0]);
408 }
409 else if ((numtabs > 1) && (cd->num_matched > 2))
410 {
411 /* cycle through all the matches */
412 snprintf(cd->completed, sizeof(cd->completed), "%s",
413 cd->match_list[(numtabs - 2) % cd->num_matched]);
414 }
415
416 /* return the completed label */
417 buf_strcpy(buf, cd->completed);
418
419 return 1;
420}
static int label_sort(const void *a, const void *b, void *sdata)
Compare two label strings - Implements sort_t -.
Definition helpers.c:355
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:491
struct Mailbox * get_current_mailbox(void)
Get the current Mailbox.
Definition index.c:721
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:72
union HashKey key
Key representing the data.
Definition hash.h:46
Cursor to iterate through a Hash Table.
Definition hash.h:134
A mailbox.
Definition mailbox.h:78
struct HashTable * label_hash
Hash Table: "X-Label" -> Email.
Definition mailbox.h:124
const char * strkey
String key.
Definition hash.h:36
+ 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:799
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 430 of file helpers.c.

431{
432 char *pt = buf->data;
433
434 if (pt[0] == '\0')
435 return 0;
436
437 SKIPWS(pt);
438 const int spaces = pt - buf->data;
439
440 pt = buf->data + pos - spaces;
441 while ((pt > buf->data) && !mutt_isspace(*pt))
442 pt--;
443 pt++; /* move past the space */
444 if (*pt == '=') /* abort if no var before the '=' */
445 return 0;
446
447 if (buf_startswith(buf, "set"))
448 {
449 char var[256] = { 0 };
450 mutt_str_copy(var, pt, sizeof(var));
451 /* ignore the trailing '=' when comparing */
452 int vlen = mutt_str_len(var);
453 if (vlen == 0)
454 return 0;
455
456 var[vlen - 1] = '\0';
457
458 struct HashElem *he = cs_subset_lookup(NeoMutt->sub, var);
459 if (!he)
460 return 0; /* no such variable. */
461
462 struct Buffer *value = buf_pool_get();
463 struct Buffer *pretty = buf_pool_get();
464 int rc = cs_subset_he_string_get(NeoMutt->sub, he, value);
465 if (CSR_RESULT(rc) == CSR_SUCCESS)
466 {
467 pretty_var(value->data, pretty);
468 snprintf(pt, buf->dsize - (pt - buf->data), "%s=%s", var, pretty->data);
469 buf_pool_release(&value);
470 buf_pool_release(&pretty);
471 return 0;
472 }
473 buf_pool_release(&value);
474 buf_pool_release(&pretty);
475 return 1;
476 }
477 return 0;
478}
size_t pretty_var(const char *str, struct Buffer *buf)
Escape and stringify a config item value.
Definition dump.c:87
#define CSR_RESULT(x)
Extract the result code from CSR_* flags.
Definition set.h:53
#define CSR_SUCCESS
Action completed successfully.
Definition set.h:33
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:338
struct HashElem * cs_subset_lookup(const struct ConfigSubset *sub, const char *name)
Find an inherited config item.
Definition subset.c:193
+ 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, const char *);
62 memset(&cd->match_list[cd->match_list_len], 0,
63 (new_size - cd->match_list_len) * sizeof(const char *));
64
65 cd->match_list_len = new_size;
66}
#define ROUND_UP(NUM, STEP)
Round up NUM to the nearest multiple of STEP.
Definition memory.h:46
#define MUTT_MEM_REALLOC(pptr, n, type)
Definition memory.h:55
+ 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 79 of file helpers.c.

80{
81 if (!dest || !user || !src)
82 return false;
83
84 if (strstr(src, user) != src)
85 return false;
86
88 cd->match_list[cd->num_matched++] = src;
89 if (dest[0] == '\0')
90 {
91 mutt_str_copy(dest, src, dlen);
92 }
93 else
94 {
95 int l;
96 for (l = 0; (src[l] != '\0') && (src[l] == dest[l]); l++)
97 ; // do nothing
98
99 dest[l] = '\0';
100 }
101 return true;
102}
+ 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 534 of file helpers.c.

534 {
535 .complete = complete_command,
536};
enum FunctionRetval complete_command(struct EnterWindowData *wdata, int op)
Complete a NeoMutt Command - Implements CompleteOps::complete() -.
Definition helpers.c:483

◆ CompleteLabelOps

const struct CompleteOps CompleteLabelOps
extern

Auto-Completion of Labels.

Definition at line 541 of file helpers.c.

541 {
542 .complete = complete_label,
543};
enum FunctionRetval complete_label(struct EnterWindowData *wdata, int op)
Complete a label - Implements CompleteOps::complete() -.
Definition helpers.c:508