Add different command historys for different types of prompts
authornicm <nicm@openbsd.org>
Thu, 10 Jun 2021 07:50:03 +0000 (07:50 +0000)
committernicm <nicm@openbsd.org>
Thu, 10 Jun 2021 07:50:03 +0000 (07:50 +0000)
("command", "search" etc). From Anindya Mukherjee.

13 files changed:
usr.bin/tmux/Makefile
usr.bin/tmux/cmd-command-prompt.c
usr.bin/tmux/cmd-confirm-before.c
usr.bin/tmux/cmd-show-prompt-history.c [new file with mode: 0644]
usr.bin/tmux/cmd.c
usr.bin/tmux/key-bindings.c
usr.bin/tmux/mode-tree.c
usr.bin/tmux/options-table.c
usr.bin/tmux/status.c
usr.bin/tmux/tmux.1
usr.bin/tmux/tmux.h
usr.bin/tmux/window-customize.c
usr.bin/tmux/window-tree.c

index d5151dc..e141324 100644 (file)
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.107 2020/12/22 09:22:14 nicm Exp $
+# $OpenBSD: Makefile,v 1.108 2021/06/10 07:50:03 nicm Exp $
 
 PROG=  tmux
 SRCS=  alerts.c \
@@ -61,6 +61,7 @@ SRCS= alerts.c \
        cmd-show-environment.c \
        cmd-show-messages.c \
        cmd-show-options.c \
+       cmd-show-prompt-history.c \
        cmd-source-file.c \
        cmd-split-window.c \
        cmd-swap-pane.c \
index aa69fbc..73dcb74 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-command-prompt.c,v 1.53 2020/05/16 16:16:07 nicm Exp $ */
+/* $OpenBSD: cmd-command-prompt.c,v 1.54 2021/06/10 07:50:03 nicm Exp $ */
 
 /*
  * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -40,25 +40,26 @@ const struct cmd_entry cmd_command_prompt_entry = {
        .name = "command-prompt",
        .alias = NULL,
 
-       .args = { "1kiI:Np:Tt:W", 0, 1 },
-       .usage = "[-1kiNTW] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " "
-                "[template]",
+       .args = { "1kiI:Np:t:T:", 0, 1 },
+       .usage = "[-1kiN] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE
+                " [-T type] [template]",
 
        .flags = CMD_CLIENT_TFLAG,
        .exec = cmd_command_prompt_exec
 };
 
 struct cmd_command_prompt_cdata {
-       int      flags;
+       int              flags;
+       enum prompt_type prompt_type;
 
-       char    *inputs;
-       char    *next_input;
+       char            *inputs;
+       char            *next_input;
 
-       char    *prompts;
-       char    *next_prompt;
+       char            *prompts;
+       char            *next_prompt;
 
-       char    *template;
-       int      idx;
+       char            *template;
+       int             idx;
 };
 
 static enum cmd_retval
@@ -67,7 +68,7 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
        struct args                     *args = cmd_get_args(self);
        struct client                   *tc = cmdq_get_target_client(item);
        struct cmd_find_state           *target = cmdq_get_target(item);
-       const char                      *inputs, *prompts;
+       const char                      *inputs, *prompts, *type;
        struct cmd_command_prompt_cdata *cdata;
        char                            *prompt, *ptr, *input = NULL;
        size_t                           n;
@@ -114,6 +115,16 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
                input = strsep(&cdata->next_input, ",");
        }
 
+       /* Get prompt type. */
+       if ((type = args_get(args, 'T')) != NULL) {
+               cdata->prompt_type = status_prompt_type(type);
+               if (cdata->prompt_type == PROMPT_TYPE_INVALID) {
+                       cmdq_error(item, "unknown type: %s", type);
+                       return (CMD_RETURN_ERROR);
+               }
+       } else
+               cdata->prompt_type = PROMPT_TYPE_COMMAND;
+
        if (args_has(args, '1'))
                cdata->flags |= PROMPT_SINGLE;
        else if (args_has(args, 'N'))
@@ -122,13 +133,9 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
                cdata->flags |= PROMPT_INCREMENTAL;
        else if (args_has(args, 'k'))
                cdata->flags |= PROMPT_KEY;
-       else if (args_has(args, 'W'))
-               cdata->flags |= PROMPT_WINDOW;
-       else if (args_has(args, 'T'))
-               cdata->flags |= PROMPT_TARGET;
        status_prompt_set(tc, target, prompt, input,
            cmd_command_prompt_callback, cmd_command_prompt_free, cdata,
-           cdata->flags);
+           cdata->flags, cdata->prompt_type);
        free(prompt);
 
        return (CMD_RETURN_NORMAL);
