NeoMutt  2025-12-11-980-ge38c27
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
commands.c File Reference

Parse key binding commands. More...

#include "config.h"
#include <stdbool.h>
#include <string.h>
#include "mutt/lib.h"
#include "config/lib.h"
#include "core/lib.h"
#include "gui/lib.h"
#include "commands.h"
#include "editor/lib.h"
#include "index/lib.h"
#include "menu/lib.h"
#include "pager/lib.h"
#include "parse/lib.h"
#include "dump.h"
#include "get.h"
#include "keymap.h"
#include "menu.h"
#include "module_data.h"
#include "notify.h"
+ Include dependency graph for commands.c:

Go to the source code of this file.

Data Structures

struct  ParseUnbind
 Parsed 'unbind' or 'unmacro' command. More...
 

Functions

enum CommandResult parse_dump (const struct Command *cmd, struct Buffer *line, const struct ParseContext *pc, struct ParseError *pe)
 Parse 'bind' and 'macro' commands - Implements Command::parse() -.
 
char * parse_keymap (const struct Command *cmd, struct MenuDefinitionArray *mda, struct Buffer *line, struct Buffer *err)
 Parse a user-config key binding.
 
void parse_menu (struct MenuDefinitionArray *menus, const char *s, struct Buffer *err)
 Parse menu-names into an array.
 
enum CommandResult parse_push (const struct Command *cmd, struct Buffer *line, const struct ParseContext *pc, struct ParseError *pe)
 Parse the 'push' command - Implements Command::parse() -.
 
enum CommandResult parse_bind (const struct Command *cmd, struct Buffer *line, const struct ParseContext *pc, struct ParseError *pe)
 Parse the 'bind' command - Implements Command::parse() -.
 
void set_default_bindings (const struct MenuDefinition *md)
 Set some safe default keybindings.
 
const char * notify_binding_name (enum NotifyBinding ev)
 Get the name for a NotifyBinding.
 
bool parse_unbind_args (const struct Command *cmd, struct Buffer *line, struct Buffer *err, struct ParseUnbind *args)
 Parse the 'unbind' and 'unmacro' commands.
 
bool parse_unbind_exec (const struct Command *cmd, struct ParseUnbind *args, struct Buffer *err)
 Execute the 'unbind' or 'unmacro' command.
 
enum CommandResult parse_unbind (const struct Command *cmd, struct Buffer *line, const struct ParseContext *pc, struct ParseError *pe)
 Parse the 'unbind' and 'unmacro' commands - Implements Command::parse() -.
 
enum CommandResult parse_macro (const struct Command *cmd, struct Buffer *line, const struct ParseContext *pc, struct ParseError *pe)
 Parse the 'macro' command - Implements Command::parse() -.
 
enum CommandResult parse_exec (const struct Command *cmd, struct Buffer *line, const struct ParseContext *pc, struct ParseError *pe)
 Parse the 'exec' command - Implements Command::parse() -.
 

Detailed Description

Parse key binding commands.

Authors
  • Richard Russon

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file commands.c.

Function Documentation

◆ parse_keymap()

char * parse_keymap ( const struct Command * cmd,
struct MenuDefinitionArray * mda,
struct Buffer * line,
struct Buffer * err )

Parse a user-config key binding.

Parameters
cmdCommand being processed
mdaArray for results
lineBuffer containing config string
errBuffer for error messages
Return values
ptrKey string for the binding

Expects to see: <menu-string>,<menu-string>,... <key-string>

Note
Caller needs to free the returned string

Definition at line 116 of file commands.c.

