NeoMutt  2025-12-11-435-g4ac674
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 "init.h"
#include "keymap.h"
#include "menu.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 */
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 */
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
#define TOKEN_NO_FLAGS
No flags are set.
Definition extract.h:45
struct MenuDefinition * menu_find_by_name(const char *name)
Find a Menu Definition by its name.
Definition menu.c:264
#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:159
Functions for a Dialog or Window.
Definition menu.h:80
+ 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 351 of file commands.c.

352{
353 bool success = false;
354
355 if (!md || (md == MdGeneric))
356 {
357 km_bind(MdGeneric, "<enter>", OP_GENERIC_SELECT_ENTRY, NULL, NULL, NULL);
358 km_bind(MdGeneric, "<return>", OP_GENERIC_SELECT_ENTRY, NULL, NULL, NULL);
359 km_bind(MdGeneric, ":", OP_ENTER_COMMAND, NULL, NULL, NULL);
360 km_bind(MdGeneric, "?", OP_HELP, NULL, NULL, NULL);
361 km_bind(MdGeneric, "q", OP_EXIT, NULL, NULL, NULL);
362 success = true;
363 }
364
365 if (!md || (md == MdIndex))
366 {
367 km_bind(MdIndex, "<enter>", OP_DISPLAY_MESSAGE, NULL, NULL, NULL);
368 km_bind(MdIndex, "<return>", OP_DISPLAY_MESSAGE, NULL, NULL, NULL);
369 km_bind(MdIndex, "q", OP_EXIT, NULL, NULL, NULL);
370 success = true;
371 }
372
373 if (!md || (md == MdEditor))
374 {
375 km_bind(MdEditor, "<backspace>", OP_EDITOR_BACKSPACE, NULL, NULL, NULL);
376 km_bind(MdEditor, "\177", OP_EDITOR_BACKSPACE, NULL, NULL, NULL);
377 success = true;
378 }
379
380 if (!md || (md == MdPager))
381 {
382 km_bind(MdPager, ":", OP_ENTER_COMMAND, NULL, NULL, NULL);
383 km_bind(MdPager, "?", OP_HELP, NULL, NULL, NULL);
384 km_bind(MdPager, "q", OP_EXIT, NULL, NULL, NULL);
385 success = true;
386 }
387
388 if (!md || (md == MdDialog))
389 {
390 km_bind(MdDialog, ":", OP_ENTER_COMMAND, NULL, NULL, NULL);
391 km_bind(MdDialog, "?", OP_HELP, NULL, NULL, NULL);
392 km_bind(MdDialog, "q", OP_EXIT, NULL, NULL, NULL);
393 success = true;
394 }
395
396 if (success)
397 {
398 mutt_debug(LL_NOTIFY, "NT_BINDING_ADD set defaults\n");
399 struct EventBinding ev_b = { md, NULL, OP_NULL };
401 }
402}
struct MenuDefinition * MdEditor
Editor Menu Definition.
Definition functions.c:46
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
struct MenuDefinition * MdDialog
Dialog Menu Definition.
Definition functions.c:53
struct MenuDefinition * MdGeneric
Generic Menu Definition.
Definition functions.c:50
struct MenuDefinition * MdIndex
Index Menu Definition.
Definition functions.c:80
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
@ NT_BINDING_ADD
Key binding has been added.
Definition notify.h:47
@ 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 * MdPager
Pager Menu Definition.
Definition functions.c:64
A key binding Event.
Definition notify.h:32
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 409 of file commands.c.

410{
411 switch (ev)
412 {
413 case NT_BINDING_ADD:
414 return "NT_BINDING_ADD";
416 return "NT_BINDING_DELETE";
417 case NT_MACRO_ADD:
418 return "NT_MACRO_ADD";
419 case NT_MACRO_DELETE:
420 return "NT_MACRO_DELETE";
421 default:
422 return "UNKNOWN";
423 }
424}
@ NT_MACRO_ADD
Key macro has been added.
Definition notify.h:49
@ NT_MACRO_DELETE
Key macro has been deleted.
Definition notify.h:50
@ NT_BINDING_DELETE
Key binding has been deleted.
Definition notify.h:48
+ 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 449 of file commands.c.

451{
452 if (!cmd || !line || !err || !args)
453 return false;
454
455 if (!MoreArgs(line))
456 {
457 buf_printf(err, _("%s: too few arguments"), cmd->name);
458 return false;
459 }
460
461 struct Buffer *token = buf_pool_get();
462 bool rc = false;
463
465 if (mutt_str_equal(buf_string(token), "*"))
466 {
467 args->all_menus = true;
468
469 if (MoreArgs(line))
470 {
471 // `unbind * key`
472 // `unmacro * key`
474 args->key = buf_strdup(token);
475 }
476 else
477 {
478 // `unbind *`
479 // `unmacro *`
480 args->all_keys = true;
481 }
482 }
483 else
484 {
485 parse_menu(&args->mda, buf_string(token), err);
486 if (!buf_is_empty(err))
487 goto done;
488
489 if (MoreArgs(line))
490 {
492 if (mutt_str_equal(buf_string(token), "*"))
493 {
494 // `unbind menu *`
495 // `unmacro menu *`
496 args->all_keys = true;
497 }
498 else
499 {
500 // `unbind menu key`
501 // `unmacro menu key`
502 args->key = buf_strdup(token);
503 }
504 }
505 else
506 {
507 // `unbind menu`
508 // `unmacro menu`
509 args->all_keys = true;
510 }
511 }
512
513 if (MoreArgs(line))
514 {
515 buf_printf(err, _("%s: too many arguments"), cmd->name);
516 goto done;
517 }
518
519 rc = true;
520
521done:
522 buf_pool_release(&token);
523 return rc;
524}
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:662
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 537 of file commands.c.

