NeoMutt  2025-12-11-435-g4ac674
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
menu.c
Go to the documentation of this file.
1
22
28
29#include "config.h"
30#include <string.h>
31#include "mutt/lib.h"
32#include "core/lib.h"
33#include "gui/lib.h"
34#include "menu.h"
35#include "init.h"
36#include "keymap.h"
37
51enum CommandResult km_bind(struct MenuDefinition *md, const char *key_str,
52 int op, char *macro, char *desc, struct Buffer *err)
53{
54 if (!md || ARRAY_EMPTY(&md->submenus))
55 return MUTT_CMD_ERROR;
56
58 struct Keymap *last = NULL;
59 struct Keymap *np = NULL;
60 struct Keymap *compare = NULL;
61 keycode_t buf[MAX_SEQ] = { 0 };
62 size_t pos = 0;
63 size_t lastpos = 0;
64
65 struct SubMenu *sm = *ARRAY_FIRST(&md->submenus);
66 struct KeymapList *kml = &sm->keymaps;
67
68 size_t len = parse_keys(key_str, buf, MAX_SEQ);
69
70 struct Keymap *map = keymap_alloc(len, buf);
71 map->op = op;
72 map->macro = mutt_str_dup(macro);
73 map->desc = mutt_str_dup(desc);
74
75 /* find position to place new keymap */
76 STAILQ_FOREACH(np, kml, entries)
77 {
78 compare = keymap_compare(map, np, &pos);
79
80 if (compare == map) /* map's keycode is bigger */
81 {
82 last = np;
83 lastpos = pos;
84 if (pos > np->eq)
85 pos = np->eq;
86 }
87 else if (compare == np) /* np's keycode is bigger, found insert location */
88 {
89 map->eq = pos;
90 break;
91 }
92 else /* equal keycodes */
93 {
94 /* Don't warn on overwriting a 'noop' binding */
95 if ((np->len != len) && (np->op != OP_NULL))
96 {
97 static const char *guide_link = "https://neomutt.org/guide/configuration.html#bind-warnings";
98 /* Overwrite with the different lengths, warn */
99 struct Buffer *old_binding = buf_pool_get();
100 struct Buffer *new_binding = buf_pool_get();
101
102 keymap_expand_key(map, old_binding);
103 keymap_expand_key(np, new_binding);
104
105 char *err_msg = _("Binding '%s' will alias '%s' Before, try: 'bind %s %s noop'");
106 if (err)
107 {
108 /* err was passed, put the string there */
109 buf_printf(err, err_msg, buf_string(old_binding),
110 buf_string(new_binding), md->name, buf_string(new_binding));
111 buf_add_printf(err, " %s", guide_link);
112 }
113 else
114 {
115 struct Buffer *tmp = buf_pool_get();
116 buf_printf(tmp, err_msg, buf_string(old_binding),
117 buf_string(new_binding), md->name, buf_string(new_binding));
118 buf_add_printf(tmp, " %s", guide_link);
119 mutt_error("%s", buf_string(tmp));
120 buf_pool_release(&tmp);
121 }
122 rc = MUTT_CMD_WARNING;
123
124 buf_pool_release(&old_binding);
125 buf_pool_release(&new_binding);
126 }
127
128 map->eq = np->eq;
129 STAILQ_REMOVE(kml, np, Keymap, entries);
130 keymap_free(&np);
131 break;
132 }
133 }
134
135 if (last) /* if queue has at least one entry */
136 {
137 if (STAILQ_NEXT(last, entries))
138 STAILQ_INSERT_AFTER(kml, last, map, entries);
139 else /* last entry in the queue */
140 STAILQ_INSERT_TAIL(kml, map, entries);
141 last->eq = lastpos;
142 }
143 else /* queue is empty, so insert from head */
144 {
145 STAILQ_INSERT_HEAD(kml, map, entries);
146 }
147
148 return rc;
149}
150
157struct Keymap *km_find_func(const struct MenuDefinition *md, int func)
158{
159 if (!md)
160 return NULL;
161
162 struct SubMenu **smp = NULL;
163
164 ARRAY_FOREACH(smp, &md->submenus)
165 {
166 struct SubMenu *sm = *smp;
167
168 struct Keymap *map = NULL;
169 STAILQ_FOREACH(map, &sm->keymaps, entries)
170 {
171 if (map->op == func)
172 return map;
173 }
174 }
175
176 return NULL;
177}
178
184int km_get_op(const char *func)
185{
186 struct MenuDefinition **mdp = NULL;
188 {
189 struct MenuDefinition *md = *mdp;
190 struct SubMenu **smp = NULL;
191
192 ARRAY_FOREACH(smp, &md->submenus)
193 {
194 struct SubMenu *sm = *smp;
195
196 for (int i = 0; sm->functions[i].name; i++)
197 {
198 if (mutt_str_equal(sm->functions[i].name, func))
199 return sm->functions[i].op;
200 }
201 }
202 }
203
204 return OP_NULL;
205}
206
213int km_get_op_menu(int mtype, const char *func)
214{
215 struct MenuDefinition **mdp = NULL;
217 {
218 struct MenuDefinition *md = *mdp;
219
220 if (md->id != mtype)
221 continue;
222
223 struct SubMenu **smp = NULL;
224
225 ARRAY_FOREACH(smp, &md->submenus)
226 {
227 struct SubMenu *sm = *smp;
228
229 for (int i = 0; sm->functions[i].name; i++)
230 {
231 if (mutt_str_equal(sm->functions[i].name, func))
232 return sm->functions[i].op;
233 }
234 }
235 }
236
237 return OP_NULL;
238}
239
245struct MenuDefinition *menu_find(int menu)
246{
247 struct MenuDefinition **mdp = NULL;
249 {
250 struct MenuDefinition *md = *mdp;
251
252 if (md->id == menu)
253 return md;
254 }
255
256 return NULL;
257}
258
265{
266 if (!name)
267 return NULL;
268
269 struct MenuDefinition **mdp = NULL;
271 {
272 struct MenuDefinition *md = *mdp;
273
274 if (mutt_str_equal(md->name, name))
275 return md;
276 }
277
278 return NULL;
279}
280
287bool is_bound(const struct MenuDefinition *md, int op)
288{
289 struct SubMenu **smp = NULL;
290
291 ARRAY_FOREACH(smp, &md->submenus)
292 {
293 struct SubMenu *sm = *smp;
294
295 struct Keymap *map = NULL;
296 STAILQ_FOREACH(map, &sm->keymaps, entries)
297 {
298 if (map->op == op)
299 return true;
300 }
301 }
302
303 return false;
304}
#define ARRAY_FIRST(head)
Convenience method to get the first element.
Definition array.h:136
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:223
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition array.h:74
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:161
int buf_add_printf(struct Buffer *buf, const char *fmt,...)
Format a string appending a Buffer.
Definition buffer.c:204
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
CommandResult
Error codes for command_t parse functions.
Definition command.h:37
@ MUTT_CMD_SUCCESS
Success: Command worked.
Definition command.h:40
@ MUTT_CMD_ERROR
Error: Can't help the user.
Definition command.h:38
@ MUTT_CMD_WARNING
Warning: Help given to the user.
Definition command.h:39
Convenience wrapper for the core headers.
#define mutt_error(...)
Definition logging2.h:94
Convenience wrapper for the gui headers.
struct MenuDefinitionArray MenuDefs
All the registered Menus.
Definition init.c:42
Set up the key bindings.
bool keymap_expand_key(struct Keymap *km, struct Buffer *buf)
Get the key string bound to a Keymap.
Definition keymap.c:229
void keymap_free(struct Keymap **pptr)
Free a Keymap.
Definition keymap.c:127
struct Keymap * keymap_compare(struct Keymap *km1, struct Keymap *km2, size_t *pos)
Compare two keymaps' keyscodes and return the bigger one.
Definition keymap.c:162
size_t parse_keys(const char *str, keycode_t *d, size_t max)
Parse a key string into key codes.
Definition keymap.c:318
struct Keymap * keymap_alloc(size_t len, keycode_t *keys)
Allocate space for a sequence of keys.
Definition keymap.c:112
int km_get_op_menu(int mtype, const char *func)
Get the OpCode for a Function from a Menu.
Definition menu.c:213
struct MenuDefinition * menu_find(int menu)
Find a Menu Definition by Menu type.
Definition menu.c:245
struct MenuDefinition * menu_find_by_name(const char *name)
Find a Menu Definition by its name.
Definition menu.c:264
enum CommandResult km_bind(struct MenuDefinition *md, const char *key_str, int op, char *macro, char *desc, struct Buffer *err)
Set up a key binding.
Definition menu.c:51
struct Keymap * km_find_func(const struct MenuDefinition *md, int func)
Find a function's mapping in a Menu.
Definition menu.c:157
bool is_bound(const struct MenuDefinition *md, int op)
Does a function have a keybinding?
Definition menu.c:287
int km_get_op(const char *func)
Get the OpCode for a Function.
Definition menu.c:184
Keymap handling.
short keycode_t
Type for key storage, the rest of neomutt works fine with int type.
Definition keymap.h:31
Maniplate Menus and SubMenus.
#define MAX_SEQ
Maximum length of a key binding sequence used for buffer in km_bind.
Definition menu.h:32
Convenience wrapper for the library headers.
#define _(a)
Definition message.h:28
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:662
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 STAILQ_REMOVE(head, elm, type, field)
Definition queue.h:441
#define STAILQ_FOREACH(var, head, field)
Definition queue.h:390
#define STAILQ_INSERT_TAIL(head, elm, field)
Definition queue.h:427
#define STAILQ_INSERT_HEAD(head, elm, field)
Definition queue.h:421
#define STAILQ_NEXT(elm, field)
Definition queue.h:439
#define STAILQ_INSERT_AFTER(head, tqelm, elm, field)
Definition queue.h:415
String manipulation buffer.
Definition buffer.h:36
A keyboard mapping.
Definition keymap.h:43
char * macro
Macro expansion (op == OP_MACRO)
Definition keymap.h:44
short eq
Number of leading keys equal to next entry.
Definition keymap.h:47
char * desc
Description of a macro for the help menu.
Definition keymap.h:45
short len
Length of key sequence (unit: sizeof (keycode_t))
Definition keymap.h:48
short op
Operation to perform.
Definition keymap.h:46
Functions for a Dialog or Window.
Definition menu.h:80
const char * name
Menu name, e.g. "alias".
Definition menu.h:82
int id
Menu ID, e.g. MENU_ALIAS.
Definition menu.h:81
struct SubMenuPArray submenus
Parts making up the Menu.
Definition menu.h:83
const char * name
Name of the function.
Definition menu.h:39
int op
Operation, e.g. OP_DELETE.
Definition menu.h:40
Collection of related functions.
Definition menu.h:68
const struct MenuFuncOp * functions
All available functions.
Definition menu.h:70
struct KeymapList keymaps
All keybindings.
Definition menu.h:71