NeoMutt  2025-12-11-911-gd8d604
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 115 of file commands.c.

117{
118 struct Buffer *token = buf_pool_get();
119 char *q = NULL;
120 char *result = NULL;
121
122 /* menu name */
123 parse_extract_token(token, line, TOKEN_NONE);
124 char *p = token->data;
125 if (MoreArgs(line))
126 {
127 while (true)
128 {
129 q = strchr(p, ',');
130 if (q)
131 *q = '\0';
132
133 struct MenuDefinition *md = menu_find_by_name(p);
134 if (!md)
135 {
136 buf_printf(err, _("%s: no such menu"), p);
137 goto done;
138 }
139 ARRAY_ADD(mda, md);
140 if (q)
141 p = q + 1;
142 else
143 break;
144 }
145 /* key sequence */
146 parse_extract_token(token, line, TOKEN_NONE);
147
148 if (buf_at(token, 0) == '\0')
149 {
150 buf_printf(err, _("%s: null key sequence"), cmd->name);
151 }
152 else if (MoreArgs(line))
153 {
154 result = buf_strdup(token);
155 goto done;
156 }
157 }
158 else
159 {
160 buf_printf(err, _("%s: too few arguments"), cmd->name);
161 }
162done:
163 buf_pool_release(&token);
164 return result;
165}
#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:161
char buf_at(const struct Buffer *buf, size_t offset)
Return the character at the given offset.
Definition buffer.c:668
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:571
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:31
@ TOKEN_NONE
No flags are set.
Definition extract.h:49
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 menu.h:77
+ 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 175 of file commands.c.

176{
177 char *menu_names_dup = mutt_str_dup(s);
178 char *marker = menu_names_dup;
179 char *menu_name = NULL;
180
181 while ((menu_name = mutt_str_sep(&marker, ",")))
182 {
183 struct MenuDefinition *md = menu_find_by_name(menu_name);
184 if (!md)
185 {
186 buf_printf(err, _("%s: no such menu"), menu_name);
187 break;
188 }
189 else
190 {
191 ARRAY_ADD(menus, md);
192 }
193 }
194
195 FREE(&menu_names_dup);
196}
#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 360 of file commands.c.

361{
362 bool success = false;
363
364 if (!md || (md == MdGeneric))
365 {
366 km_bind(MdGeneric, "<enter>", OP_GENERIC_SELECT_ENTRY, NULL, NULL, NULL);
367 km_bind(MdGeneric, "<return>", OP_GENERIC_SELECT_ENTRY, NULL, NULL, NULL);
368 km_bind(MdGeneric, ":", OP_ENTER_COMMAND, NULL, NULL, NULL);
369 km_bind(MdGeneric, "?", OP_HELP, NULL, NULL, NULL);
370 km_bind(MdGeneric, "q", OP_EXIT, NULL, NULL, NULL);
371 success = true;
372 }
373
374 if (!md || (md == MdIndex))
375 {
376 km_bind(MdIndex, "<enter>", OP_DISPLAY_MESSAGE, NULL, NULL, NULL);
377 km_bind(MdIndex, "<return>", OP_DISPLAY_MESSAGE, NULL, NULL, NULL);
378 km_bind(MdIndex, "q", OP_EXIT, NULL, NULL, NULL);
379 success = true;
380 }
381
382 if (!md || (md == MdEditor))
383 {
384 km_bind(MdEditor, "<backspace>", OP_EDITOR_BACKSPACE, NULL, NULL, NULL);
385 km_bind(MdEditor, "\177", OP_EDITOR_BACKSPACE, NULL, NULL, NULL);
386 success = true;
387 }
388
389 if (!md || (md == MdPager))
390 {
391 km_bind(MdPager, ":", OP_ENTER_COMMAND, NULL, NULL, NULL);
392 km_bind(MdPager, "?", OP_HELP, NULL, NULL, NULL);
393 km_bind(MdPager, "q", OP_EXIT, NULL, NULL, NULL);
394 success = true;
395 }
396
397 if (!md || (md == MdDialog))
398 {
399 km_bind(MdDialog, ":", OP_ENTER_COMMAND, NULL, NULL, NULL);
400 km_bind(MdDialog, "?", OP_HELP, NULL, NULL, NULL);
401 km_bind(MdDialog, "q", OP_EXIT, NULL, NULL, NULL);
402 success = true;
403 }
404
405 if (success)
406 {
407 mutt_debug(LL_NOTIFY, "NT_BINDING_ADD set defaults\n");
408 struct EventBinding ev_b = { md, NULL, OP_NULL };
410 }
411}
#define MdEditor
Definition functions.h:36
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
#define MdGeneric
Definition functions.h:33
#define MdDialog
Definition functions.h:34
#define MdIndex
Definition functions.h:72
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: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
#define MdPager
Definition functions.h:73
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 418 of file commands.c.

