From 8edece2cdb7b4425526bae904506a246edbb6409 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 28 Oct 2022 13:00:02 +0000 Subject: [PATCH 1/7] Add paste-buffer-deleted notification and fix name of paste-buffer-changed. --- control-notify.c | 15 ++++++++++++++- input.c | 11 ----------- notify.c | 12 ++++++++++-- paste.c | 12 ++++++------ tmux.1 | 4 ++++ tmux.h | 3 ++- 6 files changed, 36 insertions(+), 21 deletions(-) diff --git a/control-notify.c b/control-notify.c index a252dd05..30f94194 100644 --- a/control-notify.c +++ b/control-notify.c @@ -244,6 +244,19 @@ control_notify_paste_buffer_changed(const char *name) if (!CONTROL_SHOULD_NOTIFY_CLIENT(c)) continue; - control_write(c, "%%paste-changed %s", name); + control_write(c, "%%paste-buffer-changed %s", name); + } +} + +void +control_notify_paste_buffer_deleted(const char *name) +{ + struct client *c; + + TAILQ_FOREACH(c, &clients, entry) { + if (!CONTROL_SHOULD_NOTIFY_CLIENT(c)) + continue; + + control_write(c, "%%paste-buffer-deleted %s", name); } } diff --git a/input.c b/input.c index 8b174769..779b9013 100644 --- a/input.c +++ b/input.c @@ -1755,7 +1755,6 @@ static void input_csi_dispatch_sm_private(struct input_ctx *ictx) { struct screen_write_ctx *sctx = &ictx->ctx; - struct window_pane *wp = ictx->wp; struct grid_cell *gc = &ictx->cell.cell; u_int i; @@ -1797,17 +1796,7 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx) screen_write_mode_set(sctx, MODE_MOUSE_ALL); break; case 1004: - if (sctx->s->mode & MODE_FOCUSON) - break; screen_write_mode_set(sctx, MODE_FOCUSON); - if (wp == NULL) - break; - if (!options_get_number(global_options, "focus-events")) - break; - if (wp->flags & PANE_FOCUSED) - bufferevent_write(wp->event, "\033[I", 3); - else - bufferevent_write(wp->event, "\033[O", 3); break; case 1005: screen_write_mode_set(sctx, MODE_MOUSE_UTF8); diff --git a/notify.c b/notify.c index 03730b98..138fbeb1 100644 --- a/notify.c +++ b/notify.c @@ -153,6 +153,8 @@ notify_callback(struct cmdq_item *item, void *data) control_notify_session_window_changed(ne->session); if (strcmp(ne->name, "paste-buffer-changed") == 0) control_notify_paste_buffer_changed(ne->pbname); + if (strcmp(ne->name, "paste-buffer-deleted") == 0) + control_notify_paste_buffer_deleted(ne->pbname); notify_insert_hook(item, ne); @@ -307,10 +309,16 @@ notify_pane(const char *name, struct window_pane *wp) } void -notify_paste_buffer(const char *pbname) +notify_paste_buffer(const char *pbname, int deleted) { struct cmd_find_state fs; cmd_find_clear_state(&fs, 0); - notify_add("paste-buffer-changed", &fs, NULL, NULL, NULL, NULL, pbname); + if (deleted) { + notify_add("paste-buffer-deleted", &fs, NULL, NULL, NULL, NULL, + pbname); + } else { + notify_add("paste-buffer-changed", &fs, NULL, NULL, NULL, NULL, + pbname); + } } diff --git a/paste.c b/paste.c index 53477387..7565c207 100644 --- a/paste.c +++ b/paste.c @@ -151,7 +151,7 @@ paste_get_name(const char *name) void paste_free(struct paste_buffer *pb) { - notify_paste_buffer(pb->name); + notify_paste_buffer(pb->name, 1); RB_REMOVE(paste_name_tree, &paste_by_name, pb); RB_REMOVE(paste_time_tree, &paste_by_time, pb); @@ -210,7 +210,7 @@ paste_add(const char *prefix, char *data, size_t size) RB_INSERT(paste_name_tree, &paste_by_name, pb); RB_INSERT(paste_time_tree, &paste_by_time, pb); - notify_paste_buffer(pb->name); + notify_paste_buffer(pb->name, 0); } /* Rename a paste buffer. */ @@ -258,8 +258,8 @@ paste_rename(const char *oldname, const char *newname, char **cause) RB_INSERT(paste_name_tree, &paste_by_name, pb); - notify_paste_buffer(oldname); - notify_paste_buffer(newname); + notify_paste_buffer(oldname, 1); + notify_paste_buffer(newname, 0); return (0); } @@ -309,7 +309,7 @@ paste_set(char *data, size_t size, const char *name, char **cause) RB_INSERT(paste_name_tree, &paste_by_name, pb); RB_INSERT(paste_time_tree, &paste_by_time, pb); - notify_paste_buffer(name); + notify_paste_buffer(name, 0); return (0); } @@ -322,7 +322,7 @@ paste_replace(struct paste_buffer *pb, char *data, size_t size) pb->data = data; pb->size = size; - notify_paste_buffer(pb->name); + notify_paste_buffer(pb->name, 0); } /* Convert start of buffer into a nice string. */ diff --git a/tmux.1 b/tmux.1 index 5e896902..dbfc85b1 100644 --- a/tmux.1 +++ b/tmux.1 @@ -6612,6 +6612,10 @@ has changed mode. Paste buffer .Ar name has been changed. +.It Ic %paste-buffer-deleted Ar name +Paste buffer +.Ar name +has been deleted. .It Ic %pause Ar pane-id The pane has been paused (if the .Ar pause-after diff --git a/tmux.h b/tmux.h index 77019edc..a0f9f461 100644 --- a/tmux.h +++ b/tmux.h @@ -2163,7 +2163,7 @@ void notify_winlink(const char *, struct winlink *); void notify_session_window(const char *, struct session *, struct window *); void notify_window(const char *, struct window *); void notify_pane(const char *, struct window_pane *); -void notify_paste_buffer(const char *); +void notify_paste_buffer(const char *, int); /* options.c */ struct options *options_create(struct options *); @@ -3185,6 +3185,7 @@ void control_notify_session_created(struct session *); void control_notify_session_closed(struct session *); void control_notify_session_window_changed(struct session *); void control_notify_paste_buffer_changed(const char *); +void control_notify_paste_buffer_deleted(const char *); /* session.c */ extern struct sessions sessions; From 22910451162c5c1ffe5505ca7c9b1b8cc99ba187 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 1 Nov 2022 09:46:14 +0000 Subject: [PATCH 2/7] Use active pane in target window not current window for +/-. GitHub issue 3370. --- cmd-find.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cmd-find.c b/cmd-find.c index 9f04c4a8..2929bbc9 100644 --- a/cmd-find.c +++ b/cmd-find.c @@ -588,22 +588,22 @@ cmd_find_get_pane_with_window(struct cmd_find_state *fs, const char *pane) return (-1); return (0); } else if (strcmp(pane, "{up-of}") == 0) { - fs->wp = window_pane_find_up(fs->current->wp); + fs->wp = window_pane_find_up(fs->w->active); if (fs->wp == NULL) return (-1); return (0); } else if (strcmp(pane, "{down-of}") == 0) { - fs->wp = window_pane_find_down(fs->current->wp); + fs->wp = window_pane_find_down(fs->w->active); if (fs->wp == NULL) return (-1); return (0); } else if (strcmp(pane, "{left-of}") == 0) { - fs->wp = window_pane_find_left(fs->current->wp); + fs->wp = window_pane_find_left(fs->w->active); if (fs->wp == NULL) return (-1); return (0); } else if (strcmp(pane, "{right-of}") == 0) { - fs->wp = window_pane_find_right(fs->current->wp); + fs->wp = window_pane_find_right(fs->w->active); if (fs->wp == NULL) return (-1); return (0); @@ -615,7 +615,7 @@ cmd_find_get_pane_with_window(struct cmd_find_state *fs, const char *pane) n = strtonum(pane + 1, 1, INT_MAX, NULL); else n = 1; - wp = fs->current->wp; + wp = fs->w->active; if (pane[0] == '+') fs->wp = window_pane_next_by_number(fs->w, wp, n); else From 2d08235987efa1e2f9c932c4a5c8a0200b4804c1 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 1 Nov 2022 09:54:13 +0000 Subject: [PATCH 3/7] Add modified Tab key sequences, from Aaron Jensen, GitHub issue 3368. --- input-keys.c | 18 ++++++++++++++++++ key-string.c | 2 ++ tmux.h | 1 + tty-keys.c | 5 ++++- 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/input-keys.c b/input-keys.c index 038003df..5c4d3e1b 100644 --- a/input-keys.c +++ b/input-keys.c @@ -307,6 +307,20 @@ static struct input_key_entry input_key_defaults[] = { }, { .key = KEYC_DC|KEYC_BUILD_MODIFIERS, .data = "\033[3;_~" + }, + + /* Tab and modifiers. */ + { .key = '\011'|KEYC_CTRL, + .data = "\011" + }, + { .key = '\011'|KEYC_CTRL|KEYC_EXTENDED, + .data = "\033[9;5u" + }, + { .key = '\011'|KEYC_CTRL|KEYC_SHIFT, + .data = "\011" + }, + { .key = '\011'|KEYC_CTRL|KEYC_SHIFT|KEYC_EXTENDED, + .data = "\033[1;5Z" } }; static const key_code input_key_modifiers[] = { @@ -469,6 +483,8 @@ input_key(struct screen *s, struct bufferevent *bev, key_code key) key &= ~KEYC_KEYPAD; if (~s->mode & MODE_KCURSOR) key &= ~KEYC_CURSOR; + if (~s->mode & MODE_KEXTENDED) + key &= ~KEYC_EXTENDED; ike = input_key_get(key); if (ike == NULL && (key & KEYC_META) && (~key & KEYC_IMPLIED_META)) ike = input_key_get(key & ~KEYC_META); @@ -476,6 +492,8 @@ input_key(struct screen *s, struct bufferevent *bev, key_code key) ike = input_key_get(key & ~KEYC_CURSOR); if (ike == NULL && (key & KEYC_KEYPAD)) ike = input_key_get(key & ~KEYC_KEYPAD); + if (ike == NULL && (key & KEYC_EXTENDED)) + ike = input_key_get(key & ~KEYC_EXTENDED); if (ike != NULL) { log_debug("found key 0x%llx: \"%s\"", key, ike->data); if ((key & KEYC_META) && (~key & KEYC_IMPLIED_META)) diff --git a/key-string.c b/key-string.c index 0ca91306..086c3ac4 100644 --- a/key-string.c +++ b/key-string.c @@ -460,6 +460,8 @@ out: strlcat(out, "I", sizeof out); if (saved & KEYC_BUILD_MODIFIERS) strlcat(out, "B", sizeof out); + if (saved & KEYC_EXTENDED) + strlcat(out, "E", sizeof out); strlcat(out, "]", sizeof out); } return (out); diff --git a/tmux.h b/tmux.h index a0f9f461..6cb6cc96 100644 --- a/tmux.h +++ b/tmux.h @@ -137,6 +137,7 @@ struct winlink; #define KEYC_IMPLIED_META 0x08000000000000ULL #define KEYC_BUILD_MODIFIERS 0x10000000000000ULL #define KEYC_VI 0x20000000000000ULL +#define KEYC_EXTENDED 0x40000000000000ULL /* Masks for key bits. */ #define KEYC_MASK_MODIFIERS 0x00f00000000000ULL diff --git a/tty-keys.c b/tty-keys.c index bb9ec231..db82754f 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -208,6 +208,9 @@ static const struct tty_default_key_raw tty_default_raw_keys[] = { /* Paste keys. */ { "\033[200~", KEYC_PASTE_START }, { "\033[201~", KEYC_PASTE_END }, + + /* Extended keys. */ + { "\033[1;5Z", '\011'|KEYC_CTRL|KEYC_SHIFT|KEYC_EXTENDED }, }; /* Default xterm keys. */ @@ -974,7 +977,7 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len, log_debug("%s: extended key %.*s is %llx (%s)", c->name, (int)*size, buf, nkey, key_string_lookup_key(nkey, 1)); } - *key = nkey; + *key = nkey|KEYC_EXTENDED; return (0); } From 9614f5156079773b338a13e95ec932cc7c95b031 Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 2 Nov 2022 07:36:07 +0000 Subject: [PATCH 4/7] Instead of always setting the extended flag, set it only when searching. Allows send-keys to work. From Aaron Jensen. --- input-keys.c | 9 +++++---- tty-keys.c | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/input-keys.c b/input-keys.c index 5c4d3e1b..d48d7d09 100644 --- a/input-keys.c +++ b/input-keys.c @@ -431,7 +431,7 @@ input_key_write(const char *from, struct bufferevent *bev, const char *data, int input_key(struct screen *s, struct bufferevent *bev, key_code key) { - struct input_key_entry *ike; + struct input_key_entry *ike = NULL; key_code justkey, newkey, outkey, modifiers; struct utf8_data ud; char tmp[64], modifier; @@ -483,9 +483,10 @@ input_key(struct screen *s, struct bufferevent *bev, key_code key) key &= ~KEYC_KEYPAD; if (~s->mode & MODE_KCURSOR) key &= ~KEYC_CURSOR; - if (~s->mode & MODE_KEXTENDED) - key &= ~KEYC_EXTENDED; - ike = input_key_get(key); + if (s->mode & MODE_KEXTENDED) + ike = input_key_get(key|KEYC_EXTENDED); + if (ike == NULL) + ike = input_key_get(key); if (ike == NULL && (key & KEYC_META) && (~key & KEYC_IMPLIED_META)) ike = input_key_get(key & ~KEYC_META); if (ike == NULL && (key & KEYC_CURSOR)) diff --git a/tty-keys.c b/tty-keys.c index db82754f..cb8efd49 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -210,7 +210,7 @@ static const struct tty_default_key_raw tty_default_raw_keys[] = { { "\033[201~", KEYC_PASTE_END }, /* Extended keys. */ - { "\033[1;5Z", '\011'|KEYC_CTRL|KEYC_SHIFT|KEYC_EXTENDED }, + { "\033[1;5Z", '\011'|KEYC_CTRL|KEYC_SHIFT }, }; /* Default xterm keys. */ @@ -977,7 +977,7 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len, log_debug("%s: extended key %.*s is %llx (%s)", c->name, (int)*size, buf, nkey, key_string_lookup_key(nkey, 1)); } - *key = nkey|KEYC_EXTENDED; + *key = nkey; return (0); } From 3be369522b6de38ba08ee50a86a49a9a86af490b Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 3 Nov 2022 08:33:57 +0000 Subject: [PATCH 5/7] Add a -l flag to display-message to disable format expansion, from Aaron Jensen. GitHub issue 3372. --- cmd-display-message.c | 10 +++++++--- tmux.1 | 9 +++++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/cmd-display-message.c b/cmd-display-message.c index 7828f694..f5e91020 100644 --- a/cmd-display-message.c +++ b/cmd-display-message.c @@ -39,8 +39,8 @@ const struct cmd_entry cmd_display_message_entry = { .name = "display-message", .alias = "display", - .args = { "ac:d:INpt:F:v", 0, 1, NULL }, - .usage = "[-aINpv] [-c target-client] [-d delay] [-F format] " + .args = { "ac:d:lINpt:F:v", 0, 1, NULL }, + .usage = "[-aIlNpv] [-c target-client] [-d delay] [-F format] " CMD_TARGET_PANE_USAGE " [message]", .target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL }, @@ -132,7 +132,11 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item) return (CMD_RETURN_NORMAL); } - msg = format_expand_time(ft, template); + if (args_has(args, 'l')) + msg = xstrdup(template); + else + msg = format_expand_time(ft, template); + if (cmdq_get_client(item) == NULL) cmdq_error(item, "%s", msg); else if (args_has(args, 'p')) diff --git a/tmux.1 b/tmux.1 index dbfc85b1..36faf683 100644 --- a/tmux.1 +++ b/tmux.1 @@ -5887,7 +5887,7 @@ The following keys are also available: .El .Tg display .It Xo Ic display-message -.Op Fl aINpv +.Op Fl aIlNpv .Op Fl c Ar target-client .Op Fl d Ar delay .Op Fl t Ar target-pane @@ -5909,7 +5909,12 @@ is not given, the option is used; a delay of zero waits for a key press. .Ql N ignores key presses and closes only after the delay expires. -The format of +If +.Fl l +is given, +.Ar message +is printed unchanged. +Otherwise, the format of .Ar message is described in the .Sx FORMATS From 17290b912116c4397620526d43dcf6ddcf0044b7 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 3 Nov 2022 08:41:53 +0000 Subject: [PATCH 6/7] If there are no buffers, reset mode as soon as any key pressed. Fixes crash reported by Gaoyang Zhang in GitHub issue 3373. --- window-buffer.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/window-buffer.c b/window-buffer.c index 544a1155..aac0bc40 100644 --- a/window-buffer.c +++ b/window-buffer.c @@ -508,6 +508,11 @@ window_buffer_key(struct window_mode_entry *wme, struct client *c, struct window_buffer_itemdata *item; int finished; + if (paste_get_top(NULL) == NULL) { + finished = 1; + goto out; + } + finished = mode_tree_key(mtd, c, &key, m, NULL, NULL); switch (key) { case 'e': @@ -534,6 +539,8 @@ window_buffer_key(struct window_mode_entry *wme, struct client *c, finished = 1; break; } + +out: if (finished || paste_get_top(NULL) == NULL) window_pane_reset_mode(wp); else { From 77c135349aaaa026c3fbb24d291877ce926d682e Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 4 Nov 2022 08:03:23 +0000 Subject: [PATCH 7/7] Unescape the string for the literal operator (l:) so special characters work. --- format.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/format.c b/format.c index 535af061..5b08a7a4 100644 --- a/format.c +++ b/format.c @@ -3575,7 +3575,32 @@ found: return (found); } -/* Remove escaped characters from string. */ +/* Unescape escaped characters. */ +static char * +format_unescape(const char *s) +{ + char *out, *cp; + int brackets = 0; + + cp = out = xmalloc(strlen(s) + 1); + for (; *s != '\0'; s++) { + if (*s == '#' && s[1] == '{') + brackets++; + if (brackets == 0 && + *s == '#' && + strchr(",#{}:", s[1]) != NULL) { + *cp++ = *++s; + continue; + } + if (*s == '}') + brackets--; + *cp++ = *s; + } + *cp = '\0'; + return (out); +} + +/* Remove escaped characters. */ static char * format_strip(const char *s) { @@ -4338,7 +4363,8 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen, /* Is this a literal string? */ if (modifiers & FORMAT_LITERAL) { - value = xstrdup(copy); + format_log(es, "literal string is '%s'", copy); + value = format_unescape(copy); goto done; }