118{
119 struct Buffer *token = buf_pool_get();
120 char *q = NULL;
121 char *result = NULL;
122
123 /* menu name */
124 parse_extract_token(token, line, TOKEN_NONE);
125 char *p = token->data;
126 if (MoreArgs(line))
127 {
128 while (true)
129 {
130 q = strchr(p, ',');
131 if (q)
132 *q = '\0';
133
134 struct MenuDefinition *md = menu_find_by_name(p);
135 if (!md)
136 {
137 buf_printf(err, _("%s: no such menu"), p);
138 goto done;
139 }
140 ARRAY_ADD(mda, md);
141 if (q)
142 p = q + 1;
143 else
144 break;
145 }
146 /* key sequence */
147 parse_extract_token(token, line, TOKEN_NONE);
148
149 if (buf_at(token, 0) == '\0')
150 {
151 buf_printf(err, _("%s: null key sequence"), cmd->name);
152 }
153 else if (MoreArgs(line))
154 {
155 result = buf_strdup(token);
156 goto done;
157 }
158 }
159 else
160 {
161 buf_printf(err, _("%s: too few arguments"), cmd->name);
162 }
163done:
164 buf_pool_release(&token);
165 return result;
166}
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition array.h:157
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:168
char buf_at(const struct Buffer *buf, size_t offset)
Return the character at the given offset.
Definition buffer.c:674
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:577
int parse_extract_token(struct Buffer *dest, struct Buffer *line, TokenFlags flags)
Extract one token from a string.
Definition extract.c:49
#define MoreArgs(buf)
Definition extract.h:32
@ TOKEN_NONE
No flags are set.
Definition extract.h:50
struct MenuDefinition * menu_find_by_name(const char *name)
Find a Menu Definition by its name.
Definition menu.c:251
#define _(a)
Definition message.h:28
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
String manipulation buffer.
Definition buffer.h:36
char * data
Pointer to data.
Definition buffer.h:37
const char * name
Name of the Command.
Definition command.h:162
Functions for a Dialog or Window.
Definition menudef.h:44
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parse_menu()

void parse_menu ( struct MenuDefinitionArray * menus,
const char * s,
struct Buffer * err )

Parse menu-names into an array.

Parameters
menusArray for results
sString containing menu-names
errBuffer for error messages

Expects to see: <menu-string>[,<menu-string>]

Definition at line 176 of file commands.c.

177{
178 char *menu_names_dup = mutt_str_dup(s);
179 char *marker = menu_names_dup;
180 char *menu_name = NULL;
181
182 while ((menu_name = mutt_str_sep(&marker, ",")))
183 {
184 struct MenuDefinition *md = menu_find_by_name(menu_name);
185 if (!md)
186 {
187 buf_printf(err, _("%s: no such menu"), menu_name);
188 break;
189 }
190 else
191 {
192 ARRAY_ADD(menus, md);
193 }
194 }
195
196 FREE(&menu_names_dup);
197}
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
char * mutt_str_sep(char **stringp, const char *delim)
Find first occurrence of any of delim characters in *stringp.
Definition string.c:190
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ set_default_bindings()

void set_default_bindings ( const struct MenuDefinition * md)

Set some safe default keybindings.

Parameters
mdMenu Definition to update

Definition at line 361 of file commands.c.