index 5d2126c..8841e08 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-confirm-before.c,v 1.42 2020/05/16 16:16:07 nicm Exp $ */
+/* $OpenBSD: cmd-confirm-before.c,v 1.43 2021/06/10 07:50:03 nicm Exp $ */
 
 /*
  * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
@@ -74,7 +74,7 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
 
        status_prompt_set(tc, target, new_prompt, NULL,
            cmd_confirm_before_callback, cmd_confirm_before_free, cdata,
-           PROMPT_SINGLE);
+           PROMPT_SINGLE, PROMPT_TYPE_COMMAND);
 
        free(new_prompt);
        return (CMD_RETURN_NORMAL);
diff --git a/usr.bin/tmux/cmd-show-prompt-history.c b/usr.bin/tmux/cmd-show-prompt-history.c
new file mode 100644 (file)
index 0000000..b4b191b
--- /dev/null
@@ -0,0 +1,108 @@
+/* $OpenBSD: cmd-show-prompt-history.c,v 1.1 2021/06/10 07:50:03 nicm Exp $ */
+
+/*
+ * Copyright (c) 2021 Anindya Mukherjee <anindya49@hotmail.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "tmux.h"
+
+#include <stdlib.h>
+
+/*
+ * Show or clear prompt history.
+ */
+
+static enum cmd_retval cmd_show_prompt_history_exec(struct cmd *,
+                           struct cmdq_item *);
+
+const struct cmd_entry cmd_show_prompt_history_entry = {
+       .name = "show-prompt-history",
+       .alias = "showphist",
+
+       .args = { "T:", 0, 0 },
+       .usage = "[-T type]",
+
+       .flags = CMD_AFTERHOOK,
+       .exec = cmd_show_prompt_history_exec
+};
+
+const struct cmd_entry cmd_clear_prompt_history_entry = {
+       .name = "clear-prompt-history",
+       .alias = "clearphist",
+
+       .args = { "T:", 0, 0 },
+       .usage = "[-T type]",
+
+       .flags = CMD_AFTERHOOK,
+       .exec = cmd_show_prompt_history_exec
+};
+
+static enum cmd_retval
+cmd_show_prompt_history_exec(struct cmd *self, struct cmdq_item *item)
+{
+       struct args             *args = cmd_get_args(self);
+       const char              *typestr = args_get(args, 'T');
+       enum prompt_type         type;
+       u_int                    tidx, hidx;
+
+       if (cmd_get_entry(self) == &cmd_clear_prompt_history_entry) {
+               if (typestr == NULL) {
+                       for (tidx = 0; tidx < PROMPT_NTYPES; tidx++) {
+                               free(status_prompt_hlist[tidx]);
+                               status_prompt_hlist[tidx] = NULL;
+                               status_prompt_hsize[tidx] = 0;
+                       }
+               } else {
+                       type = status_prompt_type(typestr);
+                       if (type == PROMPT_TYPE_INVALID) {
+                               cmdq_error(item, "invalid type: %s", typestr);
+                               return (CMD_RETURN_ERROR);
+                       }
+                       free(status_prompt_hlist[type]);
+                       status_prompt_hlist[type] = NULL;
+                       status_prompt_hsize[type] = 0;
+               }
+
+               return (CMD_RETURN_NORMAL);
+       }
+
+       if (typestr == NULL) {
+               for (tidx = 0; tidx < PROMPT_NTYPES; tidx++) {
+                       cmdq_print(item, "History for %s:\n",
+                           status_prompt_type_string(tidx));
+                       for (hidx = 0; hidx < status_prompt_hsize[tidx];
+                           hidx++) {
+                               cmdq_print(item, "%d: %s", hidx + 1,
+                                   status_prompt_hlist[tidx][hidx]);
+                       }
+                       cmdq_print(item, "%s", "");
+               }
+       } else {
+               type = status_prompt_type(typestr);
+               if (type == PROMPT_TYPE_INVALID) {
+                       cmdq_error(item, "invalid type: %s", typestr);
+                       return (CMD_RETURN_ERROR);
+               }
+               cmdq_print(item, "History for %s:\n",
+                   status_prompt_type_string(type));
+               for (hidx = 0; hidx < status_prompt_hsize[type]; hidx++) {
+                       cmdq_print(item, "%d: %s", hidx + 1,
+                           status_prompt_hlist[type][hidx]);
+               }
+               cmdq_print(item, "%s", "");
+       }
+
+       return (CMD_RETURN_NORMAL);
+}
index bfceea5..fa6515a 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd.c,v 1.163 2020/06/29 15:53:28 bket Exp $ */
+/* $OpenBSD: cmd.c,v 1.164 2021/06/10 07:50:03 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -36,6 +36,7 @@ extern const struct cmd_entry cmd_choose_buffer_entry;
 extern const struct cmd_entry cmd_choose_client_entry;
 extern const struct cmd_entry cmd_choose_tree_entry;
 extern const struct cmd_entry cmd_clear_history_entry;
+extern const struct cmd_entry cmd_clear_prompt_history_entry;
 extern const struct cmd_entry cmd_clock_mode_entry;
 extern const struct cmd_entry cmd_command_prompt_entry;
 extern const struct cmd_entry cmd_confirm_before_entry;
@@ -105,6 +106,7 @@ extern const struct cmd_entry cmd_show_environment_entry;
 extern const struct cmd_entry cmd_show_hooks_entry;
 extern const struct cmd_entry cmd_show_messages_entry;
 extern const struct cmd_entry cmd_show_options_entry;
+extern const struct cmd_entry cmd_show_prompt_history_entry;
 extern const struct cmd_entry cmd_show_window_options_entry;
 extern const struct cmd_entry cmd_source_file_entry;
 extern const struct cmd_entry cmd_split_window_entry;
@@ -127,6 +129,7 @@ const struct cmd_entry *cmd_table[] = {
        &cmd_choose_client_entry,
        &cmd_choose_tree_entry,
        &cmd_clear_history_entry,
+       &cmd_clear_prompt_history_entry,
        &cmd_clock_mode_entry,
        &cmd_command_prompt_entry,
        &cmd_confirm_before_entry,
@@ -195,6 +198,7 @@ const struct cmd_entry *cmd_table[] = {
        &cmd_show_hooks_entry,
        &cmd_show_messages_entry,
        &cmd_show_options_entry,
+       &cmd_show_prompt_history_entry,
        &cmd_show_window_options_entry,
        &cmd_source_file_entry,
        &cmd_split_window_entry,
index 38d503f..d17058c 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: key-bindings.c,v 1.133 2021/06/10 07:21:09 nicm Exp $ */
+/* $OpenBSD: key-bindings.c,v 1.134 2021/06/10 07:50:03 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -350,12 +350,12 @@ key_bindings_init(void)
                "bind -N 'Rename current session' '$' command-prompt -I'#S' \"rename-session -- '%%'\"",
                "bind -N 'Split window horizontally' % split-window -h",
                "bind -N 'Kill current window' & confirm-before -p\"kill-window #W? (y/n)\" kill-window",
-               "bind -N 'Prompt for window index to select' \"'\" command-prompt -Wpindex \"select-window -t ':%%'\"",
+               "bind -N 'Prompt for window index to select' \"'\" command-prompt -T window-target -pindex \"select-window -t ':%%'\"",
                "bind -N 'Switch to previous client' ( switch-client -p",
                "bind -N 'Switch to next client' ) switch-client -n",
                "bind -N 'Rename current window' , command-prompt -I'#W' \"rename-window -- '%%'\"",
                "bind -N 'Delete the most recent paste buffer' - delete-buffer",
-               "bind -N 'Move the current window' . command-prompt -T \"move-window -t '%%'\"",
+               "bind -N 'Move the current window' . command-prompt -T target \"move-window -t '%%'\"",
                "bind -N 'Describe key binding' '/' command-prompt -kpkey 'list-keys -1N \"%%%\"'",
                "bind -N 'Select window 0' 0 select-window -t:=0",
                "bind -N 'Select window 1' 1 select-window -t:=1",
@@ -479,8 +479,8 @@ key_bindings_init(void)
                "bind -Tcopy-mode C-k send -X copy-end-of-line",
                "bind -Tcopy-mode C-n send -X cursor-down",
                "bind -Tcopy-mode C-p send -X cursor-up",
-               "bind -Tcopy-mode C-r command-prompt -ip'(search up)' -I'#{pane_search_string}' 'send -X search-backward-incremental \"%%%\"'",
-               "bind -Tcopy-mode C-s command-prompt -ip'(search down)' -I'#{pane_search_string}' 'send -X search-forward-incremental \"%%%\"'",
+               "bind -Tcopy-mode C-r command-prompt -T search -ip'(search up)' -I'#{pane_search_string}' 'send -X search-backward-incremental \"%%%\"'",
+               "bind -Tcopy-mode C-s command-prompt -T search -ip'(search down)' -I'#{pane_search_string}' 'send -X search-forward-incremental \"%%%\"'",
                "bind -Tcopy-mode C-v send -X page-down",
                "bind -Tcopy-mode C-w send -X copy-pipe-and-cancel",
                "bind -Tcopy-mode Escape send -X cancel",
@@ -559,7 +559,7 @@ key_bindings_init(void)
                "bind -Tcopy-mode-vi Space send -X begin-selection",
                "bind -Tcopy-mode-vi '$' send -X end-of-line",
                "bind -Tcopy-mode-vi , send -X jump-reverse",
-               "bind -Tcopy-mode-vi / command-prompt -p'(search down)' 'send -X search-forward \"%%%\"'",
+               "bind -Tcopy-mode-vi / command-prompt -T search -p'(search down)' 'send -X search-forward \"%%%\"'",
                "bind -Tcopy-mode-vi 0 send -X start-of-line",
                "bind -Tcopy-mode-vi 1 command-prompt -Np'(repeat)' -I1 'send -N \"%%%\"'",
                "bind -Tcopy-mode-vi 2 command-prompt -Np'(repeat)' -I2 'send -N \"%%%\"'",
@@ -572,7 +572,7 @@ key_bindings_init(void)
                "bind -Tcopy-mode-vi 9 command-prompt -Np'(repeat)' -I9 'send -N \"%%%\"'",
                "bind -Tcopy-mode-vi : command-prompt -p'(goto line)' 'send -X goto-line \"%%%\"'",
                "bind -Tcopy-mode-vi \\; send -X jump-again",
-               "bind -Tcopy-mode-vi ? command-prompt -p'(search up)' 'send -X search-backward \"%%%\"'",
+               "bind -Tcopy-mode-vi ? command-prompt -T search -p'(search up)' 'send -X search-backward \"%%%\"'",
                "bind -Tcopy-mode-vi A send -X append-selection-and-cancel",
                "bind -Tcopy-mode-vi B send -X previous-space",
                "bind -Tcopy-mode-vi D send -X copy-end-of-line",
index 5427b24..4cffe38 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: mode-tree.c,v 1.53 2021/04/12 09:36:12 nicm Exp $ */
+/* $OpenBSD: mode-tree.c,v 1.54 2021/06/10 07:50:03 nicm Exp $ */
 
 /*
  * Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -1168,7 +1168,7 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
                mtd->references++;
                status_prompt_set(c, NULL, "(search) ", "",
                    mode_tree_search_callback, mode_tree_search_free, mtd,
-                   PROMPT_NOFORMAT);
+                   PROMPT_NOFORMAT, PROMPT_TYPE_SEARCH);
                break;
        case 'n':
                mode_tree_search_set(mtd);
@@ -1177,7 +1177,7 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
                mtd->references++;
                status_prompt_set(c, NULL, "(filter) ", mtd->filter,
                    mode_tree_filter_callback, mode_tree_filter_free, mtd,
-                   PROMPT_NOFORMAT);
+                   PROMPT_NOFORMAT, PROMPT_TYPE_SEARCH);
                break;
        case 'v':
                mtd->preview = !mtd->preview;
index 4df0e87..c093ebb 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: options-table.c,v 1.141 2021/06/10 07:24:10 nicm Exp $ */
+/* $OpenBSD: options-table.c,v 1.142 2021/06/10 07:50:03 nicm Exp $ */
 
 /*
  * Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -302,6 +302,15 @@ const struct options_table_entry options_table[] = {
          .text = "Maximum number of server messages to keep."
        },
 
+       { .name = "prompt-history-limit",
+         .type = OPTIONS_TABLE_NUMBER,
+         .scope = OPTIONS_TABLE_SERVER,
+         .minimum = 0,
+         .maximum = INT_MAX,
+         .default_num = 100,
+         .text = "Maximum number of commands to keep in history."
+       },
+
        { .name = "set-clipboard",
          .type = OPTIONS_TABLE_CHOICE,
          .scope = OPTIONS_TABLE_SERVER,
index 2e7b21a..6ee4349 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: status.c,v 1.223 2021/06/10 07:38:28 nicm Exp $ */
+/* $OpenBSD: status.c,v 1.224 2021/06/10 07:50:04 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -33,9 +33,9 @@ static void    status_message_callback(int, short, void *);
 static void     status_timer_callback(int, short, void *);
 
 static char    *status_prompt_find_history_file(void);
-static const char *status_prompt_up_history(u_int *);
-static const char *status_prompt_down_history(u_int *);
-static void     status_prompt_add_history(const char *);
+static const char *status_prompt_up_history(u_int *, u_int);
+static const char *status_prompt_down_history(u_int *, u_int);
+static void     status_prompt_add_history(const char *, u_int);
 
 static char    *status_prompt_complete(struct client *, const char *, u_int);
 static char    *status_prompt_complete_window_menu(struct client *,
@@ -49,10 +49,16 @@ struct status_prompt_menu {
        char              flag;
 };
 
+static const char      *prompt_type_strings[] = {
+       "command",
+       "search",
+       "target",
+       "window-target"
+};
+
 /* Status prompt history. */