538{
539 if (!cmd || !args || !err)
540 return false;
541
542 keycode_t key_bytes[MAX_SEQ] = { 0 };
543 int key_len = 0;
544 if (args->key)
545 {
546 key_len = parse_keys(args->key, key_bytes, MAX_SEQ);
547 if (key_len == 0)
548 return false;
549 }
550
551 bool success = false;
552 struct Buffer *keystr = buf_pool_get();
554 struct MenuDefinition **mdp = NULL;
556 {
557 struct MenuDefinition *md = *mdp;
558
559 if (!args->all_menus)
560 {
561 bool found = false;
562 struct MenuDefinition **mdp2 = NULL;
563 ARRAY_FOREACH(mdp2, &args->mda)
564 {
565 if ((*mdp2)->id == md->id)
566 {
567 found = true;
568 break;
569 }
570 }
571 if (!found)
572 continue;
573 }
574
575 struct SubMenu **smp = ARRAY_GET(&md->submenus, 0);
576 if (!smp || !*smp)
577 continue;
578
579 struct SubMenu *sm = *smp;
580
581 struct Keymap *km = NULL;
582 struct Keymap *km_tmp = NULL;
583 STAILQ_FOREACH_SAFE(km, &sm->keymaps, entries, km_tmp)
584 {
585 if (args->all_keys ||
586 ((key_len == km->len) && (memcmp(km->keys, key_bytes, km->len) == 0)))
587 {
588 STAILQ_REMOVE(&sm->keymaps, km, Keymap, entries);
589 keymap_free(&km);
590 success = true;
591
592 if (!args->all_keys && !args->all_menus)
593 {
594 buf_reset(keystr);
595 keymap_expand_string(args->key, keystr);
596 mutt_debug(LL_NOTIFY, "%s: %s %s\n", notify_binding_name(nb),
597 md->name, buf_string(keystr));
598
599 struct EventBinding ev_b = { md, args->key, OP_NULL };
600 notify_send(NeoMutt->notify, NT_BINDING, nb, &ev_b);
601 }
602 }
603 }
604
605 if (args->all_keys && !args->all_menus && success)
606 {
607 buf_reset(keystr);
608 keymap_expand_string(args->key, keystr);
609 mutt_debug(LL_NOTIFY, "%s: %s %s\n", notify_binding_name(nb), md->name,
610 buf_string(keystr));
611
612 struct EventBinding ev_b = { md, args->key, OP_NULL };
613 notify_send(NeoMutt->notify, NT_BINDING, nb, &ev_b);
614
615 // restore some bindings for this menu
617 }
618 }
619
620 if (args->all_menus && success)
621 {
622 buf_reset(keystr);
623 keymap_expand_string(args->key, keystr);
624 mutt_debug(LL_NOTIFY, "%s: ALL %s\n", notify_binding_name(nb), buf_string(keystr));
625
626 struct EventBinding ev_b = { NULL, args->key, OP_NULL };
627 notify_send(NeoMutt->notify, NT_BINDING, nb, &ev_b);
628
629 // restore some bindings for all menus
631 }
632
633 buf_pool_release(&keystr);
634 return true;
635}
#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:128
struct MenuDefinitionArray MenuDefs
All the registered Menus.
Definition init.c:42
const char * notify_binding_name(enum NotifyBinding ev)
Get the name for a NotifyBinding.
Definition commands.c:409
void set_default_bindings(const struct MenuDefinition *md)
Set some safe default keybindings.
Definition commands.c:351
void keymap_expand_string(const char *str, struct Buffer *buf)
Get a human-readable key string.
Definition keymap.c:247
void keymap_free(struct Keymap **pptr)
Free a Keymap.
Definition keymap.c:127
size_t parse_keys(const char *str, keycode_t *d, size_t max)
Parse a key string into key codes.
Definition keymap.c:318
NotifyBinding
Key Binding notification types.
Definition notify.h:46
short keycode_t
Type for key storage, the rest of neomutt works fine with int type.
Definition keymap.h:31
#define MAX_SEQ
Maximum length of a key binding sequence used for buffer in km_bind.
Definition menu.h:32
#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:160
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: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
Collection of related functions.
Definition menu.h:68
struct KeymapList keymaps
All keybindings.
Definition menu.h:71
+ Here is the call graph for this function:
+ Here is the caller graph for this function: