Problem in tmux.conf with nested if or nested quotes - tmux

I ssh into machines with shared config files but different tmux versions so I try to have a single version aware .tmux.conf. The following is for my tmux 2.6 machine.
My issue seems to be the nested ifs, or perhaps the nested quotes.
the following code hides the status bar when only one window is present:
if -F '#{==:#{session_windows},1}' 'set -g status off' 'set -g status on'; \
set-hook -g window-linked 'if -F "#{==:#{session_windows},1}" "set -g status off" "set -g status on"'; \
set-hook -g window-unlinked 'if -F "#{==:#{session_windows},1}" "set -g status off" "set -g status on"';
however my version guard, which adds double quotes around single quoted strings, breaks this
if-shell -b '[ "$(echo "$TMUX_VERSION >= 2.1" | bc)" = 1 ]' " \
if -F '#{==:#{session_windows},1}' 'set -g status off' 'set -g status on'; \
set-hook -g window-linked 'if -F "#{==:#{session_windows},1}" "set -g status off" "set -g status on"'; \
set-hook -g window-unlinked 'if -F "#{==:#{session_windows},1}" "set -g status off" "set -g status on"'; \
"
tmux starts up without any errors, but the status bar is not hidden.

You need to escape " inside other " as \".
Or put your inner commands in a separate config file and load it with source-file.
If you were using a later tmux version you could use {} to avoid this problem but on older tmux versions you will need to escape the quotes.

Related

tmux : copy and paste without shift

i'm trying to follow a guide in which it's explained how to get copy/paste working without shift.
but with the following config :
set -g mouse on
set -g #plugin 'tmux-plugins/tpm'
set -g #plugin 'tmux-plugins/tmux-yank'
set -g #yank_action 'copy-pipe-no-clear'
set -g #override_copy_command 'xsel -i --clipboard'
set -g #yank_selection_mouse 'primary'
set -g #yank_selection 'primary'
bind -T copy-mode C-c send -X copy-pipe-no-clear "xsel -i --clipboard"
bind -T copy-mode-vi C-c send -X copy-pipe-no-clear "xsel -i --clipboard"
# Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf)
run '~/.tmux/plugins/tpm/tpm'
I'm expecting to select something with the mouse, press y or Control-c, then go to any other app, press Control-v and have my selection pasted, but nothing happens.
when I list the keys I can see my bind:
bind-key -T copy-mode C-c send-keys -X copy-pipe-no-clear "xsel -i --clipboard"
and xsel works fine on its own :
$ echo hello | xsel -i --clipboard # C-V contains 'hello' as expected
What am i doing wrong?

Enabling mouse support across different tmux versions

