From 0057905ca096f6ced6fd309dd5d494ccdfccdc18 Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 20 May 2026 10:56:46 +0000 Subject: [PATCH 1/4] Increase escape delay if the buffer contains a partial paste end, fixes issues with at least Windows Terminal. From jing dot empty at gmail.com GitHub issue 5088. --- tmux.h | 1 + tty-keys.c | 23 ++++++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/tmux.h b/tmux.h index 8895fef3..1fa7cb71 100644 --- a/tmux.h +++ b/tmux.h @@ -1661,6 +1661,7 @@ struct tty { #define TTY_WINSIZEQUERY 0x1000 #define TTY_WAITFG 0x2000 #define TTY_WAITBG 0x4000 +#define TTY_BRACKETPASTE 0x8000 #define TTY_ALL_REQUEST_FLAGS \ (TTY_HAVEDA|TTY_HAVEDA2|TTY_HAVEXDA) int flags; diff --git a/tty-keys.c b/tty-keys.c index 1336188d..d3a93f10 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -605,6 +605,17 @@ tty_keys_find1(struct tty_key *tk, const char *buf, size_t len, size_t *size) return (tty_keys_find1(tk, buf, len, size)); } +static int +tty_keys_partial_paste_end(const char *buf, size_t len) +{ + static const char paste_end[] = "\033[201~"; + size_t paste_end_len = (sizeof paste_end) - 1; + + if (len == 0 || len >= paste_end_len) + return (0); + return (memcmp(buf, paste_end, len) == 0); +} + /* Look up part of the next key. */ static int tty_keys_next1(struct tty *tty, const char *buf, size_t len, key_code *key, @@ -630,6 +641,10 @@ tty_keys_next1(struct tty *tty, const char *buf, size_t len, key_code *key, if (tk->next != NULL && !expired) return (1); *key = tk->key; + if ((*key & KEYC_MASK_KEY) == KEYC_PASTE_START) + tty->flags |= TTY_BRACKETPASTE; + else if ((*key & KEYC_MASK_KEY) == KEYC_PASTE_END) + tty->flags &= ~TTY_BRACKETPASTE; return (0); } @@ -955,10 +970,16 @@ partial_key: delay = options_get_number(global_options, "escape-time"); if (delay == 0) delay = 1; + if ((tty->flags & TTY_BRACKETPASTE) && + tty_keys_partial_paste_end(buf, len)) { + log_debug("%s: increasing delay (partial paste end)", c->name); + if (delay < 500) + delay = 500; + } if ((tty->flags & (TTY_WAITFG|TTY_WAITBG) || (tty->flags & TTY_ALL_REQUEST_FLAGS) != TTY_ALL_REQUEST_FLAGS) || !TAILQ_EMPTY(&c->input_requests)) { - log_debug("%s: increasing delay for active query", c->name); + log_debug("%s: increasing delay (active query)", c->name); if (delay < 500) delay = 500; } From e1f942f26a293d1c3f38150e6edf643ccc09a031 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 9 Dec 2025 08:46:00 +0000 Subject: [PATCH 2/4] Add a define for max images and bump to 20 for the moment. --- image.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/image.c b/image.c index 43808785..6e2b1701 100644 --- a/image.c +++ b/image.c @@ -25,6 +25,7 @@ static struct images all_images = TAILQ_HEAD_INITIALIZER(all_images); static u_int all_images_count; +#define MAX_IMAGE_COUNT 20 static void image_free(struct image *im) @@ -111,7 +112,7 @@ image_store(struct screen *s, struct sixel_image *si) TAILQ_INSERT_TAIL(&s->images, im, entry); TAILQ_INSERT_TAIL(&all_images, im, all_entry); - if (++all_images_count == 10/*XXX*/) + if (++all_images_count == MAX_IMAGE_COUNT) image_free(TAILQ_FIRST(&all_images)); return (im); From b8434182c9ead062be8d50a1ff88e98b41108c1f Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 27 Apr 2026 13:09:07 +0100 Subject: [PATCH 3/4] Track which list (images or saved_images) each image is on so they can be removed from the correct list when the total image count is reached. Fixes crash reported by xlabai at tencent dot com. --- image.c | 5 +++-- screen.c | 14 ++++++++++++-- tmux.h | 4 +++- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/image.c b/image.c index 6e2b1701..a64fc044 100644 --- a/image.c +++ b/image.c @@ -35,7 +35,7 @@ image_free(struct image *im) TAILQ_REMOVE(&all_images, im, all_entry); all_images_count--; - TAILQ_REMOVE(&s->images, im, entry); + TAILQ_REMOVE(im->list, im, entry); sixel_free(im->data); free(im->fallback); free(im); @@ -109,7 +109,8 @@ image_store(struct screen *s, struct sixel_image *si) image_fallback(&im->fallback, im->sx, im->sy); - TAILQ_INSERT_TAIL(&s->images, im, entry); + im->list = &s->images; + TAILQ_INSERT_TAIL(im->list, im, entry); TAILQ_INSERT_TAIL(&all_images, im, all_entry); if (++all_images_count == MAX_IMAGE_COUNT) diff --git a/screen.c b/screen.c index d82784c5..ba3e7c87 100644 --- a/screen.c +++ b/screen.c @@ -633,7 +633,10 @@ screen_reflow(struct screen *s, u_int new_x, u_int *cx, u_int *cy, int cursor) void screen_alternate_on(struct screen *s, struct grid_cell *gc, int cursor) { - u_int sx, sy; + u_int sx, sy; +#ifdef ENABLE_SIXEL + struct image *im; +#endif if (SCREEN_IS_ALTERNATE(s)) return; @@ -650,6 +653,8 @@ screen_alternate_on(struct screen *s, struct grid_cell *gc, int cursor) #ifdef ENABLE_SIXEL TAILQ_CONCAT(&s->saved_images, &s->images, entry); + TAILQ_FOREACH(im, &s->saved_images, entry) + im->list = &s->saved_images; #endif grid_view_clear(s->grid, 0, 0, sx, sy, 8); @@ -662,7 +667,10 @@ screen_alternate_on(struct screen *s, struct grid_cell *gc, int cursor) void screen_alternate_off(struct screen *s, struct grid_cell *gc, int cursor) { - u_int sx = screen_size_x(s), sy = screen_size_y(s); + u_int sx = screen_size_x(s), sy = screen_size_y(s); +#ifdef ENABLE_SIXEL + struct image *im; +#endif /* * If the current size is different, temporarily resize to the old size @@ -709,6 +717,8 @@ screen_alternate_off(struct screen *s, struct grid_cell *gc, int cursor) #ifdef ENABLE_SIXEL image_free_all(s); TAILQ_CONCAT(&s->images, &s->saved_images, entry); + TAILQ_FOREACH(im, &s->images, entry) + im->list = &s->images; #endif if (s->cx > screen_size_x(s) - 1) diff --git a/tmux.h b/tmux.h index dd62382e..1927fa95 100644 --- a/tmux.h +++ b/tmux.h @@ -936,8 +936,10 @@ struct image { u_int sx; u_int sy; - TAILQ_ENTRY (image) all_entry; + struct images *list; TAILQ_ENTRY (image) entry; + + TAILQ_ENTRY (image) all_entry; }; TAILQ_HEAD(images, image); #endif From c5fb5e8bb026b42a7ba0caa118b3d8ea8a0b54e0 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 20 May 2026 12:17:30 +0100 Subject: [PATCH 4/4] Update CHANGES. --- CHANGES | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGES b/CHANGES index bcd1e1c6..cf125fd9 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,8 @@ +CHANGES FROM 3.6a TO 3.6b + +* Remove images from the correct list when they are removed while in the + alternate screen (reported by xlabai at tencent dot com). + CHANGES FROM 3.6 TO 3.6a * Fix a buffer overread and an infinite loop in format processing (reported by