NeoMutt  2025-12-11-435-g4ac674
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 "type.h"
45
46extern char *SearchBuffers[];
47
48#define MUTT_SEARCH_UP 1
49#define MUTT_SEARCH_DOWN 2
50
58static int search(struct Menu *menu, int op)
59{
60 int rc = -1;
61 int wrap = 0;
62 int search_dir;
63 regex_t re = { 0 };
64 struct Buffer *buf = buf_pool_get();
65
66 char *search_buf = (menu->md && (menu->md->id < MENU_MAX)) ?
67 SearchBuffers[menu->md->id] :
68 NULL;
69
70 if (!(search_buf && *search_buf) || ((op != OP_SEARCH_NEXT) && (op != OP_SEARCH_OPPOSITE)))
71 {
72 buf_strcpy(buf, search_buf && (search_buf[0] != '\0') ? search_buf : "");
73 if ((mw_get_field(((op == OP_SEARCH) || (op == OP_SEARCH_NEXT)) ? _("Search for: ") : _("Reverse search for: "),
74 buf, MUTT_COMP_CLEAR, HC_OTHER, NULL, NULL) != 0) ||
75 buf_is_empty(buf))
76 {
77 goto done;
78 }
79 if (menu->md && (menu->md->id < MENU_MAX))
80 {
82 search_buf = SearchBuffers[menu->md->id];
83 }
84 menu->search_dir = ((op == OP_SEARCH) || (op == OP_SEARCH_NEXT)) ?
87 }
88
89 search_dir = (menu->search_dir == MUTT_SEARCH_UP) ? -1 : 1;
90 if (op == OP_SEARCH_OPPOSITE)
91 search_dir = -search_dir;
92
93 if (search_buf)
94 {
95 uint16_t flags = mutt_mb_is_lower(search_buf) ? REG_ICASE : 0;
96 rc = REG_COMP(&re, search_buf, REG_NOSUB | flags);
97 }
98
99 if (rc != 0)
100 {
101 regerror(rc, &re, buf->data, buf->dsize);
102 mutt_error("%s", buf_string(buf));
103 rc = -1;
104 goto done;
105 }
106
107 rc = menu->current + search_dir;
108search_next:
109 if (wrap)
110 mutt_message(_("Search wrapped to top"));
111 while ((rc >= 0) && (rc < menu->max))
112 {
113 if (menu->search(menu, &re, rc) == 0)
114 {
115 regfree(&re);
116 goto done;
117 }
118
119 rc += search_dir;
120 }
121
122 const bool c_wrap_search = cs_subset_bool(menu->sub, "wrap_search");
123 if (c_wrap_search && (wrap++ == 0))
124 {
125 rc = (search_dir == 1) ? 0 : menu->max - 1;
126 goto search_next;
127 }
128 regfree(&re);
129 mutt_error(_("Not found"));
130 rc = -1;
131
132done:
133 buf_pool_release(&buf);
134 return rc;
135}
136
137// -----------------------------------------------------------------------------
138
142static int menu_movement(struct Menu *menu, const struct KeyEvent *event)
143{
144 switch (event->op)
145 {
146 case OP_BOTTOM_PAGE:
147 menu_bottom_page(menu);
148 return FR_SUCCESS;
149
150 case OP_CURRENT_BOTTOM:
152 return FR_SUCCESS;
153
154 case OP_CURRENT_MIDDLE:
156 return FR_SUCCESS;
157
158 case OP_CURRENT_TOP:
159 menu_current_top(menu);
160 return FR_SUCCESS;
161
162 case OP_FIRST_ENTRY:
163 menu_first_entry(menu);
164 return FR_SUCCESS;
165
166 case OP_HALF_DOWN:
167 menu_half_down(menu);
168 return FR_SUCCESS;
169
170 case OP_HALF_UP:
171 menu_half_up(menu);
172 return FR_SUCCESS;
173
174 case OP_LAST_ENTRY:
175 menu_last_entry(menu);
176 return FR_SUCCESS;
177
178 case OP_MIDDLE_PAGE:
179 menu_middle_page(menu);
180 return FR_SUCCESS;
181
182 case OP_NEXT_ENTRY:
183 menu_next_entry(menu);
184 return FR_SUCCESS;
185
186 case OP_NEXT_LINE:
187 menu_next_line(menu);
188 return FR_SUCCESS;
189
190 case OP_NEXT_PAGE:
191 menu_next_page(menu);
192 return FR_SUCCESS;
193
194 case OP_PREV_ENTRY:
195 menu_prev_entry(menu);
196 return FR_SUCCESS;
197
198 case OP_PREV_LINE:
199 menu_prev_line(menu);
200 return FR_SUCCESS;
201
202 case OP_PREV_PAGE:
203 menu_prev_page(menu);
204 return FR_SUCCESS;
205
206 case OP_TOP_PAGE:
207 menu_top_page(menu);
208 return FR_SUCCESS;
209
210 default:
211 return FR_UNKNOWN;
212 }
213}
214
218static int menu_search(struct Menu *menu, const struct KeyEvent *event)
219{
220 if (menu->search)
221 {
222 int index = search(menu, event->op);
223 if (index != -1)
224 menu_set_index(menu, index);
225 }
226 return FR_SUCCESS;
227}
228
232static int op_help(struct Menu *menu, const struct KeyEvent *event)
233{
234 mutt_help(menu->md);
235 menu->redraw = MENU_REDRAW_FULL;
236 return FR_SUCCESS;
237}
238
242static int op_jump(struct Menu *menu, const struct KeyEvent *event)
243{
244 if (menu->max == 0)
245 {
246 mutt_error(_("No entries"));
247 return FR_SUCCESS;
248 }
249
250 const int digit = event->op - OP_JUMP;
251 if ((digit > 0) && (digit < 10))
252 {
253 mutt_unget_ch('0' + digit);
254 }
255
256 struct Buffer *buf = buf_pool_get();
257 if ((mw_get_field(_("Jump to: "), buf, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) == 0) &&
258 !buf_is_empty(buf))
259 {
260 int n = 0;
261 if (mutt_str_atoi_full(buf_string(buf), &n) && (n > 0) && (n < (menu->max + 1)))
262 {
263 menu_set_index(menu, n - 1); // msg numbers are 0-based
264 }
265 else
266 {
267 mutt_error(_("Invalid index number"));
268 }
269 }
270
271 buf_pool_release(&buf);
272 return FR_SUCCESS;
273}
274
275// -----------------------------------------------------------------------------
276
280static const struct MenuFunction MenuFunctions[] = {
281 // clang-format off
282 { OP_BOTTOM_PAGE, menu_movement },
283 { OP_CURRENT_BOTTOM, menu_movement },
284 { OP_CURRENT_MIDDLE, menu_movement },
285 { OP_CURRENT_TOP, menu_movement },
286 { OP_FIRST_ENTRY, menu_movement },
287 { OP_HALF_DOWN, menu_movement },
288 { OP_HALF_UP, menu_movement },
289 { OP_HELP, op_help },
290 { OP_JUMP, op_jump },
291 { OP_JUMP_1, op_jump },
292 { OP_JUMP_2, op_jump },
293 { OP_JUMP_3, op_jump },
294 { OP_JUMP_4, op_jump },
295 { OP_JUMP_5, op_jump },
296 { OP_JUMP_6, op_jump },
297 { OP_JUMP_7, op_jump },
298 { OP_JUMP_8, op_jump },
299 { OP_JUMP_9, op_jump },
300 { OP_LAST_ENTRY, menu_movement },
301 { OP_MIDDLE_PAGE, menu_movement },
302 { OP_NEXT_ENTRY, menu_movement },
303 { OP_NEXT_LINE, menu_movement },
304 { OP_NEXT_PAGE, menu_movement },
305 { OP_PREV_ENTRY, menu_movement },
306 { OP_PREV_LINE, menu_movement },
307 { OP_PREV_PAGE, menu_movement },
308 { OP_SEARCH, menu_search },
309 { OP_SEARCH_NEXT, menu_search },
310 { OP_SEARCH_OPPOSITE, menu_search },
311 { OP_SEARCH_REVERSE, menu_search },
312 { OP_TOP_PAGE, menu_movement },
313 { 0, NULL },
314 // clang-format on
315};
316
320int menu_function_dispatcher(struct MuttWindow *win, const struct KeyEvent *event)
321{
322 if (!event || !win || !win->wdata)
323 return FR_UNKNOWN;
324
325 const int op = event->op;
326 struct Menu *menu = win->wdata;
327
328 int rc = FR_UNKNOWN;
329 for (size_t i = 0; MenuFunctions[i].op != OP_NULL; i++)
330 {
331 const struct MenuFunction *fn = &MenuFunctions[i];
332 if (fn->op == op)
333 {
334 rc = fn->function(menu, event);
335 break;
336 }
337 }
338
339 if (rc == FR_UNKNOWN) // Not our function
340 return rc;
341
342 const char *result = dispatcher_get_retval_name(rc);
343 mutt_debug(LL_DEBUG1, "Handled %s (%d) -> %s\n", opcodes_get_name(op), op, NONULL(result));
344
345 return rc;
346}
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.
int digit(const char *s)
const char * dispatcher_get_retval_name(int rv)
Get the name of a return value.
Definition dispatcher.c:54
@ FR_SUCCESS
Valid function - successfully performed.
Definition dispatcher.h:40
@ FR_UNKNOWN
Unknown function.
Definition dispatcher.h:34
Edit a string.
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition wdata.h:42
#define MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition wdata.h:43
void mutt_unget_ch(int ch)
Return a keystroke to the input buffer.
Definition get.c:122
int menu_function_dispatcher(struct MuttWindow *win, const struct KeyEvent *event)
Perform a Menu function - Implements function_dispatcher_t -.
Definition functions.c:320
static int op_help(struct EnterWindowData *wdata, const struct KeyEvent *event)
Display Help - Implements enter_function_t -.
Definition functions.c:452
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:270
static int op_jump(struct IndexSharedData *shared, struct IndexPrivateData *priv, const struct KeyEvent *event)
Jump to an index number - Implements index_function_t -.
Definition functions.c:919
#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 Menu *menu, const struct KeyEvent *event)
Handle Menu searching - Implements menu_function_t -.
Definition functions.c:218
static int menu_movement(struct Menu *menu, const struct KeyEvent *event)
Handle all the common Menu movements - Implements menu_function_t -.
Definition functions.c:142
Convenience wrapper for the gui headers.
void mutt_help(const struct MenuDefinition *md)
Display the Help Page.
Definition help.c:147
Read/write command history from/to a file.
@ HC_OTHER
Miscellaneous strings.
Definition lib.h:60
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:49
#define MUTT_SEARCH_UP
Definition functions.c:48
static const struct MenuFunction MenuFunctions[]
All the NeoMutt functions that the Menu supports.
Definition functions.c:280
char * SearchBuffers[]
Previous search string, one for each MenuType.
Definition menu.c:45
static int search(struct Menu *menu, int op)
Search a menu.
Definition functions.c:58
Menu functions.
GUI present the user with a selectable list.
#define MENU_REDRAW_FULL
Redraw everything.
Definition lib.h:60
MenuRedrawFlags menu_next_page(struct Menu *menu)
Move the focus to the next page in the menu.
Definition move.c:565
MenuRedrawFlags menu_bottom_page(struct Menu *menu)
Move the focus to the bottom of the page.
Definition move.c:366
MenuRedrawFlags menu_half_up(struct Menu *menu)
Move the focus up half a page in the menu.
Definition move.c:509
MenuRedrawFlags menu_prev_line(struct Menu *menu)
Move the view up one line, keeping the selection the same.
Definition move.c:529
MenuRedrawFlags menu_current_bottom(struct Menu *menu)
Move the current selection to the bottom of the window.
Definition move.c:487
MenuRedrawFlags menu_current_middle(struct Menu *menu)
Move the current selection to the centre of the window.
Definition move.c:467
MenuRedrawFlags menu_middle_page(struct Menu *menu)
Move the focus to the centre of the page.
Definition move.c:346
MenuRedrawFlags menu_first_entry(struct Menu *menu)
Move the focus to the first entry in the menu.
Definition move.c:413
MenuRedrawFlags menu_half_down(struct Menu *menu)
Move the focus down half a page in the menu.
Definition move.c:519
MenuRedrawFlags menu_top_page(struct Menu *menu)
Move the focus to the top of the page.
Definition move.c:336
MenuRedrawFlags menu_last_entry(struct Menu *menu)
Move the focus to the last entry in the menu.
Definition move.c:429
MenuRedrawFlags menu_prev_page(struct Menu *menu)
Move the focus to the previous page in the menu.
Definition move.c:555
MenuRedrawFlags menu_next_line(struct Menu *menu)
Move the view down one line, keeping the selection the same.
Definition move.c:542
MenuRedrawFlags menu_prev_entry(struct Menu *menu)
Move the focus to the previous item in the menu.
Definition move.c:385
MenuRedrawFlags menu_current_top(struct Menu *menu)
Move the current selection to the top of the window.
Definition move.c:446
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition menu.c:178
MenuRedrawFlags menu_next_entry(struct Menu *menu)
Move the focus to the next item in the menu.
Definition move.c:399
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.
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:50
int op
Function opcode, e.g. OP_HELP.
Definition get.h:52
int id
Menu ID, e.g. MENU_ALIAS.
Definition menu.h:81
A NeoMutt function.
Definition functions.h:49
menu_function_t function
Function to call.
Definition functions.h:51
int op
Op code, e.g. OP_SEARCH.
Definition functions.h:50
Definition lib.h:80
struct MuttWindow * win
Window holding the Menu.
Definition lib.h:88
int search_dir
Direction of search.
Definition lib.h:94
int current
Current entry.
Definition lib.h:81
MenuRedrawFlags redraw
When to redraw the screen.
Definition lib.h:83
int(* search)(struct Menu *menu, regex_t *rx, int line)
Definition lib.h:121
const struct MenuDefinition * md
Menu definition for keymap entries.
Definition lib.h:84
struct ConfigSubset * sub
Inherited config items.
Definition lib.h:89
int max
Number of entries in the menu.
Definition lib.h:82
void * wdata
Private data.
Menu types.
@ MENU_MAX
Definition type.h:51