I manage several Linux machines, some with tmux version 2.1 in the repositories, and others with tmux versions less than 2.1. I use mouse mode, and I understand that in tmux 2.1, the option to enable mouse mode has changed to:
set -g mouse on
Since I use different distributions each with a different version of tmux, I wanted to make one .tmux.conf file that would enable the appropriate mouse option depending on the version.
So, I added the following to my .tmux.conf:
# Mouse Mode
if-shell "[[ `tmux -V |cut -d ' ' -f2` -ge 2.1 ]]" 'set -g mouse on'
if-shell "[[ `tmux -V |cut -d ' ' -f2` -lt 2.0 ]]" 'set -g mode-mouse on'
if-shell "[[ `tmux -V |cut -d ' ' -f2` -lt 2.0 ]]" 'set -g mouse-resize-pane on'
if-shell "[[ `tmux -V |cut -d ' ' -f2` -lt 2.0 ]]" 'set -g mouse-select-pane on'
if-shell "[[ `tmux -V |cut -d ' ' -f2` -lt 2.0 ]]" 'set -g mouse-select-window on'
Unfortunately, this does not work. tmux doesn't show any errors, but it also doesn't enable mouse mode either.
Is there some error in my logic which is preventing this configuration from working?
Building on the last two answers but replacing the shell command as below. Add this to the main config:
if-shell "tmux -V |awk ' {split($2, ver, \".\"); if (ver[1] < 2) exit 1 ; else if (ver[1] == 2 && ver[2] < 1) exit 1 }' " 'source .tmux/gt_2.0.conf' 'source .tmux/lt_2.1.conf'
This uses awk to split the version number, a clearer version of this code is:
split($2, ver, ".") #Split the second param and store it in the ver array
if ver[1] < 2) # if it's less than v2.0
exit 1
else
if (ver[1] == 2) # if it's version 2.n look at next number
if (ver[2] < 1) # If the second number is less than 1 (2.1)
exit 1
# else we exit 0
Then split the config out into the two config files.
lt_2.1.conf contains
set -g mode-mouse on
set -g mouse-resize-pane on
set -g mouse-select-pane on
set -g mouse-select-window on
gt_2.1.conf contains
set -g mouse-utf8 on
set -g mouse on
It seems that set is not a command of tmux and you can't execute it in if-shell.
I have an alternative scheme:
create two config files somewhere. Here we suppose that these two config files are tmux_ge_21.conf and tmux_lt_21.conf, they all locates at ~/.tmux/ directory.
Fill contents below to these two files:
For tmux_ge_21.conf:
set -g mouse-utf8 on
set -g mouse on
For tmux_lt_21.conf:
set -g mode-mouse on
set -g mouse-resize-pane on
set -g mouse-select-pane on
set -g mouse-select-window on
add the line below in your .tmux.conf:
if-shell "[[ `tmux -V | awk '{print ($2 >= 2.1)}'` -eq 1 ]]" 'source ~/.tmux/tmux_ge_21.conf' 'source ~/.tmux/tmux_lt_21.conf'
Execute tmux source ~/.tmux.conf in your terminal.
BTW: For tmux which greater than 2.1, the default act of mouse scroll is changed. If you want it act as before, you have to install this tmux plug: https://github.com/nhdaly/tmux-scroll-copy-mode
If you use this plugin, append set -g #plugin 'nhdaly/tmux-scroll-copy-mode' to tmux_ge_21.conf.
BTW2: -ge in [[ `tmux -V |cut -d ' ' -f2` -ge 2.1 ]] seems work only when compare two integer number, I am not very sure.
Building on the answer of #douglas-su I found a solution which currently works (see caveat below).
Follow step 1 + 2 of his answer: create two files with options for < 2.1 and >= 2.1 options. Instead of step 3 insert the following snippet in your .tmux.conf:
if-shell "[[ `tmux -V | cut -d ' ' -f2 | sed 's/[a\.]//g'` -ge 21 ]]" 'source ~/.tmux/tmux_ge_21.conf' 'source ~/.tmux/tmux_lt_21.conf'
Explanation:
cut -d ' ' -f2 selects the second part of tmux -v. Example: returns '2.1' for 'tmux 2.1'
sed 's/[a\.]//g' replaces all dots . and a's in the version string. Example: returns 19 for '1.9a'
Caveat: This solution probably does not work for all eternity but should work fine for all releases of tmux so far (current version is 2.1). If for any reason a updated older version would be released (e.g. 2.0.1 for a security fix or something similar) the proposed solution would no longer work as 201 >= 21.
Hope this helps.

How to automatically rename tmux windows to the current directory

