From e5106bfb9660d5c9470acf9defa1084c61a070d4 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Jun 2021 07:21:09 +0000 Subject: Add another couple of keys needed for extended keys, GitHub issue 2658. Handle modifier 9 as Meta, GitHub issue 2647. --- key-bindings.c | 6 ++++++ key-string.c | 10 +++++++--- tty-keys.c | 11 +++++++++-- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/key-bindings.c b/key-bindings.c index b47f6ff7..467c7f93 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -215,6 +215,9 @@ key_bindings_add(const char *name, key_code key, const char *note, int repeat, if (repeat) bd->flags |= KEY_BINDING_REPEAT; bd->cmdlist = cmdlist; + + log_debug("%s: %#llx %s = %s", __func__, bd->key, + key_string_lookup_key(bd->key, 1), cmd_list_print(bd->cmdlist, 0)); } void @@ -231,6 +234,9 @@ key_bindings_remove(const char *name, key_code key) if (bd == NULL) return; + log_debug("%s: %#llx %s", __func__, bd->key, + key_string_lookup_key(bd->key, 1)); + RB_REMOVE(key_bindings, &table->key_bindings, bd); key_bindings_free(bd); diff --git a/key-string.c b/key-string.c index 8d60f132..c24a33fc 100644 --- a/key-string.c +++ b/key-string.c @@ -164,7 +164,7 @@ key_string_get_modifiers(const char **string) key_code key_string_lookup_string(const char *string) { - static const char *other = "!#()+,-.0123456789:;<=>'\r\t\177"; + static const char *other = "!#()+,-.0123456789:;<=>'\r\t\177`/"; key_code key, modifiers; u_int u, i; struct utf8_data ud, *udp; @@ -238,8 +238,12 @@ key_string_lookup_string(const char *string) } /* Convert the standard control keys. */ - if (key < KEYC_BASE && (modifiers & KEYC_CTRL) && - strchr(other, key) == NULL) { + if (key < KEYC_BASE && + (modifiers & KEYC_CTRL) && + strchr(other, key) == NULL && + key != 9 && + key != 13 && + key != 27) { if (key >= 97 && key <= 122) key -= 96; else if (key >= 64 && key <= 95) diff --git a/tty-keys.c b/tty-keys.c index 040e7005..3012be3d 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -252,7 +252,8 @@ static const key_code tty_default_xterm_modifiers[] = { KEYC_CTRL, KEYC_SHIFT|KEYC_CTRL, KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL, - KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL + KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL, + KEYC_META|KEYC_IMPLIED_META }; /* @@ -944,6 +945,9 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len, case 8: nkey |= (KEYC_SHIFT|KEYC_META|KEYC_IMPLIED_META|KEYC_CTRL); break; + case 9: + nkey |= (KEYC_META|KEYC_IMPLIED_META); + break; default: *key = KEYC_NONE; break; @@ -955,7 +959,10 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len, */ if (nkey & KEYC_CTRL) { onlykey = (nkey & KEYC_MASK_KEY); - if (onlykey < 32 && onlykey != 9) + if (onlykey < 32 && + onlykey != 9 && + onlykey != 13 && + onlykey != 27) /* nothing */; else if (onlykey >= 97 && onlykey <= 122) onlykey -= 96; -- cgit From c46a607dc10606047f685f29a71213501de819d1 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Jun 2021 07:21:46 +0000 Subject: Adjust latest client when a client detaches, GitHub issue 2657. --- server-client.c | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/server-client.c b/server-client.c index 25d61376..1114396d 100644 --- a/server-client.c +++ b/server-client.c @@ -46,6 +46,7 @@ static void server_client_check_modes(struct client *); static void server_client_set_title(struct client *); static void server_client_reset_state(struct client *); static int server_client_assume_paste(struct session *); +static void server_client_update_latest(struct client *); static void server_client_dispatch(struct imsg *, void *); static void server_client_dispatch_command(struct client *, struct imsg *); @@ -274,6 +275,40 @@ server_client_open(struct client *c, char **cause) return (0); } +/* Lost an attached client. */ +static void +server_client_attached_lost(struct client *c) +{ + struct session *s = c->session; + struct window *w; + struct client *loop; + struct client *found; + + log_debug("lost attached client %p", c); + + /* + * By this point the session in the client has been cleared so walk all + * windows to find any with this client as the latest. + */ + RB_FOREACH(w, windows, &windows) { + if (w->latest != c) + continue; + + found = NULL; + TAILQ_FOREACH(loop, &clients, entry) { + s = loop->session; + if (loop == c || s == NULL || s->curw->window != w) + continue; + if (found == NULL || + timercmp(&loop->activity_time, &found->activity_time, + >)) + found = loop; + } + if (found != NULL) + server_client_update_latest(found); + } +} + /* Lost a client. */ void server_client_lost(struct client *c) @@ -299,8 +334,10 @@ server_client_lost(struct client *c) TAILQ_REMOVE(&clients, c, entry); log_debug("lost client %p", c); - if (c->flags & CLIENT_ATTACHED) + if (c->flags & CLIENT_ATTACHED) { + server_client_attached_lost(c); notify_client("client-detached", c); + } if (c->flags & CLIENT_CONTROL) control_stop(c); -- cgit From 788f56b40a695b21d5ee861d2789f354608cda81 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Jun 2021 07:22:06 +0000 Subject: Fix display-menu -xR, from Alexis Hildebrandt. --- cmd-display-menu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd-display-menu.c b/cmd-display-menu.c index 27a4c1d7..f2100bdb 100644 --- a/cmd-display-menu.c +++ b/cmd-display-menu.c @@ -206,7 +206,7 @@ cmd_display_menu_get_position(struct client *tc, struct cmdq_item *item, if (xp == NULL || strcmp(xp, "C") == 0) xp = "#{popup_centre_x}"; else if (strcmp(xp, "R") == 0) - xp = "#{popup_right}"; + xp = "#{popup_pane_right}"; else if (strcmp(xp, "P") == 0) xp = "#{popup_pane_left}"; else if (strcmp(xp, "M") == 0) -- cgit From 1ee231956ca9d1436e101350f4246abc1f157224 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Jun 2021 07:22:37 +0000 Subject: back-to-indentation fixes, from Anindya Mukherjee. --- grid-reader.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/grid-reader.c b/grid-reader.c index 89fe90fb..df0dd450 100644 --- a/grid-reader.c +++ b/grid-reader.c @@ -371,19 +371,26 @@ void grid_reader_cursor_back_to_indentation(struct grid_reader *gr) { struct grid_cell gc; - u_int px, py, xx, yy; + u_int px, py, xx, yy, oldx, oldy; yy = gr->gd->hsize + gr->gd->sy - 1; + oldx = gr->cx; + oldy = gr->cy; grid_reader_cursor_start_of_line(gr, 1); for (py = gr->cy; py <= yy; py++) { xx = grid_line_length(gr->gd, py); for (px = 0; px < xx; px++) { grid_get_cell(gr->gd, px, py, &gc); - if (gc.data.size != 1 || *gc.data.data != ' ') - break; + if (gc.data.size != 1 || *gc.data.data != ' ') { + gr->cx = px; + gr->cy = py; + return; + } } if (~grid_get_line(gr->gd, py)->flags & GRID_LINE_WRAPPED) break; } + gr->cx = oldx; + gr->cy = oldy; } -- cgit From 64c276c23bd729c03c2a3ff00c6f9e6ac4c644c6 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Jun 2021 07:24:10 +0000 Subject: Add an "always" value to the extended-keys option to always forward these keys to applications inside tmux. --- input.c | 2 ++ options-table.c | 6 +++++- screen.c | 4 +++- tmux.1 | 25 +++++++++++++++++++------ 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/input.c b/input.c index f6aeb027..b599f27d 100644 --- a/input.c +++ b/input.c @@ -1390,6 +1390,8 @@ input_csi_dispatch(struct input_ctx *ictx) case INPUT_CSI_MODSET: n = input_get(ictx, 0, 0, 0); m = input_get(ictx, 1, 0, 0); + if (options_get_number(global_options, "extended-keys") == 2) + break; if (n == 0 || (n == 4 && m == 0)) screen_write_mode_clear(sctx, MODE_KEXTENDED); else if (n == 4 && (m == 1 || m == 2)) diff --git a/options-table.c b/options-table.c index 8ea56918..4f4d9ff6 100644 --- a/options-table.c +++ b/options-table.c @@ -75,6 +75,9 @@ static const char *options_table_remain_on_exit_list[] = { static const char *options_table_detach_on_destroy_list[] = { "off", "on", "no-detached", NULL }; +static const char *options_table_extended_keys_list[] = { + "off", "on", "always", NULL +}; /* Status line format. */ #define OPTIONS_TABLE_STATUS_FORMAT1 \ @@ -267,8 +270,9 @@ const struct options_table_entry options_table[] = { }, { .name = "extended-keys", - .type = OPTIONS_TABLE_FLAG, + .type = OPTIONS_TABLE_CHOICE, .scope = OPTIONS_TABLE_SERVER, + .choices = options_table_extended_keys_list, .default_num = 0, .text = "Whether to request extended key sequences from terminals " "that support it." diff --git a/screen.c b/screen.c index 97ccdeec..0b1047ab 100644 --- a/screen.c +++ b/screen.c @@ -101,7 +101,9 @@ screen_reinit(struct screen *s) s->rupper = 0; s->rlower = screen_size_y(s) - 1; - s->mode = MODE_CURSOR | MODE_WRAP; + s->mode = MODE_CURSOR|MODE_WRAP; + if (options_get_number(global_options, "extended-keys") == 2) + s->mode |= MODE_KEXTENDED; if (s->saved_grid != NULL) screen_alternate_off(s, NULL, 0); diff --git a/tmux.1 b/tmux.1 index f5689bfa..146c998f 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3418,11 +3418,24 @@ sessions. .Xc If enabled, the server will exit when there are no attached clients. .It Xo Ic extended-keys -.Op Ic on | off +.Op Ic on | off | always .Xc -When enabled, extended keys are requested from the terminal and if supported -are recognised by -.Nm . +When +.Ic on +or +.Ic always , +the escape sequence to enable extended keys is sent to the terminal, if +.Nm +knows that it is supported. +.Nm +always recognises extended keys itself. +If this option is +.Ic on , +.Nm +will only forward extended keys to applications when they request them; if +.Ic always , +.Nm +will always forward the keys. .It Xo Ic focus-events .Op Ic on | off .Xc @@ -3501,8 +3514,8 @@ capabilities to be set instead, is intended for classes of functionality supported in a standard way but not reported by .Xr terminfo 5 . -Care must be taken only to configure this with features the terminal actually -support. +Care must be taken to configure this only with features the terminal actually +supports. .Pp This is an array option where each entry is a colon-separated string made up of a terminal type pattern (matched using -- cgit From 9f38a8807c6c6b3b7596f06c2bb662242337ac48 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Jun 2021 07:24:45 +0000 Subject: Include current client in size calculation for new sessions, GitHub issue 2662. --- cmd-new-session.c | 1 + resize.c | 47 +++++++++++++++++++++++++++++++++-------------- status.c | 2 ++ window.c | 2 ++ 4 files changed, 38 insertions(+), 14 deletions(-) diff --git a/cmd-new-session.c b/cmd-new-session.c index cc3494de..c47d66cd 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -269,6 +269,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item) memset(&sc, 0, sizeof sc); sc.item = item; sc.s = s; + sc.tc = c; sc.name = args_get(args, 'n'); sc.argc = args->argc; diff --git a/resize.c b/resize.c index 172cbcb5..66cb9430 100644 --- a/resize.c +++ b/resize.c @@ -108,17 +108,19 @@ clients_with_window(struct window *w) } static int -clients_calculate_size(int type, int current, struct session *s, - struct window *w, int (*skip_client)(struct client *, int, int, - struct session *, struct window *), u_int *sx, u_int *sy, u_int *xpixel, - u_int *ypixel) +clients_calculate_size(int type, int current, struct client *c, + struct session *s, struct window *w, int (*skip_client)(struct client *, + int, int, struct session *, struct window *), u_int *sx, u_int *sy, + u_int *xpixel, u_int *ypixel) { struct client *loop; u_int cx, cy, n = 0; /* Manual windows do not have their size changed based on a client. */ - if (type == WINDOW_SIZE_MANUAL) + if (type == WINDOW_SIZE_MANUAL) { + log_debug("%s: type is manual", __func__); return (0); + } /* * Start comparing with 0 for largest and UINT_MAX for smallest or @@ -139,18 +141,24 @@ clients_calculate_size(int type, int current, struct session *s, /* Loop over the clients and work out the size. */ TAILQ_FOREACH(loop, &clients, entry) { - if (ignore_client_size(loop)) + if (loop != c && ignore_client_size(loop)) { + log_debug("%s: ignoring %s", __func__, loop->name); continue; - if (skip_client(loop, type, current, s, w)) + } + if (loop != c && skip_client(loop, type, current, s, w)) { + log_debug("%s: skipping %s", __func__, loop->name); continue; + } /* * If there are multiple clients attached, only accept the * latest client; otherwise let the only client be chosen as * for smallest. */ - if (type == WINDOW_SIZE_LATEST && n > 1 && loop != w->latest) + if (type == WINDOW_SIZE_LATEST && n > 1 && loop != w->latest) { + log_debug("%s: %s is not latest", __func__, loop->name); continue; + } /* Work out this client's size. */ cx = loop->tty.sx; @@ -175,16 +183,24 @@ clients_calculate_size(int type, int current, struct session *s, *xpixel = loop->tty.xpixel; *ypixel = loop->tty.ypixel; } + log_debug("%s: after %s (%ux%u), size is %ux%u", __func__, + loop->name, cx, cy, *sx, *sy); } /* Return whether a suitable size was found. */ - if (type == WINDOW_SIZE_LARGEST) + if (type == WINDOW_SIZE_LARGEST) { + log_debug("%s: type is largest", __func__); return (*sx != 0 && *sy != 0); + } + if (type == WINDOW_SIZE_LATEST) + log_debug("%s: type is latest", __func__); + else + log_debug("%s: type is smallest", __func__); return (*sx != UINT_MAX && *sy != UINT_MAX); } static int -default_window_size_skip_client (struct client *loop, int type, +default_window_size_skip_client(struct client *loop, int type, __unused int current, struct session *s, struct window *w) { /* @@ -221,23 +237,25 @@ default_window_size(struct client *c, struct session *s, struct window *w, *sy = c->tty.sy - status_line_size(c); *xpixel = c->tty.xpixel; *ypixel = c->tty.ypixel; + log_debug("%s: using %ux%u from %s", __func__, *sx, *sy, + c->name); goto done; } - if (w == NULL) - type = WINDOW_SIZE_MANUAL; } /* * Look for a client to base the size on. If none exists (or the type * is manual), use the default-size option. */ - if (!clients_calculate_size(type, 0, s, w, + if (!clients_calculate_size(type, 0, c, s, w, default_window_size_skip_client, sx, sy, xpixel, ypixel)) { value = options_get_string(s->options, "default-size"); if (sscanf(value, "%ux%u", sx, sy) != 2) { *sx = 80; *sy = 24; } + log_debug("%s: using %ux%u from default-size", __func__, *sx, + *sy); } done: @@ -250,6 +268,7 @@ done: *sy = WINDOW_MINIMUM; if (*sy > WINDOW_MAXIMUM) *sy = WINDOW_MAXIMUM; + log_debug("%s: resulting size is %ux%u", __func__, *sx, *sy); } static int @@ -289,7 +308,7 @@ recalculate_size(struct window *w, int now) current = options_get_number(w->options, "aggressive-resize"); /* Look for a suitable client and get the new size. */ - changed = clients_calculate_size(type, current, NULL, w, + changed = clients_calculate_size(type, current, NULL, NULL, w, recalculate_size_skip_client, &sx, &sy, &xpixel, &ypixel); /* diff --git a/status.c b/status.c index f9786f4b..271e1afa 100644 --- a/status.c +++ b/status.c @@ -226,6 +226,8 @@ status_line_size(struct client *c) if (c->flags & (CLIENT_STATUSOFF|CLIENT_CONTROL)) return (0); + if (s == NULL) + return (options_get_number(global_s_options, "status")); return (s->statuslines); } diff --git a/window.c b/window.c index 36cf12d9..519f91b1 100644 --- a/window.c +++ b/window.c @@ -331,6 +331,8 @@ window_create(u_int sx, u_int sy, u_int xpixel, u_int ypixel) window_update_activity(w); + log_debug("%s: @%u create %ux%u (%ux%u)", __func__, w->id, sx, sy, + w->xpixel, w->ypixel); return (w); } -- cgit From 0c5cbbbf5cd09598ff2f3d6d1ae99fa353ec5b40 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Jun 2021 07:28:45 +0000 Subject: Three changes to fix problems with xterm in VT340 mode, reported by Thomas Sattler. 1) Do not include the DECSLRM or DECFRA features for xterm; they will be added instead if secondary DA responds as VT420 (this happens already). 2) Set or reset the individual flags after terminal-overrides is applied, so the user can properly disable them. 3) Add a capability for DECFRA ("Rect"). --- tmux.1 | 4 +++ tmux.h | 1 + tty-features.c | 13 ++++++-- tty-term.c | 98 ++++++++++++++++++++++++++++++++++++++-------------------- 4 files changed, 80 insertions(+), 36 deletions(-) diff --git a/tmux.1 b/tmux.1 index 146c998f..d2ad593f 100644 --- a/tmux.1 +++ b/tmux.1 @@ -6049,6 +6049,10 @@ Disable and enable focus reporting. These are set automatically if the .Em XT capability is present. +.It Em \&Rect +Tell +.Nm +that the terminal supports rectangle operations. .It Em \&Smol Enable the overline attribute. .It Em \&Smulx diff --git a/tmux.h b/tmux.h index fb2f35f9..1947009f 100644 --- a/tmux.h +++ b/tmux.h @@ -451,6 +451,7 @@ enum tty_code_code { TTYC_MS, TTYC_OL, TTYC_OP, + TTYC_RECT, TTYC_REV, TTYC_RGB, TTYC_RI, diff --git a/tty-features.c b/tty-features.c index f167a2d3..b42cf74a 100644 --- a/tty-features.c +++ b/tty-features.c @@ -218,9 +218,13 @@ static const struct tty_feature tty_feature_margins = { }; /* Terminal supports DECFRA rectangle fill. */ +static const char *tty_feature_rectfill_capabilities[] = { + "Rect", + NULL +}; static const struct tty_feature tty_feature_rectfill = { "rectfill", - NULL, + tty_feature_rectfill_capabilities, TERM_DECFRA }; @@ -351,8 +355,13 @@ tty_default_features(int *feat, const char *name, u_int version) ",cstyle,extkeys,margins,sync" }, { .name = "XTerm", + /* + * xterm also supports DECSLRM and DECFRA, but they can be + * disabled so not set it here - they will be added if + * secondary DA shows VT420. + */ .features = TTY_FEATURES_BASE_MODERN_XTERM - ",ccolour,cstyle,extkeys,focus,margins,rectfill" + ",ccolour,cstyle,extkeys,focus" } }; u_int i; diff --git a/tty-term.c b/tty-term.c index 9df50948..275efe2f 100644 --- a/tty-term.c +++ b/tty-term.c @@ -248,6 +248,7 @@ static const struct tty_term_code_entry tty_term_codes[] = { [TTYC_MS] = { TTYCODE_STRING, "Ms" }, [TTYC_OL] = { TTYCODE_STRING, "ol" }, [TTYC_OP] = { TTYCODE_STRING, "op" }, + [TTYC_RECT] = { TTYCODE_STRING, "Rect" }, [TTYC_REV] = { TTYCODE_STRING, "rev" }, [TTYC_RGB] = { TTYCODE_FLAG, "RGB" }, [TTYC_RIN] = { TTYCODE_STRING, "rin" }, @@ -431,10 +432,11 @@ tty_term_apply_overrides(struct tty_term *term) struct options_entry *o; struct options_array_item *a; union options_value *ov; - const char *s; + const char *s, *acs; size_t offset; char *first; + /* Update capabilities from the option. */ o = options_get_only(global_options, "terminal-overrides"); a = options_array_first(o); while (a != NULL) { @@ -447,6 +449,64 @@ tty_term_apply_overrides(struct tty_term *term) tty_term_apply(term, s + offset, 0); a = options_array_next(a); } + + /* Update the RGB flag if the terminal has RGB colours. */ + if (tty_term_has(term, TTYC_SETRGBF) && + tty_term_has(term, TTYC_SETRGBB)) + term->flags |= TERM_RGBCOLOURS; + else + term->flags &= ~TERM_RGBCOLOURS; + log_debug("RGBCOLOURS flag is %d", !!(term->flags & TERM_RGBCOLOURS)); + + /* + * Set or clear the DECSLRM flag if the terminal has the margin + * capabilities. + */ + if (tty_term_has(term, TTYC_CMG) && tty_term_has(term, TTYC_CLMG)) + term->flags |= TERM_DECSLRM; + else + term->flags &= ~TERM_DECSLRM; + log_debug("DECSLRM flag is %d", !!(term->flags & TERM_DECSLRM)); + + /* + * Set or clear the DECFRA flag if the terminal has the rectangle + * capability. + */ + if (tty_term_has(term, TTYC_RECT)) + term->flags |= TERM_DECFRA; + else + term->flags &= ~TERM_DECFRA; + log_debug("DECFRA flag is %d", !!(term->flags & TERM_DECFRA)); + + /* + * Terminals without am (auto right margin) wrap at at $COLUMNS - 1 + * rather than $COLUMNS (the cursor can never be beyond $COLUMNS - 1). + * + * Terminals without xenl (eat newline glitch) ignore a newline beyond + * the right edge of the terminal, but tmux doesn't care about this - + * it always uses absolute only moves the cursor with a newline when + * also sending a linefeed. + * + * This is irritating, most notably because it is painful to write to + * the very bottom-right of the screen without scrolling. + * + * Flag the terminal here and apply some workarounds in other places to + * do the best possible. + */ + if (!tty_term_flag(term, TTYC_AM)) + term->flags |= TERM_NOAM; + else + term->flags &= ~TERM_NOAM; + log_debug("NOAM flag is %d", !!(term->flags & TERM_NOAM)); + + /* Generate ACS table. If none is present, use nearest ASCII. */ + memset(term->acs, 0, sizeof term->acs); + if (tty_term_has(term, TTYC_ACSC)) + acs = tty_term_string(term, TTYC_ACSC); + else + acs = "a#j+k+l+m+n+o-p-q-r-s-t+u+v+w+x|y~."; + for (; acs[0] != '\0' && acs[1] != '\0'; acs += 2) + term->acs[(u_char) acs[0]][0] = acs[1]; } struct tty_term * @@ -460,7 +520,7 @@ tty_term_create(struct tty *tty, char *name, char **caps, u_int ncaps, struct options_array_item *a; union options_value *ov; u_int i, j; - const char *s, *acs, *value; + const char *s, *value; size_t offset, namelen; char *first; @@ -557,40 +617,10 @@ tty_term_create(struct tty *tty, char *name, char **caps, u_int ncaps, (!tty_term_has(term, TTYC_SETRGBF) || !tty_term_has(term, TTYC_SETRGBB))) tty_add_features(feat, "RGB", ","); - if (tty_term_has(term, TTYC_SETRGBF) && - tty_term_has(term, TTYC_SETRGBB)) - term->flags |= TERM_RGBCOLOURS; /* Apply the features and overrides again. */ - tty_apply_features(term, *feat); - tty_term_apply_overrides(term); - - /* - * Terminals without am (auto right margin) wrap at at $COLUMNS - 1 - * rather than $COLUMNS (the cursor can never be beyond $COLUMNS - 1). - * - * Terminals without xenl (eat newline glitch) ignore a newline beyond - * the right edge of the terminal, but tmux doesn't care about this - - * it always uses absolute only moves the cursor with a newline when - * also sending a linefeed. - * - * This is irritating, most notably because it is painful to write to - * the very bottom-right of the screen without scrolling. - * - * Flag the terminal here and apply some workarounds in other places to - * do the best possible. - */ - if (!tty_term_flag(term, TTYC_AM)) - term->flags |= TERM_NOAM; - - /* Generate ACS table. If none is present, use nearest ASCII. */ - memset(term->acs, 0, sizeof term->acs); - if (tty_term_has(term, TTYC_ACSC)) - acs = tty_term_string(term, TTYC_ACSC); - else - acs = "a#j+k+l+m+n+o-p-q-r-s-t+u+v+w+x|y~."; - for (; acs[0] != '\0' && acs[1] != '\0'; acs += 2) - term->acs[(u_char) acs[0]][0] = acs[1]; + if (tty_apply_features(term, *feat)) + tty_term_apply_overrides(term); /* Log the capabilities. */ for (i = 0; i < tty_term_ncodes(); i++) -- cgit From b573dbba9062fa9db3b60310cdb4d8776a0be3fd Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Jun 2021 07:29:45 +0000 Subject: Do not count client (and crash) if no window. --- resize.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resize.c b/resize.c index 66cb9430..38cda23d 100644 --- a/resize.c +++ b/resize.c @@ -136,7 +136,7 @@ clients_calculate_size(int type, int current, struct client *c, * For latest, count the number of clients with this window. We only * care if there is more than one. */ - if (type == WINDOW_SIZE_LATEST) + if (type == WINDOW_SIZE_LATEST && w != NULL) n = clients_with_window(w); /* Loop over the clients and work out the size. */ -- cgit From 84e22168a52f8fe0fa0ef0431d1752273f53e8bd Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Jun 2021 07:33:41 +0000 Subject: Change resize timers and flags into one timer and a queue which is simpler and fixes problems with vim when resized multiple times. GitHub issue 2677. --- server-client.c | 117 +++++++++++++++++++++++++++----------------------------- tmux.1 | 2 + tmux.h | 25 ++++++++---- window.c | 51 ++++++++++-------------- 4 files changed, 96 insertions(+), 99 deletions(-) diff --git a/server-client.c b/server-client.c index 1114396d..9bd2ad19 100644 --- a/server-client.c +++ b/server-client.c @@ -1450,84 +1450,79 @@ server_client_resize_timer(__unused int fd, __unused short events, void *data) evtimer_del(&wp->resize_timer); } -/* Start the resize timer. */ -static void -server_client_start_resize_timer(struct window_pane *wp) -{ - struct timeval tv = { .tv_usec = 250000 }; - - log_debug("%s: %%%u resize timer started", __func__, wp->id); - evtimer_add(&wp->resize_timer, &tv); -} - -/* Force timer event. */ -static void -server_client_force_timer(__unused int fd, __unused short events, void *data) -{ - struct window_pane *wp = data; - - log_debug("%s: %%%u force timer expired", __func__, wp->id); - evtimer_del(&wp->force_timer); - wp->flags |= PANE_RESIZENOW; -} - -/* Start the force timer. */ -static void -server_client_start_force_timer(struct window_pane *wp) -{ - struct timeval tv = { .tv_usec = 10000 }; - - log_debug("%s: %%%u force timer started", __func__, wp->id); - evtimer_add(&wp->force_timer, &tv); -} - /* Check if pane should be resized. */ static void server_client_check_pane_resize(struct window_pane *wp) { - if (!event_initialized(&wp->resize_timer)) - evtimer_set(&wp->resize_timer, server_client_resize_timer, wp); - if (!event_initialized(&wp->force_timer)) - evtimer_set(&wp->force_timer, server_client_force_timer, wp); + struct window_pane_resize *r; + struct window_pane_resize *r1; + struct window_pane_resize *first; + struct window_pane_resize *last; + struct timeval tv = { .tv_usec = 250000 }; - if (~wp->flags & PANE_RESIZE) + if (TAILQ_EMPTY(&wp->resize_queue)) return; - log_debug("%s: %%%u needs to be resized", __func__, wp->id); - if (evtimer_pending(&wp->resize_timer, NULL)) { - log_debug("%s: %%%u resize timer is running", __func__, wp->id); + if (!event_initialized(&wp->resize_timer)) + evtimer_set(&wp->resize_timer, server_client_resize_timer, wp); + if (evtimer_pending(&wp->resize_timer, NULL)) return; + + log_debug("%s: %%%u needs to be resized", __func__, wp->id); + TAILQ_FOREACH(r, &wp->resize_queue, entry) { + log_debug("queued resize: %ux%u -> %ux%u", r->osx, r->osy, + r->sx, r->sy); } - server_client_start_resize_timer(wp); - if (~wp->flags & PANE_RESIZEFORCE) { - /* - * The timer is not running and we don't need to force a - * resize, so just resize immediately. - */ - log_debug("%s: resizing %%%u now", __func__, wp->id); - window_pane_send_resize(wp, 0); - wp->flags &= ~PANE_RESIZE; + /* + * There are three cases that matter: + * + * - Only one resize. It can just be applied. + * + * - Multiple resizes and the ending size is different from the + * starting size. We can discard all resizes except the most recent. + * + * - Multiple resizes and the ending size is the same as the starting + * size. We must resize at least twice to force the application to + * redraw. So apply the first and leave the last on the queue for + * next time. + */ + first = TAILQ_FIRST(&wp->resize_queue); + last = TAILQ_LAST(&wp->resize_queue, window_pane_resizes); + if (first == last) { + /* Only one resize. */ + window_pane_send_resize(wp, first->sx, first->sy); + TAILQ_REMOVE(&wp->resize_queue, first, entry); + free(first); + } else if (last->sx != first->osx || last->sy != first->osy) { + /* Multiple resizes ending up with a different size. */ + window_pane_send_resize(wp, last->sx, last->sy); + TAILQ_FOREACH_SAFE(r, &wp->resize_queue, entry, r1) { + TAILQ_REMOVE(&wp->resize_queue, r, entry); + free(r); + } } else { /* - * The timer is not running, but we need to force a resize. If - * the force timer has expired, resize to the real size now. - * Otherwise resize to the force size and start the timer. + * Multiple resizes ending up with the same size. There will + * not be more than one to the same size in succession so we + * can just use the last-but-one on the list and leave the last + * for later. We reduce the time until the next check to avoid + * a long delay between the resizes. */ - if (wp->flags & PANE_RESIZENOW) { - log_debug("%s: resizing %%%u after forced resize", - __func__, wp->id); - window_pane_send_resize(wp, 0); - wp->flags &= ~(PANE_RESIZE|PANE_RESIZEFORCE|PANE_RESIZENOW); - } else if (!evtimer_pending(&wp->force_timer, NULL)) { - log_debug("%s: forcing resize of %%%u", __func__, - wp->id); - window_pane_send_resize(wp, 1); - server_client_start_force_timer(wp); + r = TAILQ_PREV(last, window_pane_resizes, entry); + window_pane_send_resize(wp, r->sx, r->sy); + TAILQ_FOREACH_SAFE(r, &wp->resize_queue, entry, r1) { + if (r == last) + break; + TAILQ_REMOVE(&wp->resize_queue, r, entry); + free(r); } + tv.tv_usec = 10000; } + evtimer_add(&wp->resize_timer, &tv); } + /* Check pane buffer size. */ static void server_client_check_pane_buffer(struct window_pane *wp) diff --git a/tmux.1 b/tmux.1 index d2ad593f..47cf4f2c 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2953,6 +2953,8 @@ Ctrl keys may be prefixed with .Ql C- or .Ql ^ , +Shift keys with +.Ql S- and Alt (meta) with .Ql M- . In addition, the following special key names are accepted: diff --git a/tmux.h b/tmux.h index 1947009f..508fddd3 100644 --- a/tmux.h +++ b/tmux.h @@ -918,7 +918,7 @@ struct window_mode_entry { struct screen *screen; u_int prefix; - TAILQ_ENTRY (window_mode_entry) entry; + TAILQ_ENTRY(window_mode_entry) entry; }; /* Offsets into pane buffer. */ @@ -926,6 +926,18 @@ struct window_pane_offset { size_t used; }; +/* Queued pane resize. */ +struct window_pane_resize { + u_int sx; + u_int sy; + + u_int osx; + u_int osy; + + TAILQ_ENTRY(window_pane_resize) entry; +}; +TAILQ_HEAD(window_pane_resizes, window_pane_resize); + /* Child window structure. */ struct window_pane { u_int id; @@ -950,8 +962,8 @@ struct window_pane { #define PANE_REDRAW 0x1 #define PANE_DROP 0x2 #define PANE_FOCUSED 0x4 -#define PANE_RESIZE 0x8 -#define PANE_RESIZEFORCE 0x10 +/* 0x8 unused */ +/* 0x10 unused */ #define PANE_FOCUSPUSH 0x20 #define PANE_INPUTOFF 0x40 #define PANE_CHANGED 0x80 @@ -960,7 +972,6 @@ struct window_pane { #define PANE_STATUSDRAWN 0x400 #define PANE_EMPTY 0x800 #define PANE_STYLECHANGED 0x1000 -#define PANE_RESIZENOW 0x2000 int argc; char **argv; @@ -977,8 +988,8 @@ struct window_pane { struct window_pane_offset offset; size_t base_offset; + struct window_pane_resizes resize_queue; struct event resize_timer; - struct event force_timer; struct input_ctx *ictx; @@ -996,7 +1007,7 @@ struct window_pane { struct screen status_screen; size_t status_size; - TAILQ_HEAD (, window_mode_entry) modes; + TAILQ_HEAD(, window_mode_entry) modes; char *searchstr; int searchregex; @@ -2755,7 +2766,7 @@ void window_redraw_active_switch(struct window *, struct window_pane *window_add_pane(struct window *, struct window_pane *, u_int, int); void window_resize(struct window *, u_int, u_int, int, int); -void window_pane_send_resize(struct window_pane *, int); +void window_pane_send_resize(struct window_pane *, u_int, u_int); int window_zoom(struct window_pane *); int window_unzoom(struct window *); int window_push_zoom(struct window *, int, int); diff --git a/window.c b/window.c index 519f91b1..aa448e1f 100644 --- a/window.c +++ b/window.c @@ -427,25 +427,18 @@ window_resize(struct window *w, u_int sx, u_int sy, int xpixel, int ypixel) } void -window_pane_send_resize(struct window_pane *wp, int force) +window_pane_send_resize(struct window_pane *wp, u_int sx, u_int sy) { struct window *w = wp->window; struct winsize ws; - u_int sy; if (wp->fd == -1) return; - if (!force) - sy = wp->sy; - else if (wp->sy <= 1) - sy = wp->sy + 1; - else - sy = wp->sy - 1; - log_debug("%s: %%%u resize to %u,%u", __func__, wp->id, wp->sx, sy); + log_debug("%s: %%%u resize to %u,%u", __func__, wp->id, sx, sy); memset(&ws, 0, sizeof ws); - ws.ws_col = wp->sx; + ws.ws_col = sx; ws.ws_row = sy; ws.ws_xpixel = w->xpixel * ws.ws_col; ws.ws_ypixel = w->ypixel * ws.ws_row; @@ -860,29 +853,19 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) wp->id = next_window_pane_id++; RB_INSERT(window_pane_tree, &all_window_panes, wp); - wp->argc = 0; - wp->argv = NULL; - wp->shell = NULL; - wp->cwd = NULL; - wp->fd = -1; - wp->event = NULL; wp->fg = 8; wp->bg = 8; TAILQ_INIT(&wp->modes); - wp->layout_cell = NULL; - - wp->xoff = 0; - wp->yoff = 0; + TAILQ_INIT (&wp->resize_queue); wp->sx = sx; wp->sy = sy; wp->pipe_fd = -1; - wp->pipe_event = NULL; screen_init(&wp->base, sx, sy, hlimit); wp->screen = &wp->base; @@ -898,6 +881,9 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) static void window_pane_destroy(struct window_pane *wp) { + struct window_pane_resize *r; + struct window_pane_resize *r1; + window_pane_reset_mode_all(wp); free(wp->searchstr); @@ -919,8 +905,10 @@ window_pane_destroy(struct window_pane *wp) if (event_initialized(&wp->resize_timer)) event_del(&wp->resize_timer); - if (event_initialized(&wp->force_timer)) - event_del(&wp->force_timer); + TAILQ_FOREACH_SAFE(r, &wp->resize_queue, entry, r1) { + TAILQ_REMOVE(&wp->resize_queue, r, entry); + free(r); + } RB_REMOVE(window_pane_tree, &all_window_panes, wp); @@ -989,9 +977,18 @@ void window_pane_resize(struct window_pane *wp, u_int sx, u_int sy) { struct window_mode_entry *wme; + struct window_pane_resize *r; if (sx == wp->sx && sy == wp->sy) return; + + r = xmalloc (sizeof *r); + r->sx = sx; + r->sy = sy; + r->osx = wp->sx; + r->osy = wp->sy; + TAILQ_INSERT_TAIL (&wp->resize_queue, r, entry); + wp->sx = sx; wp->sy = sy; @@ -1001,14 +998,6 @@ window_pane_resize(struct window_pane *wp, u_int sx, u_int sy) wme = TAILQ_FIRST(&wp->modes); if (wme != NULL && wme->mode->resize != NULL) wme->mode->resize(wme, sx, sy); - - /* - * If the pane has already been resized, set the force flag and make - * the application resize twice to force it to redraw. - */ - if (wp->flags & PANE_RESIZE) - wp->flags |= PANE_RESIZEFORCE; - wp->flags |= PANE_RESIZE; } void -- cgit From f9f97c8145e97b0295f0792a643286126fe2d3f8 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Jun 2021 07:36:47 +0000 Subject: 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. GitHub issue 2682. --- screen.c | 32 +++++++++++++++-- tmux.h | 14 ++++++-- tty.c | 117 +++++++++++++++++++++++++++++++++++++++++++-------------------- 3 files changed, 120 insertions(+), 43 deletions(-) diff --git a/screen.c b/screen.c index 0b1047ab..2d770abb 100644 --- a/screen.c +++ b/screen.c @@ -81,7 +81,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; @@ -156,9 +156,35 @@ screen_reset_tabs(struct screen *s) void screen_set_cursor_style(struct screen *s, u_int style) { - if (style <= 6) { - s->cstyle = style; + 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; } } diff --git a/tmux.h b/tmux.h index 508fddd3..96d829fb 100644 --- a/tmux.h +++ b/tmux.h @@ -794,6 +794,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; @@ -807,8 +815,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 */ @@ -1296,7 +1304,7 @@ struct tty { u_int cx; u_int cy; - u_int cstyle; + enum screen_cursor_style cstyle; char *ccolour; int oflag; diff --git a/tty.c b/tty.c index e8a8cbaa..367f54d5 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,11 +657,9 @@ 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; @@ -670,38 +668,83 @@ tty_update_mode(struct tty *tty, int mode, struct screen *s) 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 (s != NULL) { + if (strcmp(s->ccolour, tty->ccolour) != 0) + tty_force_cursor_colour(tty, s->ccolour); + cstyle = s->cstyle; } - - /* - * 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 (~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) && -- cgit From f02a6c34e0e8bf2c50ee1dfe9cfacf54370a1405 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Jun 2021 07:38:28 +0000 Subject: Move "special" keys into the Unicode PUA rather than making them top bit set, some compilers do not allow enums that are larger than int. GitHub issue 2673. --- input-keys.c | 2 +- key-string.c | 6 +++--- status.c | 2 +- tmux.h | 33 ++++++++++++++++++++++++--------- 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/input-keys.c b/input-keys.c index ab7d2212..b975c1ed 100644 --- a/input-keys.c +++ b/input-keys.c @@ -477,7 +477,7 @@ input_key(struct screen *s, struct bufferevent *bev, key_code key) input_key_write(__func__, bev, &ud.data[0], 1); return (0); } - if (justkey > 0x7f && justkey < KEYC_BASE) { + if (KEYC_IS_UNICODE(justkey)) { if (key & KEYC_META) input_key_write(__func__, bev, "\033", 1); utf8_to_data(justkey, &ud); diff --git a/key-string.c b/key-string.c index c24a33fc..406d26dd 100644 --- a/key-string.c +++ b/key-string.c @@ -238,7 +238,7 @@ key_string_lookup_string(const char *string) } /* Convert the standard control keys. */ - if (key < KEYC_BASE && + if (key <= 127 && (modifiers & KEYC_CTRL) && strchr(other, key) == NULL && key != 9 && @@ -368,8 +368,8 @@ key_string_lookup_key(key_code key, int with_flags) goto out; } - /* Is this a UTF-8 key? */ - if (key > 127 && key < KEYC_BASE) { + /* Is this a Unicode key? */ + if (KEYC_IS_UNICODE(key)) { utf8_to_data(key, &ud); off = strlen(out); memcpy(out + off, ud.data, ud.size); diff --git a/status.c b/status.c index 271e1afa..f4418500 100644 --- a/status.c +++ b/status.c @@ -1300,7 +1300,7 @@ process_key: return (0); append_key: - if (key <= 0x1f || key >= KEYC_BASE) + if (key <= 0x1f || (key >= KEYC_BASE && key < KEYC_BASE_END)) return (0); if (key <= 0x7f) utf8_set(&tmp, key); diff --git a/tmux.h b/tmux.h index 96d829fb..02dcdad0 100644 --- a/tmux.h +++ b/tmux.h @@ -108,11 +108,16 @@ struct winlink; #define VISUAL_ON 1 #define VISUAL_BOTH 2 -/* Special key codes. */ -#define KEYC_NONE 0x00ff000000000ULL -#define KEYC_UNKNOWN 0x00fe000000000ULL -#define KEYC_BASE 0x0001000000000ULL -#define KEYC_USER 0x0002000000000ULL +/* No key or unknown key. */ +#define KEYC_NONE 0x000ff000000000ULL +#define KEYC_UNKNOWN 0x000fe000000000ULL + +/* + * Base for special (that is, not Unicode) keys. An enum must be at most a + * signed int, so these are based in the highest Unicode PUA. + */ +#define KEYC_BASE 0x0000000010e000ULL +#define KEYC_USER 0x0000000010f000ULL /* Key modifier bits. */ #define KEYC_META 0x00100000000000ULL @@ -135,8 +140,15 @@ struct winlink; #define KEYC_NUSER 1000 /* Is this a mouse key? */ -#define KEYC_IS_MOUSE(key) (((key) & KEYC_MASK_KEY) >= KEYC_MOUSE && \ - ((key) & KEYC_MASK_KEY) < KEYC_BSPACE) +#define KEYC_IS_MOUSE(key) \ + (((key) & KEYC_MASK_KEY) >= KEYC_MOUSE && \ + ((key) & KEYC_MASK_KEY) < KEYC_BSPACE) + +/* Is this a Unicode key? */ +#define KEYC_IS_UNICODE(key) \ + (((key) & KEYC_MASK_KEY) > 0x7f && \ + (((key) & KEYC_MASK_KEY) < KEYC_BASE || \ + ((key) & KEYC_MASK_KEY) >= KEYC_BASE_END)) /* Multiple click timeout. */ #define KEYC_CLICK_TIMEOUT 300 @@ -158,8 +170,8 @@ struct winlink; { #s "Border", KEYC_ ## name ## _BORDER } /* - * A single key. This can be ASCII or Unicode or one of the keys starting at - * KEYC_BASE. + * A single key. This can be ASCII or Unicode or one of the keys between + * KEYC_BASE and KEYC_BASE_END. */ typedef unsigned long long key_code; @@ -252,6 +264,9 @@ enum { KEYC_KP_ENTER, KEYC_KP_ZERO, KEYC_KP_PERIOD, + + /* End of special keys. */ + KEYC_BASE_END }; /* Termcap codes. */ -- cgit From 02a6b39db73e55f9f30d46106c378ed4c70cb02b Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Jun 2021 07:43:44 +0000 Subject: Improve logging of screen mode changes. --- screen-write.c | 6 ++++++ screen.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++-- server-client.c | 5 ++++- tmux.h | 1 + tty.c | 8 ++++++-- 5 files changed, 67 insertions(+), 5 deletions(-) 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 2d770abb..e7ee1df9 100644 --- a/screen.c +++ b/screen.c @@ -156,8 +156,8 @@ screen_reset_tabs(struct screen *s) void screen_set_cursor_style(struct screen *s, u_int style) { - switch (style) - { + log_debug("%s: new %u, was %u", __func__, style, s->cstyle); + switch (style) { case 0: s->cstyle = SCREEN_CURSOR_DEFAULT; break; @@ -653,3 +653,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 9bd2ad19..27b264a0 100644 --- a/server-client.c +++ b/server-client.c @@ -1694,7 +1694,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/tmux.h b/tmux.h index 02dcdad0..fbe19136 100644 --- a/tmux.h +++ b/tmux.h @@ -2749,6 +2749,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 367f54d5..45868fc1 100644 --- a/tty.c +++ b/tty.c @@ -665,8 +665,12 @@ tty_update_mode(struct tty *tty, int mode, struct screen *s) mode &= ~MODE_CURSOR; changed = mode ^ tty->mode; - if (changed != 0) - log_debug("%s: update mode %x to %x", c->name, tty->mode, mode); + 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)); + } if (s != NULL) { if (strcmp(s->ccolour, tty->ccolour) != 0) -- cgit From 6c659494f5591ebba2ef91e6cfa6a24761c14915 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Jun 2021 07:45:43 +0000 Subject: Fix warnings, from Jan Tache in GitHub issue 2692. --- format.c | 2 +- server.c | 3 ++- tty-term.c | 2 +- window-buffer.c | 6 +++--- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/format.c b/format.c index 3a1385b2..03c01dc4 100644 --- a/format.c +++ b/format.c @@ -4199,7 +4199,7 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen, value = xstrdup("0"); } else { format_log(es, "search '%s' pane %%%u", new, wp->id); - value = format_search(fm, wp, new); + value = format_search(search, wp, new); } free(new); } else if (cmp != NULL) { diff --git a/server.c b/server.c index 6ac08a4d..eb6e9610 100644 --- a/server.c +++ b/server.c @@ -161,7 +161,8 @@ server_tidy_event(__unused int fd, __unused short events, __unused void *data) format_tidy_jobs(); - log_debug("%s: took %llu milliseconds", __func__, get_timer() - t); + log_debug("%s: took %llu milliseconds", __func__, + (unsigned long long)(get_timer() - t)); evtimer_add(&server_ev_tidy, &tv); } diff --git a/tty-term.c b/tty-term.c index 275efe2f..ae103fd7 100644 --- a/tty-term.c +++ b/tty-term.c @@ -688,7 +688,7 @@ tty_term_read_list(const char *name, int fd, char ***caps, u_int *ncaps, ent = &tty_term_codes[i]; switch (ent->type) { case TTYCODE_NONE: - break; + continue; case TTYCODE_STRING: s = tigetstr((char *)ent->name); if (s == NULL || s == (char *)-1) diff --git a/window-buffer.c b/window-buffer.c index 5e4dd699..30bd5092 100644 --- a/window-buffer.c +++ b/window-buffer.c @@ -294,9 +294,9 @@ window_buffer_get_key(void *modedata, void *itemdata, u_int line) struct window_buffer_modedata *data = modedata; struct window_buffer_itemdata *item = itemdata; struct format_tree *ft; - struct session *s; - struct winlink *wl; - struct window_pane *wp; + struct session *s = NULL; + struct winlink *wl = NULL; + struct window_pane *wp = NULL; struct paste_buffer *pb; char *expanded; key_code key; -- cgit From 866117636e47c9a5d961df2ac40456b7c910a932 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 10 Jun 2021 07:50:03 +0000 Subject: Add different command historys for different types of prompts ("command", "search" etc). From Anindya Mukherjee. --- Makefile | 1 + cmd-command-prompt.c | 39 ++++++---- cmd-confirm-before.c | 2 +- cmd-show-prompt-history.c | 108 +++++++++++++++++++++++++++ cmd.c | 4 + key-bindings.c | 12 +-- mode-tree.c | 4 +- options-table.c | 9 +++ status.c | 186 +++++++++++++++++++++++++++++++++------------- tmux.1 | 47 ++++++++++-- tmux.h | 22 ++++-- window-customize.c | 14 ++-- window-tree.c | 6 +- 13 files changed, 357 insertions(+), 97 deletions(-) create mode 100644 cmd-show-prompt-history.c diff --git a/Makefile b/Makefile index 21141317..4cbbd34a 100644 --- a/Makefile +++ b/Makefile @@ -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 \ diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index c82235c5..c2a2dec7 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 = { "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); 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 + * + * 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 + +/* + * 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 6b443fa2..90fa221a 100644 --- a/cmd.c +++ b/cmd.c @@ -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, diff --git a/key-bindings.c b/key-bindings.c index 467c7f93..b380f2cd 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -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-promp