"Fossies" - the Fresh Open Source Software Archive

Member "tmux-3.2a/cmd-list-keys.c" (10 Jun 2021, 9444 Bytes) of package /linux/misc/tmux-3.2a.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /* $OpenBSD$ */
    2 
    3 /*
    4  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
    5  *
    6  * Permission to use, copy, modify, and distribute this software for any
    7  * purpose with or without fee is hereby granted, provided that the above
    8  * copyright notice and this permission notice appear in all copies.
    9  *
   10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   14  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
   15  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
   16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   17  */
   18 
   19 #include <sys/types.h>
   20 
   21 #include <stdlib.h>
   22 #include <string.h>
   23 
   24 #include "tmux.h"
   25 
   26 /*
   27  * List key bindings.
   28  */
   29 
   30 static enum cmd_retval  cmd_list_keys_exec(struct cmd *, struct cmdq_item *);
   31 
   32 static enum cmd_retval  cmd_list_keys_commands(struct cmd *,
   33                 struct cmdq_item *);
   34 
   35 const struct cmd_entry cmd_list_keys_entry = {
   36     .name = "list-keys",
   37     .alias = "lsk",
   38 
   39     .args = { "1aNP:T:", 0, 1 },
   40     .usage = "[-1aN] [-P prefix-string] [-T key-table] [key]",
   41 
   42     .flags = CMD_STARTSERVER|CMD_AFTERHOOK,
   43     .exec = cmd_list_keys_exec
   44 };
   45 
   46 const struct cmd_entry cmd_list_commands_entry = {
   47     .name = "list-commands",
   48     .alias = "lscm",
   49 
   50     .args = { "F:", 0, 1 },
   51     .usage = "[-F format] [command]",
   52 
   53     .flags = CMD_STARTSERVER|CMD_AFTERHOOK,
   54     .exec = cmd_list_keys_exec
   55 };
   56 
   57 static u_int
   58 cmd_list_keys_get_width(const char *tablename, key_code only)
   59 {
   60     struct key_table    *table;
   61     struct key_binding  *bd;
   62     u_int            width, keywidth = 0;
   63 
   64     table = key_bindings_get_table(tablename, 0);
   65     if (table == NULL)
   66         return (0);
   67     bd = key_bindings_first(table);
   68     while (bd != NULL) {
   69         if ((only != KEYC_UNKNOWN && bd->key != only) ||
   70             KEYC_IS_MOUSE(bd->key) ||
   71             bd->note == NULL ||
   72             *bd->note == '\0') {
   73             bd = key_bindings_next(table, bd);
   74             continue;
   75         }
   76         width = utf8_cstrwidth(key_string_lookup_key(bd->key, 0));
   77         if (width > keywidth)
   78             keywidth = width;
   79 
   80         bd = key_bindings_next(table, bd);
   81     }
   82     return (keywidth);
   83 }
   84 
   85 static int
   86 cmd_list_keys_print_notes(struct cmdq_item *item, struct args *args,
   87     const char *tablename, u_int keywidth, key_code only, const char *prefix)
   88 {
   89     struct client       *tc = cmdq_get_target_client(item);
   90     struct key_table    *table;
   91     struct key_binding  *bd;
   92     const char      *key;
   93     char            *tmp, *note;
   94     int                  found = 0;
   95 
   96     table = key_bindings_get_table(tablename, 0);
   97     if (table == NULL)
   98         return (0);
   99     bd = key_bindings_first(table);
  100     while (bd != NULL) {
  101         if ((only != KEYC_UNKNOWN && bd->key != only) ||
  102             KEYC_IS_MOUSE(bd->key) ||
  103             ((bd->note == NULL || *bd->note == '\0') &&
  104             !args_has(args, 'a'))) {
  105             bd = key_bindings_next(table, bd);
  106             continue;
  107         }
  108         found = 1;
  109         key = key_string_lookup_key(bd->key, 0);
  110 
  111         if (bd->note == NULL || *bd->note == '\0')
  112             note = cmd_list_print(bd->cmdlist, 1);
  113         else
  114             note = xstrdup(bd->note);
  115         tmp = utf8_padcstr(key, keywidth + 1);
  116         if (args_has(args, '1') && tc != NULL) {
  117             status_message_set(tc, -1, 1, 0, "%s%s%s", prefix, tmp,
  118                 note);
  119         } else
  120             cmdq_print(item, "%s%s%s", prefix, tmp, note);
  121         free(tmp);
  122         free(note);
  123 
  124         if (args_has(args, '1'))
  125             break;
  126         bd = key_bindings_next(table, bd);
  127     }
  128     return (found);
  129 }
  130 
  131 static char *
  132 cmd_list_keys_get_prefix(struct args *args, key_code *prefix)
  133 {
  134     char    *s;
  135 
  136     *prefix = options_get_number(global_s_options, "prefix");
  137     if (!args_has(args, 'P')) {
  138         if (*prefix != KEYC_NONE)
  139             xasprintf(&s, "%s ", key_string_lookup_key(*prefix, 0));
  140         else
  141             s = xstrdup("");
  142     } else
  143         s = xstrdup(args_get(args, 'P'));
  144     return (s);
  145 }
  146 
  147 static enum cmd_retval
  148 cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
  149 {
  150     struct args     *args = cmd_get_args(self);
  151     struct key_table    *table;
  152     struct key_binding  *bd;
  153     const char      *tablename, *r;
  154     char            *key, *cp, *tmp, *start, *empty;
  155     key_code         prefix, only = KEYC_UNKNOWN;
  156     int          repeat, width, tablewidth, keywidth, found = 0;
  157     size_t           tmpsize, tmpused, cplen;
  158 
  159     if (cmd_get_entry(self) == &cmd_list_commands_entry)
  160         return (cmd_list_keys_commands(self, item));
  161 
  162     if (args->argc != 0) {
  163         only = key_string_lookup_string(args->argv[0]);
  164         if (only == KEYC_UNKNOWN) {
  165             cmdq_error(item, "invalid key: %s", args->argv[0]);
  166             return (CMD_RETURN_ERROR);
  167         }
  168         only &= (KEYC_MASK_KEY|KEYC_MASK_MODIFIERS);
  169     }
  170 
  171     tablename = args_get(args, 'T');
  172     if (tablename != NULL && key_bindings_get_table(tablename, 0) == NULL) {
  173         cmdq_error(item, "table %s doesn't exist", tablename);
  174         return (CMD_RETURN_ERROR);
  175     }
  176 
  177     if (args_has(args, 'N')) {
  178         if (tablename == NULL) {
  179             start = cmd_list_keys_get_prefix(args, &prefix);
  180             keywidth = cmd_list_keys_get_width("root", only);
  181             if (prefix != KEYC_NONE) {
  182                 width = cmd_list_keys_get_width("prefix", only);
  183                 if (width == 0)
  184                     prefix = KEYC_NONE;
  185                 else if (width > keywidth)
  186                     keywidth = width;
  187             }
  188             empty = utf8_padcstr("", utf8_cstrwidth(start));
  189 
  190             found = cmd_list_keys_print_notes(item, args, "root",
  191                 keywidth, only, empty);
  192             if (prefix != KEYC_NONE) {
  193                 if (cmd_list_keys_print_notes(item, args,
  194                     "prefix", keywidth, only, start))
  195                     found = 1;
  196             }
  197             free(empty);
  198         } else {
  199             if (args_has(args, 'P'))
  200                 start = xstrdup(args_get(args, 'P'));
  201             else
  202                 start = xstrdup("");
  203             keywidth = cmd_list_keys_get_width(tablename, only);
  204             found = cmd_list_keys_print_notes(item, args, tablename,
  205                 keywidth, only, start);
  206 
  207         }
  208         free(start);
  209         goto out;
  210     }
  211 
  212     repeat = 0;
  213     tablewidth = keywidth = 0;
  214     table = key_bindings_first_table ();
  215     while (table != NULL) {
  216         if (tablename != NULL && strcmp(table->name, tablename) != 0) {
  217             table = key_bindings_next_table(table);
  218             continue;
  219         }
  220         bd = key_bindings_first(table);
  221         while (bd != NULL) {
  222             if (only != KEYC_UNKNOWN && bd->key != only) {
  223                 bd = key_bindings_next(table, bd);
  224                 continue;
  225             }
  226             key = args_escape(key_string_lookup_key(bd->key, 0));
  227 
  228             if (bd->flags & KEY_BINDING_REPEAT)
  229                 repeat = 1;
  230 
  231             width = utf8_cstrwidth(table->name);
  232             if (width > tablewidth)
  233                 tablewidth = width;
  234             width = utf8_cstrwidth(key);
  235             if (width > keywidth)
  236                 keywidth = width;
  237 
  238             free(key);
  239             bd = key_bindings_next(table, bd);
  240         }
  241         table = key_bindings_next_table(table);
  242     }
  243 
  244     tmpsize = 256;
  245     tmp = xmalloc(tmpsize);
  246 
  247     table = key_bindings_first_table ();
  248     while (table != NULL) {
  249         if (tablename != NULL && strcmp(table->name, tablename) != 0) {
  250             table = key_bindings_next_table(table);
  251             continue;
  252         }
  253         bd = key_bindings_first(table);
  254         while (bd != NULL) {
  255             if (only != KEYC_UNKNOWN && bd->key != only) {
  256                 bd = key_bindings_next(table, bd);
  257                 continue;
  258             }
  259             found = 1;
  260             key = args_escape(key_string_lookup_key(bd->key, 0));
  261 
  262             if (!repeat)
  263                 r = "";
  264             else if (bd->flags & KEY_BINDING_REPEAT)
  265                 r = "-r ";
  266             else
  267                 r = "   ";
  268             tmpused = xsnprintf(tmp, tmpsize, "%s-T ", r);
  269 
  270             cp = utf8_padcstr(table->name, tablewidth);
  271             cplen = strlen(cp) + 1;
  272             while (tmpused + cplen + 1 >= tmpsize) {
  273                 tmpsize *= 2;
  274                 tmp = xrealloc(tmp, tmpsize);
  275             }
  276             strlcat(tmp, cp, tmpsize);
  277             tmpused = strlcat(tmp, " ", tmpsize);
  278             free(cp);
  279 
  280             cp = utf8_padcstr(key, keywidth);
  281             cplen = strlen(cp) + 1;
  282             while (tmpused + cplen + 1 >= tmpsize) {
  283                 tmpsize *= 2;
  284                 tmp = xrealloc(tmp, tmpsize);
  285             }
  286             strlcat(tmp, cp, tmpsize);
  287             tmpused = strlcat(tmp, " ", tmpsize);
  288             free(cp);
  289 
  290             cp = cmd_list_print(bd->cmdlist, 1);
  291             cplen = strlen(cp);
  292             while (tmpused + cplen + 1 >= tmpsize) {
  293                 tmpsize *= 2;
  294                 tmp = xrealloc(tmp, tmpsize);
  295             }
  296             strlcat(tmp, cp, tmpsize);
  297             free(cp);
  298 
  299             cmdq_print(item, "bind-key %s", tmp);
  300 
  301             free(key);
  302             bd = key_bindings_next(table, bd);
  303         }
  304         table = key_bindings_next_table(table);
  305     }
  306 
  307     free(tmp);
  308 
  309 out:
  310     if (only != KEYC_UNKNOWN && !found) {
  311         cmdq_error(item, "unknown key: %s", args->argv[0]);
  312         return (CMD_RETURN_ERROR);
  313     }
  314     return (CMD_RETURN_NORMAL);
  315 }
  316 
  317 static enum cmd_retval
  318 cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
  319 {
  320     struct args      *args = cmd_get_args(self);
  321     const struct cmd_entry  **entryp;
  322     const struct cmd_entry   *entry;
  323     struct format_tree   *ft;
  324     const char       *template, *s, *command = NULL;
  325     char             *line;
  326 
  327     if (args->argc != 0)
  328         command = args->argv[0];
  329 
  330     if ((template = args_get(args, 'F')) == NULL) {
  331         template = "#{command_list_name}"
  332             "#{?command_list_alias, (#{command_list_alias}),} "
  333             "#{command_list_usage}";
  334     }
  335 
  336     ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
  337     format_defaults(ft, NULL, NULL, NULL, NULL);
  338 
  339     for (entryp = cmd_table; *entryp != NULL; entryp++) {
  340         entry = *entryp;
  341         if (command != NULL &&
  342             (strcmp(entry->name, command) != 0 &&
  343             (entry->alias == NULL ||
  344             strcmp(entry->alias, command) != 0)))
  345             continue;
  346 
  347         format_add(ft, "command_list_name", "%s", entry->name);
  348         if (entry->alias != NULL)
  349             s = entry->alias;
  350         else
  351             s = "";
  352         format_add(ft, "command_list_alias", "%s", s);
  353         if (entry->usage != NULL)
  354             s = entry->usage;
  355         else
  356             s = "";
  357         format_add(ft, "command_list_usage", "%s", s);
  358 
  359         line = format_expand(ft, template);
  360         if (*line != '\0')
  361             cmdq_print(item, "%s", line);
  362         free(line);
  363     }
  364 
  365     format_free(ft);
  366     return (CMD_RETURN_NORMAL);
  367 }