aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES15
-rw-r--r--Makefile.am1
-rw-r--r--cmd-command-prompt.c43
-rw-r--r--cmd-confirm-before.c2
-rw-r--r--cmd-show-prompt-history.c108
-rw-r--r--cmd.c4
-rw-r--r--configure.ac2
-rw-r--r--grid-reader.c163
-rw-r--r--key-bindings.c14
-rw-r--r--mode-tree.c4
-rw-r--r--options-table.c15
-rw-r--r--regress/copy-mode-test-emacs.sh116
-rw-r--r--regress/copy-mode-test-vi.sh115
-rw-r--r--regress/copy-mode-test.txt5
-rw-r--r--screen-write.c6
-rw-r--r--screen.c80
-rw-r--r--server-client.c5
-rw-r--r--status.c393
-rw-r--r--tmux.168
-rw-r--r--tmux.h43
-rw-r--r--tty.c125
-rw-r--r--utf8.c2
-rw-r--r--window-copy.c102
-rw-r--r--window-customize.c14
-rw-r--r--window-tree.c6
25 files changed, 1129 insertions, 322 deletions
diff --git a/CHANGES b/CHANGES
index f9c9d007..65a96717 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,18 @@
+CHANGES FROM 3.2a TO 3.3
+
+* Change cursor style handling so tmux understands which sequences contain
+ blinking and sets the flag appropriately, means that it works whether cnorm
+ disables blinking or not. This now matches xterm's behaviour.
+
+* More accurate vi(1) word navigation in copy mode and on the status line. This
+ changes the meaning of the word-separators option - setting it to the empty
+ string is equivalent to the previous behavior.
+
+* Add -F for command-prompt and use it to fix "Rename" on the window menu.
+
+* Add different command histories for different types of prompts ("command",
+ "search" etc). From Anindya Mukherjee.
+
CHANGES FROM 3.2 TO 3.2a
* Add an "always" value for the "extended-keys" option; if set then tmux will
diff --git a/Makefile.am b/Makefile.am
index 3e15204f..9bb5b89e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -125,6 +125,7 @@ dist_tmux_SOURCES = \
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 \
diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c
index c82235c5..a955ac32 100644
--- a/cmd-command-prompt.c
+++ b/cmd-command-prompt.c
@@ -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 = { "1FkiI:Np:t:T:", 0, 1 },
+ .usage = "[-1FkiN] [-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;
@@ -86,7 +87,9 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
cdata->template = NULL;
cdata->idx = 1;
- if (args->argc != 0)
+ if (args->argc != 0 && args_has(args, 'F'))
+ cdata->template = format_single_from_target(item, args->argv[0]);
+ else if (args->argc != 0)
cdata->template = xstrdup(args->argv[0]);
else
cdata->template = xstrdup("%1");
@@ -114,6 +117,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 +135,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);
diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c
index 0c562836..0b490b17 100644
--- a/cmd-confirm-before.c
+++ b/cmd-confirm-before.c
@@ -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/cmd-show-prompt-history.c b/cmd-show-prompt-history.c
new file mode 100644
index 00000000..2091ac9d
--- /dev/null
+++ b/cmd-show-prompt-history.c
@@ -0,0 +1,108 @@
+/* $OpenBSD$ */
+
+/*
+ * 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);
+}
diff --git a/cmd.c b/cmd.c
index 775bdb73..f35186f4 100644
--- a/cmd.c
+++ b/cmd.c
@@ -35,6 +35,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;
@@ -104,6 +105,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;
@@ -126,6 +128,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,
@@ -194,6 +197,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,
diff --git a/configure.ac b/configure.ac
index 9bbfd49e..f6bdd3c7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
# configure.ac
-AC_INIT([tmux], 3.2a)
+AC_INIT([tmux], next-3.3)
AC_PREREQ([2.60])
AC_CONFIG_AUX_DIR(etc)
diff --git a/grid-reader.c b/grid-reader.c
index df0dd450..c14e3d33 100644
--- a/grid-reader.c
+++ b/grid-reader.c
@@ -153,6 +153,29 @@ grid_reader_cursor_end_of_line(struct grid_reader *gr, int wrap, int all)
gr->cx = grid_reader_line_length(gr);
}
+/* Handle line wrapping while moving the cursor. */
+static int
+grid_reader_handle_wrap(struct grid_reader *gr, u_int *xx, u_int *yy)
+{
+ /*
+ * Make sure the cursor lies within the grid reader's bounding area,
+ * wrapping to the next line as necessary. Return zero if the cursor
+ * would wrap past the bottom of the grid.
+ */
+ while (gr->cx > *xx) {
+ if (gr->cy == *yy)
+ return (0);
+ grid_reader_cursor_start_of_line(gr, 0);
+ grid_reader_cursor_down(gr);
+
+ if (grid_get_line(gr->gd, gr->cy)->flags & GRID_LINE_WRAPPED)
+ *xx = gr->gd->sx - 1;
+ else
+ *xx = grid_reader_line_length(gr);
+ }
+ return (1);
+}
+
/* Check if character under cursor is in set. */
int
grid_reader_in_set(struct grid_reader *gr, const char *set)
@@ -170,7 +193,6 @@ void
grid_reader_cursor_next_word(struct grid_reader *gr, const char *separators)
{
u_int xx, yy;
- int expected = 0;
/* Do not break up wrapped words. */
if (grid_get_line(gr->gd, gr->cy)->flags & GRID_LINE_WRAPPED)
@@ -180,33 +202,35 @@ grid_reader_cursor_next_word(struct grid_reader *gr, const char *separators)
yy = gr->gd->hsize + gr->gd->sy - 1;
/*
- * If we started inside a word, skip over word characters. Then skip
- * over separators till the next word.
+ * When navigating via spaces (for example with next-space) separators
+ * should be empty.
*
- * expected is initially set to 0 for the former and then 1 for the
- * latter. It is finally set to 0 when the beginning of the next word is
- * found.
+ * If we started on a separator that is not whitespace, skip over
+ * subsequent separators that are not whitespace. Otherwise, if we
+ * started on a non-whitespace character, skip over subsequent
+ * characters that are neither whitespace nor separators. Then, skip
+ * over whitespace (if any) until the next non-whitespace character.
*/
- do {
- while (gr->cx > xx ||
- grid_reader_in_set(gr, separators) == expected) {
- /* Move down if we are past the end of the line. */
- if (gr->cx > xx) {
- if (gr->cy == yy)
- return;
- grid_reader_cursor_start_of_line(gr, 0);
- grid_reader_cursor_down(gr);
-
- if (grid_get_line(gr->gd, gr->cy)->flags &
- GRID_LINE_WRAPPED)
- xx = gr->gd->sx - 1;
- else
- xx = grid_reader_line_length(gr);
- } else
+ if (!grid_reader_handle_wrap(gr, &xx, &yy))
+ return;
+ if (!grid_reader_in_set(gr, WHITESPACE)) {
+ if (grid_reader_in_set(gr, separators)) {
+ do
gr->cx++;
+ while (grid_reader_handle_wrap(gr, &xx, &yy) &&
+ grid_reader_in_set(gr, separators) &&
+ !grid_reader_in_set(gr, WHITESPACE));
+ } else {
+ do
+ gr->cx++;
+ while (grid_reader_handle_wrap(gr, &xx, &yy) &&
+ !(grid_reader_in_set(gr, separators) ||
+ grid_reader_in_set(gr, WHITESPACE)));
}
- expected = !expected;
- } while (expected == 1);
+ }
+ while (grid_reader_handle_wrap(gr, &xx, &yy) &&
+ grid_reader_in_set(gr, WHITESPACE))
+ gr->cx++;
}
/* Move cursor to the end of the next word. */
@@ -214,7 +238,6 @@ void
grid_reader_cursor_next_word_end(struct grid_reader *gr, const char *separators)
{
u_int xx, yy;
- int expected = 1;
/* Do not break up wrapped words. */
if (grid_get_line(gr->gd, gr->cy)->flags & GRID_LINE_WRAPPED)
@@ -224,49 +247,54 @@ grid_reader_cursor_next_word_end(struct grid_reader *gr, const char *separators)
yy = gr->gd->hsize + gr->gd->sy - 1;
/*
- * If we started on a separator, skip over separators. Then skip over
- * word characters till the next separator.
+ * When navigating via spaces (for example with next-space), separators
+ * should be empty in both modes.
*
- * expected is initially set to 1 for the former and then 1 for the
- * latter. It is finally set to 1 when the end of the next word is
- * found.
+ * If we started on a whitespace, move until reaching the first
+ * non-whitespace character. If that character is a separator, treat
+ * subsequent separators as a word, and continue moving until the first
+ * non-separator. Otherwise, continue moving until the first separator
+ * or whitespace.
*/
- do {
- while (gr->cx > xx ||
- grid_reader_in_set(gr, separators) == expected) {
- /* Move down if we are past the end of the line. */
- if (gr->cx > xx) {
- if (gr->cy == yy)
- return;
- grid_reader_cursor_start_of_line(gr, 0);
- grid_reader_cursor_down(gr);
-
- if (grid_get_line(gr->gd, gr->cy)->flags &
- GRID_LINE_WRAPPED)
- xx = gr->gd->sx - 1;
- else
- xx = grid_reader_line_length(gr);
- } else
+
+ while (grid_reader_handle_wrap(gr, &xx, &yy)) {
+ if (grid_reader_in_set(gr, WHITESPACE))
+ gr->cx++;
+ else if (grid_reader_in_set(gr, separators)) {
+ do
+ gr->cx++;
+ while (grid_reader_handle_wrap(gr, &xx, &yy) &&
+ grid_reader_in_set(gr, separators) &&
+ !grid_reader_in_set(gr, WHITESPACE));
+ return;
+ } else {
+ do
gr->cx++;
+ while (grid_reader_handle_wrap(gr, &xx, &yy) &&
+ !(grid_reader_in_set(gr, WHITESPACE) ||
+ grid_reader_in_set(gr, separators)));
+ return;
}
- expected = !expected;
- } while (expected == 0);
+ }
}
/* Move to the previous place where a word begins. */
void
grid_reader_cursor_previous_word(struct grid_reader *gr, const char *separators,
- int already)
+ int already, int stop_at_eol)
{
- int oldx, oldy, r;
+ int oldx, oldy, at_eol, word_is_letters;
/* Move back to the previous word character. */
- if (already || grid_reader_in_set(gr, separators)) {
+ if (already || grid_reader_in_set(gr, WHITESPACE)) {
for (;;) {
if (gr->cx > 0) {
gr->cx--;
- if (!grid_reader_in_set(gr, separators))
+ if (!grid_reader_in_set(gr, WHITESPACE)) {
+ word_is_letters =
+ !grid_reader_in_set(gr, separators);
break;
+ }
} else {
if (gr->cy == 0)
return;
@@ -274,17 +302,21 @@ grid_reader_cursor_previous_word(struct grid_reader *gr, const char *separators,
grid_reader_cursor_end_of_line(gr, 0, 0);
/* Stop if separator at EOL. */
- if (gr->cx > 0) {
+ if (stop_at_eol && gr->cx > 0) {
oldx = gr->cx;
gr->cx--;
- r = grid_reader_in_set(gr, separators);
+ at_eol = grid_reader_in_set(gr,
+ WHITESPACE);
gr->cx = oldx;
- if (r)
+ if (at_eol) {
+ word_is_letters = 0;
break;
+ }
}
}
}
- }
+ } else
+ word_is_letters = !grid_reader_in_set(gr, separators);
/* Move back to the beginning of this word. */
do {
@@ -292,15 +324,16 @@ grid_reader_cursor_previous_word(struct grid_reader *gr, const char *separators,
oldy = gr->cy;
if (gr->cx == 0) {
if (gr->cy == 0 ||
- ~grid_get_line(gr->gd, gr->cy - 1)->flags &
- GRID_LINE_WRAPPED)
+ (~grid_get_line(gr->gd, gr->cy - 1)->flags &
+ GRID_LINE_WRAPPED))
break;
grid_reader_cursor_up(gr);
grid_reader_cursor_end_of_line(gr, 0, 1);
}
if (gr->cx > 0)
gr->cx--;
- } while (!grid_reader_in_set(gr, separators));
+ } while (!grid_reader_in_set(gr, WHITESPACE) &&
+ word_is_letters != grid_reader_in_set(gr, separators));
gr->cx = oldx;
gr->cy = oldy;
}
@@ -324,17 +357,17 @@ grid_reader_cursor_jump(struct grid_reader *gr, const struct utf8_data *jc)
memcmp(gc.data.data, jc->data, gc.data.size) == 0) {
gr->cx = px;
gr->cy = py;
- return 1;
+ return (1);
}
px++;
}
if (py == yy ||
!(grid_get_line(gr->gd, py)->flags & GRID_LINE_WRAPPED))
- return 0;
+ return (0);
px = 0;
}
- return 0;
+ return (0);
}
/* Jump back to character. */
@@ -354,16 +387,16 @@ grid_reader_cursor_jump_back(struct grid_reader *gr, const struct utf8_data *jc)
memcmp(gc.data.data, jc->data, gc.data.size) == 0) {
gr->cx = px - 1;
gr->cy = py - 1;
- return 1;
+ return (1);
}
}
if (py == 1 ||
!(grid_get_line(gr->gd, py - 2)->flags & GRID_LINE_WRAPPED))
- return 0;
+ return (0);
xx = grid_line_length(gr->gd, py - 2);
}
- return 0;
+ return (0);
}
/* Jump back to the first non-blank character of the line. */
diff --git a/key-bindings.c b/key-bindings.c
index 467c7f93..de5c20ee 100644
--- a/key-bindings.c
+++ b/key-bindings.c
@@ -41,7 +41,7 @@
" 'Kill' 'X' {kill-window}" \
" 'Respawn' 'R' {respawn-window -k}" \
" '#{?pane_marked,Unmark,Mark}' 'm' {select-pane -m}" \
- " 'Rename' 'n' {command-prompt -I \"#W\" \"rename-window -- '%%'\"}" \
+ " 'Rename' 'n' {command-prompt -FI \"#W\" \"rename-window -t#{window_id} -- '%%'\"}" \
" ''" \
" 'New After' 'w' {new-window -a}" \
" 'New At End' 'W' {new-window}"
@@ -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",
diff --git a/mode-tree.c b/mode-tree.c
index ca7f33a4..807c1dcb 100644
--- a/mode-tree.c
+++ b/mode-tree.c
@@ -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;
diff --git a/options-table.c b/options-table.c
index 8264d1b7..101490e7 100644
--- a/options-table.c
+++ b/options-table.c
@@ -301,6 +301,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,
@@ -745,7 +754,11 @@ const struct options_table_entry options_table[] = {
{ .name = "word-separators",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION,
- .default_str = " ",
+ /*
+ * The set of non-alphanumeric printable ASCII characters minus the
+ * underscore.
+ */
+ .default_str = "!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~",
.text = "Characters considered to separate words."
},
diff --git a/regress/copy-mode-test-emacs.sh b/regress/copy-mode-test-emacs.sh
new file mode 100644
index 00000000..63293963
--- /dev/null
+++ b/regress/copy-mode-test-emacs.sh
@@ -0,0 +1,116 @@
+#!/bin/sh
+
+PATH=/bin:/usr/bin
+TERM=screen
+
+[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
+TMUX="$TEST_TMUX -f/dev/null -Ltest"
+$TMUX kill-server 2>/dev/null
+
+$TMUX new -d -x40 -y10 \
+ "cat copy-mode-test.txt; printf '\e[9;15H'; cat" || exit 1
+$TMUX set -g window-size manual || exit 1
+
+# Enter copy mode and go to the first column of the first row.
+$TMUX set-window-option -g mode-keys emacs
+$TMUX set-window-option -g word-separators ""
+$TMUX copy-mode
+$TMUX send-keys -X history-top
+$TMUX send-keys -X start-of-line
+
+# Test that `previous-word` and `previous-space`
+# do not go past the start of text.
+$TMUX send-keys -X begin-selection
+$TMUX send-keys -X previous-word
+$TMUX send-keys -X previous-space
+$TMUX send-keys -X previous-word
+$TMUX send-keys -X copy-selection
+[ "$($TMUX show-buffer 2>/dev/null)" = "" ] || exit 1
+
+# Test that `next-word-end` does not skip single-letter words.
+$TMUX send-keys -X next-word-end
+$TMUX send-keys -X begin-selection
+$TMUX send-keys -X previous-word
+$TMUX send-keys -X copy-selection
+[ "$($TMUX show-buffer)" = "A" ] || exit 1
+
+# Test that `next-word-end` wraps around indented line breaks.
+$TMUX send-keys -X next-word
+$TMUX send-keys -X next-word
+$TMUX send-keys -X next-word
+$TMUX send-keys -X begin-selection
+$TMUX send-keys -X next-word-end
+$TMUX send-keys -X next-word-end
+$TMUX send-keys -X copy-selection
+[ "$($TMUX show-buffer)" = "$(echo -e "words\n Indented")" ] || exit 1
+
+# Test that `next-word` wraps around un-indented line breaks.
+$TMUX send-keys -X next-word
+$TMUX send-keys -X begin-selection
+$TMUX send-keys -X next-word
+$TMUX send-keys -X copy-selection
+[ "$($TMUX show-buffer)" = "$(echo -e "line\n")" ] || exit 1
+
+# Test that `next-word-end` treats periods as letters.
+$TMUX send-keys -X next-word
+$TMUX send-keys -X begin-selection
+$TMUX send-keys -X next-word-end
+$TMUX send-keys -X copy-selection
+[ "$($TMUX show-buffer)" = "line..." ] || exit 1
+
+# Test that `previous-word` and `next-word` treat periods as letters.
+$TMUX send-keys -X previous-word
+$TMUX send-keys -X begin-selection
+$TMUX send-keys -X next-word
+$TMUX send-keys -X copy-selection
+[ "$($TMUX show-buffer)" = "$(echo -e "line...\n")" ] || exit 1
+
+# Test that `previous-space` and `next-space` treat periods as letters.
+$TMUX send-keys -X previous-space
+$TMUX send-keys -X begin-selection
+$TMUX send-keys -X next-space
+$TMUX send-keys -X copy-selection
+[ "$($TMUX show-buffer)" = "$(echo -e "line...\n")" ] || exit 1
+
+# Test that `next-word` and `next-word-end` treat other symbols as letters.
+$TMUX send-keys -X begin-selection
+$TMUX send-keys -X next-word
+$TMUX send-keys -X next-word
+$TMUX send-keys -X next-word-end
+$TMUX send-keys -X next-word-end
+$TMUX send-keys -X copy-selection
+[ "$($TMUX show-buffer)" = "... @nd then \$ym_bols[]{}" ] || exit 1
+
+# Test that `previous-word` treats other symbols as letters
+# and `next-word` wraps around for indented symbols
+$TMUX send-keys -X previous-word
+$TMUX send-keys -X begin-selection
+$TMUX send-keys -X next-word
+$TMUX send-keys -X copy-selection
+[ "$($TMUX show-buffer)" = "$(echo -e "\$ym_bols[]{}\n ")" ] || exit 1
+
+# Test that `next-word-end` treats digits as letters
+$TMUX send-keys -X next-word-end
+$TMUX send-keys -X begin-selection
+$TMUX send-keys -X next-word-end
+$TMUX send-keys -X copy-selection
+[ "$($TMUX show-buffer)" = " 500xyz" ] || exit 1
+
+# Test that `previous-word` treats digits as letters
+$TMUX send-keys -X begin-selection
+$TMUX send-keys -X previous-word
+$TMUX send-keys -X copy-selection
+[ "$($TMUX show-buffer)" = "500xyz" ] || exit 1
+
+# Test that `next-word` and `next-word-end` stop at the end of text.
+$TMUX send-keys -X begin-selection
+$TMUX send-keys -X next-word
+$TMUX send-keys -X next-word-end
+$TMUX send-keys -X next-word
+$TMUX send-keys -X next-space
+$TMUX send-keys -X next-space-end
+$TMUX send-keys -X copy-selection
+[ "$($TMUX show-buffer)" = "500xyz" ] || exit 1
+
+$TMUX kill-server 2>/dev/null
+exit 0
diff --git a/regress/copy-mode-test-vi.sh b/regress/copy-mode-test-vi.sh
new file mode 100644
index 00000000..0eca3fa6
--- /dev/null
+++ b/regress/copy-mode-test-vi.sh
@@ -0,0 +1,115 @@
+#!/bin/sh
+
+PATH=/bin:/usr/bin
+TERM=screen
+
+[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
+TMUX="$TEST_TMUX -f/dev/null -Ltest"
+$TMUX kill-server 2>/dev/null
+
+$TMUX new -d -x40 -y10 \
+ "cat copy-mode-test.txt; printf '\e[9;15H'; cat" || exit 1
+$TMUX set -g window-size manual || exit 1
+
+# Enter copy mode and go to the first column of the first row.
+$TMUX set-window-option -g mode-keys vi
+$TMUX copy-mode
+$TMUX send-keys -X history-top
+$TMUX send-keys -X start-of-line
+
+# Test that `previous-word` and `previous-space`
+# do not go past the start of text.
+$TMUX send-keys -X begin-selection
+$TMUX send-keys -X previous-word
+$TMUX send-keys -X previous-space
+$TMUX send-keys -X previous-word
+$TMUX send-keys -X copy-selection
+[ "$($TMUX show-buffer)" = "A" ] || exit 1
+
+# Test that `next-word-end` skips single-letter words
+# and `previous-word` does not skip multi-letter words.
+$TMUX send-keys -X next-word-end
+$TMUX send-keys -X begin-selection
+$TMUX send-keys -X previous-word
+$TMUX send-keys -X copy-selection
+[ "$($TMUX show-buffer)" = "line" ] || exit 1
+
+# Test that `next-word-end` wraps around indented line breaks.
+$TMUX send-keys -X next-word
+$TMUX send-keys -X next-word
+$TMUX send-keys -X begin-selection
+$TMUX send-keys -X next-word-end
+$TMUX send-keys -X next-word-end
+$TMUX send-keys -X copy-selection
+[ "$($TMUX show-buffer)" = "$(echo -e "words\n Indented")" ] || exit 1
+
+# Test that `next-word` wraps around un-indented line breaks.
+$TMUX send-keys -X next-word
+$TMUX send-keys -X begin-selection
+$TMUX send-keys -X next-word
+$TMUX send-keys -X copy-selection
+[ "$($TMUX show-buffer)" = "$(echo -e "line\nA")" ] || exit 1
+
+# Test that `next-word-end` does not treat periods as letters.
+$TMUX send-keys -X next-word
+$TMUX send-keys -X begin-selection
+$TMUX send-keys -X next-word-end
+$TMUX send-keys -X copy-selection
+[ "$($TMUX show-buffer)" = "line" ] || exit 1
+
+# Test that `next-space-end` treats periods as letters.
+$TMUX send-keys -X previous-word
+$TMUX send-keys -X begin-selection
+$TMUX send-keys -X next-space-end
+$TMUX send-keys -X copy-selection
+[ "$($TMUX show-buffer)" = "line..." ] || exit 1
+
+# Test that `previous-space` and `next-space` treat periods as letters.
+$TMUX send-keys -X previous-space
+$TMUX send-keys -X begin-selection
+$TMUX send-keys -X next-space
+$TMUX send-keys -X copy-selection
+[ "$($TMUX show-buffer)" = "$(echo -e "line...\n.")" ] || exit 1
+
+# Test that `next-word` and `next-word-end` do not treat other symbols as letters.
+$TMUX send-keys -X begin-selection
+$TMUX send-keys -X next-word
+$TMUX send-keys -X next-word
+$TMUX send-keys -X next-word-end
+$TMUX send-keys -X next-word-end
+$TMUX send-keys -X copy-selection
+[ "$($TMUX show-buffer)" = "... @nd then" ] || exit 1
+
+# Test that `next-space` wraps around for indented symbols
+$TMUX send-keys -X next-space
+$TMUX send-keys -X begin-selection
+$TMUX send-keys -X next-space
+$TMUX send-keys -X copy-selection
+[ "$($TMUX show-buffer)" = "$(echo -e "\$ym_bols[]{}\n ?")" ] || exit 1
+
+# Test that `next-word-end` treats digits as letters
+$TMUX send-keys -X next-word-end
+$TMUX send-keys -X begin-selection
+$TMUX send-keys -X next-word-end
+$TMUX send-keys -X copy-selection
+[ "$($TMUX show-buffer)" = "? 500xyz" ] || exit 1
+
+# Test that `previous-word` treats digits as letters
+$TMUX send-keys -X begin-selection
+$TMUX send-keys -X previous-word
+$TMUX send-keys -X copy-selection
+[ "$($TMUX show-buffer)" = "500xyz" ] || exit 1
+
+# Test that `next-word`, `next-word-end`,
+# `next-space`, and `next-space-end` stop at the end of text.
+$TMUX send-keys -X begin-selection
+$TMUX send-keys -X next-word
+$TMUX send-keys -X next-word-end
+$TMUX send-keys -X next-word
+$TMUX send-keys -X next-space
+$TMUX send-keys -X next-space-end
+$TMUX send-keys -X copy-selection
+[ "$($TMUX show-buffer)" = "500xyz" ] || exit 1
+
+$TMUX kill-server 2>/dev/null
+exit 0
diff --git a/regress/copy-mode-test.txt b/regress/copy-mode-test.txt
new file mode 100644
index 00000000..a804f1f8
--- /dev/null
+++ b/regress/copy-mode-test.txt
@@ -0,0 +1,5 @@
+A line of words
+ Indented line
+Another line...
+... @nd then $ym_bols[]{}
+ ?? 500xyz
diff --git a/screen-write.c b/screen-write.c
index 8e9ec582..e351a5e5 100644
--- a/screen-write.c
+++ b/screen-write.c
@@ -769,6 +769,9 @@ screen_write_mode_set(struct screen_write_ctx *ctx, int mode)
struct screen *s = ctx->s;
s->mode |= mode;
+
+ if (log_get_level() != 0)
+ log_debug("%s: %s", __func__, screen_mode_to_string(mode));
}
/* Clear a mode. */
@@ -778,6 +781,9 @@ screen_write_mode_clear(struct screen_write_ctx *ctx, int mode)
struct screen *s = ctx->s;
s->mode &= ~mode;
+
+ if (log_get_level() != 0)
+ log_debug("%s: %s", __func__, screen_mode_to_string(mode));
}
/* Cursor up by ny. */
diff --git a/screen.c b/screen.c
index 2b83c285..30b448e8 100644
--- a/screen.c
+++ b/screen.c
@@ -80,7 +80,7 @@ screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit)
s->titles = NULL;
s->path = NULL;
- s->cstyle = 0;
+ s->cstyle = SCREEN_CURSOR_DEFAULT;
s->ccolour = xstrdup("");
s->tabs = NULL;
s->sel = NULL;
@@ -155,9 +155,35 @@ screen_reset_tabs(struct screen *s)
void
screen_set_cursor_style(struct screen *s, u_int style)
{
- if (style <= 6) {
- s->cstyle = style;
+ log_debug("%s: new %u, was %u", __func__, style, s->cstyle);
+ switch (style) {
+ case 0:
+ s->cstyle = SCREEN_CURSOR_DEFAULT;
+ break;
+ case 1:
+ s->cstyle = SCREEN_CURSOR_BLOCK;
+ s->mode |= MODE_BLINKING;
+ break;
+ case 2:
+ s->cstyle = SCREEN_CURSOR_BLOCK;
s->mode &= ~MODE_BLINKING;
+ break;
+ case 3:
+ s->cstyle = SCREEN_CURSOR_UNDERLINE;
+ s->mode |= MODE_BLINKING;
+ break;
+ case 4:
+ s->cstyle = SCREEN_CURSOR_UNDERLINE;
+ s->mode &= ~MODE_BLINKING;
+ break;
+ case 5:
+ s->cstyle = SCREEN_CURSOR_BAR;
+ s->mode |= MODE_BLINKING;
+ break;
+ case 6:
+ s->cstyle = SCREEN_CURSOR_BAR;
+ s->mode &= ~MODE_BLINKING;
+ break;
}
}
@@ -626,3 +652,51 @@ screen_alternate_off(struct screen *s, struct grid_cell *gc, int cursor)
if (s->cy > screen_size_y(s) - 1)
s->cy = screen_size_y(s) - 1;
}
+
+/* Get mode as a string. */
+const char *
+screen_mode_to_string(int mode)
+{
+ static char tmp[1024];
+
+ if (mode == 0)
+ return "NONE";
+ if (mode == ALL_MODES)
+ return "ALL";
+
+ *tmp = '\0';
+ if (mode & MODE_CURSOR)
+ strlcat(tmp, "CURSOR,", sizeof tmp);
+ if (mode & MODE_INSERT)
+ strlcat(tmp, "INSERT,", sizeof tmp);
+ if (mode & MODE_KCURSOR)
+ strlcat(tmp, "KCURSOR,", sizeof tmp);
+ if (mode & MODE_KKEYPAD)
+ strlcat(tmp, "KKEYPAD,", sizeof tmp);
+ if (mode & MODE_WRAP)
+ strlcat(tmp, "WRAP,", sizeof tmp);
+ if (mode & MODE_MOUSE_STANDARD)
+ strlcat(tmp, "STANDARD,", sizeof tmp);
+ if (mode & MODE_MOUSE_BUTTON)
+ strlcat(tmp, "BUTTON,", sizeof tmp);
+ if (mode & MODE_BLINKING)
+ strlcat(tmp, "BLINKING,", sizeof tmp);
+ if (mode & MODE_MOUSE_UTF8)
+ strlcat(tmp, "UTF8,", sizeof tmp);
+ if (mode & MODE_MOUSE_SGR)
+ strlcat(tmp, "SGR,", sizeof tmp);
+ if (mode & MODE_BRACKETPASTE)
+ strlcat(tmp, "BRACKETPASTE,", sizeof tmp);
+ if (mode & MODE_FOCUSON)
+ strlcat(tmp, "FOCUSON,", sizeof tmp);
+ if (mode & MODE_MOUSE_ALL)
+ strlcat(tmp, "ALL,", sizeof tmp);
+ if (mode & MODE_ORIGIN)
+ strlcat(tmp, "ORIGIN,", sizeof tmp);
+ if (mode & MODE_CRLF)
+ strlcat(tmp, "CRLF,", sizeof tmp);
+ if (mode & MODE_KEXTENDED)
+ strlcat(tmp, "KEXTENDED,", sizeof tmp);
+ tmp[strlen (tmp) - 1] = '\0';
+ return (tmp);
+}
diff --git a/server-client.c b/server-client.c
index e74d893d..e3a690bd 100644
--- a/server-client.c
+++ b/server-client.c
@@ -1691,7 +1691,10 @@ server_client_reset_state(struct client *c)
s = wp->screen;
if (s != NULL)
mode = s->mode;
- log_debug("%s: client %s mode %x", __func__, c->name, mode);
+ if (log_get_level() != 0) {
+ log_debug("%s: client %s mode %s", __func__, c->name,
+ screen_mode_to_string(mode));
+ }
/* Reset region and margin. */
tty_region_off(tty);
diff --git a/status.c b/status.c
index f4418500..7435b31a 100644
--- a/status.c
+++ b/status.c
@@ -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
@@ -843,17 +876,25 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key)
*new_key = KEYC_BSPACE;
return (1);
case 'b':
- case 'B':
*new_key = 'b'|KEYC_META;
return (1);
+ case 'B':
+ *new_key = 'B'|KEYC_VI;
+ return (1);
case 'd':
*new_key = '\025';
return (1);
case 'e':
+ *new_key = 'e'|KEYC_VI;
+ return (1);
case 'E':
+ *new_key = 'E'|KEYC_VI;
+ return (1);
case 'w':
+ *new_key = 'w'|KEYC_VI;
+ return (1);
case 'W':
- *new_key = 'f'|KEYC_META;
+ *new_key = 'W'|KEYC_VI;
return (1);
case 'p':
*new_key = '\031'; /* C-y */
@@ -1028,16 +1069,125 @@ status_prompt_replace_complete(struct client *c, const char *s)
return (1);
}
+/* Prompt forward to the next beginning of a word. */
+static void
+status_prompt_forward_word(struct client *c, size_t size, int vi,
+ const char *separators)
+{
+ size_t idx = c->prompt_index;
+ int word_is_separators;
+
+ /* In emacs mode, skip until the first non-whitespace character. */
+ if (!vi)
+ while (idx != size &&
+ status_prompt_space(&c->prompt_buffer[idx]))
+ idx++;
+
+ /* Can't move forward if we're already at the end. */
+ if (idx == size) {
+ c->prompt_index = idx;
+ return;
+ }
+
+ /* Determine the current character class (separators or not). */
+ word_is_separators = status_prompt_in_list(separators,
+ &c->prompt_buffer[idx]) &&
+ !status_prompt_space(&c->prompt_buffer[idx]);
+
+ /* Skip ahead until the first space or opposite character class. */
+ do {
+ idx++;
+ if (status_prompt_space(&c->prompt_buffer[idx])) {
+ /* In vi mode, go to the start of the next word. */
+ if (vi)
+ while (idx != size &&
+ status_prompt_space(&c->prompt_buffer[idx]))
+ idx++;
+ break;
+ }
+ } while (idx != size && word_is_separators == status_prompt_in_list(
+ separators, &c->prompt_buffer[idx]));
+
+ c->prompt_index = idx;
+}
+
+/* Prompt forward to the next end of a word. */
+static void
+status_prompt_end_word(struct client *c, size_t size, const char *separators)
+{
+ size_t idx = c->prompt_index;
+ int word_is_separators;
+
+ /* Can't move forward if we're already at the end. */
+ if (idx == size)
+ return;
+
+ /* Find the next word. */
+ do {
+ idx++;
+ if (idx == size) {
+ c->prompt_index = idx;
+ return;
+ }
+ } while (status_prompt_space(&c->prompt_buffer[idx]));
+
+ /* Determine the character class (separators or not). */
+ word_is_separators = status_prompt_in_list(separators,
+ &c->prompt_buffer[idx]);
+
+ /* Skip ahead until the next space or opposite character class. */
+ do {
+ idx++;
+ if (idx == size)
+ break;
+ } while (!status_prompt_space(&c->prompt_buffer[idx]) &&
+ word_is_separators == status_prompt_in_list(separators,
+ &c->prompt_buffer[idx]));
+
+ /* Back up to the previous character to stop at the end of the word. */
+ c->prompt_index = idx - 1;
+}
+
+/* Prompt backward to the previous beginning of a word. */
+static void
+status_prompt_backward_word(struct client *c, const char *separators)
+{
+ size_t idx = c->prompt_index;
+ int word_is_separators;
+
+ /* Find non-whitespace. */
+ while (idx != 0) {
+ --idx;
+ if (!status_prompt_space(&c->prompt_buffer[idx]))
+ break;
+ }
+ word_is_separators = status_prompt_in_list(separators,
+ &c->prompt_buffer[idx]);
+
+ /* Find the character before the beginning of the word. */
+ while (idx != 0) {
+ --idx;
+ if (status_prompt_space(&c->prompt_buffer[idx]) ||
+ word_is_separators != status_prompt_in_list(separators,
+ &c->prompt_buffer[idx])) {
+ /* Go back to the word. */
+ idx++;
+ break;
+ }
+ }
+ c->prompt_index = idx;
+}
+
/* Handle keys in prompt. */
int
status_prompt_key(struct client *c, key_code key)
{
struct options *oo = c->session->options;
char *s, *cp, prefix = '=';
- const char *histstr, *ws = NULL, *keystring;
+ const char *histstr, *separators = NULL, *keystring;
size_t size, idx;
struct utf8_data tmp;
- int keys;
+ int keys, word_is_separators;
if (c->prompt_flags & PROMPT_KEY) {
keystring = key_string_lookup_key(key, 0);
@@ -1140,20 +1290,24 @@ process_key:
}
break;
case '\027': /* C-w */
- ws = options_get_string(oo, "word-separators");
+ separators = options_get_string(oo, "word-separators");
idx = c->prompt_index;
- /* Find a non-separator. */
+ /* Find non-whitespace. */
while (idx != 0) {
idx--;
- if (!status_prompt_in_list(ws, &c->prompt_buffer[idx]))
+ if (!status_prompt_space(&c->prompt_buffer[idx]))
break;
}
+ word_is_separators = status_prompt_in_list(separators,
+ &c->prompt_buffer[idx]);
- /* Find the separator at the beginning of the word. */
+ /* Find the character before the beginning of the word. */
while (idx != 0) {
idx--;
- if (status_prompt_in_list(ws, &c->prompt_buffer[idx])) {
+ if (status_prompt_space(&c->prompt_buffer[idx]) ||
+ word_is_separators != status_prompt_in_list(
+ separators, &c->prompt_buffer[idx])) {
/* Go back to the word. */
idx++;
break;
@@ -1175,54 +1329,37 @@ process_key:
c->prompt_index = idx;
goto changed;
- case 'f'|KEYC_META:
case KEYC_RIGHT|KEYC_CTRL:
- ws = options_get_string(oo, "word-separators");
-
- /* Find a word. */
- while (c->prompt_index != size) {
- idx = ++c->prompt_index;
- if (!status_prompt_in_list(ws, &c->prompt_buffer[idx]))
- break;
- }
-
- /* Find the separator at the end of the word. */
- while (c->prompt_index != size) {
- idx = ++c->prompt_index;
- if (status_prompt_in_list(ws, &c->prompt_buffer[idx]))
- break;
- }
-
- /* Back up to the end-of-word like vi. */
- if (options_get_number(oo, "status-keys") == MODEKEY_VI &&
- c->prompt_index != 0)
- c->prompt_index--;
-
+ case 'f'|KEYC_META:
+ separators = options_get_string(oo, "word-separators");
+ status_prompt_forward_word(c, size, 0, separators);
+ goto changed;
+ case 'E'|KEYC_VI:
+ status_prompt_end_word(c, size, "");
+ goto changed;
+ case 'e'|KEYC_VI:
+ separators = options_get_string(oo, "word-separators");
+ status_prompt_end_word(c, size, separators);
+ goto changed;
+ case 'W'|KEYC_VI:
+ status_prompt_forward_word(c, size, 1, "");
+ goto changed;
+ case 'w'|KEYC_VI:
+ separators = options_get_string(oo, "word-separators");
+ status_prompt_forward_word(c, size, 1, separators);
+ goto changed;
+ case 'B'|KEYC_VI:
+ status_prompt_backward_word(c, "");
goto changed;
- case 'b'|KEYC_META:
case KEYC_LEFT|KEYC_CTRL:
- ws = options_get_string(oo, "word-separators");
-
- /* Find a non-separator. */
- while (c->prompt_index != 0) {
- idx = --c->prompt_index;
- if (!status_prompt_in_list(ws, &c->prompt_buffer[idx]))
- break;
- }
-
- /* Find the separator at the beginning of the word. */
- while (c->prompt_index != 0) {
- idx = --c->prompt_index;
- if (status_prompt_in_list(ws, &c->prompt_buffer[idx])) {
- /* Go back to the word. */
- c->prompt_index++;
- break;
- }
- }
+ case 'b'|KEYC_META:
+ separators = options_get_string(oo, "word-separators");
+ status_prompt_backward_word(c, separators);
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 +1368,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 +1397,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);
@@ -1304,8 +1442,10 @@ append_key:
return (0);
if (key <= 0x7f)
utf8_set(&tmp, key);
- else
+ else if (KEYC_IS_UNICODE(key))
utf8_to_data(key, &tmp);
+ else
+ return (0);
c->prompt_buffer = xreallocarray(c->prompt_buffer, size + 2,
sizeof *c->prompt_buffer);
@@ -1348,54 +1488,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 +1665,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 +1773,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 +1881,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 +1899,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 +1910,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 +1960,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]);
+}
diff --git a/tmux.1 b/tmux.1
index 365b93f5..89d28a9c 100644
--- a/tmux.1
+++ b/tmux.1
@@ -1782,19 +1782,18 @@ commands) or when the cursor reaches the bottom (for scrolling commands).
.Ql -no-clear
variants do not clear the selection.
.Pp
-The next and previous word keys use space and the
-.Ql - ,
-.Ql _
-and
-.Ql @
-characters as word delimiters by default, but this can be adjusted by
-setting the
+The next and previous word keys skip over whitespace and treat consecutive
+runs of either word separators or other letters as words.
+Word separators can be customized with the
.Em word-separators
session option.
Next word moves to the start of the next word, next word end to the end of the
next word and previous word to the start of the previous word.
The three next and previous space keys work similarly but use a space alone as
the word separator.
+Setting
+.Em word-separators
+to the empty string makes next/previous word equivalent to next/previous space.
.Pp
The jump commands enable quick movement within a line.
For instance, typing
@@ -3453,7 +3452,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
@@ -3976,9 +3977,6 @@ If set to both, a bell and a message are produced.
Sets the session's conception of what characters are considered word
separators, for the purposes of the next and previous word commands in
copy mode.
-The default is
-.Ql \ -_@ .
-.El
.Pp
Available window options are:
.Pp
@@ -5380,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 1FikN
.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.
@@ -5395,6 +5407,11 @@ to execute commands interactively.
If
.Ar template
is specified, it is used as the command.
+With
+.Fl F ,
+.Ar template
+is expanded as a format.
+.Pp
If present,
.Fl I
is a comma-separated list of the initial text for each prompt.
@@ -5440,14 +5457,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
@@ -5669,6 +5692,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
diff --git a/tmux.h b/tmux.h
index 735f4e68..b775c219 100644
--- a/tmux.h
+++ b/tmux.h
@@ -131,6 +131,7 @@ struct winlink;
#define KEYC_CURSOR 0x04000000000000ULL
#define KEYC_IMPLIED_META 0x08000000000000ULL
#define KEYC_BUILD_MODIFIERS 0x10000000000000ULL
+#define KEYC_VI 0x20000000000000ULL
/* Masks for key bits. */
#define KEYC_MASK_MODIFIERS 0x00f00000000000ULL
@@ -590,6 +591,9 @@ struct msg_write_close {
int stream;
};
+/* Character classes. */
+#define WHITESPACE " "
+
/* Mode keys. */
#define MODEKEY_EMACS 0
#define MODEKEY_VI 1
@@ -810,6 +814,14 @@ struct style {
enum style_default_type default_type;
};
+/* Cursor style. */
+enum screen_cursor_style {
+ SCREEN_CURSOR_DEFAULT,
+ SCREEN_CURSOR_BLOCK,
+ SCREEN_CURSOR_UNDERLINE,
+ SCREEN_CURSOR_BAR
+};
+
/* Virtual screen. */
struct screen_sel;
struct screen_titles;
@@ -823,8 +835,8 @@ struct screen {
u_int cx; /* cursor x */
u_int cy; /* cursor y */
- u_int cstyle; /* cursor style */
- char *ccolour; /* cursor colour string */
+ enum screen_cursor_style cstyle; /* cursor style */
+ char *ccolour; /* cursor colour */
u_int rupper; /* scroll region top */
u_int rlower; /* scroll region bottom */
@@ -1312,7 +1324,7 @@ struct tty {
u_int cx;
u_int cy;
- u_int cstyle;
+ enum screen_cursor_style cstyle;
char *ccolour;
int oflag;
@@ -1564,6 +1576,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 *);
@@ -1727,18 +1749,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;
@@ -2510,6 +2530,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 *);
@@ -2524,13 +2546,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);
@@ -2620,7 +2644,7 @@ void grid_reader_cursor_end_of_line(struct grid_reader *, int, int);
void grid_reader_cursor_next_word(struct grid_reader *, const char *);
void grid_reader_cursor_next_word_end(struct grid_reader *, const char *);
void grid_reader_cursor_previous_word(struct grid_reader *, const char *,
- int);
+ int, int);
int grid_reader_cursor_jump(struct grid_reader *,
const struct utf8_data *);
int grid_reader_cursor_jump_back(struct grid_reader *,
@@ -2742,6 +2766,7 @@ void screen_select_cell(struct screen *, struct grid_cell *,
const struct grid_cell *);
void screen_alternate_on(struct screen *, struct grid_cell *, int);
void screen_alternate_off(struct screen *, struct grid_cell *, int);
+const char *screen_mode_to_string(int);
/* window.c */
extern struct windows windows;
diff --git a/tty.c b/tty.c
index 9e7dfde8..4b1b6777 100644
--- a/tty.c
+++ b/tty.c
@@ -98,7 +98,7 @@ tty_init(struct tty *tty, struct client *c)
memset(tty, 0, sizeof *tty);
tty->client = c;
- tty->cstyle = 0;
+ tty->cstyle = SCREEN_CURSOR_DEFAULT;
tty->ccolour = xstrdup("");
if (tcgetattr(c->fd, &tty->tio) != 0)
@@ -392,10 +392,10 @@ tty_stop_tty(struct tty *tty)
tty_raw(tty, tty_term_string(tty->term, TTYC_SGR0));
tty_raw(tty, tty_term_string(tty->term, TTYC_RMKX));
tty_raw(tty, tty_term_string(tty->term, TTYC_CLEAR));
- if (tty_term_has(tty->term, TTYC_SS) && tty->cstyle != 0) {
+ if (tty->cstyle != SCREEN_CURSOR_DEFAULT) {
if (tty_term_has(tty->term, TTYC_SE))
tty_raw(tty, tty_term_string(tty->term, TTYC_SE));
- else
+ else if (tty_term_has(tty->term, TTYC_SS))
tty_raw(tty, tty_term_string1(tty->term, TTYC_SS, 0));
}
if (tty->mode & MODE_BRACKETPASTE)
@@ -657,51 +657,98 @@ tty_force_cursor_colour(struct tty *tty, const char *ccolour)
void
tty_update_mode(struct tty *tty, int mode, struct screen *s)
{
- struct client *c = tty->client;
- int changed;
-
- if (s != NULL && strcmp(s->ccolour, tty->ccolour) != 0)
- tty_force_cursor_colour(tty, s->ccolour);
+ struct client *c = tty->client;
+ int changed;
+ enum screen_cursor_style cstyle = tty->cstyle;
if (tty->flags & TTY_NOCURSOR)
mode &= ~MODE_CURSOR;
changed = mode ^ tty->mode;
- if (changed != 0)
- log_debug("%s: update mode %x to %x", c->name, tty->mode, mode);
-
- /*
- * The cursor blinking flag can be reset by setting the cursor style, so
- * set the style first.
- */
- if (s != NULL && tty->cstyle != s->cstyle) {
- if (tty_term_has(tty->term, TTYC_SS)) {
- if (s->cstyle == 0 && tty_term_has(tty->term, TTYC_SE))
- tty_putcode(tty, TTYC_SE);
- else
- tty_putcode1(tty, TTYC_SS, s->cstyle);
- }
- tty->cstyle = s->cstyle;
- changed |= (MODE_CURSOR|MODE_BLINKING);
+ if (log_get_level() != 0 && changed != 0) {
+ log_debug("%s: current mode %s", c->name,
+ screen_mode_to_string(tty->mode));
+ log_debug("%s: setting mode %s", c->name,
+ screen_mode_to_string(mode));
}
- /*
- * Cursor invisible (RM ?25) overrides cursor blinking (SM ?12 or RM
- * 34), and we need to be careful not send cnorm after cvvis since it
- * can undo it.
- */
- if (changed & (MODE_CURSOR|MODE_BLINKING)) {
- log_debug("%s: cursor %s, %sblinking", __func__,
- (mode & MODE_CURSOR) ? "on" : "off",
- (mode & MODE_BLINKING) ? "" : "not ");
- if (~mode & MODE_CURSOR)
+ if (s != NULL) {
+ if (strcmp(s->ccolour, tty->ccolour) != 0)
+ tty_force_cursor_colour(tty, s->ccolour);
+ cstyle = s->cstyle;
+ }
+ if (~mode & MODE_CURSOR) {
+ /* Cursor now off - set as invisible. */
+ if (changed & MODE_CURSOR)
tty_putcode(tty, TTYC_CIVIS);
- else if (mode & MODE_BLINKING) {
- tty_putcode(tty, TTYC_CNORM);
- if (tty_term_has(tty->term, TTYC_CVVIS))
+ } else if ((changed & (MODE_CURSOR|MODE_BLINKING)) ||
+ cstyle != tty->cstyle) {
+ /*
+ * Cursor now on, blinking flag changed or style changed. Start
+ * by setting the cursor to normal.
+ */
+ tty_putcode(tty, TTYC_CNORM);
+ switch (cstyle) {
+ case SCREEN_CURSOR_DEFAULT:
+ /*
+ * If the old style wasn't default, then reset it to
+ * default.
+ */
+ if (tty->cstyle != SCREEN_CURSOR_DEFAULT) {
+ if (tty_term_has(tty->term, TTYC_SE))
+ tty_putcode(tty, TTYC_SE);
+ else
+ tty_putcode1(tty, TTYC_SS, 0);
+ }
+
+ /* Set the cursor as very visible if necessary. */
+ if (mode & MODE_BLINKING)
tty_putcode(tty, TTYC_CVVIS);
- } else
- tty_putcode(tty, TTYC_CNORM);
+ break;
+ case SCREEN_CURSOR_BLOCK:
+ /*
+ * Set style to either block blinking (1) or steady (2)
+ * if supported, otherwise just check the blinking
+ * flag.
+ */
+ if (tty_term_has(tty->term, TTYC_SS)) {
+ if (mode & MODE_BLINKING)
+ tty_putcode1(tty, TTYC_SS, 1);
+ else
+ tty_putcode1(tty, TTYC_SS, 2);
+ } else if (mode & MODE_BLINKING)
+ tty_putcode(tty, TTYC_CVVIS);
+ break;
+ case SCREEN_CURSOR_UNDERLINE:
+ /*
+ * Set style to either underline blinking (3) or steady
+ * (4) if supported, otherwise just check the blinking
+ * flag.
+ */
+ if (tty_term_has(tty->term, TTYC_SS)) {
+ if (mode & MODE_BLINKING)
+ tty_putcode1(tty, TTYC_SS, 3);
+ else
+ tty_putcode1(tty, TTYC_SS, 4);
+ } else if (mode & MODE_BLINKING)
+ tty_putcode(tty, TTYC_CVVIS);
+ break;
+ case SCREEN_CURSOR_BAR:
+ /*
+ * Set style to either bar blinking (5) or steady (6)
+ * if supported, otherwise just check the blinking
+ * flag.
+ */
+ if (tty_term_has(tty->term, TTYC_SS)) {
+ if (mode & MODE_BLINKING)
+ tty_putcode1(tty, TTYC_SS, 5);
+ else
+ tty_putcode1(tty, TTYC_SS, 6);
+ } else if (mode & MODE_BLINKING)
+ tty_putcode(tty, TTYC_CVVIS);
+ break;
+ }
+ tty->cstyle = cstyle;
}
if ((changed & ALL_MOUSE_MODES) &&
diff --git a/utf8.c b/utf8.c
index f43945e6..56f20cbb 100644
--- a/utf8.c
+++ b/utf8.c
@@ -64,7 +64,7 @@ static struct utf8_index_tree utf8_index_tree = RB_INITIALIZER(utf8_index_tree);
static u_int utf8_next_index;
#define UTF8_GET_SIZE(uc) (((uc) >> 24) & 0x1f)
-#define UTF8_GET_WIDTH(flags) (((uc) >> 29) - 1)
+#define UTF8_GET_WIDTH(uc) (((uc) >> 29) - 1)
#define UTF8_SET_SIZE(size) (((utf8_char)(size)) << 24)
#define UTF8_SET_WIDTH(width) ((((utf8_char)(width)) + 1) << 29)
diff --git a/window-copy.c b/window-copy.c
index f92e02ba..31875739 100644
--- a/window-copy.c
+++ b/window-copy.c
@@ -128,7 +128,7 @@ static void window_copy_cursor_next_word_end_pos(struct window_mode_entry *,
static void window_copy_cursor_next_word_end(struct window_mode_entry *,
const char *, int);
static void window_copy_cursor_previous_word_pos(struct window_mode_entry *,
- const char *, int, u_int *, u_int *);
+ const char *, u_int *, u_int *);
static void window_copy_cursor_previous_word(struct window_mode_entry *,
const char *, int);
static void window_copy_scroll_up(struct window_mode_entry *, u_int);
@@ -255,7 +255,7 @@ struct window_copy_mode_data {
SEL_LINE, /* select one line at a time */
} selflag;
- const char *ws; /* word separators */
+ const char *separators; /* word separators */
u_int dx; /* drag start position */
u_int dy;
@@ -1324,7 +1324,7 @@ window_copy_cmd_previous_matching_bracket(struct window_copy_cmd_state *cs)
tried = 1;
goto retry;
}
- window_copy_cursor_previous_word(wme, "}]) ", 1);
+ window_copy_cursor_previous_word(wme, close, 1);
}
continue;
}
@@ -1436,8 +1436,7 @@ window_copy_cmd_next_matching_bracket(struct window_copy_cmd_state *cs)
tried = 1;
goto retry;
}
- window_copy_cursor_next_word_end(wme, "{[( ",
- 0);
+ window_copy_cursor_next_word_end(wme, open, 0);
continue;
}
/* For vi, continue searching for bracket until EOL. */
@@ -1509,7 +1508,7 @@ window_copy_cmd_next_space(struct window_copy_cmd_state *cs)
u_int np = wme->prefix;
for (; np != 0; np--)
- window_copy_cursor_next_word(wme, " ");
+ window_copy_cursor_next_word(wme, "");
return (WINDOW_COPY_CMD_NOTHING);
}
@@ -1520,7 +1519,7 @@ window_copy_cmd_next_space_end(struct window_copy_cmd_state *cs)
u_int np = wme->prefix;
for (; np != 0; np--)
- window_copy_cursor_next_word_end(wme, " ", 0);
+ window_copy_cursor_next_word_end(wme, "", 0);
return (WINDOW_COPY_CMD_NOTHING);
}
@@ -1528,13 +1527,13 @@ static enum window_copy_cmd_action
window_copy_cmd_next_word(struct window_copy_cmd_state *cs)
{
struct window_mode_entry *wme = cs->wme;
- struct session *s = cs->s;
u_int np = wme->prefix;
- const char *ws;
+ const char *separators;
+
+ separators = options_get_string(cs->s->options, "word-separators");
- ws = options_get_string(s->options, "word-separators");
for (; np != 0; np--)
- window_copy_cursor_next_word(wme, ws);
+ window_copy_cursor_next_word(wme, separators);
return (WINDOW_COPY_CMD_NOTHING);
}
@@ -1542,13 +1541,13 @@ static enum window_copy_cmd_action
window_copy_cmd_next_word_end(struct window_copy_cmd_state *cs)
{
struct window_mode_entry *wme = cs->wme;
- struct session *s = cs->s;
u_int np = wme->prefix;
- const char *ws;
+ const char *separators;
+
+ separators = options_get_string(cs->s->options, "word-separators");
- ws = options_get_string(s->options, "word-separators");
for (; np != 0; np--)
- window_copy_cursor_next_word_end(wme, ws, 0);
+ window_copy_cursor_next_word_end(wme, separators, 0);
return (WINDOW_COPY_CMD_NOTHING);
}
@@ -1621,7 +1620,7 @@ window_copy_cmd_previous_space(struct window_copy_cmd_state *cs)
u_int np = wme->prefix;
for (; np != 0; np--)
- window_copy_cursor_previous_word(wme, " ", 1);
+ window_copy_cursor_previous_word(wme, "", 1);
return (WINDOW_COPY_CMD_NOTHING);
}
@@ -1629,13 +1628,13 @@ static enum window_copy_cmd_action
window_copy_cmd_previous_word(struct window_copy_cmd_state *cs)
{
struct window_mode_entry *wme = cs->wme;
- struct session *s = cs->s;
u_int np = wme->prefix;
- const char *ws;
+ const char *separators;
+
+ separators = options_get_string(cs->s->options, "word-separators");
- ws = options_get_string(s->options, "word-separators");
for (; np != 0; np--)
- window_copy_cursor_previous_word(wme, ws, 1);
+ window_copy_cursor_previous_word(wme, separators, 1);
return (WINDOW_COPY_CMD_NOTHING);
}
@@ -1781,18 +1780,20 @@ static enum window_copy_cmd_action
window_copy_cmd_select_word(struct window_copy_cmd_state *cs)
{
struct window_mode_entry *wme = cs->wme;
- struct session *s = cs->s;
+ struct options *session_options = cs->s->options;
struct window_copy_mode_data *data = wme->data;
u_int px, py, nextx, nexty;
+
data->lineflag = LINE_SEL_LEFT_RIGHT;
data->rectflag = 0;
data->selflag = SEL_WORD;
data->dx = data->cx;
data->dy = screen_hsize(data->backing) + data->cy - data->oy;
- data->ws = options_get_string(s->options, "word-separators");
- window_copy_cursor_previous_word(wme, data->ws, 0);
+ data->separators = options_get_string(session_options,
+ "word-separators");
+ window_copy_cursor_previous_word(wme, data->separators, 0);
px = data->cx;
py = screen_hsize(data->backing) + data->cy - data->oy;
data->selrx = px;
@@ -1808,8 +1809,8 @@ window_copy_cmd_select_word(struct window_copy_cmd_state *cs)
nexty++;
}
if (px >= window_copy_find_length(wme, py) ||
- !window_copy_in_set(wme, nextx, nexty, data->ws))
- window_copy_cursor_next_word_end(wme, data->ws, 1);
+ !window_copy_in_set(wme, nextx, nexty, WHITESPACE))
+ window_copy_cursor_next_word_end(wme, data->separators, 1);
else {
window_copy_update_cursor(wme, px, data->cy);
if (window_copy_update_selection(wme, 1, 1))
@@ -3733,8 +3734,8 @@ window_copy_synchronize_cursor_end(struct window_mode_entry *wme, int begin,
begin = 0;
if (data->dy > yy || (data->dy == yy && data->dx > xx)) {
/* Right to left selection. */
- window_copy_cursor_previous_word_pos(wme, data->ws, 0,
- &xx, &yy);
+ window_copy_cursor_previous_word_pos(wme,
+ data->separators, &xx, &yy);
begin = 1;
/* Reset the end. */
@@ -3743,9 +3744,10 @@ window_copy_synchronize_cursor_end(struct window_mode_entry *wme, int begin,
} else {
/* Left to right selection. */
if (xx >= window_copy_find_length(wme, yy) ||
- !window_copy_in_set(wme, xx + 1, yy, data->ws))
+ !window_copy_in_set(wme, xx + 1, yy, WHITESPACE)) {
window_copy_cursor_next_word_end_pos(wme,
- data->ws, &xx, &yy);
+ data->separators, &xx, &yy);
+ }
/* Reset the start. */
data->selx = data->selrx;
@@ -4683,19 +4685,19 @@ window_copy_cursor_next_word_end_pos(struct window_mode_entry *wme,
struct screen *back_s = data->backing;
struct grid_reader gr;
u_int px, py, hsize;
- int keys;
px = data->cx;
hsize = screen_hsize(back_s);
py = hsize + data->cy - data->oy;
grid_reader_start(&gr, back_s->grid, px, py);
- keys = options_get_number(oo, "mode-keys");
- if (keys == MODEKEY_VI && !grid_reader_in_set(&gr, separators))
- grid_reader_cursor_right(&gr, 0, 0);
- grid_reader_cursor_next_word_end(&gr, separators);
- if (keys == MODEKEY_VI)
+ if (options_get_number(oo, "mode-keys") == MODEKEY_VI) {
+ if (!grid_reader_in_set(&gr, WHITESPACE))
+ grid_reader_cursor_right(&gr, 0, 0);
+ grid_reader_cursor_next_word_end(&gr, separators);
grid_reader_cursor_left(&gr, 1);
+ } else
+ grid_reader_cursor_next_word_end(&gr, separators);
grid_reader_get_cursor(&gr, &px, &py);
*ppx = px;
*ppy = py;
@@ -4712,7 +4714,6 @@ window_copy_cursor_next_word_end(struct window_mode_entry *wme,
struct screen *back_s = data->backing;
struct grid_reader gr;
u_int px, py, oldy, hsize;
- int keys;
px = data->cx;
hsize = screen_hsize(back_s);
@@ -4720,12 +4721,13 @@ window_copy_cursor_next_word_end(struct window_mode_entry *wme,
oldy = data->cy;
grid_reader_start(&gr, back_s->grid, px, py);
- keys = options_get_number(oo, "mode-keys");
- if (keys == MODEKEY_VI && !grid_reader_in_set(&gr, separators))
- grid_reader_cursor_right(&gr, 0, 0);
- grid_reader_cursor_next_word_end(&gr, separators);
- if (keys == MODEKEY_VI)
+ if (options_get_number(oo, "mode-keys") == MODEKEY_VI) {
+ if (!grid_reader_in_set(&gr, WHITESPACE))
+ grid_reader_cursor_right(&gr, 0, 0);
+ grid_reader_cursor_next_word_end(&gr, separators);
grid_reader_cursor_left(&gr, 1);
+ } else
+ grid_reader_cursor_next_word_end(&gr, separators);
grid_reader_get_cursor(&gr, &px, &py);
window_copy_acquire_cursor_down(wme, hsize, screen_size_y(back_s),
data->oy, oldy, px, py, no_reset);
@@ -4734,7 +4736,7 @@ window_copy_cursor_next_word_end(struct window_mode_entry *wme,
/* Compute the previous place where a word begins. */
static void
window_copy_cursor_previous_word_pos(struct window_mode_entry *wme,
- const char *separators, int already, u_int *ppx, u_int *ppy)
+ const char *separators, u_int *ppx, u_int *ppy)
{
struct window_copy_mode_data *data = wme->data;
struct screen *back_s = data->backing;
@@ -4746,7 +4748,8 @@ window_copy_cursor_previous_word_pos(struct window_mode_entry *wme,
py = hsize + data->cy - data->oy;
grid_reader_start(&gr, back_s->grid, px, py);
- grid_reader_cursor_previous_word(&gr, separators, already);
+ grid_reader_cursor_previous_word(&gr, separators, /* already= */ 0,
+ /* stop_at_eol= */ 1);
grid_reader_get_cursor(&gr, &px, &py);
*ppx = px;
*ppy = py;
@@ -4761,6 +4764,11 @@ window_copy_cursor_previous_word(struct window_mode_entry *wme,
struct screen *back_s = data->backing;
struct grid_reader gr;
u_int px, py, oldy, hsize;
+ int stop_at_eol;
+
+ stop_at_eol =
+ options_get_number(wme->wp->window->options, "mode-keys")
+ == MODEKEY_EMACS;
px = data->cx;
hsize = screen_hsize(back_s);
@@ -4768,7 +4776,7 @@ window_copy_cursor_previous_word(struct window_mode_entry *wme,
oldy = data->cy;
grid_reader_start(&gr, back_s->grid, px, py);
- grid_reader_cursor_previous_word(&gr, separators, already);
+ grid_reader_cursor_previous_word(&gr, separators, already, stop_at_eol);
grid_reader_get_cursor(&gr, &px, &py);
window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px, py);
}
@@ -4910,10 +4918,10 @@ window_copy_start_drag(struct client *c, struct mouse_event *m)
data->selflag = SEL_CHAR;
switch (data->selflag) {
case SEL_WORD:
- if (data->ws != NULL) {
+ if (data->separators != NULL) {
window_copy_update_cursor(wme, x, y);
- window_copy_cursor_previous_word_pos(wme, data->ws, 0,
- &x, &y);
+ window_copy_cursor_previous_word_pos(wme,
+ data->separators, &x, &y);
y -= screen_hsize(data->backing) - data->oy;
}
window_copy_update_cursor(wme, x, y);
diff --git a/window-customize.c b/window-customize.c
index 34a13f73..782542f7 100644
--- a/window-customize.c
+++ b/window-customize.c
@@ -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':
diff --git a/window-tree.c b/window-tree.c
index 33af0413..1cfdcb70 100644
--- a/window-tree.c
+++ b/window-tree.c
@@ -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':