362{
363 bool success = false;
364
365 const struct MenuDefinition *md_generic = generic_get_menu_definition();
366 if (!md || (md == md_generic))
367 {
368 km_bind(md_generic, "<enter>", OP_GENERIC_SELECT_ENTRY, NULL, NULL, NULL);
369 km_bind(md_generic, "<return>", OP_GENERIC_SELECT_ENTRY, NULL, NULL, NULL);
370 km_bind(md_generic, ":", OP_ENTER_COMMAND, NULL, NULL, NULL);
371 km_bind(md_generic, "?", OP_HELP, NULL, NULL, NULL);
372 km_bind(md_generic, "q", OP_EXIT, NULL, NULL, NULL);
373 success = true;
374 }
375
376 const struct MenuDefinition *md_index = index_get_menu_definition();
377 if (!md || (md == md_index))
378 {
379 km_bind(md_index, "<enter>", OP_DISPLAY_MESSAGE, NULL, NULL, NULL);
380 km_bind(md_index, "<return>", OP_DISPLAY_MESSAGE, NULL, NULL, NULL);
381 km_bind(md_index, "q", OP_EXIT, NULL, NULL, NULL);
382 success = true;
383 }
384
385 const struct MenuDefinition *md_editor = editor_get_menu_definition();
386 if (!md || (md == md_editor))
387 {
388 km_bind(md_editor, "<backspace>", OP_EDITOR_BACKSPACE, NULL, NULL, NULL);
389 km_bind(md_editor, "\177", OP_EDITOR_BACKSPACE, NULL, NULL, NULL);
390 success = true;
391 }
392
393 const struct MenuDefinition *md_pager = pager_get_menu_definition();
394 if (!md || (md == md_pager))
395 {
396 km_bind(md_pager, ":", OP_ENTER_COMMAND, NULL, NULL, NULL);
397 km_bind(md_pager, "?", OP_HELP, NULL, NULL, NULL);
398 km_bind(md_pager, "q", OP_EXIT, NULL, NULL, NULL);
399 success = true;
400 }
401
402 if (success)
403 {
404 mutt_debug(LL_NOTIFY, "NT_BINDING_ADD set defaults\n");
405 struct EventBinding ev_b = { md, NULL, OP_NULL };
407 }
408}
struct MenuDefinition * editor_get_menu_definition(void)
Get the Editor Menu Definition.
Definition functions.c:575
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
struct MenuDefinition * generic_get_menu_definition(void)
Get the Generic Menu Definition.
Definition functions.c:177
struct MenuDefinition * index_get_menu_definition(void)
Get the Index Menu Definition.
Definition functions.c:4089
enum CommandResult km_bind(const struct MenuDefinition *md, const char *key_str, int op, char *macro, char *desc, struct Buffer *err)
Set up a key binding.
Definition menu.c:52
@ NT_BINDING_ADD
Key binding has been added.
Definition notify.h:48
@ LL_NOTIFY
Log of notifications.
Definition logging2.h:50
bool notify_send(struct Notify *notify, enum NotifyType event_type, int event_subtype, void *event_data)
Send out a notification message.
Definition notify.c:173
@ NT_BINDING
Key binding has changed, NotifyBinding, EventBinding.
Definition notify_type.h:40
struct MenuDefinition * pager_get_menu_definition(void)
Get the Pager Menu Definition.
Definition functions.c:1115
A key binding Event.
Definition notify.h:33
Container for Accounts, Notifications.
Definition neomutt.h:41
struct Notify * notify
Notifications handler.
Definition neomutt.h:45
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ notify_binding_name()

const char * notify_binding_name ( enum NotifyBinding ev)

Get the name for a NotifyBinding.

Parameters
evEvent type
Return values
strName of the NotifyBinding

Definition at line 415 of file commands.c.

416{
417 switch (ev)
418 {
419 case NT_BINDING_ADD:
420 return "NT_BINDING_ADD";
422 return "NT_BINDING_DELETE";
423 case NT_MACRO_ADD:
424 return "NT_MACRO_ADD";
425 case NT_MACRO_DELETE:
426 return "NT_MACRO_DELETE";
427 default:
428 return "UNKNOWN";
429 }
430}
@ NT_MACRO_ADD
Key macro has been added.
Definition notify.h:50
@ NT_MACRO_DELETE
Key macro has been deleted.
Definition notify.h:51
@ NT_BINDING_DELETE
Key binding has been deleted.
Definition notify.h:49
+ Here is the caller graph for this function:

◆ parse_unbind_args()

bool parse_unbind_args ( const struct Command * cmd,
struct Buffer * line,
struct Buffer * err,
struct ParseUnbind * args )

Parse the 'unbind' and 'unmacro' commands.

Parameters
[in]cmdCommand being parsed
[in]lineText to parse
[out]errBuffer for error messages
[out]argsParsed args
Return values
trueSuccess

Command unbinds:

  • all bindings in all menu-names
    • unbind *
  • all bindings in one/many menu-names
    • unbind index *
    • unbind index
    • unbind index,pager *
    • unbind index,pager
  • one binding in one/many/all menu-names
    • unbind index j
    • unbind index,pager j
    • unbind * j

The same applies to unmacro.

Definition at line 455 of file commands.c.