I would like to have tmux to automatically rename the window with the current working directory (cwd). As it is by default, it names the tab/window as the name of the current process, such as zsh or vim.
When I open a new window in tmux, the name is reattach-to-use-namespace and then it immediately switches to zsh.
I'm on OS X 10.10.2, I use zshell, and I have tmux 1.9a.
To be clear, I don't want the entire path in the name of the window, just the current directory, so for example, I want projectName, not /Users/username/Development/projectName.
If you want to see my current tmux.conf, here it is.
With tmux 2.3+, the b: format modifier shows the "basename" (or "tail") of a path.
set-option -g status-interval 5
set-option -g automatic-rename on
set-option -g automatic-rename-format '#{b:pane_current_path}'
The FORMATS section of man tmux describes other modifiers, such as #{d:} and even #{s/foo/bar/:}.
With tmux 2.2 or older, the basename shell command can be used instead.
set-option -g status-interval 5
set-option -g automatic-rename on
set-option -g automatic-rename-format '#(basename "#{pane_current_path}")'
Expanding on what Josef wrote, you can put the basename of the directory in the status using a shell snippet:
# be sure to see note* below
set -g window-status-format '#I:#(pwd="#{pane_current_path}"; echo ${pwd####*/})#F'
set -g window-status-current-format '#I:#(pwd="#{pane_current_path}"; echo ${pwd####*/})#F'
# status bar updates every 15s by default**, change to 1s here
# (this step is optional - a lower latency might have negative battery/cpu usage impacts)
set -g status-interval 1
*Note that what would be ${pwd##*/} is escaped to ${pwd####*/} since # has special meaning in the format string.
**See here for an example default tmux config.
Show the top N components
Showing just the basename generates too much ambiguity, but full paths are too much clutter, so I settled for:
the/last/path
instead of:
/a/very/long/the/last/path
or just:
path
.tmux.conf
set-window-option -g window-status-current-format '#[fg=white,bold]** #{window_index} #[fg=green]#{pane_current_command} #[fg=blue]#(echo "#{pane_current_path}" | rev | cut -d'/' -f-3 | rev) #[fg=white]**|'
set-window-option -g window-status-format '#[fg=white,bold]#{window_index} #[fg=green]#{pane_current_command} #[fg=blue]#(echo "#{pane_current_path}" | rev | cut -d'/' -f-3 | rev) #[fg=white]|'
Trick taken from: Remove part of path on Unix
If that still does not solve ambiguity, I go for:
bind-key -r w choose-window -F '#{window_index} | #{pane_current_command} | #{host} | #{pane_current_path}'
Tested on Tmux 2.1, Ubuntu 16.04.
To get the best of both worlds - window name is path when you're at a shell prompt, but name of executable when you're running something, try this:
set-option -g status-interval 1
set-option -g automatic-rename on
set-option -g automatic-rename-format "#{?#{==:#{pane_current_command},bash},#{b:pane_current_path},#{pane_current_command}}"
Replace "bash" with whatever shell you're using.
Adding this config to your ~/.tmux.conf file should work:
set-option -g window-status-current-format '#I:#{pane_current_path}#F'
set-option -g window-status-format '#I:#{pane_current_path}#F'
set-option -g status-interval 1
It depends however on your Tmux version. I wasn't able to make it work on 1.9a3 (in Cygwin) - but with Tmux 1.8 on Ubuntu (in Vagrant) it worked fine.
I use the following in ~/.tmux.conf to achieve this (working on OSX, zsh, tmux-2.3):
set -g automatic-rename-format '#{pane_current_path}'
set -g status-interval 5
You can set status-interval to 1 to make it respond faster to changing directories.
According to the changelog (https://raw.githubusercontent.com/tmux/tmux/master/CHANGES) this should work in tmux 1.9 and up.
Using ssh into a CentOS machine with tmux 2.3 the window name doesn't change until I press return in the new panel, not sure why that is happening.
Do something like this in a tmux session for zsh shell:
setopt PROMPT_SUBST
export PS1=$'\ek$(basename $(pwd))\e\\> '
If someone uses bash shell:
export PS1="\033k\$(basename \$(pwd))\033\\> "
You can add these commands in the shell initialization file on the condition the $TERM env variable is set to the value "screen"
I am using zsh hook for that
Add following in ~/.zshrc
precmd () {
if [ -n "$TMUX" ]; then
tmux set-window-option -q window-status-format "#[fg=cyan bg=cyan] | #[fg=white, bg=cyan] #I | ${PWD##/*/} #[fg=cyan, bg=cyan] | "
tmux set-window-option -q window-status-current-format "#[fg=cyan, bg=cyan] | #[fg=white, bg=cyan] #I | ${PWD##/*/} #[fg=cyan, bg=cyan] | "
fi
}
This doesn't strictly answer your question--it doesn't automatically rename an existing tmux session to the current working directory.
Rather, when creating a new session, it names that session after the current working directory.
Here's what I did:
to
~/.aliases
add
alias tm='tmux new -s `basename $PWD`'
Open a new terminal window and type:
tm
This now creates a new tmux session which is named after the current working directory.
Note: This relies on basename which does not exist in Windows.
I am sure that you want use this:
set -g status-left '#{pane_current_path} '
To change what you see in the window list you can specify a format when you define the key-binding for the chose-window function like this:
bind-key '"' choose-window -F "#{session_name} | #{window_name} - #{b:pane_current_path} (#{pane_current_command})"

Change tmux prefix key depending on environment variable

I want to change the prefix if a environment variable is declared. I've tried the follwing configurations on .tmux.conf
This always change (with $SSH_CLIENT declared or not):
if-shell "test -n $SSH_CLIENT" "set -g prefix C-a"
and also:
if-shell "[[ -n $SSH_CLIENT ]]" "set -g prefix C-a"
But this code never change:
if-shell "[ -n $SSH_CLIENT ]" "set -g prefix C-a"
Finally, it worked, with the help from tmux-users mailing list, but there is still a problem with 1.8
# if if-shell goes in the beggining it will break the following command. this is going to be fixed after 1.8
# make c-a work as c-b
if-shell 'test -z "$SSH_CLIENT"' 'set -g prefix C-a'
http://sourceforge.net/mailarchive/forum.php?thread_name=20140201002909.GG11126%40yelena.nicm.ath.cx&forum_name=tmux-users
https://github.com/brauliobo/gitconfig/blob/master/configs/.tmux.conf

tmux set -g mouse-select-window not working

from what I understand
set -g mouse-select-window on
Should allow me to click on a window in the status bar and go to that window. I put that in my tmux.conf file though and nothing happens when I click on a window. What am I doing wrong?
In my .tmux.conf I have the following:
set -g mode-mouse on
set -g mouse-select-window on
set -g mouse-select-pane on
Do you have the mode-mouse on setting?
On 2.1 this config got deprecated and the new option to allow all mouse support is:
set -g mouse on
This break the nice mouse scroll support, but can be enabled with this:
bind -n WheelUpPane if-shell -F -t = "#{mouse_any_flag}" "send-keys -M" "if -Ft= '#{pane_in_mode}' 'send-keys -M' 'select-pane -t=; copy-mode -e; send-keys -M'"

Resources