NeoMutt  2023-11-03-107-g582dc1
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
lib.h File Reference

Auto-completion. More...

#include <stddef.h>
#include <stdbool.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 pos, 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

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 110 of file helpers.c.

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

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

310{
311 char *pt = buf->data;
312
313 struct Mailbox *m_cur = get_current_mailbox();
314 if (!m_cur || !m_cur->label_hash)
315 return 0;
316
317 SKIPWS(pt);
318
319 /* first TAB. Collect all the matches */
320 if (numtabs == 1)
321 {
322 struct HashElem *he = NULL;
323 struct HashWalkState hws = { 0 };
324
325 cd->num_matched = 0;
326 mutt_str_copy(cd->user_typed, buf_string(buf), sizeof(cd->user_typed));
327 memset(cd->match_list, 0, cd->match_list_len);
328 memset(cd->completed, 0, sizeof(cd->completed));
329 while ((he = mutt_hash_walk(m_cur->label_hash, &hws)))
330 candidate(cd, cd->user_typed, he->key.strkey, cd->completed, sizeof(cd->completed));
332 mutt_qsort_r(cd->match_list, cd->num_matched, sizeof(char *), label_sort, NULL);
333 cd->match_list[cd->num_matched++] = cd->user_typed;
334
335 /* All matches are stored. Longest non-ambiguous string is ""
336 * i.e. don't change 'buf'. Fake successful return this time */
337 if (cd->user_typed[0] == '\0')
338 return 1;
339 }
340
341 if ((cd->completed[0] == '\0') && (cd->user_typed[0] != '\0'))
342 return 0;
343
344 /* cd->num_matched will _always_ be at least 1 since the initial
345 * user-typed string is always stored */
346 if ((numtabs == 1) && (cd->num_matched == 2))
347 {
348 snprintf(cd->completed, sizeof(cd->completed), "%s", cd->match_list[0]);
349 }
350 else if ((numtabs > 1) && (cd->num_matched > 2))
351 {
352 /* cycle through all the matches */
353 snprintf(cd->completed, sizeof(cd->completed), "%s",
354 cd->match_list[(numtabs - 2) % cd->num_matched]);
355 }
356
357 /* return the completed label */
358 buf_strcpy(buf, cd->completed);
359
360 return 1;
361}
static int label_sort(const void *a, const void *b, void *sdata)
Compare two label strings - Implements sort_t -.
Definition: helpers.c:296
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:662
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:66
Cursor to iterate through a Hash Table.
Definition: hash.h:133
A mailbox.
Definition: mailbox.h:79
struct HashTable * label_hash
Hash Table: "x-labels" -> Email.
Definition: mailbox.h:124
+ 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  pos,
int  numtabs 
)

Complete to the nearest notmuch tag.

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

Complete the nearest "tag:"-prefixed string previous to pos.

Definition at line 102 of file complete.c.

103{
104 char *pt = buf->data;
105 int spaces;
106
107 SKIPWS(pt);
108 spaces = pt - buf->data;
109
110 pt = (char *) mutt_strn_rfind((char *) buf, pos, "tag:");
111 if (pt)
112 {
113 pt += 4;
114 if (numtabs == 1)
115 {
116 /* First TAB. Collect all the matches */
117 complete_all_nm_tags(cd, pt);
118
119 /* All matches are stored. Longest non-ambiguous string is ""
120 * i.e. don't change 'buf'. Fake successful return this time. */
121 if (cd->user_typed[0] == '\0')
122 return true;
123 }
124
125 if ((cd->completed[0] == '\0') && (cd->user_typed[0] != '\0'))
126 return false;
127
128 /* cd->num_matched will _always_ be at least 1 since the initial
129 * user-typed string is always stored */
130 if ((numtabs == 1) && (cd->num_matched == 2))
131 {
132 snprintf(cd->completed, sizeof(cd->completed), "%s", cd->match_list[0]);
133 }
134 else if ((numtabs > 1) && (cd->num_matched > 2))
135 {
136 /* cycle through all the matches */
137 snprintf(cd->completed, sizeof(cd->completed), "%s",
138 cd->match_list[(numtabs - 2) % cd->num_matched]);
139 }
140
141 /* return the completed query */
142 strncpy(pt, cd->completed, buf->data + buf->dsize - pt - spaces);
143 }
144 else
145 {
146 return false;
147 }
148
149 return true;
150}
const char * mutt_strn_rfind(const char *haystack, size_t haystack_length, const char *needle)
Find last instance of a substring.
Definition: string.c:791
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 162 of file complete.c.

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

372{
373 char *pt = buf->data;
374
375 if (pt[0] == '\0')
376 return 0;
377
378 SKIPWS(pt);
379 const int spaces = pt - buf->data;
380
381 pt = buf->data + pos - spaces;
382 while ((pt > buf->data) && !isspace((unsigned char) *pt))
383 pt--;
384 pt++; /* move past the space */
385 if (*pt == '=') /* abort if no var before the '=' */
386 return 0;
387
388 if (buf_startswith(buf, "set"))
389 {
390 char var[256] = { 0 };
391 mutt_str_copy(var, pt, sizeof(var));
392 /* ignore the trailing '=' when comparing */
393 int vlen = mutt_str_len(var);
394 if (vlen == 0)
395 return 0;
396
397 var[vlen - 1] = '\0';
398
399 struct HashElem *he = cs_subset_lookup(NeoMutt->sub, var);
400 if (!he)
401 return 0; /* no such variable. */
402
403 struct Buffer *value = buf_pool_get();
404 struct Buffer *pretty = buf_pool_get();
405 int rc = cs_subset_he_string_get(NeoMutt->sub, he, value);
406 if (CSR_RESULT(rc) == CSR_SUCCESS)
407 {
408 pretty_var(value->data, pretty);
409 snprintf(pt, buf->dsize - (pt - buf->data), "%s=%s", var, pretty->data);
410 buf_pool_release(&value);
411 buf_pool_release(&pretty);
412 return 0;
413 }
414 buf_pool_release(&value);
415 buf_pool_release(&pretty);
416 return 1;
417 }
418 return 0;
419}
size_t pretty_var(const char *str, struct Buffer *buf)
Escape and stringify a config item value.
Definition: dump.c:83
#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:353
struct HashElem * cs_subset_lookup(const struct ConfigSubset *sub, const char *name)
Find an inherited config item.
Definition: subset.c:178
+ 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 52 of file helpers.c.

53{
54 if (new_size <= (cd->match_list_len - 2))
55 return;
56
57 new_size = ROUND_UP(new_size + 2, 512);
58
59 mutt_mem_realloc(&cd->match_list, new_size * sizeof(char *));
60 memset(&cd->match_list[cd->match_list_len], 0, new_size - cd->match_list_len);
61
62 cd->match_list_len = new_size;
63}
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
#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 76 of file helpers.c.

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

◆ CompleteLabelOps

const struct CompleteOps CompleteLabelOps
extern

Auto-Completion of Labels.

Definition at line 482 of file helpers.c.