419{
420 switch (ev)
421 {
422 case NT_BINDING_ADD:
423 return "NT_BINDING_ADD";
425 return "NT_BINDING_DELETE";
426 case NT_MACRO_ADD:
427 return "NT_MACRO_ADD";
428 case NT_MACRO_DELETE:
429 return "NT_MACRO_DELETE";
430 default:
431 return "UNKNOWN";
432 }
433}
@ 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 458 of file commands.c.

460{
461 if (!cmd || !line || !err || !args)
462 return false;
463
464 if (!MoreArgs(line))
465 {
466 buf_printf(err, _("%s: too few arguments"), cmd->name);
467 return false;
468 }
469
470 struct Buffer *token = buf_pool_get();
471 bool rc = false;
472
473 parse_extract_token(token, line, TOKEN_NONE);
474 if (mutt_str_equal(buf_string(token), "*"))
475 {
476 args->all_menus = true;
477
478 if (MoreArgs(line))
479 {
480 // `unbind * key`
481 // `unmacro * key`
482 parse_extract_token(token, line, TOKEN_NONE);
483 args->key = buf_strdup(token);
484 }
485 else
486 {
487 // `unbind *`
488 // `unmacro *`
489 args->all_keys = true;
490 }
491 }
492 else
493 {
494 parse_menu(&args->mda, buf_string(token), err);
495 if (!buf_is_empty(err))
496 goto done;
497
498 if (MoreArgs(line))
499 {
500 parse_extract_token(token, line, TOKEN_NONE);
501 if (mutt_str_equal(buf_string(token), "*"))
502 {
503 // `unbind menu *`
504 // `unmacro menu *`
505 args->all_keys = true;
506 }
507 else
508 {
509 // `unbind menu key`
510 // `unmacro menu key`
511 args->key = buf_strdup(token);
512 }
513 }
514 else
515 {
516 // `unbind menu`
517 // `unmacro menu`
518 args->all_keys = true;
519 }
520 }
521
522 if (MoreArgs(line))
523 {
524 buf_printf(err, _("%s: too many arguments"), cmd->name);
525 goto done;
526 }
527
528 rc = true;
529
530done:
531 buf_pool_release(&token);
532 return rc;
533}
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:291
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
void parse_menu(struct MenuDefinitionArray *menus, const char *s, struct Buffer *err)
Parse menu-names into an array.
Definition commands.c:175
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:665
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: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. We choose not to distinguish the two, since a key can only be bound to one or the other. i.e. unbind will also clear macros, unmacro will also clear bindings

Definition at line 546 of file commands.c.

