From 6137fd04e98297134ce882b304c51c128f6f76ab Mon Sep 17 00:00:00 2001 From: Michael Grant Date: Mon, 5 Oct 2026 16:55:22 +0100 Subject: [PATCH] Preserve the copy-mode entry column after trailing blanks --- regress/copy-mode-entry-column.sh | 47 ++++++++++++++++++++++++++++- window-copy.c | 49 +++++++++++++++++-------------- 2 files changed, 73 insertions(+), 23 deletions(-) diff --git a/regress/copy-mode-entry-column.sh b/regress/copy-mode-entry-column.sh index 42c614728..6e98ddfd9 100644 --- a/regress/copy-mode-entry-column.sh +++ b/regress/copy-mode-entry-column.sh @@ -137,6 +137,51 @@ x cursor-up check_cursor 7,0 x cancel +# Trailing blanks must not replace the initial preference on the first move. +for entry_line in 'prompt> ' ' '; do + $TMUX respawn-pane -k \ + "printf '\033[H\033[2J'; \ + printf '%s\r\n' ABCDEFGHIJKLMNOPQRST abc ABCDEFGHIJKLMNOPQRST \ + '$entry_line' ABCDEFGHIJKLMNOP ab 01234567890123456789; \ + printf '\033[4;9H'; exec cat" || fail "respawn-pane failed" + wait_cursor 8,3 + for mode in emacs vi; do + $TMUX set-window-option -g mode-keys "$mode" || + fail "set mode-keys failed" + for direction in up down; do + if [ "$direction" = up ]; then + row=2 + end=20 + short=3 + last=0 + else + row=4 + end=16 + short=2 + last=6 + fi + [ "$mode" = emacs ] || end=$((end - 1)) + $TMUX copy-mode || fail "copy-mode failed" + x "cursor-$direction" + check_cursor "$end,$row" + x cancel + + $TMUX copy-mode -c || fail "copy-mode -c failed" + check_cursor 8,3 + x "cursor-$direction" + check_cursor "8,$row" + x "cursor-$direction" + x "cursor-$direction" + if [ "$mode" = emacs ]; then + check_cursor "8,$last" + else + check_cursor "$((short - 1)),$last" + fi + x cancel + done + done +done + # An empty entry line has a numeric column zero with -c. $TMUX respawn-pane -k \ "printf '\033[H\033[2JABCDEFGHIJKLMNOPQRST\033[2;1H'; exec cat" || @@ -172,7 +217,7 @@ done # Initialize before the optional entry-time page movement. $TMUX respawn-pane -k \ "printf '\033[H\033[2JABCDEFGHIJKLMNOPQRST'; \ - printf '\033[9;1Habcdefgh\033[10;1HABCDEFGHIJKLMNOP\033[9;9H'; \ + printf '\033[9;1Hprompt> \033[10;1HABCDEFGHIJKLMNOP\033[9;9H'; \ exec cat" || fail "respawn-pane failed" wait_cursor 8,8 diff --git a/window-copy.c b/window-copy.c index 9bd4b90f6..ed1afb6c1 100644 --- a/window-copy.c +++ b/window-copy.c @@ -106,6 +106,8 @@ static int window_copy_search_down(struct window_mode_entry *, int); static void window_copy_goto_line(struct window_mode_entry *, const char *); static void window_copy_update_cursor(struct window_mode_entry *, u_int, u_int); +static void window_copy_update_preferred_column( + struct window_copy_mode_data *, u_int); static void window_copy_start_selection(struct window_mode_entry *); static int window_copy_mouse_in_selection(struct window_mode_entry *, u_int, u_int, int *, int *); @@ -615,9 +617,9 @@ window_copy_init(struct window_mode_entry *wme, data->cx = cx; if (args_has(args, 'c')) { - /* Start with a preferred column rather than end of line. */ + /* Preserve the entry column on the first vertical move. */ data->lastcx = cx; - data->lastsx = cx + 1; + data->lastsx = UINT_MAX; } if (cy < screen_hsize(data->backing)) { data->cy = 0; @@ -832,10 +834,7 @@ window_copy_scroll1(struct window_mode_entry *wme, struct window_pane *wp, oy = screen_hsize(data->backing) + data->cy - data->oy; ox = window_copy_find_length(wme, oy); - if (data->cx != ox) { - data->lastcx = data->cx; - data->lastsx = ox; - } + window_copy_update_preferred_column(data, ox); data->cx = data->lastcx; if (delta >= 0) { @@ -899,10 +898,7 @@ window_copy_pageup1(struct window_mode_entry *wme, int half_page) oy = screen_hsize(data->backing) + data->cy - data->oy; ox = window_copy_find_length(wme, oy); - if (data->cx != ox) { - data->lastcx = data->cx; - data->lastsx = ox; - } + window_copy_update_preferred_column(data, ox); data->cx = data->lastcx; n = 1; @@ -958,10 +954,7 @@ window_copy_pagedown1(struct window_mode_entry *wme, int half_page, oy = screen_hsize(data->backing) + data->cy - data->oy; ox = window_copy_find_length(wme, oy); - if (data->cx != ox) { - data->lastcx = data->cx; - data->lastsx = ox; - } + window_copy_update_preferred_column(data, ox); data->cx = data->lastcx; n = 1; @@ -6317,6 +6310,22 @@ window_copy_find_length(struct window_mode_entry *wme, u_int py) return (grid_line_length(data->backing->grid, py)); } +static void +window_copy_update_preferred_column(struct window_copy_mode_data *data, + u_int sx) +{ + if (data->lastsx == UINT_MAX) { + /* Treat the entry column as inside a line. */ + data->lastsx = data->lastcx + 1; + if (data->cx == data->lastcx) + return; + } + if (data->cx != sx) { + data->lastcx = data->cx; + data->lastsx = sx; + } +} + static u_int window_copy_cursor_limit(struct window_mode_entry *wme, u_int py, int allow_onemore) @@ -6503,10 +6512,8 @@ window_copy_cursor_up(struct window_mode_entry *wme, int scroll_only) norectsel = data->screen.sel == NULL || !data->rectflag; oy = screen_hsize(data->backing) + data->cy - data->oy; ox = window_copy_find_length(wme, oy); - if (norectsel && data->cx != ox) { - data->lastcx = data->cx; - data->lastsx = ox; - } + if (norectsel) + window_copy_update_preferred_column(data, ox); if (data->lineflag == LINE_SEL_LEFT_RIGHT && oy == data->sely) window_copy_other_end(wme); @@ -6583,10 +6590,8 @@ window_copy_cursor_down(struct window_mode_entry *wme, int scroll_only) norectsel = data->screen.sel == NULL || !data->rectflag; oy = screen_hsize(data->backing) + data->cy - data->oy; ox = window_copy_find_length(wme, oy); - if (norectsel && data->cx != ox) { - data->lastcx = data->cx; - data->lastsx = ox; - } + if (norectsel) + window_copy_update_preferred_column(data, ox); if (data->lineflag == LINE_SEL_RIGHT_LEFT && oy == data->endsely) window_copy_other_end(wme);