From 6afbd898c6cbed6d3cef3ba4747815edfae0bc56 Mon Sep 17 00:00:00 2001 From: Steven Chan Date: Tue, 7 May 2019 11:02:13 -0700 Subject: [PATCH] Ability to add comments into help view [#809] 1. keys.h Add a run_request.help field, analogous to the req_info.help field. 2. options.c a. read_option() Identify any #comment text string that may have accompanied a bind command option, and add it to the head of the argv list (argv[0]), so that it is available to the option_bind_command() when it is eventually called. The #comment text string is trimmed of any white space. b. option_bind_command() Since argv[0] is now a container for a possible comment text string, the function needs to treat the argv list elements as shifted by one. When calling add_run_request(), pass in argv[0] as an extra argument. c. set_repo_config_option() option_bind_command() is directly called to handle keybindings defined in a repo configuration file. argv[0] must be prepared similarly to read_option(). However, argv[0] is set to an empty string, because comment text is never available from a repo configuration file. 3. keys.c a. add_run_request() A help text string is passed in as an extra argument; it is duplicated into the new run_request.help field. 4. help.c a. help_draw() Analogous to drawing req_info.help as a LINE_DEFAULT, draw the run_request.help text using draw_text(), even though it will be misaligned with existing help text. --- include/tig/keys.h | 3 ++- src/help.c | 1 + src/keys.c | 8 +++++++- src/options.c | 42 ++++++++++++++++++++++++++++++------------ 4 files changed, 40 insertions(+), 14 deletions(-) diff --git a/include/tig/keys.h b/include/tig/keys.h index 493e58d1a..06158284d 100644 --- a/include/tig/keys.h +++ b/include/tig/keys.h @@ -90,10 +90,11 @@ struct run_request { struct keymap *keymap; struct run_request_flags flags; const char **argv; + char *help; }; struct run_request *get_run_request(enum request request); -enum status_code add_run_request(struct keymap *keymap, const struct key key[], size_t keys, const char **argv); +enum status_code add_run_request(struct keymap *keymap, const struct key key[], size_t keys, const char **argv, const char *help); enum status_code parse_run_request_flags(struct run_request_flags *flags, const char **argv); const char *format_run_request_flags(const struct run_request *req); diff --git a/src/help.c b/src/help.c index 1b90cfcc7..d6d6a537a 100644 --- a/src/help.c +++ b/src/help.c @@ -62,6 +62,7 @@ help_draw(struct view *view, struct line *line, unsigned int lineno) return true; sep = " "; } + if (req->help) draw_text(view, LINE_DEFAULT, req->help); } else { const struct request_info *req_info = help->data.req_info; diff --git a/src/keys.c b/src/keys.c index a1c82ef55..c746e9168 100644 --- a/src/keys.c +++ b/src/keys.c @@ -486,7 +486,7 @@ parse_run_request_flags(struct run_request_flags *flags, const char **argv) enum status_code add_run_request(struct keymap *keymap, const struct key key[], - size_t keys, const char **argv) + size_t keys, const char **argv, const char *help) { struct run_request *req; struct run_request_flags flags = {0}; @@ -505,6 +505,12 @@ add_run_request(struct keymap *keymap, const struct key key[], req->flags = flags; req->keymap = keymap; + /* If there is help text, then dupe it into the run_request struct */ + req->help = NULL; + if (help) + if ((req->help = strdup(help)) == NULL) + return ERROR_OUT_OF_MEMORY; + return add_keybinding(keymap, REQ_RUN_REQUESTS + run_requests, key, keys); } diff --git a/src/options.c b/src/options.c index a4e254741..8b95b1971 100644 --- a/src/options.c +++ b/src/options.c @@ -789,6 +789,11 @@ option_set_command(int argc, const char *argv[]) } /* Wants: mode request key */ +/* Assuming the bind option is 'bind keymap key !command parameters # comments', + * the calling convention for the function is as follows: + * argv[0] will contain the trimmed comment text string (optional) + * argv[n] where n > 0 will contain command and parameters + */ static enum status_code option_bind_command(int argc, const char *argv[]) { @@ -798,6 +803,12 @@ option_bind_command(int argc, const char *argv[]) struct keymap *keymap; const char *key_arg; + /* Cache the help text */ + const char *help = argv[0]; + + /* Shift argv list by one position */ + argv++; argc--; + if (argc < 3) return error("Invalid key binding: bind keymap key action"); @@ -870,7 +881,7 @@ option_bind_command(int argc, const char *argv[]) const char *toggle[] = { ":toggle", mapped, arg, NULL}; const char *other[] = { mapped, NULL }; const char **prompt = *mapped == ':' ? other : toggle; - enum status_code code = add_run_request(keymap, key, keys, prompt); + enum status_code code = add_run_request(keymap, key, keys, prompt, NULL); if (code == SUCCESS) code = error("%s has been replaced by `%s%s%s%s'", @@ -882,7 +893,7 @@ option_bind_command(int argc, const char *argv[]) } if (request == REQ_UNKNOWN) - return add_run_request(keymap, key, keys, argv + 2); + return add_run_request(keymap, key, keys, argv + 2, help); return add_keybinding(keymap, request, key, keys); } @@ -957,12 +968,19 @@ read_option(char *opt, size_t optlen, char *value, size_t valuelen, void *data) const char *argv[SIZEOF_ARG]; int argc = 0; - if (len < valuelen) { + bool have_comments = len < valuelen; + if (have_comments) { valuelen = len; value[valuelen] = 0; } - if (!argv_from_string(argv, &argc, value)) + /* If handling a bind option, then add any trimmed comment text to head of the argv list */ + if (!strcmp(opt, "bind")) { + argv[0] = have_comments ? string_trim(value + len + 1) : NULL; + argc++; + } + + if (!argv_from_string(argv, &argc, value )) status = error("Too many option arguments for %s", opt); else status = set_option(opt, argc, argv); @@ -1324,14 +1342,14 @@ set_remote_branch(const char *name, const char *value, size_t valuelen) static void set_repo_config_option(char *name, char *value, enum status_code (*cmd)(int, const char **)) { - const char *argv[SIZEOF_ARG] = { name, "=" }; - int argc = 1 + (cmd == option_set_command); - enum status_code code; - - if (!argv_from_string(argv, &argc, value)) - code = error("Too many arguments"); - else - code = cmd(argc, argv); + const char *argv[SIZEOF_ARG]; int argc; + if (cmd == option_set_command ) { argv[0] = name; argv[1] = "="; argc = 2; } + else if (cmd == option_bind_command) { argv[0] = ""; argv[1] = name; argc = 2; } + else { argv[0] = name; argc = 1; } + + enum status_code code = !argv_from_string(argv, &argc, value) + ? error("Too many arguments") + : cmd(argc, argv); if (code != SUCCESS) warn("Option 'tig.%s': %s", name, get_status_message(code));