-#define PROMPT_HISTORY 100
-static char    **status_prompt_hlist;
-static u_int     status_prompt_hsize;
+char           **status_prompt_hlist[PROMPT_NTYPES];
+u_int            status_prompt_hsize[PROMPT_NTYPES];
 
 /* Find the history file to load/save from/to. */
 static char *
@@ -75,6 +81,28 @@ status_prompt_find_history_file(void)
        return (path);
 }
 
+/* Add loaded history item to the appropriate list. */
+static void
+status_prompt_add_typed_history(char *line)
+{
+       char                    *typestr;
+       enum prompt_type         type = PROMPT_TYPE_INVALID;
+
+       typestr = strsep(&line, ":");
+       if (line != NULL)
+               type = status_prompt_type(typestr);
+       if (type == PROMPT_TYPE_INVALID) {
+               /*
+                * Invalid types are not expected, but this provides backward
+                * compatibility with old history files.
+                */
+               if (line != NULL)
+                       *(--line) = ':';
+               status_prompt_add_history(typestr, PROMPT_TYPE_COMMAND);
+       } else
+               status_prompt_add_history(line, type);
+}
+
 /* Load status prompt history from file. */
 void
 status_prompt_load_history(void)
@@ -102,12 +130,12 @@ status_prompt_load_history(void)
                if (length > 0) {
                        if (line[length - 1] == '\n') {
                                line[length - 1] = '\0';
-                               status_prompt_add_history(line);
+                               status_prompt_add_typed_history(line);
                        } else {
                                tmp = xmalloc(length + 1);
                                memcpy(tmp, line, length);
                                tmp[length] = '\0';
-                               status_prompt_add_history(tmp);
+                               status_prompt_add_typed_history(tmp);
                                free(tmp);
                        }
                }
