NeoMutt  2022-04-29-145-g9b6a0e
Teaching an old dog new tricks
DOXYGEN
functions.c
Go to the documentation of this file.
1 
29 #include "config.h"
30 #include <stddef.h>
31 #include <stdbool.h>
32 #include <stdint.h>
33 #include "mutt/lib.h"
34 #include "config/lib.h"
35 #include "core/lib.h"
36 #include "gui/lib.h"
37 #include "mutt.h"
38 #include "functions.h"
39 #include "lib.h"
40 #include "enter/lib.h"
41 #include "opcodes.h"
42 #include "protos.h"
43 #include "type.h"
44 
45 extern char *SearchBuffers[];
46 
47 #define MUTT_SEARCH_UP 1
48 #define MUTT_SEARCH_DOWN 2
49 
57 static int search(struct Menu *menu, int op)
58 {
59  int rc = -1;
60  int wrap = 0;
61  int search_dir;
62  regex_t re = { 0 };
63  struct Buffer *buf = mutt_buffer_pool_get();
64 
65  char *search_buf = ((menu->type < MENU_MAX)) ? SearchBuffers[menu->type] : NULL;
66 
67  if (!(search_buf && *search_buf) || ((op != OP_SEARCH_NEXT) && (op != OP_SEARCH_OPPOSITE)))
68  {
69  mutt_buffer_strcpy(buf, search_buf && (search_buf[0] != '\0') ? search_buf : "");
70  if ((mutt_buffer_get_field(((op == OP_SEARCH) || (op == OP_SEARCH_NEXT)) ?
71  _("Search for: ") :
72  _("Reverse search for: "),
73  buf, MUTT_COMP_CLEAR, false, NULL, NULL, NULL) != 0) ||
75  {
76  goto done;
77  }
78  if (menu->type < MENU_MAX)
79  {
81  search_buf = SearchBuffers[menu->type];
82  }
83  menu->search_dir = ((op == OP_SEARCH) || (op == OP_SEARCH_NEXT)) ?
86  }
87 
88  search_dir = (menu->search_dir == MUTT_SEARCH_UP) ? -1 : 1;
89  if (op == OP_SEARCH_OPPOSITE)
90  search_dir = -search_dir;
91 
92  if (search_buf)
93  {
94  uint16_t flags = mutt_mb_is_lower(search_buf) ? REG_ICASE : 0;
95  rc = REG_COMP(&re, search_buf, REG_NOSUB | flags);
96  }
97 
98  if (rc != 0)
99  {
100  regerror(rc, &re, buf->data, buf->dsize);
101  mutt_error("%s", mutt_buffer_string(buf));
102  rc = -1;
103  goto done;
104  }
105 
106  rc = menu->current + search_dir;
107 search_next:
108  if (wrap)
109  mutt_message(_("Search wrapped to top"));
110  while ((rc >= 0) && (rc < menu->max))
111  {
112  if (menu->search(menu, &re, rc) == 0)
113  {
114  regfree(&re);
115  goto done;
116  }
117 
118  rc += search_dir;
119  }
120 
121  const bool c_wrap_search = cs_subset_bool(menu->sub, "wrap_search");
122  if (c_wrap_search && (wrap++ == 0))
123  {
124  rc = (search_dir == 1) ? 0 : menu->max - 1;
125  goto search_next;
126  }
127  regfree(&re);
128  mutt_error(_("Not found"));
129  rc = -1;
130 
131 done:
133  return rc;
134 }
135 
136 // -----------------------------------------------------------------------------
137 
141 static int menu_movement(struct Menu *menu, int op)
142 {
143  switch (op)
144  {
145  case OP_BOTTOM_PAGE:
146  menu_bottom_page(menu);
147  return FR_SUCCESS;
148 
149  case OP_CURRENT_BOTTOM:
150  menu_current_bottom(menu);
151  return FR_SUCCESS;
152 
153  case OP_CURRENT_MIDDLE:
154  menu_current_middle(menu);
155  return FR_SUCCESS;
156 
157  case OP_CURRENT_TOP:
158  menu_current_top(menu);
159  return FR_SUCCESS;
160 
161  case OP_FIRST_ENTRY:
162  menu_first_entry(menu);
163  return FR_SUCCESS;
164 
165  case OP_HALF_DOWN:
166  menu_half_down(menu);
167  return FR_SUCCESS;
168 
169  case OP_HALF_UP:
170  menu_half_up(menu);
171  return FR_SUCCESS;
172 
173  case OP_LAST_ENTRY:
174  menu_last_entry(menu);
175  return FR_SUCCESS;
176 
177  case OP_MIDDLE_PAGE:
178  menu_middle_page(menu);
179  return FR_SUCCESS;
180 
181  case OP_NEXT_ENTRY:
182  menu_next_entry(menu);
183  return FR_SUCCESS;
184 
185  case OP_NEXT_LINE:
186  menu_next_line(menu);
187  return FR_SUCCESS;
188 
189  case OP_NEXT_PAGE:
190  menu_next_page(menu);
191  return FR_SUCCESS;
192 
193  case OP_PREV_ENTRY:
194  menu_prev_entry(menu);
195  return FR_SUCCESS;
196 
197  case OP_PREV_LINE:
198  menu_prev_line(menu);
199  return FR_SUCCESS;
200 
201  case OP_PREV_PAGE:
202  menu_prev_page(menu);
203  return FR_SUCCESS;
204 
205  case OP_TOP_PAGE:
206  menu_top_page(menu);
207  return FR_SUCCESS;
208 
209  default:
210  return FR_UNKNOWN;
211  }
212 }
213 
217 static int menu_search(struct Menu *menu, int op)
218 {
219  if (menu->search)
220  {
221  int index = search(menu, op);
222  if (index != -1)
223  menu_set_index(menu, index);
224  }
225  return FR_SUCCESS;
226 }
227 
231 static int op_help(struct Menu *menu, int op)
232 {
233  mutt_help(menu->type);
234  menu->redraw = MENU_REDRAW_FULL;
235  return FR_SUCCESS;
236 }
237 
241 static int op_jump(struct Menu *menu, int op)
242 {
243  if (menu->max == 0)
244  {
245  mutt_error(_("No entries"));
246  return FR_SUCCESS;
247  }
248 
249  const int digit = op - OP_JUMP;
250  if (digit > 0 && digit < 10)
251  {
252  mutt_unget_ch('0' + digit);
253  }
254 
255  struct Buffer *buf = mutt_buffer_pool_get();
256  if ((mutt_buffer_get_field(_("Jump to: "), buf, MUTT_COMP_NO_FLAGS, false,
257  NULL, NULL, NULL) == 0) &&
258  !mutt_buffer_is_empty(buf))
259  {
260  int n = 0;
261  if (mutt_str_atoi_full(mutt_buffer_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 
272  return FR_SUCCESS;
273 }
274 
275 // -----------------------------------------------------------------------------
276 
280 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 
321 {
322  if (!win || !win->wdata)
323  return FR_UNKNOWN;
324 
325  struct Menu *menu = win->wdata;
326 
327  int rc = FR_UNKNOWN;
328  for (size_t i = 0; MenuFunctions[i].op != OP_NULL; i++)
329  {
330  const struct MenuFunction *fn = &MenuFunctions[i];
331  if (fn->op == op)
332  {
333  rc = fn->function(menu, op);
334  break;
335  }
336  }
337 
338  if (rc == FR_UNKNOWN) // Not our function
339  return rc;
340 
341  const char *result = dispacher_get_retval_name(rc);
342  mutt_debug(LL_DEBUG1, "Handled %s (%d) -> %s\n", opcodes_get_name(op), op, NONULL(result));
343 
344  return rc;
345 }
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:250
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:310
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
Convenience wrapper for the config headers.
Convenience wrapper for the core headers.
int digit(const char *s)
void mutt_unget_ch(int ch)
Return a keystroke to the input buffer.
Definition: curs_lib.c:522
const char * dispacher_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:39
@ FR_UNKNOWN
Unknown function.
Definition: dispatcher.h:33
Enter a string.
int mutt_buffer_get_field(const char *field, struct Buffer *buf, CompletionFlags complete, bool multiple, struct Mailbox *m, char ***files, int *numfiles)
Ask the user for a string.
Definition: window.c:180
int menu_function_dispatcher(struct MuttWindow *win, int op)
Perform a Menu function - Implements function_dispatcher_t -.
Definition: functions.c:320
#define mutt_error(...)
Definition: logging.h:87
#define mutt_message(...)
Definition: logging.h:86
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
static int op_help(struct Menu *menu, int op)
Show the help screen - Implements menu_function_t -.
Definition: functions.c:231
static int menu_search(struct Menu *menu, int op)
Handle Menu searching - Implements menu_function_t -.
Definition: functions.c:217
static int op_jump(struct Menu *menu, int op)
Jump to an index number - Implements menu_function_t -.
Definition: functions.c:241
static int menu_movement(struct Menu *menu, int op)
Handle all the common Menu movements - Implements menu_function_t -.
Definition: functions.c:141
Convenience wrapper for the gui headers.
void mutt_help(enum MenuType menu)
Display the help menu.
Definition: help.c:386
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
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
#define MUTT_SEARCH_UP
Definition: functions.c:47
char * SearchBuffers[]
Definition: menu.c:39
struct MenuFunction MenuFunctions[]
All the NeoMutt functions that the Menu supports.
Definition: functions.c:280
static int search(struct Menu *menu, int op)
Search a menu.
Definition: functions.c:57
#define MENU_REDRAW_FULL
Redraw everything.
Definition: lib.h:59
MenuRedrawFlags menu_next_page(struct Menu *menu)
Move the focus to the next page in the menu.
Definition: move.c:562
MenuRedrawFlags menu_bottom_page(struct Menu *menu)
Move the focus to the bottom of the page.
Definition: move.c:363
MenuRedrawFlags menu_half_up(struct Menu *menu)
Move the focus up half a page in the menu.
Definition: move.c:506
MenuRedrawFlags menu_prev_line(struct Menu *menu)
Move the view up one line, keeping the selection the same.
Definition: move.c:526
MenuRedrawFlags menu_current_bottom(struct Menu *menu)
Move the current selection to the bottom of the window.
Definition: move.c:484
MenuRedrawFlags menu_current_middle(struct Menu *menu)
Move the current selection to the centre of the window.
Definition: move.c:464
MenuRedrawFlags menu_middle_page(struct Menu *menu)
Move the focus to the centre of the page.
Definition: move.c:343
MenuRedrawFlags menu_first_entry(struct Menu *menu)
Move the focus to the first entry in the menu.
Definition: move.c:410
MenuRedrawFlags menu_half_down(struct Menu *menu)
Move the focus down half a page in the menu.
Definition: move.c:516
MenuRedrawFlags menu_top_page(struct Menu *menu)
Move the focus to the top of the page.
Definition: move.c:333
MenuRedrawFlags menu_last_entry(struct Menu *menu)
Move the focus to the last entry in the menu.
Definition: move.c:426
MenuRedrawFlags menu_prev_page(struct Menu *menu)
Move the focus to the previous page in the menu.
Definition: move.c:552
MenuRedrawFlags menu_next_line(struct Menu *menu)
Move the view down one line, keeping the selection the same.
Definition: move.c:539
MenuRedrawFlags menu_prev_entry(struct Menu *menu)
Move the focus to the previous item in the menu.
Definition: move.c:382
MenuRedrawFlags menu_current_top(struct Menu *menu)
Move the current selection to the top of the window.
Definition: move.c:443
MenuRedrawFlags menu_set_index(struct Menu *menu, int index)
Set the current selection in the Menu.
Definition: menu.c:168
MenuRedrawFlags menu_next_entry(struct Menu *menu)
Move the focus to the next item in the menu.
Definition: move.c:396
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:326
Many unsorted constants and some structs.
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:52
#define MUTT_COMP_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:62
const char * opcodes_get_name(int op)
Get the name of an opcode.
Definition: opcodes.c:46
All user-callable functions.
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
Prototypes for many functions.
#define REG_COMP(preg, regex, cflags)
Compile a regular expression.
Definition: regex3.h:53
Sidebar functions.
Key value store.
#define NONULL(x)
Definition: string2.h:37
String manipulation buffer.
Definition: buffer.h:34
size_t dsize
Length of data.
Definition: buffer.h:37
char * data
Pointer to data.
Definition: buffer.h:35
A NeoMutt function.
Definition: functions.h:44
menu_function_t function
Function to call.
Definition: functions.h:46
int op
Op code, e.g. OP_SEARCH.
Definition: functions.h:45
Definition: lib.h:69
struct MuttWindow * win
Window holding the Menu.
Definition: lib.h:76
int search_dir
Direction of search.
Definition: lib.h:82
int current
Current entry.
Definition: lib.h:70
MenuRedrawFlags redraw
When to redraw the screen.
Definition: lib.h:72
int(* search)(struct Menu *menu, regex_t *rx, int line)
Definition: lib.h:109
enum MenuType type
Menu definition for keymap entries.
Definition: lib.h:73
struct ConfigSubset * sub
Inherited config items.
Definition: lib.h:77
int max
Number of entries in the menu.
Definition: lib.h:71
void * wdata
Private data.
Definition: mutt_window.h:145
Menu types.
@ MENU_MAX
Definition: type.h:59