457{
458 if (!cmd || !line || !err || !args)
459 return false;
460
461 if (!MoreArgs(line))
462 {
463 buf_printf(err, _("%s: too few arguments"), cmd->name);
464 return false;
465 }
466
467 struct Buffer *token = buf_pool_get();
468 bool rc = false;
469
470 parse_extract_token(token, line, TOKEN_NONE);
471 if (mutt_str_equal(buf_string(token), "*"))
472 {
473 args->all_menus = true;
474
475 if (MoreArgs(line))
476 {
477 // `unbind * key`
478 // `unmacro * key`
479 parse_extract_token(token, line, TOKEN_NONE);
480 if (mutt_str_equal(buf_string(token), "*"))
481 args->all_keys = true;
482 else
483 args->key = buf_strdup(token);
484 }
485 else
486 {
487 // `unbind *`
488 // `unmacro *`
489 args->all_keys = true;
490 args->restore_defaults = (cmd->id == CMD_UNBIND);
491 }
492 }
493 else
494 {
495 if (mutt_str_equal(buf_string(token), "*"))
496 {
497 args->all_menus = true;
498 }
499 else
500 {
501 parse_menu(&args->mda, buf_string(token), err);
502 if (!buf_is_empty(err))
503 goto done;
504 }
505
506 if (MoreArgs(line))
507 {
508 parse_extract_token(token, line, TOKEN_NONE);
509 if (mutt_str_equal(buf_string(token), "*"))
510 {
511 // `unbind menu *`
512 // `unmacro menu *`
513 args->all_keys = true;
514 }
515 else
516 {
517 // `unbind menu key`
518 // `unmacro menu key`
519 args->key = buf_strdup(token);
520 }
521 }
522 else
523 {
524 // `unbind menu`
525 // `unmacro menu`
526 args->all_keys = true;
527 args->restore_defaults = (cmd->id == CMD_UNBIND);
528 }
529 }
530
531 if (MoreArgs(line))
532 {
533 buf_printf(err, _("%s: too many arguments"), cmd->name);
534 goto done;
535 }
536
537 rc = true;
538
539done:
540 buf_pool_release(&token);
541 return rc;
542}
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:298
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
@ CMD_UNBIND
:unbind
Definition command.h:131
void parse_menu(struct MenuDefinitionArray *menus, const char *s, struct Buffer *err)
Parse menu-names into an array.
Definition commands.c:176
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:666
enum CommandId id
ID of the Command.
Definition command.h:163
bool all_menus
Command affects all Menus.
Definition commands.c:55
struct MenuDefinitionArray mda
Menus to work on.
Definition commands.c:54
const char * key
Key string to be removed.
Definition commands.c:58
bool restore_defaults
Restore fallback bindings after unbind.
Definition commands.c:57
bool all_keys
Command affects all key bindings.
Definition commands.c:56
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parse_unbind_exec()

bool parse_unbind_exec ( const struct Command * cmd,
struct ParseUnbind * args,
struct Buffer * err )

Execute the 'unbind' or 'unmacro' command.

Parameters
[in]cmdCommand being executed
[in]argsParsed arguments
[out]errBuffer for error messages
Return values
trueSuccess

The user is trying to remove a binding or a macro. unbind only removes regular bindings; unmacro only removes macros.

Definition at line 554 of file commands.c.

