NeoMutt  2025-12-11-911-gd8d604
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
functions.c
Go to the documentation of this file.
1
23
29
30#include "config.h"
31#include <stdbool.h>
32#include <stddef.h>
33#include <stdint.h>
34#include "mutt/lib.h"
35#include "config/lib.h"
36#include "core/lib.h"
37#include "gui/lib.h"
38#include "mutt.h"
39#include "functions.h"
40#include "lib.h"
41#include "editor/lib.h"
42#include "history/lib.h"
43#include "key/lib.h"
44#include "module_data.h"
45#include "type.h"
46
47#define MUTT_SEARCH_UP 1
48#define MUTT_SEARCH_DOWN 2
49
59static int search(struct Menu *menu, int op, int *match)
60{
62 int reg_rc = 0;
63 int wrap = 0;
64 int search_dir;
65 int rc = FR_ERROR;
66 regex_t re = { 0 };
67 struct Buffer *buf = buf_pool_get();
68
69 *match = -1;
70
71 char *search_buf = (menu->md && (menu->md->id < MENU_MAX)) ?
72 mod_data->search_buffers[menu->md->id] :
73 NULL;
74
75 if (!(search_buf && *search_buf) || ((op != OP_SEARCH_NEXT) && (op != OP_SEARCH_OPPOSITE)))
76 {
77 buf_strcpy(buf, search_buf && (search_buf[0] != '\0') ? search_buf : "");
78 if ((mw_get_field(((op == OP_SEARCH) || (op == OP_SEARCH_NEXT)) ? _("Search for: ") : _("Reverse search for: "),
79 buf, MUTT_COMP_CLEAR, HC_OTHER, NULL, NULL) != 0) ||
80 buf_is_empty(buf))
81 {
82 rc = FR_NO_ACTION;
83 goto done;
84 }
85 if (menu->md && (menu->md->id < MENU_MAX))
86 {
87 mutt_str_replace(&mod_data->search_buffers[menu->md->id], buf_string(buf));
88 search_buf = mod_data->search_buffers[menu->md->id];
89 }
90 menu->search_dir = ((op == OP_SEARCH) || (op == OP_SEARCH_NEXT)) ?
93 }
94
95 search_dir = (menu->search_dir == MUTT_SEARCH_UP) ? -1 : 1;
96 if (op == OP_SEARCH_OPPOSITE)
97 search_dir = -search_dir;
98
99 if (search_buf)
100 {
101 uint16_t flags = mutt_mb_is_lower(search_buf) ? REG_ICASE : 0;
102 reg_rc = REG_COMP(&re, search_buf, REG_NOSUB | flags);
103 }
104
105 if (reg_rc != 0)
106 {
107 regerror(reg_rc, &re, buf->data, buf->dsize);
108 mutt_error("%s", buf_string(buf));
109 goto done;
110 }
111
112 *match = menu->current + search_dir;
113search_next:
114 if (wrap)
115 mutt_message(_("Search wrapped to top"));
116 while ((*match >= 0) && (*match < menu->max))
117 {
118 if (menu->search(menu, &re, *match) == 0)
119 {
120 regfree(&re);
121 rc = FR_SUCCESS;
122 goto done;
123 }
124
125 *match += search_dir;
126 }
127
128 const bool c_wrap_search = cs_subset_bool(menu->sub, "wrap_search");
129 if (c_wrap_search && (wrap++ == 0))
130 {
131 *match = (search_dir == 1) ? 0 : menu->max - 1;
132 goto search_next;
133 }
134 regfree(&re);
135 mutt_error(_("Not found"));
136
137done:
138 buf_pool_release(&buf);
139 return rc;
140}
141
142// -----------------------------------------------------------------------------
143
165static int menu_movement(struct MenuFunctionData *fdata, const struct KeyEvent *event)
166{
167 struct Menu *menu = fdata->menu;
168 const int old_top = menu->top;
169 const int old_current = menu->current;
171
172 const int count = event->count;
173 switch (event->op)
174 {
175 case OP_BOTTOM_PAGE:
176 flags = menu_bottom_page(menu);
177 return (menu->max == 0) ? FR_ERROR : FR_SUCCESS;
178
179 case OP_CURRENT_BOTTOM:
180 flags = menu_current_bottom(menu);
181 return (menu->max == 0) ? FR_ERROR : FR_SUCCESS;
182
183 case OP_CURRENT_MIDDLE:
184 flags = menu_current_middle(menu);
185 return (menu->max == 0) ? FR_ERROR : FR_SUCCESS;
186
187 case OP_CURRENT_TOP:
188 flags = menu_current_top(menu);
189 return (menu->max == 0) ? FR_ERROR : FR_SUCCESS;
190
191 case OP_FIRST_ENTRY:
192 flags = menu_first_entry(menu, count);
193 return (menu->max == 0) ? FR_ERROR : FR_SUCCESS;
194
195 case OP_HALF_DOWN:
196 menu_half_down(menu, count);
197 return FR_SUCCESS;
198
199 case OP_HALF_UP:
200 menu_half_up(menu, count);
201 return FR_SUCCESS;
202
203 case OP_LAST_ENTRY:
204 flags = menu_last_entry(menu, count);
205 return (menu->max == 0) ? FR_ERROR : FR_SUCCESS;
206
207 case OP_MIDDLE_PAGE:
208 flags = menu_middle_page(menu);
209 return (menu->max == 0) ? FR_ERROR : FR_SUCCESS;
210
211 case OP_NEXT_ENTRY:
212 flags = menu_next_entry(menu, count);
213 return ((flags == MENU_REDRAW_NONE) && (menu->top == old_top) &&
214 (menu->current == old_current)) ?
215 FR_ERROR :
217
218 case OP_NEXT_LINE:
219 flags = menu_next_line(menu, count);
220 return ((flags == MENU_REDRAW_NONE) && (menu->top == old_top) &&
221 (menu->current == old_current)) ?
222 FR_ERROR :
224
225 case OP_NEXT_PAGE:
226 menu_next_page(menu, count);
227 return FR_SUCCESS;
228
229 case OP_PREV_ENTRY:
230 flags = menu_prev_entry(menu, count);
231 return ((flags == MENU_REDRAW_NONE) && (menu->top == old_top) &&
232 (menu->current == old_current)) ?
233 FR_ERROR :
235
236 case OP_PREV_LINE:
237 flags = menu_prev_line(menu, count);
238 return ((flags == MENU_REDRAW_NONE) && (menu->top == old_top) &&
239 (menu->current == old_current)) ?
240 FR_ERROR :
242
243 case OP_PREV_PAGE:
244 menu_prev_page(menu, count);
245 return FR_SUCCESS;
246
247 case OP_TOP_PAGE:
248 menu_top_page(menu);
249 return FR_SUCCESS;
250
251 default:
252 return FR_UNKNOWN;
253 }
254}
255
265static int menu_search(struct MenuFunctionData *fdata, const struct KeyEvent *event)
266{
267 struct Menu *menu = fdata->menu;
268 if (menu->search)
269 {
270 int index = -1;
271 const int rc = search(menu, event->op, &index);
272 if ((rc == FR_SUCCESS) && (index != -1))
273 menu_set_index(menu, index);
274 return rc;
275 }
276 return FR_SUCCESS;
277}
278
282static int op_help(struct MenuFunctionData *fdata, const struct KeyEvent *event)
283{
284 struct Menu *menu = fdata->menu;
285 mutt_help(menu->md);
286 menu->redraw = MENU_REDRAW_FULL;
287 return FR_SUCCESS;
288}
289
293static int op_jump(struct MenuFunctionData *fdata, const struct KeyEvent *event)
294{
295 struct Menu *menu = fdata->menu;
296 if (menu->max == 0)
297 {
298 mutt_error(_("No entries"));
299 return FR_ERROR;
300 }
301
302 struct Buffer *buf = buf_pool_get();
303 int rc = FR_ERROR;
304
305 int num = event->count;
306 if (num == 0)
307 {
308 if ((mw_get_field(_("Jump to: "), buf, MUTT_COMP_NONE, HC_OTHER, NULL, NULL) != 0) ||
309 buf_is_empty(buf))
310 {
311 rc = FR_NO_ACTION;
312 goto done;
313 }
314
315 if (!mutt_str_atoi_full(buf_string(buf), &num) || (num < 1) || (num > menu->max))
316 {
317 mutt_error(_("Invalid index number"));
318 goto done;
319 }
320 }
321
322 menu_set_index(menu, num - 1); // msg numbers are 0-based
323 rc = FR_SUCCESS;
324
325done:
326 buf_pool_release(&buf);
327 return rc;
328}
329
330// -----------------------------------------------------------------------------
331
335static const struct MenuFunction MenuFunctions[] = {
336 // clang-format off
337 { OP_BOTTOM_PAGE, menu_movement },
338 { OP_CURRENT_BOTTOM, menu_movement },
339 { OP_CURRENT_MIDDLE, menu_movement },
340 { OP_CURRENT_TOP, menu_movement },
341 { OP_FIRST_ENTRY, menu_movement },
342 { OP_HALF_DOWN, menu_movement },
343 { OP_HALF_UP, menu_movement },
344 { OP_HELP, op_help },
345 { OP_JUMP, op_jump },
346 { OP_LAST_ENTRY, menu_movement },
347 { OP_MIDDLE_PAGE, menu_movement },
348 { OP_NEXT_ENTRY, menu_movement },
349 { OP_NEXT_LINE, menu_movement },
350 { OP_NEXT_PAGE, menu_movement },
351 { OP_PREV_ENTRY, menu_movement },
352 { OP_PREV_LINE, menu_movement },
353 { OP_PREV_PAGE, menu_movement },
354 { OP_SEARCH, menu_search },
355 { OP_SEARCH_NEXT, menu_search },
356 { OP_SEARCH_OPPOSITE, menu_search },
357 { OP_SEARCH_REVERSE, menu_search },
358 { OP_TOP_PAGE, menu_movement },
359 { 0, NULL },
360 // clang-format on
361};
362
366int menu_function_dispatcher(struct MuttWindow *win, const struct KeyEvent *event)
367{
368 if (!event || !win || !win->wdata)
369 return FR_UNKNOWN;
370
371 const int op = event->op;
372 struct Menu *menu = win->wdata;
373
374 struct MenuFunctionData fdata = {
375 .n = NeoMutt,
376 .menu = menu,
377 };
378
379 int rc = FR_UNKNOWN;
380 for (size_t i = 0; MenuFunctions[i].op != OP_NULL; i++)
381 {
382 const struct MenuFunction *fn = &MenuFunctions[i];
383 if (fn->op == op)
384 {
385 rc = fn->function(&fdata, event);
386 break;
387 }
388 }
389
390 if (rc == FR_UNKNOWN) // Not our function
391 return rc;
392
393 const char *result = dispatcher_get_retval_name(rc);
394 mutt_debug(LL_DEBUG1, "Handled %s (%d) -> %s\n", opcodes_get_name(op), op, NONULL(result));
395
397 return rc;
398}
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:291
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition buffer.c:395
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
const char * dispatcher_get_retval_name(int rv)
Get the name of a return value.
Definition dispatcher.c:55
void dispatcher_flush_on_error(int rv)
Flush pending keys after a dispatch error.
Definition dispatcher.c:65
@ FR_SUCCESS
Valid function - successfully performed.
Definition dispatcher.h:40
@ FR_UNKNOWN
Unknown function.
Definition dispatcher.h:34
@ FR_ERROR
Valid function - error occurred.
Definition dispatcher.h:39
@ FR_NO_ACTION
Valid function - no action performed.
Definition dispatcher.h:38
Edit a string.
@ MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition wdata.h:47
@ MUTT_COMP_NONE
No flags are set.
Definition wdata.h:46
static int op_jump(struct AliasFunctionData *fdata, const struct KeyEvent *event)
Jump to an index number - Implements alias_function_t -.
Definition functions.c:320
int menu_function_dispatcher(struct MuttWindow *win, const struct KeyEvent *event)
Perform a Menu function - Implements function_dispatcher_t -.
Definition functions.c:366
static int op_help(struct EnterFunctionData *fdata, const struct KeyEvent *event)
Display Help - Implements enter_function_t -.
Definition functions.c:476
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition window.c:502
#define mutt_error(...)
Definition logging2.h:94
#define mutt_message(...)
Definition logging2.h:93
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
static int menu_search(struct MenuFunctionData *fdata, const struct KeyEvent *event)
Handle Menu searching - Implements menu_function_t -.
Definition functions.c:265
static int menu_movement(struct MenuFunctionData *fdata, const struct KeyEvent *event)
Handle all the common Menu movements - Implements menu_function_t -.
Definition functions.c:165
Convenience wrapper for the gui headers.
void mutt_help(const struct MenuDefinition *md)
Display the Help Page.
Definition help.c:146
Read/write command history from/to a file.
@ HC_OTHER
Miscellaneous strings.
Definition lib.h:61
Manage keymappings.
@ LL_DEBUG1
Log at debug level 1.
Definition logging2.h:45
bool mutt_mb_is_lower(const char *s)
Does a multi-byte string contain only lowercase characters?
Definition mbyte.c:355
#define MUTT_SEARCH_DOWN
Definition functions.c:48
static int search(struct Menu *menu, int op, int *match)
Search a menu.
Definition functions.c:59
#define MUTT_SEARCH_UP
Definition functions.c:47
static const struct MenuFunction MenuFunctions[]
All the NeoMutt functions that the Menu supports.
Definition functions.c:335
Menu functions.
GUI present the user with a selectable list.
MenuRedrawFlags menu_bottom_page(struct Menu *menu)
Move the focus to the bottom of the page.
Definition move.c:369
MenuRedrawFlags menu_next_page(struct Menu *menu, int count)
Move the focus to the next page in the menu.
Definition move.c:590
MenuRedrawFlags menu_prev_page(struct Menu *menu, int count)
Move the focus to the previous page in the menu.
Definition move.c:579
MenuRedrawFlags menu_current_bottom(struct Menu *menu)
Move the current selection to the bottom of the window.
Definition move.c:506
MenuRedrawFlags menu_current_middle(struct Menu *menu)
Move the current selection to the centre of the window.
Definition move.c:486
MenuRedrawFlags menu_middle_page(struct Menu *menu)
Move the focus to the centre of the page.
Definition move.c:349
MenuRedrawFlags menu_first_entry(struct Menu *menu, int count)
Move the focus to the first entry in the menu.
Definition move.c:425
uint8_t MenuRedrawFlags
Definition lib.h:66
MenuRedrawFlags menu_prev_line(struct Menu *menu, int count)
Move the view up one line, keeping the selection the same.
Definition move.c:551
MenuRedrawFlags menu_top_page(struct Menu *menu)
Move the focus to the top of the page.
Definition move.c:339
@ MENU_REDRAW_FULL
Redraw everything.
Definition lib.h:64
@ MENU_REDRAW_NONE
No flags are set.
Definition lib.h:60
MenuRedrawFlags menu_prev_entry(struct Menu *menu, int count)
Move the focus to the previous item in the menu.
Definition move.c:389
MenuRedrawFlags menu_next_line(struct Menu *menu, int count)
Move the view down one line, keeping the selection the same.
Definition move.c:565
MenuRedrawFlags menu_last_entry(struct Menu *menu, int count)
Move the focus to the last entry in the menu.
Definition move.c:445
MenuRedrawFlags menu_next_entry(struct Menu *menu, int count)
Move the focus to the next item in the menu.
Definition move.c:407
MenuRedrawFlags menu_current_top(struct Menu *menu)
Move the current selection to the top of the window.
Definition move.c:465
MenuRedrawFlags menu_half_down(struct Menu *menu, int count)
Move the focus down half a page in the menu.
Definition move.c:540
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition menu.c:169
MenuRedrawFlags menu_half_up(struct Menu *menu, int count)
Move the focus up half a page in the menu.
Definition move.c:529
Menu private Module data.
@ MODULE_ID_MENU
ModuleMenu, Menu
Definition module_api.h:77
Convenience wrapper for the library headers.
#define _(a)
Definition message.h:28
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition string.c:284
Many unsorted constants and some structs.
void * neomutt_get_module_data(struct NeoMutt *n, enum ModuleId id)
Get the private data for a Module.
Definition neomutt.c:663
const char * opcodes_get_name(int op)
Get the name of an opcode.
Definition opcodes.c:48
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 REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition regex3.h:49
#define NONULL(x)
Definition string2.h:44
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
An event such as a keypress.
Definition get.h:75
int op
Function opcode, e.g. OP_HELP.
Definition get.h:77
int id
Menu ID, e.g. MENU_ALIAS.
Definition menu.h:78
Data passed to Menu worker functions.
Definition functions.h:32
struct Menu * menu
Menu data.
Definition functions.h:34
A NeoMutt function.
Definition functions.h:56
menu_function_t function
Function to call.
Definition functions.h:58
int op
Op code, e.g. OP_SEARCH.
Definition functions.h:57
Menu private Module data.
Definition module_data.h:32
char * search_buffers[MENU_MAX]
Previous search string, one for each MenuType.
Definition module_data.h:34
Definition lib.h:86
struct MuttWindow * win
Window holding the Menu.
Definition lib.h:94
int search_dir
Direction of search.
Definition lib.h:100
int current
Current entry.
Definition lib.h:87
MenuRedrawFlags redraw
When to redraw the screen.
Definition lib.h:89
int(* search)(struct Menu *menu, regex_t *rx, int line)
Definition lib.h:127
int top
Entry that is the top of the current page.
Definition lib.h:98
const struct MenuDefinition * md
Menu definition for keymap entries.
Definition lib.h:90
struct ConfigSubset * sub
Inherited config items.
Definition lib.h:95
int max
Number of entries in the menu.
Definition lib.h:88
int old_current
For driver use only.
Definition lib.h:99
void * wdata
Private data.
Container for Accounts, Notifications.
Definition neomutt.h:41
Menu types.
@ MENU_MAX
Definition type.h:52