NeoMutt  2024-10-02-34-g9dd811
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
complete.c
Go to the documentation of this file.
1
29#include "config.h"
30#include <stdbool.h>
31#include <stdio.h>
32#include <string.h>
33#include "mutt/lib.h"
34#include "core/lib.h"
35#include "gui/lib.h"
36#include "complete/lib.h"
37#include "editor/lib.h"
38#include "index/lib.h"
39#include "notmuch/lib.h"
40
48int complete_all_nm_tags(struct CompletionData *cd, const char *pt)
49{
50 struct Mailbox *m_cur = get_current_mailbox();
51 int tag_count_1 = 0;
52 int tag_count_2 = 0;
53 int rc = -1;
54
55 mutt_str_copy(cd->user_typed, pt, sizeof(cd->user_typed));
56 memset(cd->match_list, 0, cd->match_list_len);
57 memset(cd->completed, 0, sizeof(cd->completed));
58 cd->free_match_strings = true;
59
60 nm_db_longrun_init(m_cur, false);
61
62 /* Work out how many tags there are. */
63 if ((nm_get_all_tags(m_cur, NULL, &tag_count_1) != 0) || (tag_count_1 == 0))
64 goto done;
65
66 /* Get all the tags. */
67 const char **nm_tags = mutt_mem_calloc(tag_count_1, sizeof(char *));
68 if ((nm_get_all_tags(m_cur, nm_tags, &tag_count_2) != 0) || (tag_count_1 != tag_count_2))
69 {
71 goto done;
72 }
73
74 /* Put them into the completion machinery. */
75 for (int i = 0; i < tag_count_1; i++)
76 {
77 if (!candidate(cd, cd->user_typed, nm_tags[i], cd->completed, sizeof(cd->completed)))
78 FREE(&nm_tags[i]);
79 }
80
83 rc = 0;
84
85done:
86 FREE(&nm_tags);
87 nm_db_longrun_done(m_cur);
88 return rc;
89}
90
101bool mutt_nm_query_complete(struct CompletionData *cd, struct Buffer *buf, int numtabs)
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}
150
161bool mutt_nm_tag_complete(struct CompletionData *cd, struct Buffer *buf, int numtabs)
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}
209
214{
215 if (!wdata || ((op != OP_EDITOR_COMPLETE) && (op != OP_EDITOR_COMPLETE_QUERY)))
216 return FR_NO_ACTION;
217
218 int rc = FR_SUCCESS;
219 buf_mb_wcstombs(wdata->buffer, wdata->state->wbuf, wdata->state->curpos);
220 if (!mutt_nm_query_complete(wdata->cd, wdata->buffer, wdata->tabs))
221 rc = FR_ERROR;
222
223 replace_part(wdata->state, 0, buf_string(wdata->buffer));
224 return rc;
225}
226
231{
232 if (!wdata || ((op != OP_EDITOR_COMPLETE) && (op != OP_EDITOR_COMPLETE_QUERY)))
233 return FR_NO_ACTION;
234
235 int rc = FR_SUCCESS;
236 buf_mb_wcstombs(wdata->buffer, wdata->state->wbuf, wdata->state->curpos);
237 if (!mutt_nm_tag_complete(wdata->cd, wdata->buffer, wdata->tabs))
238 rc = FR_ERROR;
239
240 replace_part(wdata->state, 0, buf_string(wdata->buffer));
241 return rc;
242}
243
249};
250
256};
const char * buf_rfind(const struct Buffer *buf, const char *str)
Find last instance of a substring.
Definition: buffer.c:797
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:96
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
Auto-completion.
Convenience wrapper for the core headers.
void completion_data_free_match_strings(struct CompletionData *cd)
Free the Completion strings.
Definition: data.c:38
FunctionRetval
Possible return values for NeoMutt functions.
Definition: dispatcher.h:32
@ FR_SUCCESS
Valid function - successfully performed.
Definition: dispatcher.h:39
@ FR_ERROR
Valid function - error occurred.
Definition: dispatcher.h:38
@ FR_NO_ACTION
Valid function - no action performed.
Definition: dispatcher.h:37
void replace_part(struct EnterState *es, size_t from, const char *buf)
Search and replace on a buffer.
Definition: functions.c:132
Edit a string.
enum FunctionRetval complete_nm_query(struct EnterWindowData *wdata, int op)
Complete a Notmuch Query - Implements CompleteOps::complete() -.
Definition: complete.c:213
enum FunctionRetval complete_nm_tag(struct EnterWindowData *wdata, int op)
Complete a Notmuch Tag - Implements CompleteOps::complete() -.
Definition: complete.c:230
Convenience wrapper for the gui headers.
GUI manage the main index (list of emails)
struct Mailbox * get_current_mailbox(void)
Get the current Mailbox.
Definition: index.c:715
void buf_mb_wcstombs(struct Buffer *dest, const wchar_t *wstr, size_t wlen)
Convert a string from wide to multibyte characters.
Definition: mbyte.c:256
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:51
#define FREE(x)
Definition: memory.h:45
Convenience wrapper for the library headers.
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:253
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
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
bool mutt_nm_query_complete(struct CompletionData *cd, struct Buffer *buf, int numtabs)
Complete to the nearest notmuch tag.
Definition: complete.c:101
const struct CompleteOps CompleteNmTagOps
Auto-Completion of NmTags.
Definition: complete.c:254
bool mutt_nm_tag_complete(struct CompletionData *cd, struct Buffer *buf, int numtabs)
Complete to the nearest notmuch tag.
Definition: complete.c:161
const struct CompleteOps CompleteNmQueryOps
Auto-Completion of NmQuerys.
Definition: complete.c:247
void nm_db_longrun_done(struct Mailbox *m)
Finish a long transaction.
Definition: db.c:379
void nm_db_longrun_init(struct Mailbox *m, bool writable)
Start a long transaction.
Definition: db.c:364
Notmuch virtual mailbox type.
int nm_get_all_tags(struct Mailbox *m, const char **tag_list, int *tag_count)
Fill a list with all notmuch tags.
Definition: notmuch.c:1979
#define SKIPWS(ch)
Definition: string2.h:45
String manipulation buffer.
Definition: buffer.h:36
size_t dsize
Length of data.
Definition: buffer.h:39
char * data
Pointer to data.
Definition: buffer.h:37
enum FunctionRetval(* complete)(struct EnterWindowData *wdata, int op)
Definition: compapi.h:46
State data for auto-completion.
Definition: data.h:33
int match_list_len
Enough space for all of the config items.
Definition: data.h:38
bool free_match_strings
Should the strings in match_list be freed?
Definition: data.h:39
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
size_t curpos
Position of the cursor.
Definition: state.h:36
wchar_t * wbuf
Buffer for the string being entered.
Definition: state.h:33
Data to fill the Enter Window.
Definition: wdata.h:46
int tabs
Number of times the user has hit tab.
Definition: wdata.h:63
struct CompletionData * cd
Auto-completion state data.
Definition: wdata.h:67
struct Buffer * buffer
struct Buffer for the result
Definition: wdata.h:48
struct EnterState * state
Current state of text entry.
Definition: wdata.h:50
A mailbox.
Definition: mailbox.h:79