Reputation: 5316
I have a .tmux.conf which I use on different machines with different tmux versions installed.
I want to set different mouse options, depending on the tmux version.
On one machine I have version 2.0
on the other 2.1
.
I do not get his part right
if "[[(( $(tmux -V | cut -c 6-) < 2.1 ))]]" \
"set -g mode-mouse on;" \
"set -g mouse-resize-pane on;" \
"set -g select-pane on;" \
"set -g select-window on" "set -g mouse on"
When I source the file
$ tmux source-file .tmux.conf
I get this message
.tmux.conf:12: unknown command: set -g mouse-resize-pane on
The machine where I run it has version 2.1
so it shouldn't set the four options.
I want to set the four options when running tmux 2.0 or less or the one option when running tmux 2.1.
This bash statement works
$ tmux -V
tmux 2.1
$ if [[(( $(tmux -V | cut -c 6-) < 2.1 ))]];then echo $?;else echo $?;fi
1
Upvotes: 66
Views: 43351
Reputation: 97
Tmux's if-shell
can be used to check the tmux version.
[[ `tmux -V | cut -d' ' -f2` -lt 2.1 ]]
checks whether or not the tmux version is greater than or equal to 2.1. Using this we can set your mouse commands depending on the tmux version.
if-shell "[[ `tmux -V | cut -d' ' -f2` -lt 2.1 ]]" \
'set -g mode-mouse on; set -g mouse-resize-pane on; set -g mouse-select-pane on; set -g mouse-select-window on'
And set it for later versions of tmux:
if-shell "[[ `tmux -V | cut -d' ' -f2` -ge 2.1 ]]" \
'set -g mouse on; set -g mouse-utf8 on'
Upvotes: 7
Reputation: 3421
If you want to check split-window
in different tmux version to solve https://github.com/christoomey/dotfiles/issues/127
try
run-shell 'tmux setenv -g TMUX_VERSION $(tmux -V | \
sed -En "s/^tmux[^0-9]*([.0-9]+).*/\1/p")'
# split panes using \ and -
# https://github.com/christoomey/dotfiles/issues/127
if-shell -b '[ "$(echo "$TMUX_VERSION >= 3.0" | bc)" = 1 ]' \
"bind \\\\ split-window -h -c '#{pane_current_path}'; \
"
if-shell -b '[ "$(echo "$TMUX_VERSION < 3.0" | bc)" = 1 ]' \
"bind \\ split-window -h -c '#{pane_current_path}'; \
"
if-shell
will re-escape \
, so you need \\\\
reason: https://github.com/tmux/tmux/issues/1827#issuecomment-508985729
Upvotes: 0
Reputation: 4471
This is kind of a hassle. The correct way to do this within tmux (not relying on an external shell script) combines features of both Vincent and jdloft's responses.
The if-shell
command in tmux is used as
if-shell [-bF] [-t target-pane] shell-command command [command]
(alias: if)
Execute the first command if shell-command returns success or the second command otherwise. Before
being executed, shell-command is expanded using the rules specified in the FORMATS section, including
those relevant to target-pane. With -b, shell-command is run in the background.
If -F is given, shell-command is not executed but considered success if neither empty nor zero (after
formats are expanded).
Note that tmux shell-command expansion will expand variables of the form #{pane_current_path}
but otherwise will leave the command alone.
More importantly, note that tmux uses /bin/sh -c
to execute the shell command we specify. Thus, the command must be POSIX compliant, so tests of the form [[
are not guaranteed to be portable. Modern Ubuntu and Debian systems, for example, symlink /bin/sh
to dash
.
We want to run a POSIX compliant shell command that tests the tmux version and returns 0 (true) if the desired version is found.
if-shell '[ $(echo "$(tmux -V | cut -d" " -f2) >= 2.1" | bc) -eq 1 ]' \
'command if true' \
'command if false'
Example:
if-shell '[ $(echo "$(tmux -V | cut -d" " -f2) >= 2.1" | bc) -eq 1 ]' \
'set -g mouse on; set -g mouse-utf8 on' \
'set -g mode-mouse on; set -g mouse-resize-pane on; set -g mouse-select-pane on; set -g mouse-select-window on'
This correctly deals with the fact that we are doing floating point arithmetic, so bc
is required. Additionally, there is no need for an if/then/else/fi construct, as the [
operator produces a truthy value by itself.
A couple notes
;
/bin/sh -c
. Other approaches that use [[
or other non-POSIX syntax are not guaranteed to work.EDIT: A previous version of this answer used [[
, which doesn't work on systems that don't use bash. Replacing with [
solves this.
Upvotes: 25
Reputation: 5770
Another option is to use set -gq
(c.f. FAQ) to set options silently. If they are not available in older versions of tmux
, they will just be silently ignored.
For example, this is one way to set the newly added allow-passthrough
option, without erroring out in tmux
versions prior to 3.3a
.
Upvotes: 0
Reputation: 3215
TL;DR some key improvements can:
sh
and tmux compatibility back to at least 1.8bc
requirement for portabilityif
statements{}
on larger complicated nested string blocks, provided those are for 3.0 and newerI prefer awk
and sed
(core linux tools) approach to getting the version:
run-shell 'tmux setenv -g TMUX_VERSION $(\
tmux -V | \
sed -En "s/^tmux[^0-9]*([.0-9]+).*/\1/p" | \
awk "{major=int(\$1); \
minor=\$1-major; \
print int(major*100+minor*10) }")'
This is very similar to solution that use string manipulation techniques, except I'm able to easily do math in awk
.
E.g.
tmux 1.3
becomes 103
tmux 3.2a
becomes 302
Now instead of having to remember the bc
/other expression every time you want to if-shell
, it's a fairly normal sh
expression.
'[ "${TMUX_VERSION}" -lt "200" ]' # Version < 2.0
'[ "${TMUX_VERSION}" -le "215" ]' # Version <= 2.15 (a pretend version 2.15)
Note Some ancient versions of GNU sed
don't like -E
flag and need -r
instead. (BSD (darwin) doesn't support -r
). These are all EOL and should no longer be a problem. But if that level of portability matters, an addition run-shell
test could resolve that distinction.
if-shell -b '[ "${TMUX_VERSION}" -lt "200" ]' " \
setw -g mode-mouse on; \
set -g mouse-select-window on; \
set -g mouse-select-pane on; \
set -g mouse-resize-pane on; \
set -g mouse-utf on"
if-shell -b '[ "${TMUX_VERSION}" -ge "200" ]' " \
set-window-option -g mouse on"
I could not get @Tom Hale solution using {}
to work. This appears to be a tmux 3.0 feature. Just having }
on a line by itself will upset tmux 1.8 - 2.9, so I can't figure out how to use it.
What I found works, is if I used '
as the outer most string quotes, then I can use {} internally, if and only if I escape it so that it is interpreted as a single line (although it will be readable as multiple lines for me)
To keep older versions of tmux happy:
{
and }
must come at the end of the line, no }
on their own\
. The essentially means it's a single line, partially defeating the key multiline benefit of {}
. However this still improves readability and allows easier string nesting.\
, multiple command will still need ;
between them when on multiple lines (See copy-mode
below)Rehash This parses successfully on 1.8 (I never test older) and newer, as long as the tmux version check is for versions 3.0 or greater. The examples above target versions 1 and 2, so cannot use the escaped {}
method
if-shell -b '[ "${TMUX_VERSION}" -ge "300" ]' ' \
bind-key -T root MouseDown3Pane \
if-shell -F -t = "#{||:#{mouse_any_flag},#{&&:#{pane_in_mode},#{?#{m/r:(copy|view)-mode,#{pane_mode}},0,1}}}" \
"select-pane -t= ; send -M" { \
display-menu -t= -xM -yM -T \
"#[align=centre]#{pane_index} (#{pane_id})" \
"#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Top,}" < "send -X history-top" \
"#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Bottom,}" > "send -X history-bottom" \
"" \
"#{?mouse_word,Search For #[underscore]#{=/9/...:mouse_word},}" C-r { \
if -F "#{?#{m/r:(copy|view)-mode,#{pane_mode}},0,1}" \
"copy-mode -t=" ; \
send -Xt= search-backward "#{q:mouse_word}" \
} \
"#{?mouse_word,Type #[underscore]#{=/9/...:mouse_word},}" C-y { \
copy-mode -q ; \
send-keys -l -- "#{q:mouse_word}" \
} \
... } \
'
Life hack: The outer ''
can be replaced with {}
while you use your editor of choice for syntax highlighting, but you'll have to remember to put it back
Upvotes: 3
Reputation: 47013
Based on @ericx's answer and @thiagowfx's answer I put the following together which covers many of the listed incompatibilties from version 2.0 onwards:
# Version-specific commands [grumble, grumble]
# See: https://github.com/tmux/tmux/blob/master/CHANGES
run-shell 'tmux setenv -g TMUX_VERSION $(tmux -V | \
sed -En "s/^tmux[^0-9]*([.0-9]+).*/\1/p")'
if-shell -b '[ "$(echo "$TMUX_VERSION < 2.1" | bc)" = 1 ]' {
set -g mouse-select-pane on; set -g mode-mouse on
set -g mouse-resize-pane on; set -g mouse-select-window on
set -g message-fg red
set -g message-bg black
set -g message-attr bright
set -g window-status-bg default
set -g window-status-fg default
set -g window-status-current-attr bold
set -g window-status-current-bg cyan
set -g window-status-current-fg default
set -g window-status-bell-fg red
set -g window-status-bell-bg black
set -g window-status-activity-fg white
set -g window-status-activity-bg black
}
# In version 2.1 "mouse" replaced the previous 4 mouse options
if-shell -b '[ "$(echo "$TMUX_VERSION >= 2.1" | bc)" = 1 ]' {
set -g mouse on
}
# UTF8 is autodetected in 2.2 onwards, but errors if explicitly set
if-shell -b '[ "$(echo "$TMUX_VERSION < 2.2" | bc)" = 1 ]' \
set -g utf8 on
set -g status-utf8 on
set -g mouse-utf8 on
}
# bind-key syntax changed in 2.4 -- selection / copy / paste
if-shell -b '[ "$(echo "$TMUX_VERSION < 2.4" | bc)" = 1 ]' {
bind-key -t vi-copy v begin-selection
bind-key -t vi-copy V send -X select-line
bind-key -t vi-copy C-v rectangle-toggle
bind-key -t vi-copy y copy-pipe 'xclip -selection clipboard -in'
}
# Newer versions
if-shell -b '[ "$(echo "$TMUX_VERSION < 2.9" | bc)" = 1 ]' {
bind-key -T copy-mode-vi v send -X begin-selection
bind-key -T copy-mode-vi V send -X select-line
bind-key -T copy-mode-vi C-v send -X rectangle-toggle
bind-key -T copy-mode-vi y send -X copy-pipe-and-cancel 'xclip -selection clipboard -in'
}
if-shell -b '[ "$(echo "$TMUX_VERSION >= 2.9" | bc)" = 1 ]' {
set -g message-style fg=red,bg=black
set -g message-style bright
set -g window-status-style fg=default,bg=default
set -g window-status-current-style fg=default,bg=cyan,bold
set -g window-status-bell-style fg=red,bg=black
set -g window-status-activity-style fg=white,bg=black
}
I raised an issue about the problems with tmux
's non-backward-compatibility here. The summary is that the tmux
devs will not support backward compatibility, nor will they adopt a version numbering scheme which highlights which versions contain breaking changes. 😢
I raised an issue to support numeric comparators for %if
which was implemented in v3.0.
Upvotes: 75
Reputation: 900
Newer versions of tmux support neater if conditions. The below works on tmux version 3.2a:
if-shell '[ "$(tmux -V)" = "tmux 3.2a" ]' {
set -g status-bg red
set -g status-fg yellow
}
Upvotes: 2
Reputation: 829
tmux 3.0a
# execute a tmux command if a shell-command succeeded
# if-shell '[[ -z "$SSH_CLIENT" ]]' \ # use test or [ , instead of [[
# if-shell "[ $HOST == 'redmi14-leo' ]" # can't work don't know why
if-shell '[[ -z "$SSH_CLIENT" ]]' \
'source-file ~/.tmux.remote.conf'
Upvotes: -1
Reputation: 199
I have this config for many years.
tmux 2.4
tmux 2.4a
tmux next-3.3
bc
command# Tmux version before 2.4
if-shell -b '[ `tmux -V | cut -d" " -f2 | tr -d " |\-|.|[:alpha:]"` -lt 24 ]' \
'bind-key -t vi-copy v begin-selection; \
bind-key -t vi-copy Q cancel; \
bind-key -t vi-copy Enter cancel'
# Tmux version 2.4 onwards
if-shell -b '[ `tmux -V | cut -d" " -f2 | tr -d " |\-|.|[:alpha:]"` -ge 24 ]' \
'bind-key -T copy-mode-vi C-w send-keys -X cancel; \
bind-key -T copy-mode-vi C-u send-keys -X halfpage-up; \
bind-key -T copy-mode-vi C-j send-keys -X halfpage-down; \
bind-key -T copy-mode-vi C-l send-keys -X select-line'
Upvotes: 2
Reputation: 7060
I recently ran into this issue and my solution was to write an "tmux-older-than" script:
#! /bin/bash
TMUX_VERSION="$(tmux -V | cut -d" " -f2)"
test 1 -eq "$( echo "$TMUX_VERSION < $1" | bc)"
This makes tmux.conf much more readable:
if-shell 'tmux-older-than 3.0' \
'bind-key ^P swap-window -t -1' \
'bind-key ^P swap-window -d -t -1'
Upvotes: 4
Reputation: 369
This is not an alternative, but rather an extension to the accepted answers - (Tom Hale's answer is the most robust & complete).
For less repetition in your .tmux.conf
, you can store your shell test strings in tmux env vars (available since 0.8 in 2008) & interpolate them at run-time for if-shell
:
# Use which sed pattern actually works in the accepted answers
run-shell 'tmux setenv -g TMUX_VERSION $(tmux -V | sed -En "...")'
# Setup condition checks
V33_GTE='[ "$(echo "$TMUX_VERSION >= 3.3" | bc)" = 1 ]'
V33_LT='[ "$(echo "$TMUX_VERSION < 3.3" | bc)" = 1 ]'
# So on for other versions
# ...
### Example binding
# Toggle mouse
bind m set -g mouse on \; display 'Mouse: ON'
bind M set -g mouse off \; display 'Mouse: OFF'
# As of 3.1 you can annotate your keybindings
# As of 3.3 you can attach a note to existing bindings without setting the binding
# If running >= 3.3 , attach a note to the binding for `list-keys -N`
if "$V33_GTE" bind -N "Enable mouse mode" m
if "$V33_GTE" bind -N "Disable mouse mode" M
Upvotes: 0
Reputation: 300
Current latest release is 2.9a
, which throws off many of the direct comparisons used here.
My alternative makes use of sort -V
, which is much more robust for handling version comparisons.
Edit: A commenter points out that sort -V
is not available in BSD sort
, for example on native OSX. However this is still an answer that accounts for versions that aren't purely numerical.
# ver >= 2.3
[ ! "$(printf "%s\n%s" "$TMUX_VERSION" "2.3" | sort -V | head -n1)" == "$TMUX_VERSION" ]' \
"command"
# ver > 2.3
[ ! "$(printf "%s\n%s" "$TMUX_VERSION" "2.4" | sort -V | head -n1)" == "$TMUX_VERSION" ]' \
"command"
# ver < 2.3
[ "$(printf "%s\n%s" "$TMUX_VERSION" "2.3" | sort -V | head -n1)" == "$TMUX_VERSION" ]' \
"command"
Upvotes: 1
Reputation: 193
I have combined suggested solutions to a working one (tested on tmux 1.8 and 2.7):
run-shell "tmux setenv -g TMUX_VERSION $(tmux -V | cut -c 6-)"
if-shell -b '[[ "$TMUX_VERSION" < "2.6" ]]' \
"bind w choose-tree -u"
if-shell -b '[[ "$TMUX_VERSION" < "2.2" ]]' \
"set -g status-utf8 on"
Upvotes: 0
Reputation: 172758
I also stumbled over configuration mismatches in different tmux versions. After reviewing all the solutions here and in this related question on SuperUser, I've implemented the following variant:
# Version-specific configuration can be placed in ~/.tmux/${TMUX_VERSION}/*.conf
run-shell "for conf in ~/.tmux/$(tmux -V | cut -d' ' -f2)/*.conf; do tmux source-file \"\$conf\"; done"
With this, version-specific configuration can be put in (multiple) configuration snippets for a particular version. This is similar to the solution of @VincentHsu, but:
~/.tmux.conf
. Other solutions like the one from @TomHale duplicate the version test for each configuration element.Upvotes: 21
Reputation: 111
On some machines I was getting a false-positive result with the double bracket ('[[') syntax. So I came up with an alternative using awk:
# Enable mouse for different versions of tmux
# (If 'awk' exits with status 0, 'if-shell' evaluates to true)
# tmux < v2.1:
if-shell "tmux -V | awk '{exit !($2 < \"2.1\")}'" \
"setw -g mode-mouse on ; set -g mouse-select-pane on ; set -g mouse-resize-pane on ; set -g mouse-select-window on ;"
# tmux >= v2.1:
if-shell "tmux -V | awk '{exit !($2 >= \"2.1\")}'" \
"set -g mouse on ;"
Upvotes: 8
Reputation: 291
if-shell
doesn't always work. Instead, I use a shell script for loading the correct version of tmux.conf:
In .tmux.conf:
run-shell "bash ~/.tmux/verify_tmux_version.sh"
In verify_tmux_version.sh:
#!/bin/bash
verify_tmux_version () {
tmux_home=~/.tmux
tmux_version="$(tmux -V | cut -c 6-)"
if [[ $(echo "$tmux_version >= 2.1" | bc) -eq 1 ]] ; then
tmux source-file "$tmux_home/tmux_2.1_up.conf"
exit
elif [[ $(echo "$tmux_version >= 1.9" | bc) -eq 1 ]] ; then
tmux source-file "$tmux_home/tmux_1.9_to_2.1.conf"
exit
else
tmux source-file "$tmux_home/tmux_1.9_down.conf"
exit
fi
}
verify_tmux_version
For more details: https://gist.github.com/vincenthsu/6847a8f2a94e61735034e65d17ca0d66
Upvotes: 29