Quick background for anyone who doesn’t use tmux or screen: both are utilities that run in terminal that provide a bunch of nifty functionality. The big ones are:
-
The ability to disconnect from a remote host and reconnect via software like ssh or mosh, leaving the remote programs running. This also ensures that connection loss doesn’t kill off remote programs, making it – in my opinion, at any rate – pretty essential for
ssh
, thoughmosh
has more-limited built-in functionality. -
The ability to have multiple virtual terminals in one. There are a bunch of ways to do this (the Linux kernel has multiple ttys, X11 window managers or Wayland compositors can provide virtual desktops with different graphical virtual terminal programs running on each, and some virtual terminal programs provide a way to run multiple virtual terminals, usually in a tab or something). I prefer this route, though, because among other reasons, it works everywhere.
But they also provide a lot of other handy functionality, including things like file transfer via the terminal (well, screen
does), logging of what the current terminal is receiving, copy-pasting using vi or emacs keybindings, a terminal-level “status bar”, and such.
But I was doing work on my tmux
config, and thought that I’d go over my ~/.tmux.conf
, since it addressed a few things that annoyed me, and I figure that other people might have crashed into. Maybe others could share some of their neat tmux
or screen
stuff, if they’re in the moon:
unbind-key C-b
set-option -g prefix C-o
bind-key C-o send-prefix
This sets tmux
to use “Control-o” as the “prefix key”, which it uses before all other keybindings. Out-of-box, both screen
and tmux
grab keybindings which conflict with very-common emacs
keybindings, C-a
(beginning of line) and C-b
(previous character), respectively. Control-o is only used by (what I’d call) a fairly-obscure emacs feature, which you can still access by hitting Control-o twice. If you use vi keybindings (including in bash
and other programs that use readline, which default to using emacs-style keybindings), probably not necessary. Been using this for many years, ever since screen; it’s apparently a very common problem for new tmux
and screen
users.
set-option -g status-bg black
set-option -g status-fg cyan
By default, tmux
uses black text on a bright green background for the status bar; while this shows up well, for me, at least, this is kind of overwhelming. I prefer light text on a black background, or “dark mode”, as it’s popularly called these days. On some terminals, blue is hard to read out-of-box, and while I generally try to tweak my terminals to get it readable, cyan (bright blue) avoids this.
set-option -g status-left '#I|#H #(cut -d " " -f 1-4 /proc/loadavg)'
set-option -g status-right ""
set-option -g window-status-format ""
set-option -g window-status-current-format ""
The default tmux
configuration follows a convention where, for each “window” one opens, there’s a visual indicator showing a per-window entry. This is a common convention that many GUI programs use (opening a tab per window). Emacs traditionally has not done this, the idea being that you should be able to have many buffers open, that screen space is a limited resource and that if you want to switch the content that you’re looking at, you’re better-off bringing up a full-screen, scrollable list. tmux
can do this with prefix-key w out-of-box. If you have, say, ten open, there isn’t gonna be space to show 'em all. So I pull that out.
I do want to see the host, to ensure that I don’t confuse a tmux
instance running on Host A running ssh
in a window with sshing to Host B and running tmux
there.
Tmux defaults to showing a clock, which I get rid of with the above. I already have a clock on my desktop, and I don’t see much sense in throwing them elsewhere in each terminal. Tmux even defaults to showing a large one if you hit prefix-key t, though I can’t imagine that many people use that.
The current loadavg isn’t essential, but it’s a useful bit of status that tells one immediately whether some program is either still doing work or running away.
I don’t use window names: just numbers; so I hide names. It’s normally obvious from looking at a virtual termainal what something is, and switching by number is faster by keystroke.
set-option -g update-environment "DISPLAY WAYLAND_DISPLAY SWAYSOCK SSH_AUTH_SOCK"
This updates the environment variables in a tmux session when re-attaching. Various programs don’t do well if you detach from one session, log out of a graphical session, and then log in again; this fixes those. DISPLAY
is for X11, WAYLAND_DISPLAY
for Wayland, SWAYSOCK
for the Wayland Sway compositor (if you use that), and SSH_AUTH_SOCK
for ssh-agent
, which remembers a password to unlock an ssh key for a while.
bind-key H pipe-pane -o "exec cat >>$HOME/'tmux-#I.log'" \; display-message "Toggled logging to $HOME/tmux-#I.log"
This sets up tmux
to provide functionality that screen
has out-of-box – if you trigger it, it will start logging the output of the current console to a logfile in your home directory. Useful when you’ve already started a program and it’s spitting out information that you need a copy of, or if you want it to not disable color output (something that many programs do when they detect that their output is connected to a pipe rather than a tty); with my settings, Control-o H will toggle logging for a given window.
# emacs-style keys
bind-key C-n next-window
bind-key C-p previous-window
set -g mode-keys emacs
set -g status-keys emacs
I like emacs
-style keys rather than vi
-style.
bind-key C-c new-window -c "#{pane_current_path}"
While tmux has a default keybinding (prefix-key c) to create a new window at the current working directory that tmux was started at, it has no binding to start a new window at the current working directory being viewed in a window at the moment, something I frequently want to do – this makes prefix-key Control-c open a new shell at that point.
set -g visual-bell on
Beeping is obnoxious and in an open environment, can be disruptive to other people; many people switched to having their terminal flash rather than beep years back; many programs supported “visual bell”, which is just flashing rather than playing a sound. It’s not so bad these days, as Linux machines aren’t typically playing irritating beeps out of on-motherboard speakers, but in general, I don’t like having things beep.
Anyone else got useful snippets that they’d like to share that they use with tmux
or screen
?
Here’s my .tmux.conf
I’m using ctrl-s as the prefix key, vim keybindings for pane navigating, v and f for new panes, and the Dracula theme.
# enable mouse set -g mouse on # enable leader r to relaod config file unbind r bind r source-file ~/.tmux.conf # change leader key combo from ctrl-b (C-b) to C-s set -g prefix C-s # toggle through panes with vim keys bind-key h select-pane -L bind-key j select-pane -D bind-key k select-pane -U bind-key l select-pane -R # change pane splits from % & - to v & f unbind f bind-key v split-pane -h bind-key f split-pane -v # List of plugins set -g @plugin 'tmux-plugins/tpm' set -g @plugin 'tmux-plugins/tmux-sensible' #dracula theme appearance and customizations set -g @plugin 'dracula/tmux' set -g @dracula-show-powerline true set -g @dracula-show-left-icon session set -g @dracula-plugins "ssh-session time" # Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf) run '~/.tmux/plugins/tpm/tpm'
Edit: fix stupid autocorrect.
your pipe-pane command was real neat, I appreciate you sharing!
I get frustrated with the default ESC delay so I use
set -sg escape-time 0
I re-bind the bind-keys without the default
-r
to avoid switching panes, hitting $DIRECTION arrow and going to the next pane $DIRECTION instead of my intent to move the cursor or view history etc…bind-key Up select-pane -U bind-key Down select-pane -D bind-key Left select-pane -L bind-key Right select-pane -R
lastly, I really like these plugins
set -g @plugin 'tmux-plugins/tpm' set -g @plugin 'tmux-plugins/tmux-sensible' set -g @plugin 'Morantron/tmux-fingers' set -g @plugin 'tmux-plugins/tmux-resurrect' set -g @resurrect-capture-pane-contents 'on'
come on people, show us your filthy tmux conf
I get frustrated with the default ESC delay so I use
set -sg escape-time 0
Hmm.
thinks
So, some keys on a terminal are encoded using the escape character normally sent by the Escape key and Control-[. The way the escape sequence is used is as a slightly-unreliable way to permit sending more types of keystrokes and modified keystrokes over an existing terminal connection, as you can send an escape character, but not have it interpreted as an escape key as long as whatever you transport is can move following characters prior to the guard interval expiring. That used to be pretty safe if your connection was a dedicated serial connection. Now it’s a little more-questionable, as a lot of links are traveling over stuff like wireless links and the Internet and can experience delays, so it’s maybe easier to exceed the guard interval.
As long as your link has relatively-little jitter, I’d think that you could maybe get away with lowering it.
But…if you set it to 0, I’d think that, absent terminal protocols changing, that you’d break use of a number of keys. Like, I think that Alt-sequences typically send escape.
kagis
Yeah:
https://superuser.com/questions/942677/consequences-of-escape-time-0-tmux-setting
Setting escape-time to zero interferes with tmux recognizing function-keys. Its manual page says
escape-time time Set the time in milliseconds for which tmux waits after an escape is input to determine if it is part of a function or meta key sequences. The default is 500 milliseconds.
The term “function key” applies to anything that has that format (including pageup, used in scrolling by tmux, and cursor-keys). 500 milliseconds may be excessive if you never work remotely. 20 milliseconds is workable for local connections. The analogous ESCDELAY in ncurses defaults to 1000 milliseconds; only a very small fraction of users find it necessary to change that.
And:
https://unix.stackexchange.com/questions/608142/whats-the-effect-of-escape-time-in-tmux
You can see stuff that I’d think would be problematic by invoking
cat
and then hitting key sequences; if what you see starts with^[
, then I think that setting the guard interval to 0 would break it. Alt-a is:$ cat ^[a
I think that it’ll also break certain protocols that you probably don’t care about (but can still technically run over a terminal, like XMODEM).
Are you, perchance, a vimmer? I know that vi sticks Escape on critical functionality by default, so a lot of vimmers get really irritated at the guard interval. I’ve seen a number of people on vim just use a different key sequence for what Escape normally does (“jj” seems to be a popular choice, for some reason, I suppose because enough people don’t normally hit it). I’d probably use something chorded, like Alt-` (but then, I do emacs, so adding more-chords to things is just kinda the way to go…)
You can also double-tap Escape, and as soon as the second Escape character shows up, the other end will immediately interpret the first escape character as Escape.
tests
It looks like the second escape character will make it through, though. Dunno if that’s problematic in vim.
I expect that you can also reconfigure vim to use a totally different character or character sequence and reconfigure Escape to send that, though I don’t know if that would be problematic; one thing I’ve noticed that a number of vi folks like (and one reason that I think that it’s popular with some IT folks) is the ability to to use vi without further configuration, so you can get by on a foreign system that you’ve never seen before.
Just to hyperlink your above:
set -g @plugin ‘tmux-plugins/tpm’
Looks like this is the “Tmux Plugin Manager”.
set -g @plugin ‘tmux-plugins/tmux-sensible’
Looks like this sets a set of default settings. Hmm. I’m not sure that I agree with all of these.
-
It sets the escape guard interval to 0; mentioned my concern above.
-
Increases the scrollback buffer length. Sure, that seems reasonable, especially if you turn off the scrollback buffer in any other virtual terminal that are also maintaining a scrollback buffer.
-
Increases the tmux
display-message
delay by several times, which determines how long messages from tmux remain on-screen. That seems legit; the default is really short. -
Increase the rate of
status-right
andstatus-left
refreshing. I don’t put much there, and generally, I think that that’s probably overhead that I wouldn’t get much from. I suppose that if someone put something that they needed to be pretty current there, that could be a real improvement. -
sets
TERM
to"screen-256color"
. I used to do this too (though I usedxterm-256color
) but I don’t today, and I don’t think that it’s necessarily a good idea. So, okay. The basic problem that this is attempting to fix is thatTERM
, as designed, has no “fallback” mechanism for if the remote end doesn’t understand the term type that you’re sending inTERM
; it’d be much better ifTERM
looked something like “tmux-256color:screen-256color:screen:xterm-256color:xterm” or something, where the remote end uses the first entry that it recognizes, and then informs the other end which type it picked. This “you can only pick one TERM” type thing makes it really hard to introduce a new terminal type, because initially nothing works correctly with a newTERM
type and attempting to ask the remote end to use a new TERM type that nobody supports yet means that you immediately see everything not work on most hosts. Back when, nothing had a tmux entry in its terminfo database, so when working with really old systems, they’d break, as the remote software wouldn’t know how to display things in a tmux terminal. But setting this globally just exacerbates the problem of systems not supporting tmux. And, worse, thescreen
andtmux
protocols are not identical – I’ve (occasionally) broken things when trying to run tmux on aTERM
impersonating screen, though it works a fair bit of the time. I think what I’d do is, if I had to work with an old host or two that didn’t have a tmux terminfo entry – and I wasn’t able to create them – then I’d just setTERM
impersonating some terminal type that it does know about prior to connecting to that host. I bet that there’s some way to set this in ssh in a Host directive. kagis Yeah, it looks like OpenSSH has the ability to setTERM
in a Host directive:https://serverfault.com/questions/302159/is-it-possible-to-change-value-of-term-when-calling-ssh
On 2021-06-04, “allow ssh_config SetEnv to override $TERM” was committed to openssh-portable, which sounds like it will let you set SetEnv TERM in ~/.ssh/config, such as in a Host directive. (Or it will let you as soon as a release is cut with this patch, presumably.)
My guess is that for most people, having a Host directive in their
~/.ssh/config
is maybe the least-intrusive way to deal with this for broken hosts until those hosts get updated.
I agree that impersonating
screen
inTERM
is addressing a real issue…just don’t know if that’s how I’d go about solving the problem, due to the side effects.set -g @plugin 'Morantron/tmux-fingers'
Now, that’s interesting. It looks like a context-sensitive way to rapidly copy out of the current terminal. Basically, an form of using the copy mode optimized to reduce keystrokes and for very recent stuff (like, not in the scrollback buffer).
set -g @plugin 'tmux-plugins/tmux-resurrect' set -g @resurrect-capture-pane-contents 'on'
Ah, okay, this saves and restores a tmux configuration (pane layout and such). I don’t use panes, but I could imagine that or a variant on it being useful. Emacs has a couple of different modes that do something kinda similar, like desktop-mode.
EDIT: Looking around, it looks like
mintty
addresses the Escape key guard interval problem by using a different escape sequence, as I was suggesting above. If more virtual terminals did that, that’d be neat and eliminate the problem for people who want to use the Escape key to, like, do stuff in software packages that treat it as “back out” rather than “send a literal escape sequence down the line”, but I suppose that any effort to change things is gonna run into the same “lots of hosts lack a current terminfo” problem that you’re trying to fix with theTERM=screen-256color
thing above until they get updates, so it’d be a fix that’d take years to roll out. Still, if everyone had started on this like ten years ago, then the problem would be pretty much solved now…Gah, haven’t had to think about my tmux conf in like 5 years but here we go. This was quite the writeup, thanks for looking!
You appear to be exactly right about
set -sg escape-time 0
. I don’t think it’s ever caused me an issue but I am fortunate to have a very homogeneous environment and it looks like the tmux team circumvented me anyway. As of tmux 3.4:If escape-time is 0, force to 1 instead
https://github.com/tmux/tmux/commit/201a8d8e7eb0bf208918c698e64aa120864c6dfc
and related discussion: https://github.com/wez/wezterm/issues/2060#issuecomment-1143775552
The only time I’ve been bit by the TERM value from tmux-sensible is when logging into junos boxes. In which case I need to
export TERM=xterm-256color
or arrow keys don’t work (among other things). Per the docs:https://github.com/tmux/tmux/wiki/FAQ#why-do-you-use-the-screen-terminal-description-inside-tmux
I might try
tmux-256color
for a bit and see how it goes.Anyway, appreciate the breakdown and the suggestions!
-
I use CTRL-A locally on my computers and CTRL-B on servers. Keeps it easy and consistent to switch between windows and tasks.
Isn’t c-o really hard to hit, or am I missing something?
Nice config bro