@@ -120,7 +148,7 @@ void
 status_prompt_save_history(void)
 {
        FILE    *f;
-       u_int    i;
+       u_int    i, type;
        char    *history_file;
 
        if ((history_file = status_prompt_find_history_file()) == NULL)
@@ -135,9 +163,13 @@ status_prompt_save_history(void)
        }
        free(history_file);
 
-       for (i = 0; i < status_prompt_hsize; i++) {
-               fputs(status_prompt_hlist[i], f);
-               fputc('\n', f);
+       for (type = 0; type < PROMPT_NTYPES; type++) {
+               for (i = 0; i < status_prompt_hsize[type]; i++) {
+                       fputs(prompt_type_strings[type], f);
+                       fputc(':', f);
+                       fputs(status_prompt_hlist[type][i], f);
+                       fputc('\n', f);
+               }
        }
        fclose(f);
 
@@ -545,7 +577,7 @@ status_message_redraw(struct client *c)
 void
 status_prompt_set(struct client *c, struct cmd_find_state *fs,
     const char *msg, const char *input, prompt_input_cb inputcb,
-    prompt_free_cb freecb, void *data, int flags)
+    prompt_free_cb freecb, void *data, int flags, enum prompt_type prompt_type)
 {
        struct format_tree      *ft;
        char                    *tmp;
@@ -581,9 +613,10 @@ status_prompt_set(struct client *c, struct cmd_find_state *fs,
        c->prompt_freecb = freecb;
        c->prompt_data = data;
 
-       c->prompt_hindex = 0;
+       memset(c->prompt_hindex, 0, sizeof c->prompt_hindex);
 
        c->prompt_flags = flags;
+       c->prompt_type = prompt_type;
        c->prompt_mode = PROMPT_ENTRY;
 
        if (~flags & PROMPT_INCREMENTAL)
@@ -644,7 +677,7 @@ status_prompt_update(struct client *c, const char *msg, const char *input)
        c->prompt_buffer = utf8_fromcstr(tmp);
        c->prompt_index = utf8_strlen(c->prompt_buffer);
 
-       c->prompt_hindex = 0;
+       memset(c->prompt_hindex, 0, sizeof c->prompt_hindex);
 
        c->flags |= CLIENT_REDRAWSTATUS;
 
@@ -768,7 +801,7 @@ status_prompt_space(const struct utf8_data *ud)
 }
 
 /*
- * Translate key from emacs to vi. Return 0 to drop key, 1 to process the key
+ * Translate key from vi to emacs. Return 0 to drop key, 1 to process the key
  * as an emacs key; return 2 to append to the buffer.
  */
 static int
@@ -1222,7 +1255,8 @@ process_key:
                goto changed;
        case KEYC_UP:
        case '\020': /* C-p */
-               histstr = status_prompt_up_history(&c->prompt_hindex);
+               histstr = status_prompt_up_history(c->prompt_hindex,
+                   c->prompt_type);
                if (histstr == NULL)
                        break;
                free(c->prompt_buffer);
@@ -1231,7 +1265,8 @@ process_key:
                goto changed;
        case KEYC_DOWN:
        case '\016': /* C-n */
-               histstr = status_prompt_down_history(&c->prompt_hindex);
+               histstr = status_prompt_down_history(c->prompt_hindex,
+                   c->prompt_type);
                if (histstr == NULL)
                        break;
                free(c->prompt_buffer);
@@ -1259,7 +1294,7 @@ process_key:
        case '\n':
                s = utf8_tocstr(c->prompt_buffer);
                if (*s != '\0')
-                       status_prompt_add_history(s);
+                       status_prompt_add_history(s, c->prompt_type);
                if (c->prompt_inputcb(c, c->prompt_data, s, 1) == 0)
                        status_prompt_clear(c);
                free(s);
@@ -1348,54 +1383,78 @@ changed:
 
 /* Get previous line from the history. */
 static const char *
-status_prompt_up_history(u_int *idx)
+status_prompt_up_history(u_int *idx, u_int type)
 {
        /*
         * History runs from 0 to size - 1. Index is from 0 to size. Zero is
         * empty.
         */
 
-       if (status_prompt_hsize == 0 || *idx == status_prompt_hsize)
+       if (status_prompt_hsize[type] == 0 ||
+           idx[type] == status_prompt_hsize[type])
                return (NULL);
-       (*idx)++;
-       return (status_prompt_hlist[status_prompt_hsize - *idx]);
+       idx[type]++;
+       return (status_prompt_hlist[type][status_prompt_hsize[type] - idx[type]]);
 }
 
 /* Get next line from the history. */
 static const char *
-status_prompt_down_history(u_int *idx)
+status_prompt_down_history(u_int *idx, u_int type)
 {
-       if (status_prompt_hsize == 0 || *idx == 0)
+       if (status_prompt_hsize[type] == 0 || idx[type] == 0)
                return ("");
-       (*idx)--;
-       if (*idx == 0)
+       idx[type]--;
+       if (idx[type] == 0)
                return ("");
-       return (status_prompt_hlist[status_prompt_hsize - *idx]);
+       return (status_prompt_hlist[type][status_prompt_hsize[type] - idx[type]]);
 }
 
 /* Add line to the history. */
 static void
-status_prompt_add_history(const char *line)
+status_prompt_add_history(const char *line, u_int type)
 {
-       size_t  size;
-
-       if (status_prompt_hsize > 0 &&
-           strcmp(status_prompt_hlist[status_prompt_hsize - 1], line) == 0)
-               return;
-
-       if (status_prompt_hsize == PROMPT_HISTORY) {
-               free(status_prompt_hlist[0]);
-
-               size = (PROMPT_HISTORY - 1) * sizeof *status_prompt_hlist;
-               memmove(&status_prompt_hlist[0], &status_prompt_hlist[1], size);
+       u_int   i, oldsize, newsize, freecount, hlimit, new = 1;
+       size_t  movesize;
+
+       oldsize = status_prompt_hsize[type];
+       if (oldsize > 0 &&
+           strcmp(status_prompt_hlist[type][oldsize - 1], line) == 0)
+               new = 0;
+
+       hlimit = options_get_number(global_options, "prompt-history-limit");
+       if (hlimit > oldsize) {
+               if (new == 0)
+                       return;
+               newsize = oldsize + new;
+       } else {
+               newsize = hlimit;
+               freecount = oldsize + new - newsize;
+               if (freecount > oldsize)
+                       freecount = oldsize;
+               if (freecount == 0)
+                       return;
+               for (i = 0; i < freecount; i++)
+                       free(status_prompt_hlist[type][i]);
+               movesize = (oldsize - freecount) *
+                   sizeof *status_prompt_hlist[type];
+               if (movesize > 0) {
+                       memmove(&status_prompt_hlist[type][0],
+                           &status_prompt_hlist[type][freecount], movesize);
+               }
+       }
 
-               status_prompt_hlist[status_prompt_hsize - 1] = xstrdup(line);
-               return;
+       if (newsize == 0) {
+               free(status_prompt_hlist[type]);
+               status_prompt_hlist[type] = NULL;
+       } else if (newsize != oldsize) {
+               status_prompt_hlist[type] =
+                   xreallocarray(status_prompt_hlist[type], newsize,
+                       sizeof *status_prompt_hlist[type]);
        }
 
-       status_prompt_hlist = xreallocarray(status_prompt_hlist,
-           status_prompt_hsize + 1, sizeof *status_prompt_hlist);
-       status_prompt_hlist[status_prompt_hsize++] = xstrdup(line);
+       if (new == 1 && newsize > 0)
+               status_prompt_hlist[type][newsize - 1] = xstrdup(line);
+       status_prompt_hsize[type] = newsize;
 }
 
 /* Build completion list. */
@@ -1501,7 +1560,7 @@ status_prompt_menu_callback(__unused struct menu *menu, u_int idx, key_code key,
                        s = xstrdup(spm->list[idx]);
                else
                        xasprintf(&s, "-%c%s", spm->flag, spm->list[idx]);
-               if (c->prompt_flags & PROMPT_WINDOW) {
+               if (c->prompt_type == PROMPT_TYPE_WINDOW_TARGET) {
                        free(c->prompt_buffer);
                        c->prompt_buffer = utf8_fromcstr(s);
                        c->prompt_index = utf8_strlen(c->prompt_buffer);
@@ -1609,7 +1668,7 @@ status_prompt_complete_window_menu(struct client *c, struct session *s,
                }
 
                list = xreallocarray(list, size + 1, sizeof *list);
-               if (c->prompt_flags & PROMPT_WINDOW) {
+               if (c->prompt_type == PROMPT_TYPE_WINDOW_TARGET) {
                        xasprintf(&tmp, "%d (%s)", wl->idx, wl->window->name);
                        xasprintf(&list[size++], "%d", wl->idx);
                } else {
@@ -1717,10 +1776,12 @@ status_prompt_complete(struct client *c, const char *word, u_int offset)
        u_int             size = 0, i;
 
        if (*word == '\0' &&
-           ((c->prompt_flags & (PROMPT_TARGET|PROMPT_WINDOW)) == 0))
+           c->prompt_type != PROMPT_TYPE_TARGET &&
+           c->prompt_type != PROMPT_TYPE_WINDOW_TARGET)
                return (NULL);
 
-       if (((c->prompt_flags & (PROMPT_TARGET|PROMPT_WINDOW)) == 0) &&
+       if (c->prompt_type != PROMPT_TYPE_TARGET &&
+           c->prompt_type != PROMPT_TYPE_WINDOW_TARGET &&
            strncmp(word, "-t", 2) != 0 &&
            strncmp(word, "-s", 2) != 0) {
                list = status_prompt_complete_list(&size, word, offset == 0);
@@ -1733,7 +1794,8 @@ status_prompt_complete(struct client *c, const char *word, u_int offset)
                goto found;
        }
 
-       if (c->prompt_flags & (PROMPT_TARGET|PROMPT_WINDOW)) {
+       if (c->prompt_type == PROMPT_TYPE_TARGET ||
+           c->prompt_type == PROMPT_TYPE_WINDOW_TARGET) {
                s = word;
                flag = '\0';
        } else {
@@ -1743,7 +1805,7 @@ status_prompt_complete(struct client *c, const char *word, u_int offset)
        }
 
        /* If this is a window completion, open the window menu. */
-       if (c->prompt_flags & PROMPT_WINDOW) {
+       if (c->prompt_type == PROMPT_TYPE_WINDOW_TARGET) {
                out = status_prompt_complete_window_menu(c, c->session, s,
                    offset, '\0');
                goto found;
@@ -1793,3 +1855,25 @@ found:
        }
        return (out);
 }
+
+/* Return the type of the prompt as an enum. */
+enum prompt_type
+status_prompt_type(const char *type)
+{
+       u_int   i;
+
+       for (i = 0; i < PROMPT_NTYPES; i++) {
+               if (strcmp(type, status_prompt_type_string(i)) == 0)
+                       return (i);
+       }
+       return (PROMPT_TYPE_INVALID);
+}
+
+/* Accessor for prompt_type_strings. */
+const char *
+status_prompt_type_string(u_int type)
+{
+       if (type >= PROMPT_NTYPES)
+               return ("invalid");
+       return (prompt_type_strings[type]);
+}
index eb927b1..e566311 100644 (file)
@@ -1,4 +1,4 @@
-.\" $OpenBSD: tmux.1,v 1.838 2021/06/10 07:33:41 nicm Exp $
+.\" $OpenBSD: tmux.1,v 1.839 2021/06/10 07:50:04 nicm Exp $
 .\"
 .\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
 .\"
@@ -3453,7 +3453,9 @@ will write command prompt history on exit and load it from on start.
 .It Ic message-limit Ar number
 Set the number of error or information messages to save in the message log for
 each client.
-The default is 100.
+.It Ic prompt-history-limit Ar number
+Set the number of history items to save in the history file for each type of
+command prompt.
 .It Xo Ic set-clipboard
 .Op Ic on | external | off
 .Xc
@@ -5376,11 +5378,25 @@ session option.
 .Pp
 Commands related to the status line are as follows:
 .Bl -tag -width Ds
+.It Xo Ic clear-prompt-history
+.Op Fl T Ar prompt-type
+.Xc
+.D1 (alias: Ic clrphist)
+Clear status prompt history for prompt type
+.Ar prompt-type .
+If
+.Fl T
+is omitted, then clear history for all types.
+See
+.Ic command-prompt
+for possible values for
+.Ar prompt-type .
 .It Xo Ic command-prompt
-.Op Fl 1ikNTW
+.Op Fl 1ikN
 .Op Fl I Ar inputs
 .Op Fl p Ar prompts
 .Op Fl t Ar target-client
+.Op Fl T Ar prompt-type
 .Op Ar template
 .Xc
 Open the command prompt in a client.
@@ -5436,14 +5452,20 @@ makes the prompt only accept numeric key presses.
 .Fl i
 executes the command every time the prompt input changes instead of when the
 user exits the command prompt.
+.Pp
 .Fl T
 tells
 .Nm
-that the prompt is for a target which affects what completions are offered when
+the prompt type.
+This affects what completions are offered when
 .Em Tab
-is pressed;
-.Fl W
-is similar but indicates the prompt is for a window.
+is pressed.
+Available types are:
+.Ql command ,
+.Ql search ,
+.Ql target
+and
+.Ql window-target .
 .Pp
 The following keys have a special meaning in the command prompt, depending
 on the value of the
@@ -5665,6 +5687,19 @@ If omitted, half of the terminal size is used.
 The
 .Fl C
 flag closes any popup on the client.
+.It Xo Ic show-prompt-history
+.Op Fl T Ar prompt-type
+.Xc
+.D1 (alias: Ic showphist)
+Display status prompt history for prompt type
+.Ar prompt-type .
+If
+.Fl T
+is omitted, then show history for all types.
+See
+.Ic command-prompt
+for possible values for
+.Ar prompt-type .
 .El
 .Sh BUFFERS
 .Nm
index 6b023f2..2000204 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmux.h,v 1.1108 2021/06/10 07:43:44 nicm Exp $ */
+/* $OpenBSD: tmux.h,v 1.1109 2021/06/10 07:50:04 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -1571,6 +1571,16 @@ struct status_line {
        struct status_line_entry entries[STATUS_LINES_LIMIT];
 };
 
+/* Prompt type. */
+#define PROMPT_NTYPES 4
+enum prompt_type {
+       PROMPT_TYPE_COMMAND,
+       PROMPT_TYPE_SEARCH,
+       PROMPT_TYPE_TARGET,
+       PROMPT_TYPE_WINDOW_TARGET,
+       PROMPT_TYPE_INVALID = 0xff
+};
+
 /* File in client. */
 typedef void (*client_file_cb) (struct client *, const char *, int, int,
     struct evbuffer *, void *);
@@ -1734,18 +1744,16 @@ struct client {
        prompt_input_cb  prompt_inputcb;
        prompt_free_cb   prompt_freecb;
        void            *prompt_data;
-       u_int            prompt_hindex;
+       u_int            prompt_hindex[PROMPT_NTYPES];
        enum { PROMPT_ENTRY, PROMPT_COMMAND } prompt_mode;
        struct utf8_data *prompt_saved;
-
 #define PROMPT_SINGLE 0x1
 #define PROMPT_NUMERIC 0x2
 #define PROMPT_INCREMENTAL 0x4
 #define PROMPT_NOFORMAT 0x8
 #define PROMPT_KEY 0x10
-#define PROMPT_WINDOW 0x20
-#define PROMPT_TARGET 0x40
        int              prompt_flags;
+       enum prompt_type prompt_type;
 
        struct session  *session;
        struct session  *last_session;
@@ -2517,6 +2525,8 @@ void       server_check_unattached(void);
 void    server_unzoom_window(struct window *);
 
 /* status.c */
+extern char    **status_prompt_hlist[];
+extern u_int     status_prompt_hsize[];
 void    status_timer_start(struct client *);
 void    status_timer_start_all(void);
 void    status_update_cache(struct session *);
@@ -2531,13 +2541,15 @@ void     status_message_clear(struct client *);
 int     status_message_redraw(struct client *);
 void    status_prompt_set(struct client *, struct cmd_find_state *,
             const char *, const char *, prompt_input_cb, prompt_free_cb,
-            void *, int);
+            void *, int, enum prompt_type);
 void    status_prompt_clear(struct client *);
 int     status_prompt_redraw(struct client *);
 int     status_prompt_key(struct client *, key_code);
 void    status_prompt_update(struct client *, const char *, const char *);
 void    status_prompt_load_history(void);
 void    status_prompt_save_history(void);
+const char *status_prompt_type_string(u_int);
+enum prompt_type status_prompt_type(const char *type);
 
 /* resize.c */
 void    resize_window(struct window *, u_int, u_int, int, int);
index 37203cd..efbb4a4 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: window-customize.c,v 1.10 2021/04/12 09:36:12 nicm Exp $ */
+/* $OpenBSD: window-customize.c,v 1.11 2021/06/10 07:50:04 nicm Exp $ */
 
 /*
  * Copyright (c) 2020 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -1123,7 +1123,7 @@ window_customize_set_option(struct client *c,
                status_prompt_set(c, NULL, prompt, value,
                    window_customize_set_option_callback,
                    window_customize_free_item_callback, new_item,
-                   PROMPT_NOFORMAT);
+                   PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND);
 
                free(prompt);
                free(value);
@@ -1264,7 +1264,7 @@ window_customize_set_key(struct client *c,
                status_prompt_set(c, NULL, prompt, value,
                    window_customize_set_command_callback,
                    window_customize_free_item_callback, new_item,
-                   PROMPT_NOFORMAT);
+                   PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND);
                free(prompt);
                free(value);
        } else if (strcmp(s, "Note") == 0) {
@@ -1281,7 +1281,7 @@ window_customize_set_key(struct client *c,
                    (bd->note == NULL ? "" : bd->note),
                    window_customize_set_note_callback,
                    window_customize_free_item_callback, new_item,
-                   PROMPT_NOFORMAT);
+                   PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND);
                free(prompt);
        }
 }
@@ -1458,7 +1458,7 @@ window_customize_key(struct window_mode_entry *wme, struct client *c,
                status_prompt_set(c, NULL, prompt, "",
                    window_customize_change_current_callback,
                    window_customize_free_callback, data,
-                   PROMPT_SINGLE|PROMPT_NOFORMAT);
+                   PROMPT_SINGLE|PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND);
                free(prompt);
                break;
        case 'D':
@@ -1471,7 +1471,7 @@ window_customize_key(struct window_mode_entry *wme, struct client *c,
                status_prompt_set(c, NULL, prompt, "",
                    window_customize_change_tagged_callback,
                    window_customize_free_callback, data,
-                   PROMPT_SINGLE|PROMPT_NOFORMAT);
+                   PROMPT_SINGLE|PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND);
                free(prompt);
                break;
        case 'u':
@@ -1487,7 +1487,7 @@ window_customize_key(struct window_mode_entry *wme, struct client *c,
                status_prompt_set(c, NULL, prompt, "",
                    window_customize_change_current_callback,
                    window_customize_free_callback, data,
-                   PROMPT_SINGLE|PROMPT_NOFORMAT);
+                   PROMPT_SINGLE|PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND);
                free(prompt);
                break;
        case 'U':
@@ -1500,7 +1500,7 @@ window_customize_key(struct window_mode_entry *wme, struct client *c,
                status_prompt_set(c, NULL, prompt, "",
                    window_customize_change_tagged_callback,
                    window_customize_free_callback, data,
-                   PROMPT_SINGLE|PROMPT_NOFORMAT);
+                   PROMPT_SINGLE|PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND);
                free(prompt);
                break;
        case 'H':
index c60fede..2190aa6 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: window-tree.c,v 1.54 2021/04/12 06:50:25 nicm Exp $ */
+/* $OpenBSD: window-tree.c,v 1.55 2021/06/10 07:50:04 nicm Exp $ */
 
 /*
  * Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -1296,7 +1296,7 @@ window_tree_key(struct window_mode_entry *wme, struct client *c,
                data->references++;
                status_prompt_set(c, NULL, prompt, "",
                    window_tree_kill_current_callback, window_tree_command_free,
-                   data, PROMPT_SINGLE|PROMPT_NOFORMAT);
+                   data, PROMPT_SINGLE|PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND);
                free(prompt);
                break;
        case 'X':
@@ -1307,7 +1307,7 @@ window_tree_key(struct window_mode_entry *wme, struct client *c,
                data->references++;
                status_prompt_set(c, NULL, prompt, "",
                    window_tree_kill_tagged_callback, window_tree_command_free,
-                   data, PROMPT_SINGLE|PROMPT_NOFORMAT);
+                   data, PROMPT_SINGLE|PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND);
                free(prompt);
                break;
        case ':':
@@ -1319,7 +1319,7 @@ window_tree_key(struct window_mode_entry *wme, struct client *c,
                data->references++;
                status_prompt_set(c, NULL, prompt, "",
                    window_tree_command_callback, window_tree_command_free,
-                   data, PROMPT_NOFORMAT);
+                   data, PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND);
                free(prompt);
                break;
        case '\r':