From e2cf226ea6fdf8031a92112c3b889b23a96ec777 Mon Sep 17 00:00:00 2001 From: Christopher John CZETTEL Date: Sun, 25 Sep 2016 21:50:17 +0200 Subject: [PATCH] add ICommand for new :ex-style commands These are needed for the new summary tables feature (and inspired by the Command lookup table in init.c) added: ICommand wrapper / lookup table allowing easy addition of new informational commands that will not be parsed in .muttrc files and override any existing rc-line commands when executed in mutt. added: hook in mutt_enter_command in command.c to integrate new ICommands facility Issue #162 --- Makefile.autosetup | 2 +- commands.c | 47 ++++++++++++++--------- functions.h | 11 ++++++ icommands.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++ icommands.h | 53 ++++++++++++++++++++++++++ keymap.c | 2 + keymap.h | 1 + pager.c | 1 + 8 files changed, 192 insertions(+), 19 deletions(-) create mode 100644 icommands.c create mode 100644 icommands.h diff --git a/Makefile.autosetup b/Makefile.autosetup index 9b7addd81..77b122d07 100644 --- a/Makefile.autosetup +++ b/Makefile.autosetup @@ -72,7 +72,7 @@ NEOMUTTOBJS= account.o addrbook.o alias.o bcache.o browser.o color.o commands.o pager.o pattern.o postpone.o progress.o query.o recvattach.o \ recvcmd.o resize.o rfc1524.o rfc3676.o safe_asprintf.o \ score.o send.o sendlib.o sidebar.o smtp.o sort.o state.o \ - status.o system.o terminal.o version.o + status.o system.o terminal.o version.o icommands.o @if !HAVE_WCSCASECMP NEOMUTTOBJS+= wcscasecmp.o diff --git a/commands.c b/commands.c index c8297bfba..f1ce0cc6c 100644 --- a/commands.c +++ b/commands.c @@ -49,6 +49,7 @@ #include "globals.h" #include "hdrline.h" #include "hook.h" +#include "icommands.h" #include "keymap.h" #include "mailbox.h" #include "mutt_curses.h" @@ -730,32 +731,42 @@ void mutt_shell_escape(void) */ void mutt_enter_command(void) { - struct Buffer err, token; - char buffer[LONG_STRING]; - enum CommandResult r; + char buffer[LONG_STRING] = { 0 }; - buffer[0] = '\0'; + /* if enter is pressed after : with no command, just return */ if (mutt_get_field(":", buffer, sizeof(buffer), MUTT_COMMAND) != 0 || !buffer[0]) return; - mutt_buffer_init(&err); - err.dsize = STRING; - err.data = mutt_mem_malloc(err.dsize); - err.dptr = err.data; - mutt_buffer_init(&token); - r = mutt_parse_rc_line(buffer, &token, &err); - FREE(&token.data); - if (err.data[0]) + + struct Buffer *err = mutt_buffer_alloc(STRING); + struct Buffer *token = mutt_buffer_alloc(STRING); + + /* check if buffer is a valid icommand, else fall back quietly to parse_rc_lines */ + enum CommandResult rc = mutt_parse_icommand(buffer, err); + if (!mutt_buffer_is_empty(err)) { /* since errbuf could potentially contain printf() sequences in it, - we must call mutt_error() in this fashion so that vsprintf() - doesn't expect more arguments that we passed */ - if (r == MUTT_CMD_SUCCESS) - mutt_message("%s", err.data); + * we must call mutt_error() in this fashion so that vsprintf() + * doesn't expect more arguments that we passed */ + if (rc == MUTT_CMD_ERROR) + mutt_error("%s", err->data); else - mutt_error("%s", err.data); + mutt_warning("%s", err->data); + } + else if (rc != MUTT_CMD_SUCCESS) + { + rc = mutt_parse_rc_line(buffer, token, err); + if (!mutt_buffer_is_empty(err)) + { + if (rc == MUTT_CMD_SUCCESS) /* command succeeded with message */ + mutt_message("%s", err->data); + else /* error executing command */ + mutt_error("%s", err->data); + } } + /* else successful command */ - FREE(&err.data); + mutt_buffer_free(&token); + mutt_buffer_free(&err); } /** diff --git a/functions.h b/functions.h index 4f8c019b5..3666479f4 100644 --- a/functions.h +++ b/functions.h @@ -649,6 +649,17 @@ const struct Binding OpMix[] = { /* map: mixmaster */ { NULL, 0, NULL }, }; #endif /* MIXMASTER */ + +/** + * OpSummary - Key bindings for the summary menu + */ +const struct Binding OpSummary[] = +{ + { "quit", OP_QUIT, "q" }, + { "help", OP_HELP, "?" }, + { NULL, 0, NULL }, +}; + // clang-format on #endif /* MUTT_FUNCTIONS_H */ diff --git a/icommands.c b/icommands.c new file mode 100644 index 000000000..1f39ee1ec --- /dev/null +++ b/icommands.c @@ -0,0 +1,94 @@ +/** + * @file + * Information commands + * + * @authors + * Copyright (C) 2016 Christopher John Czettel + * Copyright (C) 2018 Richard Russon + * + * @copyright + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, either version 2 of the License, or (at your option) any later + * version. + * + * 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 . + */ + +#include "config.h" +#include +#include +#include "mutt/mutt.h" +#include "config/lib.h" +#include "mutt.h" +#include "icommands.h" +#include "globals.h" +#include "muttlib.h" +#include "pager.h" +#include "version.h" + +// clang-format off +/** + * ICommandList - All available informational commands + * + * @note These commands take precendence over conventional mutt rc-lines + */ +const struct ICommand ICommandList[] = { + { NULL, NULL, 0 }, +}; +// clang-format on + +/** + * mutt_parse_icommand - Parse an informational command + * @param line Command to execute + * @param err Buffer for error messages + * @retval #MUTT_CMD_SUCCESS Success + * @retval #MUTT_CMD_ERROR Error (no message): command not found + * @retval #MUTT_CMD_ERROR Error with message: command failed + * @retval #MUTT_CMD_WARNING Warning with message: command failed + */ +enum CommandResult mutt_parse_icommand(/* const */ char *line, struct Buffer *err) +{ + if (!line || !*line || !err) + return MUTT_CMD_ERROR; + + enum CommandResult rc = MUTT_CMD_ERROR; + + struct Buffer expn, token; + + mutt_buffer_init(&expn); + mutt_buffer_init(&token); + + expn.data = expn.dptr = line; + expn.dsize = mutt_str_strlen(line); + + mutt_buffer_reset(err); + + SKIPWS(expn.dptr); + while (*expn.dptr) + { + mutt_extract_token(&token, &expn, 0); + for (size_t i = 0; ICommandList[i].name; i++) + { + if (mutt_str_strcmp(token.data, ICommandList[i].name) != 0) + continue; + + rc = ICommandList[i].func(&token, &expn, ICommandList[i].data, err); + if (rc != 0) + goto finish; + + break; /* Continue with next command */ + } + } + +finish: + if (expn.destroy) + FREE(&expn.data); + return rc; +} diff --git a/icommands.h b/icommands.h new file mode 100644 index 000000000..f3ae5079c --- /dev/null +++ b/icommands.h @@ -0,0 +1,53 @@ +/** + * @file + * Information commands + * + * @authors + * Copyright (C) 2016 Christopher John Czettel + * Copyright (C) 2018 Richard Russon + * + * @copyright + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, either version 2 of the License, or (at your option) any later + * version. + * + * 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 . + */ + +#ifndef MUTT_ICOMMANDS_H +#define MUTT_ICOMMANDS_H + +#include "mutt_commands.h" + +struct Buffer; + +/** + * typedef icommand_t - Prototype for information commands + * @param buf Command + * @param s Entire command line + * @param data Private data to pass to parse function + * @param err Buffer for error messages + * @retval enum e.g. #MUTT_CMD_SUCCESS + */ +typedef enum CommandResult icommand_t(struct Buffer *buf, struct Buffer *s, unsigned long data, struct Buffer *err); + +/** + * struct ICommand - An Informational Command + */ +struct ICommand +{ + char *name; ///< Name of the command + icommand_t *func; ///< Function to parse the command + unsigned long data; ///< Private data to pass to the command +}; + +int mutt_parse_icommand(/* const */ char *line, struct Buffer *err); + +#endif /* MUTT_ICOMMANDS_H */ diff --git a/keymap.c b/keymap.c index 6f2ee2ca3..0871d112f 100644 --- a/keymap.c +++ b/keymap.c @@ -1235,6 +1235,8 @@ const struct Binding *km_get_table(int menu) return OpPost; case MENU_QUERY: return OpQuery; + case MENU_SUMMARY: + return OpSummary; } return NULL; } diff --git a/keymap.h b/keymap.h index 0ad4bf060..7263a736b 100644 --- a/keymap.h +++ b/keymap.h @@ -84,6 +84,7 @@ enum MenuTypes #ifdef MIXMASTER MENU_MIX, ///< Create/edit a Mixmaster chain #endif + MENU_SUMMARY, MENU_MAX, }; diff --git a/pager.c b/pager.c index 5046be3e3..b00cae411 100644 --- a/pager.c +++ b/pager.c @@ -3038,6 +3038,7 @@ int mutt_pager(const char *banner, const char *fname, int flags, struct Pager *e old_PagerIndexLines = PagerIndexLines; mutt_enter_command(); + pager_menu->redraw = REDRAW_FULL; if (OptNeedResort) { -- 2.40.0