From 672e89a6407e248bfc0098bbdbea5d6d7dd09401 Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 10 Dec 2025 21:24:43 +0000 Subject: [PATCH] Add a scroll-to-mouse command for copy mode to scroll to the mouse position and bind to the scrollbar, brings the scrollbar keys into line with the other mouse keys. From Michael Grant, GitHub issue 4731. --- key-bindings.c | 6 +++--- tmux.1 | 15 ++++++++++----- window-copy.c | 19 +++++++++++++++++++ 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/key-bindings.c b/key-bindings.c index a5e1f9c8..22e5cf59 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -480,9 +480,9 @@ key_bindings_init(void) "bind -n M-MouseDown3Pane { display-menu -t= -xM -yM -T '#[align=centre]#{pane_index} (#{pane_id})' " DEFAULT_PANE_MENU " }", /* Mouse on scrollbar. */ - "bind -n MouseDown1ScrollbarUp { copy-mode -u }", - "bind -n MouseDown1ScrollbarDown { copy-mode -d }", - "bind -n MouseDrag1ScrollbarSlider { copy-mode -S }", + "bind -n MouseDown1ScrollbarUp { if -Ft= '#{pane_in_mode}' { send -X page-up } {copy-mode -u } }", + "bind -n MouseDown1ScrollbarDown { if -Ft= '#{pane_in_mode}' { send -X page-down } {copy-mode -d } }", + "bind -n MouseDrag1ScrollbarSlider { if -Ft= '#{pane_in_mode}' { send -X scroll-to-mouse } { copy-mode -S } }", /* Copy mode (emacs) keys. */ "bind -Tcopy-mode C-Space { send -X begin-selection }", diff --git a/tmux.1 b/tmux.1 index dac3a648..dc1bfc00 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2211,6 +2211,13 @@ but also exit copy mode if the cursor reaches the bottom. Scroll so that the current line becomes the middle one while keeping the cursor on that line. .It Xo +.Ic scroll-to-mouse +.Xc +Scroll pane in copy-mode when bound to a mouse drag event. +.Fl e +causes copy mode to exit when at the bottom. +.Pp +.It Xo .Ic scroll-top .Xc Scroll down until the current line is at the top while keeping the cursor on @@ -2447,12 +2454,10 @@ cancels copy mode and any other modes. .Fl M begins a mouse drag (only valid if bound to a mouse key binding, see .Sx MOUSE SUPPORT ) . +.Pp .Fl S -scrolls when bound to a mouse drag event; for example, -.Ic copy-mode -Se -is bound to -.Ar MouseDrag1ScrollbarSlider -by default. +enters copy-mode and scrolls when bound to a mouse drag event; See +.Ic scroll-to-mouse . .Pp .Fl s copies from diff --git a/window-copy.c b/window-copy.c index 2d528496..f8700555 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1479,6 +1479,20 @@ window_copy_cmd_scroll_middle(struct window_copy_cmd_state *cs) return (window_copy_cmd_scroll_to(cs, mid_value)); } +/* Scroll the pane to the mouse in the scrollbar. */ +static enum window_copy_cmd_action +window_copy_cmd_scroll_to_mouse(struct window_copy_cmd_state *cs) +{ + struct window_mode_entry *wme = cs->wme; + struct window_pane *wp = wme->wp; + struct client *c = cs->c; + struct mouse_event *m = cs->m; + int scroll_exit = args_has(cs->wargs, 'e'); + + window_copy_scroll(wp, c->tty.mouse_slider_mpos, m->y, scroll_exit); + return (WINDOW_COPY_CMD_NOTHING); +} + /* 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) @@ -3044,6 +3058,11 @@ static const struct { .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .f = window_copy_cmd_scroll_middle }, + { .command = "scroll-to-mouse", + .args = { "e", 0, 0, NULL }, + .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, + .f = window_copy_cmd_scroll_to_mouse + }, { .command = "scroll-top", .args = { "", 0, 0, NULL }, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,