547{
548 if (!cmd || !args || !err)
549 return false;
550
552 keycode_t key_bytes[KEY_SEQ_MAX_LEN] = { 0 };
553 int key_len = 0;
554 if (args->key)
555 {
556 key_len = parse_keys(args->key, key_bytes, KEY_SEQ_MAX_LEN);
557 if (key_len == 0)
558 return false;
559 }
560
561 bool success = false;
562 struct Buffer *keystr = buf_pool_get();
564 struct MenuDefinition **mdp = NULL;
565 ARRAY_FOREACH(mdp, &mod_data->menu_defs)
566 {
567 struct MenuDefinition *md = *mdp;
568
569 if (!args->all_menus)
570 {
571 bool found = false;
572 struct MenuDefinition **mdp2 = NULL;
573 ARRAY_FOREACH(mdp2, &args->mda)
574 {
575 if ((*mdp2)->id == md->id)
576 {
577 found = true;
578 break;
579 }
580 }
581 if (!found)
582 continue;
583 }
584
585 struct SubMenu **smp = ARRAY_GET(&md->submenus, 0);
586 if (!smp || !*smp)
587 continue;
588
589 struct SubMenu *sm = *smp;
590
591 struct Keymap *km = NULL;
592 struct Keymap *km_tmp = NULL;
593 STAILQ_FOREACH_SAFE(km, &sm->keymaps, entries, km_tmp)
594 {
595 if (args->all_keys ||
596 ((key_len == km->len) && (memcmp(km->keys, key_bytes, km->len) == 0)))
597 {
598 STAILQ_REMOVE(&sm->keymaps, km, Keymap, entries);
599 keymap_free(&km);
600 success = true;
601
602 if (!args->all_keys && !args->all_menus)
603 {
604 buf_reset(keystr);
605 keymap_expand_string(args->key, keystr);
606 mutt_debug(LL_NOTIFY, "%s: %s %s\n", notify_binding_name(nb),
607 md->name, buf_string(keystr));
608
609 struct EventBinding ev_b = { md, args->key, OP_NULL };
610 notify_send(NeoMutt->notify, NT_BINDING, nb, &ev_b);
611 }
612 }
613 }
614
615 if (args->all_keys && !args->all_menus && success)
616 {
617 buf_reset(keystr);
618 keymap_expand_string(args->key, keystr);
619 mutt_debug(LL_NOTIFY, "%s: %s %s\n", notify_binding_name(nb), md->name,
620 buf_string(keystr));
621
622 struct EventBinding ev_b = { md, args->key, OP_NULL };
623 notify_send(NeoMutt->notify, NT_BINDING, nb, &ev_b);
624
625 // restore some bindings for this menu
627 }
628 }
629
630 if (args->all_menus && success)
631 {
632 buf_reset(keystr);
633 keymap_expand_string(args->key, keystr);
634 mutt_debug(LL_NOTIFY, "%s: ALL %s\n", notify_binding_name(nb), buf_string(keystr));
635
636 struct EventBinding ev_b = { NULL, args->key, OP_NULL };
637 notify_send(NeoMutt->notify, NT_BINDING, nb, &ev_b);
638
639 // restore some bindings for all menus
641 }
642
643 buf_pool_release(&keystr);
644 return true;
645}
#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:76
@ CMD_UNBIND
:unbind
Definition command.h:131
#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:418
void set_default_bindings(const struct MenuDefinition *md)
Set some safe default keybindings.
Definition commands.c:360
void keymap_expand_string(const char *str, struct Buffer *buf)
Get a human-readable key string.
Definition keymap.c:266
void keymap_free(struct Keymap **pptr)
Free a Keymap.
Definition keymap.c:146
size_t parse_keys(const char *str, keycode_t *d, size_t max)
Parse a key string into key codes.
Definition keymap.c:337
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:73
void * neomutt_get_module_data(struct NeoMutt *n, enum ModuleId id)
Get the private data for a Module.
Definition neomutt.c:663
#define STAILQ_REMOVE(head, elm, type, field)
Definition queue.h:441
#define STAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition queue.h:400
enum CommandId id
ID of the Command.
Definition command.h:163
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
const char * name
Menu name, e.g. "alias".
Definition menu.h:79
int id
Menu ID, e.g. MENU_ALIAS.
Definition menu.h:78
struct SubMenuPArray submenus
Parts making up the Menu.
Definition menu.h:80
Collection of related functions.
Definition menu.h:65
struct KeymapList keymaps
All keybindings.
Definition menu.h:68
+ Here is the call graph for this function:
+ Here is the caller graph for this function: