From 68dc9af9ac1a8ea332c82fd510b01c46602fa03a Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 31 Aug 2022 08:07:05 +0000 Subject: [PATCH 01/13] Fix window size report, from Vincent Bernat. --- input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/input.c b/input.c index d8b334de..37d64218 100644 --- a/input.c +++ b/input.c @@ -1899,7 +1899,7 @@ input_csi_dispatch_winops(struct input_ctx *ictx) } break; case 18: - input_reply(ictx, "\033[8;%u;%ut", x, y); + input_reply(ictx, "\033[8;%u;%ut", y, x); break; default: log_debug("%s: unknown '%c'", __func__, ictx->ch); From 0a0ded32685edafe934b767e6df9d218e227eb95 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 7 Sep 2022 07:28:26 +0100 Subject: [PATCH 02/13] Regress typos. --- regress/conf/2eae5d47049c1f6d0bef3db4e171aed7.conf | 2 +- regress/conf/a46e6e84cd1071105aa807256dbc158d.conf | 2 +- regress/conf/ad21dbb0893240563ddfdd954b9903a1.conf | 2 +- regress/conf/b9f0ce1976ec62ec60dc5da7dd92c160.conf | 6 +++--- regress/conf/e2661d67d0d45a8647fb95de76ec8174.conf | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/regress/conf/2eae5d47049c1f6d0bef3db4e171aed7.conf b/regress/conf/2eae5d47049c1f6d0bef3db4e171aed7.conf index c09adc24..c3a4da4b 100644 --- a/regress/conf/2eae5d47049c1f6d0bef3db4e171aed7.conf +++ b/regress/conf/2eae5d47049c1f6d0bef3db4e171aed7.conf @@ -12,7 +12,7 @@ set-window-option -g pane-base-index 1 unbind ^B bind ^B select-pane -t :.+ -# Reload config wtih a key +# Reload config with a key bind-key r source-file ~/.tmux.conf \; display "Config reloaded!" # Mouse works as expected diff --git a/regress/conf/a46e6e84cd1071105aa807256dbc158d.conf b/regress/conf/a46e6e84cd1071105aa807256dbc158d.conf index bfbb2d3e..d8fd9d20 100644 --- a/regress/conf/a46e6e84cd1071105aa807256dbc158d.conf +++ b/regress/conf/a46e6e84cd1071105aa807256dbc158d.conf @@ -24,7 +24,7 @@ set-option -g default-terminal 'screen-256color' # allow Vim to receive focus events from terminal window set-option -g focus-events on -# allow Vim to recieve modifier keys: Shift, Control, Alt +# allow Vim to receive modifier keys: Shift, Control, Alt set-window-option -g xterm-keys on # prevent tmux from catching modifier keys meant for Vim diff --git a/regress/conf/ad21dbb0893240563ddfdd954b9903a1.conf b/regress/conf/ad21dbb0893240563ddfdd954b9903a1.conf index 27d8f310..0c41caa4 100644 --- a/regress/conf/ad21dbb0893240563ddfdd954b9903a1.conf +++ b/regress/conf/ad21dbb0893240563ddfdd954b9903a1.conf @@ -552,7 +552,7 @@ setw -g status-keys emacs # Changelog: https://github.com/tmux/tmux/blob/master/CHANGES # style colors: default, black, red, green, yellow, blue, magenta, cyan, white, -# colour0-colour255, hexdecimal RGB string '#ffffff' +# colour0-colour255, hexadecimal RGB string '#ffffff' # Use $SCRIPTS/bash/256-colors.sh to figure out the color number you want # style attributes: none, bold/bright, dim, underscore, blink, reverse, hidden, # or italics diff --git a/regress/conf/b9f0ce1976ec62ec60dc5da7dd92c160.conf b/regress/conf/b9f0ce1976ec62ec60dc5da7dd92c160.conf index 0a878369..845002c2 100644 --- a/regress/conf/b9f0ce1976ec62ec60dc5da7dd92c160.conf +++ b/regress/conf/b9f0ce1976ec62ec60dc5da7dd92c160.conf @@ -1,6 +1,6 @@ -# none of these attempts worked, to bind keys, except sometimes during the sesssion. Oh well. +# none of these attempts worked, to bind keys, except sometimes during the session. Oh well. # I thought maybe that was because F1 is handled differently in a console than in X, but -# even just C-1 didnt work. Using just "a" or "x" as the key did, but not yet sure why not "C-". +# even just C-1 didn't work. Using just "a" or "x" as the key did, but not yet sure why not "C-". #bind-key -T root C-1 attach-session -t$0 #But this one works now, only picks the wrong one? Mbe need2understand what "$1" or $0 mean, better, #but with the stub maybe this doesn't matter: @@ -47,7 +47,7 @@ select-window -t :=3 #$3 for email (mutt) new-session sula new-window sula ; send-keys mutt Enter -#nah, probly betr not?: +#nah, probably better not?: #send-keys -l z #send-keys -l "thepassifdecide" #send-keys Enter diff --git a/regress/conf/e2661d67d0d45a8647fb95de76ec8174.conf b/regress/conf/e2661d67d0d45a8647fb95de76ec8174.conf index 79f46df1..3cf1ae9d 100644 --- a/regress/conf/e2661d67d0d45a8647fb95de76ec8174.conf +++ b/regress/conf/e2661d67d0d45a8647fb95de76ec8174.conf @@ -63,7 +63,7 @@ bind N command-prompt -p hosts: 'run-shell -b "bash -c \"~/lbin/nw %% >/dev/null #05:59 < Celti> annihilannic: I believe the #{pane_in_mode} format does what you want #05:59 < Celti> put it in your statusline #05:59 < Celti> annihilannic: No, my mistake, I should have read farther down, you want #{pane_synchronized} -# only works in tmux 2.0?, higher than 1.6.3 anyawy +# only works in tmux 2.0?, higher than 1.6.3 anyway set-option -g window-status-format ' #I:#W#F#{?pane_synchronized,S,}' #set-option -g window-status-current-format ' #I:#W#{?pane_synchronized,[sync],}#F' # to highlight in red when sync is on... not sure why I did this with set-window-option instead of set-option, perhaps From f03c3ca6c36cd52ae5ec4ae8cd4fa137cf79aaf3 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 9 Sep 2022 11:02:23 +0000 Subject: [PATCH 03/13] Add message-line option to control where message and prompt go, from Varun Kumar E in GitHub issue 3324. --- options-table.c | 13 ++++++++++++- status.c | 37 ++++++++++++++++++++++++++++--------- tmux.1 | 4 ++++ 3 files changed, 44 insertions(+), 10 deletions(-) diff --git a/options-table.c b/options-table.c index 377835bb..6fc5a96f 100644 --- a/options-table.c +++ b/options-table.c @@ -42,6 +42,9 @@ static const char *options_table_clock_mode_style_list[] = { static const char *options_table_status_list[] = { "off", "on", "2", "3", "4", "5", NULL }; +static const char *options_table_message_line_list[] = { + "0", "1", "2", "3", "4", NULL +}; static const char *options_table_status_keys_list[] = { "emacs", "vi", NULL }; @@ -542,13 +545,21 @@ const struct options_table_entry options_table[] = { "'mode-keys' is set to 'vi'." }, + { .name = "message-line", + .type = OPTIONS_TABLE_CHOICE, + .scope = OPTIONS_TABLE_SESSION, + .choices = options_table_message_line_list, + .default_num = 0, + .text = "Position (line) of messages and the command prompt." + }, + { .name = "message-style", .type = OPTIONS_TABLE_STRING, .scope = OPTIONS_TABLE_SESSION, .default_str = "bg=yellow,fg=black", .flags = OPTIONS_TABLE_IS_STYLE, .separator = ",", - .text = "Style of the command prompt." + .text = "Style of messages and the command prompt." }, { .name = "mouse", diff --git a/status.c b/status.c index 929276d2..baf6ed2b 100644 --- a/status.c +++ b/status.c @@ -263,6 +263,17 @@ status_line_size(struct client *c) return (s->statuslines); } +/* Get the prompt line number for client's session. 1 means at the bottom. */ +static u_int +status_prompt_line_at(struct client *c) +{ + struct session *s = c->session; + + if (c->flags & (CLIENT_STATUSOFF|CLIENT_CONTROL)) + return (1); + return (options_get_number(s->options, "status-prompt-line")); +} + /* Get window at window list position. */ struct style_range * status_get_range(struct client *c, u_int x, u_int y) @@ -533,7 +544,7 @@ status_message_redraw(struct client *c) struct session *s = c->session; struct screen old_screen; size_t len; - u_int lines, offset; + u_int lines, offset, messageline; struct grid_cell gc; struct format_tree *ft; @@ -546,6 +557,10 @@ status_message_redraw(struct client *c) lines = 1; screen_init(sl->active, c->tty.sx, lines, 0); + messageline = status_prompt_line_at(c); + if (messageline > lines - 1) + messageline = lines - 1; + len = screen_write_strlen("%s", c->message_string); if (len > c->tty.sx) len = c->tty.sx; @@ -555,11 +570,11 @@ status_message_redraw(struct client *c) format_free(ft); screen_write_start(&ctx, sl->active); - screen_write_fast_copy(&ctx, &sl->screen, 0, 0, c->tty.sx, lines - 1); - screen_write_cursormove(&ctx, 0, lines - 1, 0); + screen_write_fast_copy(&ctx, &sl->screen, 0, 0, c->tty.sx, lines); + screen_write_cursormove(&ctx, 0, messageline, 0); for (offset = 0; offset < c->tty.sx; offset++) screen_write_putc(&ctx, &gc, ' '); - screen_write_cursormove(&ctx, 0, lines - 1, 0); + screen_write_cursormove(&ctx, 0, messageline, 0); if (c->message_ignore_styles) screen_write_nputs(&ctx, len, &gc, "%s", c->message_string); else @@ -695,7 +710,7 @@ status_prompt_redraw(struct client *c) struct session *s = c->session; struct screen old_screen; u_int i, lines, offset, left, start, width; - u_int pcursor, pwidth; + u_int pcursor, pwidth, promptline; struct grid_cell gc, cursorgc; struct format_tree *ft; @@ -708,6 +723,10 @@ status_prompt_redraw(struct client *c) lines = 1; screen_init(sl->active, c->tty.sx, lines, 0); + promptline = status_prompt_line_at(c); + if (promptline > lines - 1) + promptline = lines - 1; + ft = format_create_defaults(NULL, c, NULL, NULL, NULL); if (c->prompt_mode == PROMPT_COMMAND) style_apply(&gc, s->options, "message-command-style", ft); @@ -723,13 +742,13 @@ status_prompt_redraw(struct client *c) start = c->tty.sx; screen_write_start(&ctx, sl->active); - screen_write_fast_copy(&ctx, &sl->screen, 0, 0, c->tty.sx, lines - 1); - screen_write_cursormove(&ctx, 0, lines - 1, 0); + screen_write_fast_copy(&ctx, &sl->screen, 0, 0, c->tty.sx, lines); + screen_write_cursormove(&ctx, 0, promptline, 0); for (offset = 0; offset < c->tty.sx; offset++) screen_write_putc(&ctx, &gc, ' '); - screen_write_cursormove(&ctx, 0, lines - 1, 0); + screen_write_cursormove(&ctx, 0, promptline, 0); format_draw(&ctx, &gc, start, c->prompt_string, NULL, 0); - screen_write_cursormove(&ctx, start, lines - 1, 0); + screen_write_cursormove(&ctx, start, promptline, 0); left = c->tty.sx - start; if (left == 0) diff --git a/tmux.1 b/tmux.1 index bf72cc0c..485b5d3a 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3873,6 +3873,10 @@ For how to specify see the .Sx STYLES section. +.It Xo Ic message-line +.Op Ic 0 | 1 | 2 | 3 | 4 +.Xc +Set line on which status line messages and the command prompt are shown. .It Ic message-style Ar style Set status line message style. This is used for messages and for the command prompt. From 9ab1ba36cd2de4ca83694c3d475061323ffcc4d4 Mon Sep 17 00:00:00 2001 From: nicm Date: Sat, 10 Sep 2022 17:01:33 +0000 Subject: [PATCH 04/13] Use correct option name. --- status.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/status.c b/status.c index baf6ed2b..b504bbbe 100644 --- a/status.c +++ b/status.c @@ -271,7 +271,7 @@ status_prompt_line_at(struct client *c) if (c->flags & (CLIENT_STATUSOFF|CLIENT_CONTROL)) return (1); - return (options_get_number(s->options, "status-prompt-line")); + return (options_get_number(s->options, "message-line")); } /* Get window at window list position. */ From a2cc601c3d1a569037ccd238b2638b5c416baca8 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 12 Sep 2022 12:02:17 +0000 Subject: [PATCH 05/13] Don't use options from pane if pane is NULL. --- input.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/input.c b/input.c index 37d64218..8b174769 100644 --- a/input.c +++ b/input.c @@ -2242,7 +2242,6 @@ static int input_dcs_dispatch(struct input_ctx *ictx) { struct window_pane *wp = ictx->wp; - struct options *oo = wp->options; struct screen_write_ctx *sctx = &ictx->ctx; u_char *buf = ictx->input_buf; size_t len = ictx->input_len; @@ -2254,7 +2253,8 @@ input_dcs_dispatch(struct input_ctx *ictx) return (0); if (ictx->flags & INPUT_DISCARD) return (0); - allow_passthrough = options_get_number(oo, "allow-passthrough"); + allow_passthrough = options_get_number(wp->options, + "allow-passthrough"); if (!allow_passthrough) return (0); log_debug("%s: \"%s\"", __func__, buf); From 19344ec890e0c4343e3c20695806d482c631d67c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 19 Sep 2022 07:03:17 +0100 Subject: [PATCH 06/13] Add headers and fix type, from Marvin Schmidt. GitHub issue 3332. --- compat/systemd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compat/systemd.c b/compat/systemd.c index 7317e43a..9a3adbb3 100644 --- a/compat/systemd.c +++ b/compat/systemd.c @@ -21,6 +21,8 @@ #include +#include + #include "tmux.h" int @@ -29,7 +31,7 @@ systemd_create_socket(int flags, char **cause) int fds; int fd; struct sockaddr_un sa; - int addrlen = sizeof sa; + socklen_t addrlen = sizeof sa; fds = sd_listen_fds(0); if (fds > 1) { /* too many file descriptors */ From 9cc8e40aa08ff91bc1c5d0211c1d2cef02f2c7a2 Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 28 Sep 2022 07:55:29 +0000 Subject: [PATCH 07/13] Add a -T flag to capture-pane to stop at the last used cell instead of the full width. Restore the previous behaviour by making it default to off unless -J is used (the only time it matters). Fixes mosh unit tests; GitHub issue 3339. --- cmd-capture-pane.c | 18 ++++++---- grid-view.c | 2 +- grid.c | 86 ++++++++++++++++++++++++++-------------------- tmux.h | 11 +++++- 4 files changed, 70 insertions(+), 47 deletions(-) diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c index 422f87d6..57e9716d 100644 --- a/cmd-capture-pane.c +++ b/cmd-capture-pane.c @@ -40,7 +40,7 @@ const struct cmd_entry cmd_capture_pane_entry = { .alias = "capturep", .args = { "ab:CeE:JNpPqS:t:", 0, 0, NULL }, - .usage = "[-aCeJNpPq] " CMD_BUFFER_USAGE " [-E end-line] " + .usage = "[-aCeJNpPqT] " CMD_BUFFER_USAGE " [-E end-line] " "[-S start-line] " CMD_TARGET_PANE_USAGE, .target = { 't', CMD_FIND_PANE, 0 }, @@ -110,7 +110,7 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item, struct grid *gd; const struct grid_line *gl; struct grid_cell *gc = NULL; - int n, with_codes, escape_c0, join_lines, no_trim; + int n, join_lines, flags = 0; u_int i, sx, top, bottom, tmp; char *cause, *buf, *line; const char *Sflag, *Eflag; @@ -169,15 +169,19 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item, top = tmp; } - with_codes = args_has(args, 'e'); - escape_c0 = args_has(args, 'C'); join_lines = args_has(args, 'J'); - no_trim = args_has(args, 'N'); + if (args_has(args, 'e')) + flags |= GRID_STRING_WITH_SEQUENCES; + if (args_has(args, 'C')) + flags |= GRID_STRING_ESCAPE_SEQUENCES; + if (!join_lines && !args_has(args, 'T')) + flags |= GRID_STRING_EMPTY_CELLS; + if (!join_lines && !args_has(args, 'N')) + flags |= GRID_STRING_TRIM_SPACES; buf = NULL; for (i = top; i <= bottom; i++) { - line = grid_string_cells(gd, 0, i, sx, &gc, with_codes, - escape_c0, !join_lines && !no_trim, wp->screen); + line = grid_string_cells(gd, 0, i, sx, &gc, flags, wp->screen); linelen = strlen(line); buf = cmd_capture_pane_append(buf, len, line, linelen); diff --git a/grid-view.c b/grid-view.c index 689ac4e4..4d687339 100644 --- a/grid-view.c +++ b/grid-view.c @@ -231,5 +231,5 @@ grid_view_string_cells(struct grid *gd, u_int px, u_int py, u_int nx) px = grid_view_x(gd, px); py = grid_view_y(gd, py); - return (grid_string_cells(gd, px, py, nx, NULL, 0, 0, 0, NULL)); + return (grid_string_cells(gd, px, py, nx, NULL, 0, NULL)); } diff --git a/grid.c b/grid.c index b1afd398..58de03a3 100644 --- a/grid.c +++ b/grid.c @@ -861,40 +861,45 @@ grid_string_cells_us(const struct grid_cell *gc, int *values) /* Add on SGR code. */ static void grid_string_cells_add_code(char *buf, size_t len, u_int n, int *s, int *newc, - int *oldc, size_t nnewc, size_t noldc, int escape_c0) + int *oldc, size_t nnewc, size_t noldc, int flags) { u_int i; char tmp[64]; + int reset = (n != 0 && s[0] == 0); - if (nnewc != 0 && - (nnewc != noldc || - memcmp(newc, oldc, nnewc * sizeof newc[0]) != 0 || - (n != 0 && s[0] == 0))) { - if (escape_c0) - strlcat(buf, "\\033[", len); + if (nnewc == 0) + return; /* no code to add */ + if (!reset && + nnewc == noldc && + memcmp(newc, oldc, nnewc * sizeof newc[0]) == 0) + return; /* no reset and colour unchanged */ + if (reset && (newc[0] == 49 || newc[0] == 39)) + return; /* reset and colour default */ + + if (flags & GRID_STRING_ESCAPE_SEQUENCES) + strlcat(buf, "\\033[", len); + else + strlcat(buf, "\033[", len); + for (i = 0; i < nnewc; i++) { + if (i + 1 < nnewc) + xsnprintf(tmp, sizeof tmp, "%d;", newc[i]); else - strlcat(buf, "\033[", len); - for (i = 0; i < nnewc; i++) { - if (i + 1 < nnewc) - xsnprintf(tmp, sizeof tmp, "%d;", newc[i]); - else - xsnprintf(tmp, sizeof tmp, "%d", newc[i]); - strlcat(buf, tmp, len); - } - strlcat(buf, "m", len); + xsnprintf(tmp, sizeof tmp, "%d", newc[i]); + strlcat(buf, tmp, len); } + strlcat(buf, "m", len); } static int grid_string_cells_add_hyperlink(char *buf, size_t len, const char *id, - const char *uri, int escape_c0) + const char *uri, int flags) { char *tmp; if (strlen(uri) + strlen(id) + 17 >= len) return (0); - if (escape_c0) + if (flags & GRID_STRING_ESCAPE_SEQUENCES) strlcat(buf, "\\033]8;", len); else strlcat(buf, "\033]8;", len); @@ -905,7 +910,7 @@ grid_string_cells_add_hyperlink(char *buf, size_t len, const char *id, } else strlcat(buf, ";", len); strlcat(buf, uri, len); - if (escape_c0) + if (flags & GRID_STRING_ESCAPE_SEQUENCES) strlcat(buf, "\\033\\\\", len); else strlcat(buf, "\033\\", len); @@ -918,7 +923,7 @@ grid_string_cells_add_hyperlink(char *buf, size_t len, const char *id, */ static void grid_string_cells_code(const struct grid_cell *lastgc, - const struct grid_cell *gc, char *buf, size_t len, int escape_c0, + const struct grid_cell *gc, char *buf, size_t len, int flags, struct screen *sc, int *has_link) { int oldc[64], newc[64], s[128]; @@ -927,7 +932,7 @@ grid_string_cells_code(const struct grid_cell *lastgc, char tmp[64]; const char *uri, *id; - struct { + static const struct { u_int mask; u_int code; } attrs[] = { @@ -966,7 +971,7 @@ grid_string_cells_code(const struct grid_cell *lastgc, /* Write the attributes. */ *buf = '\0'; if (n > 0) { - if (escape_c0) + if (flags & GRID_STRING_ESCAPE_SEQUENCES) strlcat(buf, "\\033[", len); else strlcat(buf, "\033[", len); @@ -988,29 +993,29 @@ grid_string_cells_code(const struct grid_cell *lastgc, nnewc = grid_string_cells_fg(gc, newc); noldc = grid_string_cells_fg(lastgc, oldc); grid_string_cells_add_code(buf, len, n, s, newc, oldc, nnewc, noldc, - escape_c0); + flags); /* If the background colour changed, append its parameters. */ nnewc = grid_string_cells_bg(gc, newc); noldc = grid_string_cells_bg(lastgc, oldc); grid_string_cells_add_code(buf, len, n, s, newc, oldc, nnewc, noldc, - escape_c0); + flags); /* If the underscore colour changed, append its parameters. */ nnewc = grid_string_cells_us(gc, newc); noldc = grid_string_cells_us(lastgc, oldc); grid_string_cells_add_code(buf, len, n, s, newc, oldc, nnewc, noldc, - escape_c0); + flags); /* Append shift in/shift out if needed. */ if ((attr & GRID_ATTR_CHARSET) && !(lastattr & GRID_ATTR_CHARSET)) { - if (escape_c0) + if (flags & GRID_STRING_ESCAPE_SEQUENCES) strlcat(buf, "\\016", len); /* SO */ else strlcat(buf, "\016", len); /* SO */ } if (!(attr & GRID_ATTR_CHARSET) && (lastattr & GRID_ATTR_CHARSET)) { - if (escape_c0) + if (flags & GRID_STRING_ESCAPE_SEQUENCES) strlcat(buf, "\\017", len); /* SI */ else strlcat(buf, "\017", len); /* SI */ @@ -1020,10 +1025,10 @@ grid_string_cells_code(const struct grid_cell *lastgc, if (sc != NULL && sc->hyperlinks != NULL && lastgc->link != gc->link) { if (hyperlinks_get(sc->hyperlinks, gc->link, &uri, &id, NULL)) { *has_link = grid_string_cells_add_hyperlink(buf, len, - id, uri, escape_c0); + id, uri, flags); } else if (*has_link) { grid_string_cells_add_hyperlink(buf, len, "", "", - escape_c0); + flags); *has_link = 0; } } @@ -1032,15 +1037,14 @@ grid_string_cells_code(const struct grid_cell *lastgc, /* Convert cells into a string. */ char * grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx, - struct grid_cell **lastgc, int with_codes, int escape_c0, int trim, - struct screen *s) + struct grid_cell **lastgc, int flags, struct screen *s) { struct grid_cell gc; static struct grid_cell lastgc1; const char *data; char *buf, code[8192]; size_t len, off, size, codelen; - u_int xx, has_link = 0; + u_int xx, has_link = 0, end; const struct grid_line *gl; if (lastgc != NULL && *lastgc == NULL) { @@ -1053,16 +1057,20 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx, off = 0; gl = grid_peek_line(gd, py); + if (flags & GRID_STRING_EMPTY_CELLS) + end = gl->cellsize; + else + end = gl->cellused; for (xx = px; xx < px + nx; xx++) { - if (gl == NULL || xx >= gl->cellused) + if (gl == NULL || xx >= end) break; grid_get_cell(gd, xx, py, &gc); if (gc.flags & GRID_FLAG_PADDING) continue; - if (with_codes) { + if (flags & GRID_STRING_WITH_SEQUENCES) { grid_string_cells_code(*lastgc, &gc, code, sizeof code, - escape_c0, s, &has_link); + flags, s, &has_link); codelen = strlen(code); memcpy(*lastgc, &gc, sizeof **lastgc); } else @@ -1070,7 +1078,9 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx, data = gc.data.data; size = gc.data.size; - if (escape_c0 && size == 1 && *data == '\\') { + if ((flags & GRID_STRING_ESCAPE_SEQUENCES) && + size == 1 && + *data == '\\') { data = "\\\\"; size = 2; } @@ -1090,7 +1100,7 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx, if (has_link) { grid_string_cells_add_hyperlink(code, sizeof code, "", "", - escape_c0); + flags); codelen = strlen(code); while (len < off + size + codelen + 1) { buf = xreallocarray(buf, 2, len); @@ -1100,7 +1110,7 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx, off += codelen; } - if (trim) { + if (flags & GRID_STRING_TRIM_SPACES) { while (off > 0 && buf[off - 1] == ' ') off--; } diff --git a/tmux.h b/tmux.h index 9b43e0fd..77019edc 100644 --- a/tmux.h +++ b/tmux.h @@ -667,6 +667,14 @@ struct colour_palette { #define GRID_LINE_EXTENDED 0x2 #define GRID_LINE_DEAD 0x4 +/* Grid string flags. */ +#define GRID_STRING_WITH_SEQUENCES 0x1 +#define GRID_STRING_ESCAPE_SEQUENCES 0x2 +#define GRID_STRING_TRIM_SPACES 0x4 +#define GRID_STRING_USED_ONLY 0x8 +#define GRID_STRING_EMPTY_CELLS 0x10 + +/* Cell positions. */ #define CELL_INSIDE 0 #define CELL_TOPBOTTOM 1 #define CELL_LEFTRIGHT 2 @@ -681,6 +689,7 @@ struct colour_palette { #define CELL_JOIN 11 #define CELL_OUTSIDE 12 +/* Cell borders. */ #define CELL_BORDERS " xqlkmjwvtun~" #define SIMPLE_BORDERS " |-+++++++++." #define PADDED_BORDERS " " @@ -2783,7 +2792,7 @@ void grid_clear_lines(struct grid *, u_int, u_int, u_int); void grid_move_lines(struct grid *, u_int, u_int, u_int, u_int); void grid_move_cells(struct grid *, u_int, u_int, u_int, u_int, u_int); char *grid_string_cells(struct grid *, u_int, u_int, u_int, - struct grid_cell **, int, int, int, struct screen *); + struct grid_cell **, int, struct screen *); void grid_duplicate_lines(struct grid *, u_int, struct grid *, u_int, u_int); void grid_reflow(struct grid *, u_int); From a10452be2d84d4ff1b9d4e636627b7a9c5a2c42a Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 28 Sep 2022 07:59:50 +0000 Subject: [PATCH 08/13] Add scroll-top and scroll-bottom commands to scroll so cursor is at top or bottom. From Anindya Mukherjee, GitHub issue 3334. --- tmux.1 | 11 ++++++++-- window-copy.c | 56 +++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 59 insertions(+), 8 deletions(-) diff --git a/tmux.1 b/tmux.1 index 485b5d3a..5e896902 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1808,7 +1808,9 @@ The following commands are supported in copy mode: .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 "" @@ -2011,7 +2013,7 @@ but a different format may be specified with .Fl F . .Tg capturep .It Xo Ic capture-pane -.Op Fl aepPqCJN +.Op Fl aAepPqCJN .Op Fl b Ar buffer-name .Op Fl E Ar end-line .Op Fl S Ar start-line @@ -2036,10 +2038,15 @@ is given, the output includes escape sequences for text and background attributes. .Fl C also escapes non-printable characters as octal \exxx. +.Fl T +ignores trailing positions that do not contain a character. .Fl N preserves trailing spaces at each line's end and .Fl J -preserves trailing spaces and joins any wrapped lines. +preserves trailing spaces and joins any wrapped lines; +.Fl J +implies +.Fl T . .Fl P captures only any output that the pane has received that is the beginning of an as-yet incomplete escape sequence. diff --git a/window-copy.c b/window-copy.c index 743364d6..ed481d70 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1250,20 +1250,23 @@ window_copy_cmd_cursor_right(struct window_copy_cmd_state *cs) return (WINDOW_COPY_CMD_NOTHING); } +/* Scroll line containing the cursor to the given position. */ static enum window_copy_cmd_action -window_copy_cmd_scroll_middle(struct window_copy_cmd_state *cs) +window_copy_cmd_scroll_to(struct window_copy_cmd_state *cs, u_int to) { struct window_mode_entry *wme = cs->wme; struct window_copy_mode_data *data = wme->data; - u_int mid_value, oy, delta; + u_int oy, delta; int scroll_up; /* >0 up, <0 down */ - mid_value = (screen_size_y(&data->screen) - 1) / 2; - scroll_up = data->cy - mid_value; + scroll_up = data->cy - to; delta = abs(scroll_up); - oy = screen_hsize(data->backing) + data->cy - data->oy; + oy = screen_hsize(data->backing) - data->oy; - log_debug ("XXX %u %u %u %d %u", mid_value, oy, delta, scroll_up, data->oy); + /* + * oy is the maximum scroll down amount, while data->oy is the maximum + * scroll up amount. + */ if (scroll_up > 0 && data->oy >= delta) { window_copy_scroll_up(wme, delta); data->cy -= delta; @@ -1276,6 +1279,35 @@ window_copy_cmd_scroll_middle(struct window_copy_cmd_state *cs) return (WINDOW_COPY_CMD_REDRAW); } +/* Scroll line containing the cursor to the bottom. */ +static enum window_copy_cmd_action +window_copy_cmd_scroll_bottom(struct window_copy_cmd_state *cs) +{ + struct window_copy_mode_data *data = cs->wme->data; + u_int bottom; + + bottom = screen_size_y(&data->screen) - 1; + return (window_copy_cmd_scroll_to(cs, bottom)); +} + +/* Scroll line containing the cursor to the middle. */ +static enum window_copy_cmd_action +window_copy_cmd_scroll_middle(struct window_copy_cmd_state *cs) +{ + struct window_copy_mode_data *data = cs->wme->data; + u_int mid_value; + + mid_value = (screen_size_y(&data->screen) - 1) / 2; + return (window_copy_cmd_scroll_to(cs, mid_value)); +} + +/* Scroll line containing the cursor to the top. */ +static enum window_copy_cmd_action +window_copy_cmd_scroll_top(struct window_copy_cmd_state *cs) +{ + return (window_copy_cmd_scroll_to(cs, 0)); +} + static enum window_copy_cmd_action window_copy_cmd_cursor_up(struct window_copy_cmd_state *cs) { @@ -2794,6 +2826,12 @@ static const struct { .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .f = window_copy_cmd_refresh_from_pane }, + { .command = "scroll-bottom", + .minargs = 0, + .maxargs = 0, + .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, + .f = window_copy_cmd_scroll_bottom + }, { .command = "scroll-down", .minargs = 0, .maxargs = 0, @@ -2812,6 +2850,12 @@ static const struct { .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .f = window_copy_cmd_scroll_middle }, + { .command = "scroll-top", + .minargs = 0, + .maxargs = 0, + .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, + .f = window_copy_cmd_scroll_top + }, { .command = "scroll-up", .minargs = 0, .maxargs = 0, From ff2766b024e6657b5f5f70dfd5acdb32085d7b70 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 17 Oct 2022 10:59:42 +0000 Subject: [PATCH 09/13] Preserve marked pane when renumbering windows. --- session.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/session.c b/session.c index 5bc5330e..c9a98d23 100644 --- a/session.c +++ b/session.c @@ -710,7 +710,7 @@ session_renumber_windows(struct session *s) struct winlink *wl, *wl1, *wl_new; struct winlinks old_wins; struct winlink_stack old_lastw; - int new_idx, new_curw_idx; + int new_idx, new_curw_idx, marked_idx = -1; /* Save and replace old window list. */ memcpy(&old_wins, &s->windows, sizeof old_wins); @@ -727,6 +727,8 @@ session_renumber_windows(struct session *s) winlink_set_window(wl_new, wl->window); wl_new->flags |= wl->flags & WINLINK_ALERTFLAGS; + if (wl == marked_pane.wl) + marked_idx = wl_new->idx; if (wl == s->curw) new_curw_idx = wl_new->idx; @@ -743,6 +745,11 @@ session_renumber_windows(struct session *s) } /* Set the current window. */ + if (marked_idx != -1) { + marked_pane.wl = winlink_find_by_index(&s->windows, marked_idx); + if (marked_pane.wl == NULL) + server_clear_marked(); + } s->curw = winlink_find_by_index(&s->windows, new_curw_idx); /* Free the old winlinks (reducing window references too). */ From 5ce34add77fa3517a01e63b915c5f4e3241af470 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 18 Oct 2022 15:58:06 +0100 Subject: [PATCH 10/13] Do not attempt to connect to the socket as a client if systemd is active, from Julien Moutinho in GitHub issue 3345. --- client.c | 6 ++++++ compat.h | 1 + compat/systemd.c | 6 ++++++ 3 files changed, 13 insertions(+) diff --git a/client.c b/client.c index df6cee94..7f712ffb 100644 --- a/client.c +++ b/client.c @@ -284,6 +284,12 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags, log_debug("flags are %#llx", (unsigned long long)client_flags); /* Initialize the client socket and start the server. */ +#ifdef HAVE_SYSTEMD + if (systemd_activated()) { + /* socket-based activation, do not even try to be a client. */ + fd = server_start(client_proc, flags, base, 0, NULL); + } else +#endif fd = client_connect(base, socket_path, client_flags); if (fd == -1) { if (errno == ECONNREFUSED) { diff --git a/compat.h b/compat.h index 6eb97619..aefc0d38 100644 --- a/compat.h +++ b/compat.h @@ -423,6 +423,7 @@ void *recallocarray(void *, size_t, size_t, size_t); #ifdef HAVE_SYSTEMD /* systemd.c */ +int systemd_activated(void); int systemd_create_socket(int, char **); #endif diff --git a/compat/systemd.c b/compat/systemd.c index 9a3adbb3..cce42ed4 100644 --- a/compat/systemd.c +++ b/compat/systemd.c @@ -25,6 +25,12 @@ #include "tmux.h" +int +systemd_activated(void) +{ + return (sd_listen_fds(0) >= 1); +} + int systemd_create_socket(int flags, char **cause) { From 0fc961b22ee6c7298e8dd40d3ce8e2b484bc6b1d Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 25 Oct 2022 09:04:49 +0000 Subject: [PATCH 11/13] Do not fire redraw callback if NULL. --- screen-write.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/screen-write.c b/screen-write.c index 476fe4dd..a2107f2a 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1505,8 +1505,10 @@ screen_write_fullredraw(struct screen_write_ctx *ctx) screen_write_collect_flush(ctx, 0, __func__); - screen_write_initctx(ctx, &ttyctx, 1); - ttyctx.redraw_cb(&ttyctx); + if (ttyctx.redraw_cb != NULL) { + screen_write_initctx(ctx, &ttyctx, 1); + ttyctx.redraw_cb(&ttyctx); + } } /* Trim collected items. */ @@ -2127,8 +2129,10 @@ screen_write_alternateon(struct screen_write_ctx *ctx, struct grid_cell *gc, screen_write_collect_flush(ctx, 0, __func__); screen_alternate_on(ctx->s, gc, cursor); - screen_write_initctx(ctx, &ttyctx, 1); - ttyctx.redraw_cb(&ttyctx); + if (ttyctx.redraw_cb != NULL) { + screen_write_initctx(ctx, &ttyctx, 1); + ttyctx.redraw_cb(&ttyctx); + } } /* Turn alternate screen off. */ @@ -2145,6 +2149,8 @@ screen_write_alternateoff(struct screen_write_ctx *ctx, struct grid_cell *gc, screen_write_collect_flush(ctx, 0, __func__); screen_alternate_off(ctx->s, gc, cursor); - screen_write_initctx(ctx, &ttyctx, 1); - ttyctx.redraw_cb(&ttyctx); + if (ttyctx.redraw_cb != NULL) { + screen_write_initctx(ctx, &ttyctx, 1); + ttyctx.redraw_cb(&ttyctx); + } } From 2111142cf1715eeac174cd5c71ed90f00595b17e Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 25 Oct 2022 09:12:05 +0000 Subject: [PATCH 12/13] Fix a memory leak, from Japin Li in GitHub issue 3358. --- cmd-parse.y | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd-parse.y b/cmd-parse.y index 1d692770..cdf026f3 100644 --- a/cmd-parse.y +++ b/cmd-parse.y @@ -1086,7 +1086,8 @@ cmd_parse_from_arguments(struct args_value *values, u_int count, arg->type = CMD_PARSE_STRING; arg->string = copy; TAILQ_INSERT_TAIL(&cmd->arguments, arg, entry); - } + } else + free(copy); } else if (values[i].type == ARGS_COMMANDS) { arg = xcalloc(1, sizeof *arg); arg->type = CMD_PARSE_PARSED_COMMANDS; From c2580cfe2466589c8bd9348225820888a3fc4c0a Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 25 Oct 2022 17:53:31 +0000 Subject: [PATCH 13/13] Initialize context before testing it. --- screen-write.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/screen-write.c b/screen-write.c index a2107f2a..24195708 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1505,10 +1505,9 @@ screen_write_fullredraw(struct screen_write_ctx *ctx) screen_write_collect_flush(ctx, 0, __func__); - if (ttyctx.redraw_cb != NULL) { - screen_write_initctx(ctx, &ttyctx, 1); + screen_write_initctx(ctx, &ttyctx, 1); + if (ttyctx.redraw_cb != NULL) ttyctx.redraw_cb(&ttyctx); - } } /* Trim collected items. */ @@ -2129,10 +2128,9 @@ screen_write_alternateon(struct screen_write_ctx *ctx, struct grid_cell *gc, screen_write_collect_flush(ctx, 0, __func__); screen_alternate_on(ctx->s, gc, cursor); - if (ttyctx.redraw_cb != NULL) { - screen_write_initctx(ctx, &ttyctx, 1); + screen_write_initctx(ctx, &ttyctx, 1); + if (ttyctx.redraw_cb != NULL) ttyctx.redraw_cb(&ttyctx); - } } /* Turn alternate screen off. */ @@ -2149,8 +2147,7 @@ screen_write_alternateoff(struct screen_write_ctx *ctx, struct grid_cell *gc, screen_write_collect_flush(ctx, 0, __func__); screen_alternate_off(ctx->s, gc, cursor); - if (ttyctx.redraw_cb != NULL) { - screen_write_initctx(ctx, &ttyctx, 1); + screen_write_initctx(ctx, &ttyctx, 1); + if (ttyctx.redraw_cb != NULL) ttyctx.redraw_cb(&ttyctx); - } }