555{
556 if (!cmd || !args || !err)
557 return false;
558
560 keycode_t key_bytes[KEY_SEQ_MAX_LEN] = { 0 };
561 int key_len = 0;
562 if (args->key)
563 {
564 key_len = parse_keys(args->key, key_bytes, KEY_SEQ_MAX_LEN);
565 if (key_len == 0)
566 return false;
567 }
568
569 bool success = false;
570 struct Buffer *keystr = buf_pool_get();
572 struct MenuDefinition **mdp = NULL;
573 ARRAY_FOREACH(mdp, &mod_data->menu_defs)
574 {
575 struct MenuDefinition *md = *mdp;
576 bool menu_success = false;
577
578 if (!args->all_menus)
579 {
580 bool found = false;
581 struct MenuDefinition **mdp2 = NULL;
582 ARRAY_FOREACH(mdp2, &args->mda)
583 {
584 if ((*mdp2)->id == md->id)
585 {
586 found = true;
587 break;
588 }
589 }
590 if (!found)
591 continue;
592 }
593
594 struct SubMenu **smp = ARRAY_GET(&md->submenus, 0);
595 if (!smp || !*smp)
596 continue;
597
598 struct SubMenu *sm = *smp;
599
600 struct Keymap *km = NULL;
601 struct Keymap *km_tmp = NULL;
602 STAILQ_FOREACH_SAFE(km, &sm->keymaps, entries, km_tmp)
603 {
604 bool match = args->all_keys || ((key_len == km->len) &&
605 (memcmp(km->keys, key_bytes, km->len) == 0));
606 if ((cmd->id == CMD_UNMACRO) && (km->op != OP_MACRO))
607 match = false;
608 if ((cmd->id == CMD_UNBIND) && (km->op == OP_MACRO))
609 match = false;
610
611 if (match)
612 {
613 STAILQ_REMOVE(&sm->keymaps, km, Keymap, entries);
614 keymap_free(&km);
615 success = true;
616 menu_success = true;
617
618 if (!args->all_keys && !args->all_menus)
619 {
620 buf_reset(keystr);
621 keymap_expand_string(args->key, keystr);
622 mutt_debug(LL_NOTIFY, "%s: %s %s\n", notify_binding_name(nb),
623 md->name, buf_string(keystr));
624
625 struct EventBinding ev_b = { md, args->key, OP_NULL };
626 notify_send(NeoMutt->notify, NT_BINDING, nb, &ev_b);
627 }
628 }
629 }
630
631 if (args->all_keys && !args->all_menus)
632 {
633 if (menu_success)
634 {
635 buf_reset(keystr);
636 keymap_expand_string(args->key, keystr);
637 mutt_debug(LL_NOTIFY, "%s: %s %s\n", notify_binding_name(nb), md->name,
638 buf_string(keystr));
639
640 struct EventBinding ev_b = { md, args->key, OP_NULL };
641 notify_send(NeoMutt->notify, NT_BINDING, nb, &ev_b);
642 }
643
644 if (args->restore_defaults)
646 }
647 }
648
649 if (args->all_menus && args->all_keys)
650 {
651 if (success)
652 {
653 buf_reset(keystr);
654 keymap_expand_string(args->key, keystr);
655 mutt_debug(LL_NOTIFY, "%s: ALL %s\n", notify_binding_name(nb), buf_string(keystr));
656
657 struct EventBinding ev_b = { NULL, args->key, OP_NULL };
658 notify_send(NeoMutt->notify, NT_BINDING, nb, &ev_b);
659 }
660
661 if (args->restore_defaults)
663 }
664
665 buf_pool_release(&keystr);
666 return true;
667}
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition array.h:223
#define ARRAY_GET(head, idx)
Return the element at index.
Definition array.h:109
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:89
@ CMD_UNMACRO
:unmacro
Definition command.h:138
#define KEY_SEQ_MAX_LEN
Maximum number of keys in a key sequence, e.g. abc
Definition get.h:48
const char * notify_binding_name(enum NotifyBinding ev)
Get the name for a NotifyBinding.
Definition commands.c:415
void set_default_bindings(const struct MenuDefinition *md)
Set some safe default keybindings.
Definition commands.c:361
void keymap_expand_string(const char *str, struct Buffer *buf)
Get a human-readable key string.
Definition keymap.c:265
void keymap_free(struct Keymap **pptr)
Free a Keymap.
Definition keymap.c:145
size_t parse_keys(const char *str, keycode_t *d, size_t max)
Parse a key string into key codes.
Definition keymap.c:336
NotifyBinding
Key Binding notification types.
Definition notify.h:47
short keycode_t
Type for key storage, the rest of neomutt works fine with int type.
Definition keymap.h:31
@ MODULE_ID_KEY
ModuleKey, Key mappings
Definition module_api.h:74
void * neomutt_get_module_data(struct NeoMutt *n, enum ModuleId id)
Get the private data for a Module.
Definition neomutt.c:666
#define STAILQ_REMOVE(head, elm, type, field)
Definition queue.h:441
#define STAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition queue.h:400
Key private Module data.
Definition module_data.h:34
struct MenuDefinitionArray menu_defs
All registered Menus.
Definition module_data.h:39
A keyboard mapping.
Definition keymap.h:43
keycode_t * keys
Key sequence.
Definition keymap.h:49
short len
Length of key sequence (unit: sizeof (keycode_t))
Definition keymap.h:48
short op
Operation to perform.
Definition keymap.h:46
struct SubMenuArray submenus
Parts making up the Menu.
Definition menudef.h:47
const char * name
Menu name, e.g. "alias".
Definition menudef.h:46
int id
Menu ID, e.g. MENU_ALIAS.
Definition menudef.h:45
Collection of related functions.
Definition menudef.h:33
struct KeymapList keymaps
All keybindings.
Definition menudef.h:36
+ Here is the call graph for this function:
+ Here is the caller graph for this function: