1

Edit: this answer is written with respect to Windows Terminal, but I expect it's an issue for xterm more generally.

By default, running tmux in Windows Terminal doesn't show the scroll bar, and doesn't allow you to scroll with the mouse scroll wheel.

As a solution, people often suggest turning on tmux's mouse mode, e.g. by adding set -g mouse on to ~/.tmux.conf. This re-enables scrolling with the mouse scroll wheel but interferes with selecting text and disables right-click-to-paste, and still doesn't enable the right scroll bar.

Fortunately, you can enable native xterm scrolling in tmux by adding set -g terminal-overrides 'xterm*:smcup@:rmcup@' to ~/.tmux.conf, as suggested here and (with a slight variation) here. This restores the usual scrolling behavior. According to the second link, it works by "fooling [tmux] into thinking that the terminal has no 'alternate screen' mode", and xterm* should be replaced by the output of echo $TERM if you're not using xterm.

However, it's glitchy: when attaching to an existing tmux session (tmux a or tmux attach), scrolling up shows you the contents of the parent terminal session from before you attached, instead of the past contents of the tmux session. One of the comments to the first link complains that this solution "doesn't keep the scrollback buffer after a(n) (re)attach" - but that's not actually true, since if you zoom out a bunch (e.g. with Ctrl + mouse wheel) and then zoom in again, you can see the entire past contents of the tmux session, or at least as far back as the number of lines you were able to fit on the screen when you zoomed out. The farther you zoom out, the farther back you're able to scroll when you zoom in.

Is there a way to skip this zoom in/zoom out trick and get Windows Terminal to re-render the entire tmux scrollback buffer when attaching? Honestly, set -g terminal-overrides 'xterm*:smcup@:rmcup@' seems like a hack anyway, so maybe there's a more robust way to re-enable native xterm scrolling?

1 Answer 1

2
+50

After re-attaching, invoke this in a shell in the topmost pane:

tmux capture-pane -pqeS -

I think the above command will populate the scrollback buffer of your terminal only for a top pane that takes the entire width of the terminal. Invoking the command from any other pane makes no sense. In general what you want to do cannot work well with arbitrary layout of panes. And if you select another tmux window then you will need to repeat the command in the topmost pane in the new window, otherwise you will still see the buffer from the old window. This is a misery you get by enforcing a scrollback buffer tmux cannot control fully and easily.

I suppose a terminal emulator that integrates with tmux (using the control mode of tmux, example) may be able to also integrate its scrolling behavior with tmux without tricks. Even then it will probably be limited.

The scrollback buffer you want to use is in general quite simple. It works by saving lines that would otherwise be moved (scrolled) beyond the top edge of the screen and disappear. Programs may rewrite (parts of) the screen, so no new line appears and there is nothing to scroll, nothing to save; or they may at some point write "beyond the bottom", so the terminal emulator scrolls the text automatically and the top line is the one to add to the scrollback buffer. Programs may also try to clear the buffer (it's somewhat complicated). There's not much more they can do to alter the buffer.

Imagine a 2x2 grid of panes in tmux. In theory one could craft content for the scrollback buffer that looks like the history from the two top panes. But if a line is added to the bottom of the top-left pane and the text in the pane needs to scroll, the top line cannot be simply saved in the buffer, because it would also scroll the history of the top-right pane in the buffer. For the buffer to look sane now, it would have to be totally rebuilt, its left half shifted up with respect to the "static" right part. Resizing the panes would also require rebuilding the buffer.

Obviously the two bottom panes cannot sanely save their history in the scrollback buffer of the terminal emulator at all.

It seems tmux, when used with this terminal-overrides trick, acts sanely and (re)writes in a way that only allows lines from the topmost pane of full width (if any) to be saved in the scrollback buffer.

This is the misery you're after. :) Maybe you use tmux only to be able to re-attach to a single pane in a single window. In such case using the scrollback buffer of the terminal emulator may kinda work, after we fix the problem in question.

The following hooks (in .tmux.conf) will try to run capture-pane … automatically:

set-hook -g client-attached        'run-shell -t {top} "tmux capture-pane -t {top} -pqeS - | head -c -1 >\"#{pane_tty}\"'
set-hook -g session-window-changed 'run-shell -t {top} "tmux capture-pane -t {top} -pqeS - | head -c -1 >\"#{pane_tty}\"'

They are not perfect; head -c -1 is not portable; you may want more hooks. Treat them as a proof of concept. I tested in Linux.

Additional notes:

  • If you always use a single window in tmux, then you don't really need this session-window-changed hook. No harm in having it though, just in case you start using more windows in the future.
  • If you always use a single pane per window in tmux, then you can delete all instances of -t {top} from the code. This will be particularly useful if you tmux is old and does not understand -t {top}.
9
  • Yes, I just use a single pane in a single window, good point! Your set-hook solution gives me errors when I launch tmux: .tmux.conf:7: unknown command: top and .tmux.conf:8: unknown command: top.
    – 1''
    Aug 22, 2022 at 23:58
  • @1'' My tmux reports its version as 3.2a. What is the output of tmux -V in your case? Aug 23, 2022 at 0:02
  • @1'' The answer has been expanded. See "additional notes". Do they help? Aug 23, 2022 at 0:21
  • I've got tmux 3.3, the most recent version. I took out all the instances of -t {top}, and it does seem to enable some scrollback! But I'm realizing that the scrolling is still pretty messed up though, even in a new tmux session (regardless of whether your fix is enabled). For instance, I tried for i in {1..100}; do echo $i; done in a new tmux session and the numbers get totally mangled when you scroll up (e.g. 27, 30, 36, 40, 44, 50, 51, 52, ...). Do you get that as well with the Linux terminal emulator you're using?
    – 1''
    Aug 23, 2022 at 3:21
  • 2
    @1'' Don't hurry. Frankly I do wish somebody else will answer and find a better way. I have all the reputation I need, I will gladly take new knowledge instead of the bounty. OTOH I cannot imagine a better way (if I could then I would investigate it in my answer), so I don't expect much. Oh, the nicer the surprise will be. :) Aug 23, 2022 at 6:18

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .