From 645bf8b3ab9606bff1d94842ea14556c9f1d620a Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 21 Jun 2023 06:28:18 +0000 Subject: [PATCH 01/19] Check fdopen return value, from Christian Menges. --- popup.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/popup.c b/popup.c index 2195adf5..9ab8490f 100644 --- a/popup.c +++ b/popup.c @@ -788,6 +788,8 @@ popup_editor(struct client *c, const char *buf, size_t len, if (fd == -1) return (-1); f = fdopen(fd, "w"); + if (f == NULL) + return (-1); if (fwrite(buf, len, 1, f) != 1) { fclose(f); return (-1); From 9e14c1f88de6bf812e0eaae0c05b782702e687f1 Mon Sep 17 00:00:00 2001 From: nicm Date: Sun, 25 Jun 2023 15:53:07 +0000 Subject: [PATCH 02/19] SGR 0 should not end hyperlink, reported by Lucas Trzesniewski. --- input.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/input.c b/input.c index 5a14104b..b2d28386 100644 --- a/input.c +++ b/input.c @@ -2065,7 +2065,7 @@ static void input_csi_dispatch_sgr(struct input_ctx *ictx) { struct grid_cell *gc = &ictx->cell.cell; - u_int i; + u_int i, link; int n; if (ictx->param_list_len == 0) { @@ -2097,7 +2097,9 @@ input_csi_dispatch_sgr(struct input_ctx *ictx) switch (n) { case 0: + link = gc->link; memcpy(gc, &grid_default_cell, sizeof *gc); + gc->link = link; break; case 1: gc->attr |= GRID_ATTR_BRIGHT; From ff8882a24f44594c871ad849f885bcd895836e73 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 26 Jun 2023 07:17:40 +0000 Subject: [PATCH 03/19] Add "us" to styles for underscore colour, GitHub issue 3589. --- style.c | 15 +++++++++++++++ tmux.1 | 2 ++ tty.c | 13 ++++++++++--- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/style.c b/style.c index 8407dc68..3d9d317d 100644 --- a/style.c +++ b/style.c @@ -77,6 +77,7 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in) if (strcasecmp(tmp, "default") == 0) { sy->gc.fg = base->fg; sy->gc.bg = base->bg; + sy->gc.us = base->us; sy->gc.attr = base->attr; sy->gc.flags = base->flags; } else if (strcasecmp(tmp, "ignore") == 0) @@ -162,6 +163,13 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in) sy->gc.bg = base->bg; } else goto error; + } else if (end > 3 && strncasecmp(tmp, "us=", 3) == 0) { + if ((value = colour_fromstring(tmp + 3)) == -1) + goto error; + if (value != 8) + sy->gc.us = value; + else + sy->gc.us = base->us; } else if (strcasecmp(tmp, "none") == 0) sy->gc.attr = 0; else if (end > 2 && strncasecmp(tmp, "no", 2) == 0) { @@ -258,6 +266,11 @@ style_tostring(struct style *sy) colour_tostring(gc->bg)); comma = ","; } + if (gc->us != 8) { + off += xsnprintf(s + off, sizeof s - off, "%sus=%s", comma, + colour_tostring(gc->us)); + comma = ","; + } if (gc->attr != 0) { xsnprintf(s + off, sizeof s - off, "%s%s", comma, attributes_tostring(gc->attr)); @@ -287,6 +300,8 @@ style_add(struct grid_cell *gc, struct options *oo, const char *name, gc->fg = sy->gc.fg; if (sy->gc.bg != 8) gc->bg = sy->gc.bg; + if (sy->gc.us != 8) + gc->us = sy->gc.us; gc->attr |= sy->gc.attr; if (ft0 != NULL) diff --git a/tmux.1 b/tmux.1 index 4881b820..8b76bbac 100644 --- a/tmux.1 +++ b/tmux.1 @@ -5384,6 +5384,8 @@ for the terminal default colour; or a hexadecimal RGB string such as .Ql #ffffff . .It Ic bg=colour Set the background colour. +.It Ic us=colour +Set the underscore colour. .It Ic none Set no attributes (turn off any active attributes). .It Xo Ic acs , diff --git a/tty.c b/tty.c index 225d0058..e34b186a 100644 --- a/tty.c +++ b/tty.c @@ -483,6 +483,12 @@ tty_update_features(struct tty *tty) if (tty->term->flags & TERM_VT100LIKE) tty_puts(tty, "\033[?7727h"); + /* + * Features might have changed since the first draw during attach. For + * example, this happens when DA responses are received. + */ + server_redraw_client(c); + tty_invalidate(tty); } @@ -2808,9 +2814,10 @@ tty_check_us(__unused struct tty *tty, struct colour_palette *palette, gc->us = c; } - /* Underscore colour is set as RGB so convert a 256 colour to RGB. */ - if (gc->us & COLOUR_FLAG_256) - gc->us = colour_256toRGB (gc->us); + /* Underscore colour is set as RGB so convert. */ + gc->us = colour_force_rgb (gc->us); + if (gc->us == -1) + gc->us = 8; } static void From 2546216019efcbb37bfa67ba8ac101c49d42c48b Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 26 Jun 2023 08:14:19 +0000 Subject: [PATCH 04/19] When exiting alternate screen, there is no need to reflow when going back to old size since the contents will be overwritten. GitHub issue 3510. --- screen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/screen.c b/screen.c index 09326b2d..c0a8468d 100644 --- a/screen.c +++ b/screen.c @@ -626,7 +626,7 @@ screen_alternate_off(struct screen *s, struct grid_cell *gc, int cursor) * before copying back. */ if (s->saved_grid != NULL) - screen_resize(s, s->saved_grid->sx, s->saved_grid->sy, 1); + screen_resize(s, s->saved_grid->sx, s->saved_grid->sy, 0); /* * Restore the cursor position and cell. This happens even if not From 8c9fbbf4f3baae95c0ec437108f39483ced815cb Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 29 Jun 2023 15:31:06 +0100 Subject: [PATCH 05/19] Add libterminfo for NetBSD, from Thomas Klausner. --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index b09dfbbd..0d43485f 100644 --- a/configure.ac +++ b/configure.ac @@ -315,7 +315,7 @@ fi if test "x$found_ncurses" = xno; then AC_SEARCH_LIBS( setupterm, - [tinfo ncurses ncursesw], + [tinfo terminfo ncurses ncursesw], found_ncurses=yes, found_ncurses=no ) @@ -451,7 +451,7 @@ fi # Check for b64_ntop. If we have b64_ntop, we assume b64_pton as well. AC_MSG_CHECKING(for b64_ntop) - AC_LINK_IFELSE([AC_LANG_PROGRAM( +AC_LINK_IFELSE([AC_LANG_PROGRAM( [ #include #include From 4e57894e8506f27844fc0e6353475a0b61fd7807 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 30 Jun 2023 13:19:32 +0000 Subject: [PATCH 06/19] Get rid of some warnings with GCC 10, from Thomas Klausner. --- cmd-resize-window.c | 3 +-- format.c | 2 +- hyperlinks.c | 2 +- input.c | 4 +++- notify.c | 4 ++-- tty-keys.c | 2 +- tty-term.c | 4 +++- 7 files changed, 12 insertions(+), 9 deletions(-) diff --git a/cmd-resize-window.c b/cmd-resize-window.c index ad739165..c420451c 100644 --- a/cmd-resize-window.c +++ b/cmd-resize-window.c @@ -53,8 +53,7 @@ cmd_resize_window_exec(struct cmd *self, struct cmdq_item *item) struct session *s = target->s; const char *errstr; char *cause; - u_int adjust, sx, sy; - int xpixel = -1, ypixel = -1; + u_int adjust, sx, sy, xpixel = 0, ypixel = 0; if (args_count(args) == 0) adjust = 1; diff --git a/format.c b/format.c index 8cbf0a64..e383a141 100644 --- a/format.c +++ b/format.c @@ -3813,7 +3813,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s, argc = 0; /* Single argument with no wrapper character. */ - if (!ispunct(cp[1]) || cp[1] == '-') { + if (!ispunct((u_char)cp[1]) || cp[1] == '-') { end = format_skip(cp + 1, ":;"); if (end == NULL) break; diff --git a/hyperlinks.c b/hyperlinks.c index 18163cb2..913ed2fa 100644 --- a/hyperlinks.c +++ b/hyperlinks.c @@ -43,7 +43,7 @@ #define MAX_HYPERLINKS 5000 -static uint64_t hyperlinks_next_external_id = 1; +static long long hyperlinks_next_external_id = 1; static u_int global_hyperlinks_count; struct hyperlinks_uri { diff --git a/input.c b/input.c index b2d28386..dd22ac75 100644 --- a/input.c +++ b/input.c @@ -2842,9 +2842,11 @@ input_reply_clipboard(struct bufferevent *bev, const char *buf, size_t len, const char *end) { char *out = NULL; - size_t outlen = 0; + int outlen = 0; if (buf != NULL && len != 0) { + if (len >= ((size_t)INT_MAX * 3 / 4) - 1) + return; outlen = 4 * ((len + 2) / 3) + 1; out = xmalloc(outlen); if ((outlen = b64_ntop(buf, len, out, outlen)) == -1) { diff --git a/notify.c b/notify.c index 138fbeb1..aadfd450 100644 --- a/notify.c +++ b/notify.c @@ -194,7 +194,7 @@ notify_add(const char *name, struct cmd_find_state *fs, struct client *c, ne->client = c; ne->session = s; ne->window = w; - ne->pane = (wp != NULL ? wp->id : -1); + ne->pane = (wp != NULL ? (int)wp->id : -1); ne->pbname = (pbname != NULL ? xstrdup(pbname) : NULL); ne->formats = format_create(NULL, NULL, 0, FORMAT_NOJOBS); @@ -241,7 +241,7 @@ notify_hook(struct cmdq_item *item, const char *name) ne.client = cmdq_get_client(item); ne.session = target->s; ne.window = target->w; - ne.pane = (target->wp != NULL ? target->wp->id : -1); + ne.pane = (target->wp != NULL ? (int)target->wp->id : -1); ne.formats = format_create(NULL, NULL, 0, FORMAT_NOJOBS); format_add(ne.formats, "hook", "%s", name); diff --git a/tty-keys.c b/tty-keys.c index 25956c4d..e3000e5a 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -1160,7 +1160,7 @@ tty_keys_clipboard(struct tty *tty, const char *buf, size_t len, size_t *size) { struct client *c = tty->client; struct window_pane *wp; - size_t end, terminator, needed; + size_t end, terminator = 0, needed; char *copy, *out; int outlen; u_int i; diff --git a/tty-term.c b/tty-term.c index 9b897c67..a2798347 100644 --- a/tty-term.c +++ b/tty-term.c @@ -709,7 +709,7 @@ tty_term_read_list(const char *name, int fd, char ***caps, u_int *ncaps, s = tmp; break; case TTYCODE_FLAG: - n = tigetflag((char *) ent->name); + n = tigetflag((char *)ent->name); if (n == -1) continue; if (n) @@ -717,6 +717,8 @@ tty_term_read_list(const char *name, int fd, char ***caps, u_int *ncaps, else s = "0"; break; + default: + fatalx("unknown capability type"); } *caps = xreallocarray(*caps, (*ncaps) + 1, sizeof **caps); xasprintf(&(*caps)[*ncaps], "%s=%s", ent->name, s); From a2a02fd7d75a9d866570261fd428fefa773a6bf8 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 30 Jun 2023 21:55:08 +0000 Subject: [PATCH 07/19] Change a few types to fix warnings, from Thomas Klausner. --- arguments.c | 2 +- grid.c | 3 ++- regsub.c | 4 ++-- utf8.c | 2 +- window-tree.c | 4 ++-- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/arguments.c b/arguments.c index df05d328..3bc888a2 100644 --- a/arguments.c +++ b/arguments.c @@ -189,7 +189,7 @@ out: /* Parse flags argument. */ static int args_parse_flags(const struct args_parse *parse, struct args_value *values, - u_int count, char **cause, struct args *args, int *i) + u_int count, char **cause, struct args *args, u_int *i) { struct args_value *value; u_char flag; diff --git a/grid.c b/grid.c index 3afbfb6a..014e8b8f 100644 --- a/grid.c +++ b/grid.c @@ -1044,7 +1044,8 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx, const char *data; char *buf, code[8192]; size_t len, off, size, codelen; - u_int xx, has_link = 0, end; + u_int xx, end; + int has_link = 0; const struct grid_line *gl; if (lastgc != NULL && *lastgc == NULL) { diff --git a/regsub.c b/regsub.c index 4039b9be..61a9c324 100644 --- a/regsub.c +++ b/regsub.c @@ -24,7 +24,7 @@ #include "tmux.h" static void -regsub_copy(char **buf, size_t *len, const char *text, size_t start, size_t end) +regsub_copy(char **buf, ssize_t *len, const char *text, size_t start, size_t end) { size_t add = end - start; @@ -34,7 +34,7 @@ regsub_copy(char **buf, size_t *len, const char *text, size_t start, size_t end) } static void -regsub_expand(char **buf, size_t *len, const char *with, const char *text, +regsub_expand(char **buf, ssize_t *len, const char *with, const char *text, regmatch_t *m, u_int n) { const char *cp; diff --git a/utf8.c b/utf8.c index 3c6f88ff..f93891a6 100644 --- a/utf8.c +++ b/utf8.c @@ -95,7 +95,7 @@ utf8_item_by_index(u_int index) /* Add a UTF-8 item. */ static int -utf8_put_item(const char *data, size_t size, u_int *index) +utf8_put_item(const u_char *data, size_t size, u_int *index) { struct utf8_item *ui; diff --git a/window-tree.c b/window-tree.c index 00c7c0cc..8c956d00 100644 --- a/window-tree.c +++ b/window-tree.c @@ -671,9 +671,9 @@ window_tree_draw_window(struct window_tree_modedata *data, struct session *s, struct window_pane *wp; u_int cx = ctx->s->cx, cy = ctx->s->cy; u_int loop, total, visible, each, width, offset; - u_int current, start, end, remaining, i; + u_int current, start, end, remaining, i, pane_idx; struct grid_cell gc; - int colour, active_colour, left, right, pane_idx; + int colour, active_colour, left, right; char *label; total = window_count_panes(w); From e79fb214f8001c309c9ae11eba5fcbbac97f1acf Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 3 Jul 2023 08:37:14 +0000 Subject: [PATCH 08/19] Another warning fix for GCC from Thomas Klausner. --- utf8.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utf8.c b/utf8.c index f93891a6..10ccf422 100644 --- a/utf8.c +++ b/utf8.c @@ -72,7 +72,7 @@ static u_int utf8_next_index; /* Get a UTF-8 item from data. */ static struct utf8_item * -utf8_item_by_data(const char *data, size_t size) +utf8_item_by_data(const u_char *data, size_t size) { struct utf8_item ui; From ac43186dff0f4e92a566987bb9108d6c5421e9ff Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 3 Jul 2023 10:48:26 +0000 Subject: [PATCH 09/19] Do not risk writing over the end of the buffer when it ends in # (because strchr \0 will be non-NULL), reported by Robert Morris in GitHub issue 3610. --- format.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/format.c b/format.c index e383a141..3f745141 100644 --- a/format.c +++ b/format.c @@ -3664,7 +3664,9 @@ format_skip(const char *s, const char *end) for (; *s != '\0'; s++) { if (*s == '#' && s[1] == '{') brackets++; - if (*s == '#' && strchr(",#{}:", s[1]) != NULL) { + if (*s == '#' && + s[1] != '\0' && + strchr(",#{}:", s[1]) != NULL) { s++; continue; } From 43b841f188c994966e00e59c96581b876652bef1 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 3 Jul 2023 16:47:43 +0000 Subject: [PATCH 10/19] Add support for marking lines with a shell prompt based on the OSC 133 extension, from Munif Tanjim in GitHub issue 3596. --- input.c | 22 ++++++++++++++++ tmux.1 | 12 +++++++++ tmux.h | 1 + window-copy.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 108 insertions(+) diff --git a/input.c b/input.c index dd22ac75..ee31b7e1 100644 --- a/input.c +++ b/input.c @@ -144,6 +144,7 @@ static void input_osc_104(struct input_ctx *, const char *); static void input_osc_110(struct input_ctx *, const char *); static void input_osc_111(struct input_ctx *, const char *); static void input_osc_112(struct input_ctx *, const char *); +static void input_osc_133(struct input_ctx *, const char *); /* Transition entry/exit handlers. */ static void input_clear(struct input_ctx *); @@ -2347,6 +2348,9 @@ input_exit_osc(struct input_ctx *ictx) case 112: input_osc_112(ictx, p); break; + case 133: + input_osc_133(ictx, p); + break; default: log_debug("%s: unknown '%u'", __func__, option); break; @@ -2736,6 +2740,24 @@ input_osc_112(struct input_ctx *ictx, const char *p) screen_set_cursor_colour(ictx->ctx.s, -1); } +/* Handle the OSC 133 sequence. */ +static void +input_osc_133(struct input_ctx *ictx, const char *p) +{ + struct grid *gd = ictx->ctx.s->grid; + u_int line = ictx->ctx.s->cy + gd->hsize; + struct grid_line *gl; + + if (line > gd->hsize + gd->sy - 1) + return; + gl = grid_get_line(gd, line); + + switch (*p) { + case 'A': + gl->flags |= GRID_LINE_START_PROMPT; + break; + } +} /* Handle the OSC 52 sequence for setting the clipboard. */ static void diff --git a/tmux.1 b/tmux.1 index 8b76bbac..781ea9fc 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1787,6 +1787,7 @@ The following commands are supported in copy mode: .It Li "middle-line" Ta "M" Ta "M-r" .It Li "next-matching-bracket" Ta "%" Ta "M-C-f" .It Li "next-paragraph" Ta "}" Ta "M-}" +.It Li "next-prompt" Ta "" Ta "" .It Li "next-space" Ta "W" Ta "" .It Li "next-space-end" Ta "E" Ta "" .It Li "next-word" Ta "w" Ta "" @@ -1800,6 +1801,7 @@ The following commands are supported in copy mode: .It Li "pipe-and-cancel [] []" Ta "" Ta "" .It Li "previous-matching-bracket" Ta "" Ta "M-C-b" .It Li "previous-paragraph" Ta "{" Ta "M-{" +.It Li "previous-prompt" Ta "" Ta "" .It Li "previous-space" Ta "B" Ta "" .It Li "previous-word" Ta "b" Ta "M-b" .It Li "rectangle-on" Ta "" Ta "" @@ -1849,6 +1851,16 @@ repeats the last search and does the same but reverses the direction (forward becomes backward and backward becomes forward). .Pp +The +.Ql next-prompt +and +.Ql previous-prompt +move between shell prompts, but require the shell to emit an escape sequence +(\e033]133;A\e033\e\e) to tell +.Nm +where the prompts are located; if the shell does not do this, these commands +will do nothing. +.Pp Copy commands may take an optional buffer prefix argument which is used to generate the buffer name (the default is .Ql buffer diff --git a/tmux.h b/tmux.h index bd2f6a63..d2a5671b 100644 --- a/tmux.h +++ b/tmux.h @@ -671,6 +671,7 @@ struct colour_palette { #define GRID_LINE_WRAPPED 0x1 #define GRID_LINE_EXTENDED 0x2 #define GRID_LINE_DEAD 0x4 +#define GRID_LINE_START_PROMPT 0x8 /* Grid string flags. */ #define GRID_STRING_WITH_SEQUENCES 0x1 diff --git a/window-copy.c b/window-copy.c index ed481d70..b0f14098 100644 --- a/window-copy.c +++ b/window-copy.c @@ -131,6 +131,7 @@ static void window_copy_cursor_previous_word_pos(struct window_mode_entry *, const char *, u_int *, u_int *); static void window_copy_cursor_previous_word(struct window_mode_entry *, const char *, int); +static void window_copy_cursor_prompt(struct window_mode_entry *, int); static void window_copy_scroll_up(struct window_mode_entry *, u_int); static void window_copy_scroll_down(struct window_mode_entry *, u_int); static void window_copy_rectangle_set(struct window_mode_entry *, int); @@ -2240,6 +2241,24 @@ window_copy_cmd_jump_to_mark(struct window_copy_cmd_state *cs) return (WINDOW_COPY_CMD_NOTHING); } +static enum window_copy_cmd_action +window_copy_cmd_next_prompt(struct window_copy_cmd_state *cs) +{ + struct window_mode_entry *wme = cs->wme; + + window_copy_cursor_prompt(wme, 1); + return (WINDOW_COPY_CMD_NOTHING); +} + +static enum window_copy_cmd_action +window_copy_cmd_previous_prompt(struct window_copy_cmd_state *cs) +{ + struct window_mode_entry *wme = cs->wme; + + window_copy_cursor_prompt(wme, 0); + return (WINDOW_COPY_CMD_NOTHING); +} + static enum window_copy_cmd_action window_copy_cmd_search_backward(struct window_copy_cmd_state *cs) { @@ -2694,6 +2713,18 @@ static const struct { .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .f = window_copy_cmd_jump_to_mark }, + { .command = "next-prompt", + .minargs = 0, + .maxargs = 0, + .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, + .f = window_copy_cmd_next_prompt + }, + { .command = "previous-prompt", + .minargs = 0, + .maxargs = 0, + .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, + .f = window_copy_cmd_previous_prompt + }, { .command = "middle-line", .minargs = 0, .maxargs = 0, @@ -5357,6 +5388,48 @@ window_copy_cursor_previous_word(struct window_mode_entry *wme, window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px, py); } +static void +window_copy_cursor_prompt(struct window_mode_entry *wme, int direction) +{ + struct window_copy_mode_data *data = wme->data; + struct screen *s = data->backing; + struct grid *gd = s->grid; + u_int end_line; + u_int line = gd->hsize - data->oy + data->cy; + int add; + + if (direction == 0) { /* up */ + add = -1; + end_line = 0; + } else { /* down */ + add = 1; + end_line = gd->hsize + gd->sy - 1; + } + + if (line == end_line) + return; + for (;;) { + if (line == end_line) + return; + line += add; + + if (grid_get_line(gd, line)->flags & GRID_LINE_START_PROMPT) + break; + } + + data->cx = 0; + if (line > gd->hsize) { + data->cy = line - gd->hsize; + data->oy = 0; + } else { + data->cy = 0; + data->oy = gd->hsize - line; + } + + window_copy_update_selection(wme, 1, 0); + window_copy_redraw_screen(wme); +} + static void window_copy_scroll_up(struct window_mode_entry *wme, u_int ny) { From b7e22d00b4530ecf6b86884c0f27cbad38a6345c Mon Sep 17 00:00:00 2001 From: nicm Date: Sun, 9 Jul 2023 22:54:52 +0000 Subject: [PATCH 11/19] Call closefrom after removing signals because newer libevent doesn't like its signal fd being closed Azat Khuzhin. --- spawn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spawn.c b/spawn.c index 98c9ba52..dd3f6f50 100644 --- a/spawn.c +++ b/spawn.c @@ -415,8 +415,8 @@ spawn_pane(struct spawn_context *sc, char **cause) _exit(1); /* Clean up file descriptors and signals and update the environment. */ - closefrom(STDERR_FILENO + 1); proc_clear_signals(server_proc, 1); + closefrom(STDERR_FILENO + 1); sigprocmask(SIG_SETMASK, &oldset, NULL); log_close(); environ_push(child); From 8b3e2eab5afde62a4eb87b132b4196105c1cfaa6 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 10 Jul 2023 09:24:53 +0000 Subject: [PATCH 12/19] Use a stack for last panes line windows, from Thomas Bertschinger in GitHub issue 3588. --- cmd-find.c | 2 +- cmd-select-pane.c | 6 ++++- cmd-swap-pane.c | 6 ++--- format.c | 2 +- spawn.c | 1 + tmux.h | 12 +++++++--- window.c | 56 +++++++++++++++++++++++++++++++++-------------- 7 files changed, 59 insertions(+), 26 deletions(-) diff --git a/cmd-find.c b/cmd-find.c index 2929bbc9..c651448d 100644 --- a/cmd-find.c +++ b/cmd-find.c @@ -583,7 +583,7 @@ cmd_find_get_pane_with_window(struct cmd_find_state *fs, const char *pane) /* Try special characters. */ if (strcmp(pane, "!") == 0) { - fs->wp = fs->w->last; + fs->wp = TAILQ_FIRST(&fs->w->last_panes); if (fs->wp == NULL) return (-1); return (0); diff --git a/cmd-select-pane.c b/cmd-select-pane.c index ae21d4ce..135729f5 100644 --- a/cmd-select-pane.c +++ b/cmd-select-pane.c @@ -98,7 +98,11 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item) struct options_entry *o; if (entry == &cmd_last_pane_entry || args_has(args, 'l')) { - lastwp = w->last; + /* + * Check for no last pane found in case the other pane was + * spawned without being visited (for example split-window -d). + */ + lastwp = TAILQ_FIRST(&w->last_panes); if (lastwp == NULL && window_count_panes(w) == 2) { lastwp = TAILQ_PREV(w->active, window_panes, entry); if (lastwp == NULL) diff --git a/cmd-swap-pane.c b/cmd-swap-pane.c index 80c20c80..6931bd16 100644 --- a/cmd-swap-pane.c +++ b/cmd-swap-pane.c @@ -128,10 +128,8 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item) window_set_active_pane(dst_w, src_wp, 1); } if (src_w != dst_w) { - if (src_w->last == src_wp) - src_w->last = NULL; - if (dst_w->last == dst_wp) - dst_w->last = NULL; + window_pane_stack_remove(&src_w->last_panes, src_wp); + window_pane_stack_remove(&dst_w->last_panes, dst_wp); colour_palette_from_option(&src_wp->palette, src_wp->options); colour_palette_from_option(&dst_wp->palette, dst_wp->options); } diff --git a/format.c b/format.c index 3f745141..0c3bd3ba 100644 --- a/format.c +++ b/format.c @@ -1902,7 +1902,7 @@ static void * format_cb_pane_last(struct format_tree *ft) { if (ft->wp != NULL) { - if (ft->wp == ft->wp->window->last) + if (ft->wp == TAILQ_FIRST(&ft->wp->window->last_panes)) return (xstrdup("1")); return (xstrdup("0")); } diff --git a/spawn.c b/spawn.c index dd3f6f50..7ae3f938 100644 --- a/spawn.c +++ b/spawn.c @@ -115,6 +115,7 @@ spawn_window(struct spawn_context *sc, char **cause) window_pane_resize(sc->wp0, w->sx, w->sy); layout_init(w, sc->wp0); + w->active = NULL; window_set_active_pane(w, sc->wp0, 0); } diff --git a/tmux.h b/tmux.h index d2a5671b..9588c285 100644 --- a/tmux.h +++ b/tmux.h @@ -1038,7 +1038,7 @@ struct window_pane { #define PANE_REDRAW 0x1 #define PANE_DROP 0x2 #define PANE_FOCUSED 0x4 -/* 0x8 unused */ +#define PANE_VISITED 0x8 /* 0x10 unused */ /* 0x20 unused */ #define PANE_INPUTOFF 0x40 @@ -1093,7 +1093,8 @@ struct window_pane { int border_gc_set; struct grid_cell border_gc; - TAILQ_ENTRY(window_pane) entry; + TAILQ_ENTRY(window_pane) entry; /* link in list of all panes */ + TAILQ_ENTRY(window_pane) sentry; /* link in list of last visited */ RB_ENTRY(window_pane) tree_entry; }; TAILQ_HEAD(window_panes, window_pane); @@ -1114,7 +1115,7 @@ struct window { struct timeval activity_time; struct window_pane *active; - struct window_pane *last; + struct window_panes last_panes; struct window_panes panes; int lastlayout; @@ -1167,6 +1168,7 @@ struct winlink { #define WINLINK_ACTIVITY 0x2 #define WINLINK_SILENCE 0x4 #define WINLINK_ALERTFLAGS (WINLINK_BELL|WINLINK_ACTIVITY|WINLINK_SILENCE) +#define WINLINK_VISITED 0x8 RB_ENTRY(winlink) entry; TAILQ_ENTRY(winlink) wentry; @@ -3041,6 +3043,10 @@ struct window_pane *window_pane_find_up(struct window_pane *); struct window_pane *window_pane_find_down(struct window_pane *); struct window_pane *window_pane_find_left(struct window_pane *); struct window_pane *window_pane_find_right(struct window_pane *); +void window_pane_stack_push(struct window_panes *, + struct window_pane *); +void window_pane_stack_remove(struct window_panes *, + struct window_pane *); void window_set_name(struct window *, const char *); void window_add_ref(struct window *, const char *); void window_remove_ref(struct window *, const char *); diff --git a/window.c b/window.c index 8f650a96..c1365993 100644 --- a/window.c +++ b/window.c @@ -248,21 +248,15 @@ winlink_stack_push(struct winlink_stack *stack, struct winlink *wl) winlink_stack_remove(stack, wl); TAILQ_INSERT_HEAD(stack, wl, sentry); + wl->flags |= WINLINK_VISITED; } void winlink_stack_remove(struct winlink_stack *stack, struct winlink *wl) { - struct winlink *wl2; - - if (wl == NULL) - return; - - TAILQ_FOREACH(wl2, stack, sentry) { - if (wl2 == wl) { - TAILQ_REMOVE(stack, wl, sentry); - return; - } + if (wl != NULL && (wl->flags & WINLINK_VISITED)) { + TAILQ_REMOVE(stack, wl, sentry); + wl->flags &= ~WINLINK_VISITED; } } @@ -312,6 +306,7 @@ window_create(u_int sx, u_int sy, u_int xpixel, u_int ypixel) w->flags = 0; TAILQ_INIT(&w->panes); + TAILQ_INIT(&w->last_panes); w->active = NULL; w->lastlayout = -1; @@ -512,18 +507,23 @@ window_pane_update_focus(struct window_pane *wp) int window_set_active_pane(struct window *w, struct window_pane *wp, int notify) { + struct window_pane *lastwp; + log_debug("%s: pane %%%u", __func__, wp->id); if (wp == w->active) return (0); - w->last = w->active; + lastwp = w->active; + + window_pane_stack_remove(&w->last_panes, wp); + window_pane_stack_push(&w->last_panes, lastwp); w->active = wp; w->active->active_point = next_active_point++; w->active->flags |= PANE_CHANGED; if (options_get_number(global_options, "focus-events")) { - window_pane_update_focus(w->last); + window_pane_update_focus(lastwp); window_pane_update_focus(w->active); } @@ -746,21 +746,21 @@ window_lost_pane(struct window *w, struct window_pane *wp) if (wp == marked_pane.wp) server_clear_marked(); + window_pane_stack_remove(&w->last_panes, wp); if (wp == w->active) { - w->active = w->last; - w->last = NULL; + w->active = TAILQ_FIRST(&w->last_panes); if (w->active == NULL) { w->active = TAILQ_PREV(wp, window_panes, entry); if (w->active == NULL) w->active = TAILQ_NEXT(wp, entry); } if (w->active != NULL) { + window_pane_stack_remove(&w->last_panes, w->active); w->active->flags |= PANE_CHANGED; notify_window("window-pane-changed", w); window_update_focus(w); } - } else if (wp == w->last) - w->last = NULL; + } } void @@ -844,6 +844,11 @@ window_destroy_panes(struct window *w) { struct window_pane *wp; + while (!TAILQ_EMPTY(&w->last_panes)) { + wp = TAILQ_FIRST(&w->last_panes); + window_pane_stack_remove(&w->last_panes, wp); + } + while (!TAILQ_EMPTY(&w->panes)) { wp = TAILQ_FIRST(&w->panes); TAILQ_REMOVE(&w->panes, wp, entry); @@ -1478,6 +1483,25 @@ window_pane_find_right(struct window_pane *wp) return (best); } +void +window_pane_stack_push(struct window_panes *stack, struct window_pane *wp) +{ + if (wp != NULL) { + window_pane_stack_remove(stack, wp); + TAILQ_INSERT_HEAD(stack, wp, sentry); + wp->flags |= PANE_VISITED; + } +} + +void +window_pane_stack_remove(struct window_panes *stack, struct window_pane *wp) +{ + if (wp != NULL && (wp->flags & PANE_VISITED)) { + TAILQ_REMOVE(stack, wp, sentry); + wp->flags &= ~PANE_VISITED; + } +} + /* Clear alert flags for a winlink */ void winlink_clear_flags(struct winlink *wl) From 4ece43a02961dc6726e97b05caca9a3c53793826 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 10 Jul 2023 09:35:46 +0000 Subject: [PATCH 13/19] Loop around waitpid in client, from Azat Khuzhin. --- client.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/client.c b/client.c index 4f91d30e..be17540c 100644 --- a/client.c +++ b/client.c @@ -526,11 +526,22 @@ client_signal(int sig) { struct sigaction sigact; int status; + pid_t pid; log_debug("%s: %s", __func__, strsignal(sig)); - if (sig == SIGCHLD) - waitpid(WAIT_ANY, &status, WNOHANG); - else if (!client_attached) { + if (sig == SIGCHLD) { + for (;;) { + pid = waitpid(WAIT_ANY, &status, WNOHANG); + if (pid == 0) + break; + if (pid == -1) { + if (errno == ECHILD) + break; + log_debug("waitpid failed: %s", + strerror(errno)); + } + } + } else if (!client_attached) { if (sig == SIGTERM || sig == SIGHUP) proc_exit(client_proc); } else { From 63b728237716594d711ef9e7ee3a0203d43f6723 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 10 Jul 2023 12:00:08 +0000 Subject: [PATCH 14/19] It should no longer be necessary to ignore SIGCHLD because it is now blocked around daemon(), and doing so causes trouble with newer libevent (it cannot restore the original handler). Reported by Azat Khuzhin in GitHub issue 3626. --- client.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/client.c b/client.c index be17540c..ff89e6f8 100644 --- a/client.c +++ b/client.c @@ -246,9 +246,6 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags, u_int ncaps = 0; struct args_value *values; - /* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */ - signal(SIGCHLD, SIG_IGN); - /* Set up the initial command. */ if (shell_command != NULL) { msg = MSG_SHELL; From efded95ed7f5d206527bf517940f08a54f3c5930 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 11 Jul 2023 07:34:23 +0000 Subject: [PATCH 15/19] Add descriptions of copy mode commands, from Michael Bianco. --- tmux.1 | 363 +++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 276 insertions(+), 87 deletions(-) diff --git a/tmux.1 b/tmux.1 index 781ea9fc..0c745226 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1742,93 +1742,282 @@ Key tables may be viewed with the command. .Pp The following commands are supported in copy mode: -.Bl -column "CommandXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "viXXXXXXXXXX" "emacs" -offset indent -.It Sy "Command" Ta Sy "vi" Ta Sy "emacs" -.It Li "append-selection" Ta "" Ta "" -.It Li "append-selection-and-cancel" Ta "A" Ta "" -.It Li "back-to-indentation" Ta "^" Ta "M-m" -.It Li "begin-selection" Ta "Space" Ta "C-Space" -.It Li "bottom-line" Ta "L" Ta "" -.It Li "cancel" Ta "q" Ta "Escape" -.It Li "clear-selection" Ta "Escape" Ta "C-g" -.It Li "copy-end-of-line []" Ta "" Ta "" -.It Li "copy-end-of-line-and-cancel []" Ta "" Ta "" -.It Li "copy-pipe-end-of-line [] []" Ta "" Ta "" -.It Li "copy-pipe-end-of-line-and-cancel [] []" Ta "D" Ta "C-k" -.It Li "copy-line []" Ta "" Ta "" -.It Li "copy-line-and-cancel []" Ta "" Ta "" -.It Li "copy-pipe-line [] []" Ta "" Ta "" -.It Li "copy-pipe-line-and-cancel [] []" Ta "" Ta "" -.It Li "copy-pipe [] []" Ta "" Ta "" -.It Li "copy-pipe-no-clear [] []" Ta "" Ta "" -.It Li "copy-pipe-and-cancel [] []" Ta "" Ta "" -.It Li "copy-selection []" Ta "" Ta "" -.It Li "copy-selection-no-clear []" Ta "" Ta "" -.It Li "copy-selection-and-cancel []" Ta "Enter" Ta "M-w" -.It Li "cursor-down" Ta "j" Ta "Down" -.It Li "cursor-down-and-cancel" Ta "" Ta "" -.It Li "cursor-left" Ta "h" Ta "Left" -.It Li "cursor-right" Ta "l" Ta "Right" -.It Li "cursor-up" Ta "k" Ta "Up" -.It Li "end-of-line" Ta "$" Ta "C-e" -.It Li "goto-line " Ta ":" Ta "g" -.It Li "halfpage-down" Ta "C-d" Ta "M-Down" -.It Li "halfpage-down-and-cancel" Ta "" Ta "" -.It Li "halfpage-up" Ta "C-u" Ta "M-Up" -.It Li "history-bottom" Ta "G" Ta "M->" -.It Li "history-top" Ta "g" Ta "M-<" -.It Li "jump-again" Ta ";" Ta ";" -.It Li "jump-backward " Ta "F" Ta "F" -.It Li "jump-forward " Ta "f" Ta "f" -.It Li "jump-reverse" Ta "," Ta "," -.It Li "jump-to-backward " Ta "T" Ta "" -.It Li "jump-to-forward " Ta "t" Ta "" -.It Li "jump-to-mark" Ta "M-x" Ta "M-x" -.It Li "middle-line" Ta "M" Ta "M-r" -.It Li "next-matching-bracket" Ta "%" Ta "M-C-f" -.It Li "next-paragraph" Ta "}" Ta "M-}" -.It Li "next-prompt" Ta "" Ta "" -.It Li "next-space" Ta "W" Ta "" -.It Li "next-space-end" Ta "E" Ta "" -.It Li "next-word" Ta "w" Ta "" -.It Li "next-word-end" Ta "e" Ta "M-f" -.It Li "other-end" Ta "o" Ta "" -.It Li "page-down" Ta "C-f" Ta "PageDown" -.It Li "page-down-and-cancel" Ta "" Ta "" -.It Li "page-up" Ta "C-b" Ta "PageUp" -.It Li "pipe [] []" Ta "" Ta "" -.It Li "pipe-no-clear [] []" Ta "" Ta "" -.It Li "pipe-and-cancel [] []" Ta "" Ta "" -.It Li "previous-matching-bracket" Ta "" Ta "M-C-b" -.It Li "previous-paragraph" Ta "{" Ta "M-{" -.It Li "previous-prompt" Ta "" Ta "" -.It Li "previous-space" Ta "B" Ta "" -.It Li "previous-word" Ta "b" Ta "M-b" -.It Li "rectangle-on" Ta "" Ta "" -.It Li "rectangle-off" Ta "" Ta "" -.It Li "rectangle-toggle" Ta "v" Ta "R" -.It Li "refresh-from-pane" Ta "r" Ta "r" -.It Li "scroll-down" Ta "C-e" Ta "C-Down" -.It Li "scroll-down-and-cancel" Ta "" Ta "" -.It Li "scroll-up" Ta "C-y" Ta "C-Up" -.It Li "search-again" Ta "n" Ta "n" -.It Li "search-backward " Ta "?" Ta "" -.It Li "search-backward-incremental " Ta "" Ta "C-r" -.It Li "search-backward-text " Ta "" Ta "" -.It Li "search-forward " Ta "/" Ta "" -.It Li "search-forward-incremental " Ta "" Ta "C-s" -.It Li "search-forward-text " Ta "" Ta "" -.It Li "scroll-bottom" Ta "" Ta "" -.It Li "scroll-middle" Ta "z" Ta "" -.It Li "scroll-top" Ta "" Ta "" -.It Li "search-reverse" Ta "N" Ta "N" -.It Li "select-line" Ta "V" Ta "" -.It Li "select-word" Ta "" Ta "" -.It Li "set-mark" Ta "X" Ta "X" -.It Li "start-of-line" Ta "0" Ta "C-a" -.It Li "stop-selection" Ta "" Ta "" -.It Li "toggle-position" Ta "P" Ta "P" -.It Li "top-line" Ta "H" Ta "M-R" +.Bl -tag -width Ds +.It Xo +.Nm append-selection +.Ns +.Xc +Append the selection to the top paste buffer. +.It Xo +.Nm append-selection-and-cancel +.Ns +.Li (vi: A) +.Xc +Append the selection to the top paste buffer and exit copy mode. +.It Xo +.Nm back-to-indentation +.Ns +.Li (vi: ^) (emacs: M-m) +.Xc +Move the cursor back to the indentation. +.It Xo +.Nm begin-selection +.Ns +.Li (vi: Space) (emacs: C-Space) +.Xc +Begin selection. +.It Xo +.Nm bottom-line +.Ns +.Li (vi: L) +.Xc +Move to the bottom line. +.It Xo +.Nm cancel +.Ns +.Li (vi: q) (emacs: Escape) +.Xc +Exit copy mode. +.It Xo +.Nm clear-selection +.Ns +.Li (vi: Escape) (emacs: C-g) +.Xc +Clear the current selection. +.It Xo +.Nm copy-end-of-line [] +.Ns +.Xc +Copy from the cursor position to the end of the line. +.Ar prefix +is used to name the new paste buffer. +.It Xo +.Nm copy-end-of-line-and-cancel [] +.Ns +.Xc +Copy from the cursor position and exit copy mode. +.It Xo +.Nm copy-line [] +.Ns +.Xc +Copy the entire line. +.It Xo +.Nm copy-line-and-cancel [] +.Ns +.Xc +Copy the entire line and exit copy mode. +.It Xo +.Nm copy-selection [] +.Ns +.Xc +Copies the current selection. +.It Xo +.Nm copy-selection-and-cancel [] +.Ns +.Li (vi: Enter) (emacs: M-w) +.Xc +Copy the current selection and exit copy mode. +.It Xo +.Nm cursor-down +.Ns +.Li (vi: j) (emacs: Down) +.Xc +Move the cursor down. +.It Xo +.Nm cursor-left +.Ns +.Li (vi: h) (emacs: Left) +.Xc +Move the cursor left. +.It Xo +.Nm cursor-right +.Ns +.Li (vi: l) (emacs: Right) +.Xc +Move the cursor right. +.It Xo +.Nm cursor-up +.Ns +.Li (vi: k) (emacs: Up) +.Xc +Move the cursor up. +.It Xo +.Nm end-of-line +.Ns +.Li (vi: $) (emacs: C-e) +.Xc +Move the cursor to the end of the line. +.It Xo +.Nm goto-line +.Ns +.Li (vi: :) (emacs: g) +.Xc +Move the cursor to a specific line. +.It Xo +.Nm history-bottom +.Ns +.Li (vi: G) (emacs: M->) +.Xc +Scroll to the bottom of the history. +.It Xo +.Nm history-top +.Ns +.Li (vi: g) (emacs: M-<) +.Xc +Scroll to the top of the history. +.It Xo +.Nm jump-again +.Ns +.Li (vi: ;) (emacs: ;) +.Xc +Repeat the last jump. +.It Xo +.Nm jump-backward +.Ns +.Li (vi: F) (emacs: F) +.Xc +Jump backwards to the specified text. +.It Xo +.Nm jump-forward +.Ns +.Li (vi: f) (emacs: f) +.Xc +Jump forward to the specified text. +.It Xo +.Nm jump-to-mark +.Ns +.Li (vi: M-x) (emacs: M-x) +.Xc +Jump to the last mark. +.It Xo +.Nm middle-line +.Ns +.Li (vi: M) (emacs: M-r) +.Xc +Move to the middle line. +.It Xo +.Nm next-matching-bracket +.Ns +.Li (vi: %) (emacs: M-C-f) +.Xc +Move to the next matching bracket. +.It Xo +.Nm next-paragraph +.Ns +.Li (vi: }) (emacs: M-}) +.Xc +Move to the next paragraph. +.It Xo +.Nm next-prompt +.Ns +.Xc +Move to the next prompt. +.It Xo +.Nm next-word +.Ns +.Li (vi: w) +.Xc +Move to the next word. +.It Xo +.Nm page-down +.Ns +.Li (vi: C-f) (emacs: PageDown) +.Xc +Scroll down by one page. +.It Xo +.Nm page-up +.Ns +.Li (vi: C-b) (emacs: PageUp) +.Xc +Scroll up by one page. +.It Xo +.Nm previous-matching-bracket +.Ns +.Li (emacs: M-C-b) +.Xc +Move to the previous matching bracket. +.It Xo +.Nm previous-paragraph +.Ns +.Li (vi: {) (emacs: M-{) +.Xc +Move to the previous paragraph. +.It Xo +.Nm previous-prompt +.Ns +.Xc +Move to the previous prompt. +.It Xo +.Nm previous-word +.Ns +.Li (vi: b) (emacs: M-b) +.Xc +Move to the previous word. +.It Xo +.Nm rectangle-toggle +.Ns +.Li (vi: v) (emacs: R) +.Xc +Toggle rectangle selection mode. +.It Xo +.Nm refresh-from-pane +.Ns +.Li (vi: r) (emacs: r) +.Xc +Refresh the content from the pane. +.It Xo +.Nm search-again +.Ns +.Li (vi: n) (emacs: n) +.Xc +Repeat the last search. +.It Xo +.Nm search-backward +.Ns +.Li (vi: ?) +.Xc +Search backwards for the specified text. +.It Xo +.Nm search-forward +.Ns +.Li (vi: /) +.Xc +Search forward for the specified text. +.It Xo +.Nm select-line +.Ns +.Li (vi: V) +.Xc +Select the current line. +.It Xo +.Nm select-word +.Ns +.Xc +Select the current word. +.It Xo +.Nm start-of-line +.Ns +.Li (vi: 0) (emacs: C-a) +.Xc +Move the cursor to the start of the line. +.It Xo +.Nm top-line +.Ns +.Li (vi: H) (emacs: M-R) +.Xc +Move to the top line. +.It Xo +.Nm next-prompt +.Ns +.Li (vi: C-n) (emacs: C-n) +.Xc +Move to the next prompt. +.It Xo +.Nm previous-prompt +.Ns +.Li (vi: C-p) (emacs: C-p) +.Xc +Move to the previous prompt. .El .Pp The search commands come in several varieties: From 8fcc212e7a24cfb4cc3973469c4ee8974e7d9bde Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 11 Jul 2023 16:09:09 +0000 Subject: [PATCH 16/19] Remove Ns and Li and change Nm to Ic, suggested by jmc. --- tmux.1 | 248 +++++++++++++++++++++++++++------------------------------ 1 file changed, 116 insertions(+), 132 deletions(-) diff --git a/tmux.1 b/tmux.1 index 0c745226..0fdbe41b 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1744,278 +1744,262 @@ command. The following commands are supported in copy mode: .Bl -tag -width Ds .It Xo -.Nm append-selection -.Ns +.Ic append-selection .Xc Append the selection to the top paste buffer. .It Xo -.Nm append-selection-and-cancel -.Ns -.Li (vi: A) +.Ic append-selection-and-cancel +(vi: A) .Xc Append the selection to the top paste buffer and exit copy mode. .It Xo -.Nm back-to-indentation -.Ns -.Li (vi: ^) (emacs: M-m) +.Ic back-to-indentation +(vi: ^) +(emacs: M-m) .Xc Move the cursor back to the indentation. .It Xo -.Nm begin-selection -.Ns -.Li (vi: Space) (emacs: C-Space) +.Ic begin-selection +(vi: Space) +(emacs: C-Space) .Xc Begin selection. .It Xo -.Nm bottom-line -.Ns -.Li (vi: L) +.Ic bottom-line +(vi: L) .Xc Move to the bottom line. .It Xo -.Nm cancel -.Ns -.Li (vi: q) (emacs: Escape) +.Ic cancel +(vi: q) +(emacs: Escape) .Xc Exit copy mode. .It Xo -.Nm clear-selection -.Ns -.Li (vi: Escape) (emacs: C-g) +.Ic clear-selection +(vi: Escape) +(emacs: C-g) .Xc Clear the current selection. .It Xo -.Nm copy-end-of-line [] -.Ns +.Ic copy-end-of-line [] .Xc Copy from the cursor position to the end of the line. .Ar prefix is used to name the new paste buffer. .It Xo -.Nm copy-end-of-line-and-cancel [] -.Ns +.Ic copy-end-of-line-and-cancel [] .Xc Copy from the cursor position and exit copy mode. .It Xo -.Nm copy-line [] -.Ns +.Ic copy-line [] .Xc Copy the entire line. .It Xo -.Nm copy-line-and-cancel [] -.Ns +.Ic copy-line-and-cancel [] .Xc Copy the entire line and exit copy mode. .It Xo -.Nm copy-selection [] -.Ns +.Ic copy-selection [] .Xc Copies the current selection. .It Xo -.Nm copy-selection-and-cancel [] -.Ns -.Li (vi: Enter) (emacs: M-w) +.Ic copy-selection-and-cancel [] +(vi: Enter) +(emacs: M-w) .Xc Copy the current selection and exit copy mode. .It Xo -.Nm cursor-down -.Ns -.Li (vi: j) (emacs: Down) +.Ic cursor-down +(vi: j) +(emacs: Down) .Xc Move the cursor down. .It Xo -.Nm cursor-left -.Ns -.Li (vi: h) (emacs: Left) +.Ic cursor-left +(vi: h) +(emacs: Left) .Xc Move the cursor left. .It Xo -.Nm cursor-right -.Ns -.Li (vi: l) (emacs: Right) +.Ic cursor-right +(vi: l) +(emacs: Right) .Xc Move the cursor right. .It Xo -.Nm cursor-up -.Ns -.Li (vi: k) (emacs: Up) +.Ic cursor-up +(vi: k) +(emacs: Up) .Xc Move the cursor up. .It Xo -.Nm end-of-line -.Ns -.Li (vi: $) (emacs: C-e) +.Ic end-of-line +(vi: $) +(emacs: C-e) .Xc Move the cursor to the end of the line. .It Xo -.Nm goto-line -.Ns -.Li (vi: :) (emacs: g) +.Ic goto-line +(vi: :) +(emacs: g) .Xc Move the cursor to a specific line. .It Xo -.Nm history-bottom -.Ns -.Li (vi: G) (emacs: M->) +.Ic history-bottom +(vi: G) +(emacs: M->) .Xc Scroll to the bottom of the history. .It Xo -.Nm history-top -.Ns -.Li (vi: g) (emacs: M-<) +.Ic history-top +(vi: g) +(emacs: M-<) .Xc Scroll to the top of the history. .It Xo -.Nm jump-again -.Ns -.Li (vi: ;) (emacs: ;) +.Ic jump-again +(vi: ;) +(emacs: ;) .Xc Repeat the last jump. .It Xo -.Nm jump-backward -.Ns -.Li (vi: F) (emacs: F) +.Ic jump-backward +(vi: F) +(emacs: F) .Xc Jump backwards to the specified text. .It Xo -.Nm jump-forward -.Ns -.Li (vi: f) (emacs: f) +.Ic jump-forward +(vi: f) +(emacs: f) .Xc Jump forward to the specified text. .It Xo -.Nm jump-to-mark -.Ns -.Li (vi: M-x) (emacs: M-x) +.Ic jump-to-mark +(vi: M-x) +(emacs: M-x) .Xc Jump to the last mark. .It Xo -.Nm middle-line -.Ns -.Li (vi: M) (emacs: M-r) +.Ic middle-line +(vi: M) +(emacs: M-r) .Xc Move to the middle line. .It Xo -.Nm next-matching-bracket -.Ns -.Li (vi: %) (emacs: M-C-f) +.Ic next-matching-bracket +(vi: %) +(emacs: M-C-f) .Xc Move to the next matching bracket. .It Xo -.Nm next-paragraph -.Ns -.Li (vi: }) (emacs: M-}) +.Ic next-paragraph +(vi: }) +(emacs: M-}) .Xc Move to the next paragraph. .It Xo -.Nm next-prompt -.Ns +.Ic next-prompt .Xc Move to the next prompt. .It Xo -.Nm next-word -.Ns -.Li (vi: w) +.Ic next-word +(vi: w) .Xc Move to the next word. .It Xo -.Nm page-down -.Ns -.Li (vi: C-f) (emacs: PageDown) +.Ic page-down +(vi: C-f) +(emacs: PageDown) .Xc Scroll down by one page. .It Xo -.Nm page-up -.Ns -.Li (vi: C-b) (emacs: PageUp) +.Ic page-up +(vi: C-b) +(emacs: PageUp) .Xc Scroll up by one page. .It Xo -.Nm previous-matching-bracket -.Ns -.Li (emacs: M-C-b) +.Ic previous-matching-bracket +(emacs: M-C-b) .Xc Move to the previous matching bracket. .It Xo -.Nm previous-paragraph -.Ns -.Li (vi: {) (emacs: M-{) +.Ic previous-paragraph +(vi: {) +(emacs: M-{) .Xc Move to the previous paragraph. .It Xo -.Nm previous-prompt -.Ns +.Ic previous-prompt .Xc Move to the previous prompt. .It Xo -.Nm previous-word -.Ns -.Li (vi: b) (emacs: M-b) +.Ic previous-word +(vi: b) +(emacs: M-b) .Xc Move to the previous word. .It Xo -.Nm rectangle-toggle -.Ns -.Li (vi: v) (emacs: R) +.Ic rectangle-toggle +(vi: v) +(emacs: R) .Xc Toggle rectangle selection mode. .It Xo -.Nm refresh-from-pane -.Ns -.Li (vi: r) (emacs: r) +.Ic refresh-from-pane +(vi: r) +(emacs: r) .Xc Refresh the content from the pane. .It Xo -.Nm search-again -.Ns -.Li (vi: n) (emacs: n) +.Ic search-again +(vi: n) +(emacs: n) .Xc Repeat the last search. .It Xo -.Nm search-backward -.Ns -.Li (vi: ?) +.Ic search-backward +(vi: ?) .Xc Search backwards for the specified text. .It Xo -.Nm search-forward -.Ns -.Li (vi: /) +.Ic search-forward +(vi: /) .Xc Search forward for the specified text. .It Xo -.Nm select-line -.Ns -.Li (vi: V) +.Ic select-line +(vi: V) .Xc Select the current line. .It Xo -.Nm select-word -.Ns +.Ic select-word .Xc Select the current word. .It Xo -.Nm start-of-line -.Ns -.Li (vi: 0) (emacs: C-a) +.Ic start-of-line +(vi: 0) +(emacs: C-a) .Xc Move the cursor to the start of the line. .It Xo -.Nm top-line -.Ns -.Li (vi: H) (emacs: M-R) +.Ic top-line +(vi: H) +(emacs: M-R) .Xc Move to the top line. .It Xo -.Nm next-prompt -.Ns -.Li (vi: C-n) (emacs: C-n) +.Ic next-prompt +(vi: C-n) +(emacs: C-n) .Xc Move to the next prompt. .It Xo -.Nm previous-prompt -.Ns -.Li (vi: C-p) (emacs: C-p) +.Ic previous-prompt +(vi: C-p) +(emacs: C-p) .Xc Move to the previous prompt. .El From 84936b832f7a2ec1d4b98aad4eb285087a1a2708 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 13 Jul 2023 06:03:48 +0000 Subject: [PATCH 17/19] Use 8 for underscore colour defaults instead of 0 which is less confusing, and fix writing tge default colour. GitHub issue 3627. --- grid.c | 10 +++++----- input.c | 2 +- tty.c | 7 ++++--- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/grid.c b/grid.c index 014e8b8f..edada819 100644 --- a/grid.c +++ b/grid.c @@ -37,7 +37,7 @@ /* Default grid cell data. */ const struct grid_cell grid_default_cell = { - { { ' ' }, 0, 1, 1 }, 0, 0, 8, 8, 0, 0 + { { ' ' }, 0, 1, 1 }, 0, 0, 8, 8, 8, 0 }; /* @@ -45,12 +45,12 @@ const struct grid_cell grid_default_cell = { * appears in the grid - because of this, they are always extended cells. */ static const struct grid_cell grid_padding_cell = { - { { '!' }, 0, 0, 0 }, 0, GRID_FLAG_PADDING, 8, 8, 0, 0 + { { '!' }, 0, 0, 0 }, 0, GRID_FLAG_PADDING, 8, 8, 8, 0 }; /* Cleared grid cell data. */ static const struct grid_cell grid_cleared_cell = { - { { ' ' }, 0, 1, 1 }, 0, GRID_FLAG_CLEARED, 8, 8, 0, 0 + { { ' ' }, 0, 1, 1 }, 0, GRID_FLAG_CLEARED, 8, 8, 8, 0 }; static const struct grid_cell_entry grid_cleared_entry = { { .data = { 0, 8, 8, ' ' } }, GRID_FLAG_CLEARED @@ -528,7 +528,7 @@ grid_get_cell1(struct grid_line *gl, u_int px, struct grid_cell *gc) gc->bg = gce->data.bg; if (gce->flags & GRID_FLAG_BG256) gc->bg |= COLOUR_FLAG_256; - gc->us = 0; + gc->us = 8; utf8_set(&gc->data, gce->data.data); gc->link = 0; } @@ -956,7 +956,7 @@ grid_string_cells_code(const struct grid_cell *lastgc, for (i = 0; i < nitems(attrs); i++) { if (((~attr & attrs[i].mask) && (lastattr & attrs[i].mask)) || - (lastgc->us != 0 && gc->us == 0)) { + (lastgc->us != 8 && gc->us == 8)) { s[n++] = 0; lastattr &= GRID_ATTR_CHARSET; break; diff --git a/input.c b/input.c index ee31b7e1..5f2cac46 100644 --- a/input.c +++ b/input.c @@ -2186,7 +2186,7 @@ input_csi_dispatch_sgr(struct input_ctx *ictx) gc->attr &= ~GRID_ATTR_OVERLINE; break; case 59: - gc->us = 0; + gc->us = 8; break; case 90: case 91: diff --git a/tty.c b/tty.c index e34b186a..ad4a110a 100644 --- a/tty.c +++ b/tty.c @@ -2815,9 +2815,10 @@ tty_check_us(__unused struct tty *tty, struct colour_palette *palette, } /* Underscore colour is set as RGB so convert. */ - gc->us = colour_force_rgb (gc->us); - if (gc->us == -1) + if ((c = colour_force_rgb (gc->us)) == -1) gc->us = 8; + else + gc->us = c; } static void @@ -2892,7 +2893,7 @@ tty_colours_us(struct tty *tty, const struct grid_cell *gc) u_char r, g, b; /* Clear underline colour. */ - if (gc->us == 0) { + if (COLOUR_DEFAULT(gc->us)) { tty_putcode(tty, TTYC_OL); goto save; } From 2f74e811f12a3d5d2e61789dbd184a23849e8cce Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 14 Jul 2023 19:32:59 +0000 Subject: [PATCH 18/19] Set extended keys flag again after reset, from Eric T Johnson. --- screen-write.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/screen-write.c b/screen-write.c index 8a440052..d7c196e1 100644 --- a/screen-write.c +++ b/screen-write.c @@ -326,7 +326,9 @@ screen_write_reset(struct screen_write_ctx *ctx) screen_reset_tabs(s); screen_write_scrollregion(ctx, 0, 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; screen_write_clearscreen(ctx, 8); screen_write_set_cursor(ctx, 0, 0); From b13c2307497c1d905c07e7c21cd78b2c223fa4ee Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 19 Jul 2023 13:03:36 +0000 Subject: [PATCH 19/19] Correct visited flag when the last window list is rebuilt by renumbering windows, appears to fix hang reported by Mark Kelly. --- session.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/session.c b/session.c index c9a98d23..de3f336f 100644 --- a/session.c +++ b/session.c @@ -739,9 +739,12 @@ session_renumber_windows(struct session *s) memcpy(&old_lastw, &s->lastw, sizeof old_lastw); TAILQ_INIT(&s->lastw); TAILQ_FOREACH(wl, &old_lastw, sentry) { + wl->flags &= ~WINLINK_VISITED; wl_new = winlink_find_by_window(&s->windows, wl->window); - if (wl_new != NULL) + if (wl_new != NULL) { TAILQ_INSERT_TAIL(&s->lastw, wl_new, sentry); + wl_new->flags |= WINLINK_VISITED; + } } /* Set the current window. */