Tmux remap prompt for command -- Ctrl-b + : - tmux

The goal is to be able to type Ctrl-b + ; instead of Ctrl - b + : to activate the tmux command prompt.
I can't figure out how create this particular binding.
I know how to use bind-keys to have a shortcut to execute commands to creating new windows etc.

via shell:
tmux bind-key -T prefix "\;" command-prompt
In .tmux.conf configuration or tmux command-prompt:
bind \; command-prompt
For explanation, see tmux bind semicolon. It's escaped because it's a command separator in tmux commands.

Related

Tmux name window at creation and use the name in zsh command

Currently, in my tmux.conf I have the following binding which allows me to name a window when I create a new one. Then the window opens in the same directory I was in the last window:
# Name windows before you create them
bind-key c command-prompt -p "window name:" "new-window -c '#{pane_current_path}'; rename-window '%%'"
I want to achieve the following instead:
When I type the name, it will create the window and execute a bash command like z <TYPED_NAME> - the idea is that it will use the name I typed to search for the most relevant directory (using the z command for example) and cd into it. Can that be achieved?
If no relevant directory is found with z it will use the current behaviour which is to cd into the current path.
One problem is that only the first %% in the template is replaced. The other is that a cd command done in a subshell will be lost when you return to the parent shell. For bash you can try a binding something like this:
bind-key c command-prompt -p "window name:" \
"new-window -c '#{pane_current_path}' 'myfn \"%%\"'"
This runs a bash script myfn that must be in your PATH to do the work. It contains:
#!/bin/bash
name=$1
tmux rename-window "$name"
cd ../"$name" || echo "failed to cd to $name" >&2
exec bash -i
Remember to chmod +x the script. It calls tmux to rename the window, and then you would have your z code to find and cd to a directory. In this example, I just look in ../ for it. The final exec ensures we replace the current shell by an interactive one.
For zsh, you can do something similar, but if you want myfn to be found in your fpath you need new-window to run zsh with the -i option, as zsh only does this for interactive shells. So use a binding like
bind-key c command-prompt -p "window name:" \
"new-window -c '#{pane_current_path}' 'exec zsh -ic \"myfn %%\"'"
Here I've added an exec to avoid having a pointless parent shell, and since -c must be followed by the command as a single string I've put myfn and %% inside the same double-quotes. You'll need to add more quoting if your name can contain whitespace etc.
The myfn zsh script can be the same, with bash replaced by zsh.
I don't know enough about zsh to avoid the final exec zsh -i which is needed to stop the zsh -ic shell from terminating.

zsh attach to tmux by key binding

I am trying to make Alt-M in zsh attach to a tmux session.
Content of .zshrc:
tmux-open() {
tmux attach
}
zle -N tmux-open
bindkey '^[m' tmux-open
When I press Alt-M, instead of attaching to the tmux session, I get:
open terminal failed: not a terminal
Calling tmux-open from the zsh prompt attaches to the tmux session. What is the problem with the key binding?
A possible alternative is to make a keybinding that just types the command tmux attach:
bindkey -s '^[m' 'tmux attach\n'
That will work when the prompt is on an empty command line

How to bind Ctrl-Tab and Ctrl-Shift-Tab in tmux for mintty

I would like to bind CTRL+TAB and CTRL+SHIFT+TAB (without prefix) to tmux functions, under minTTY/cygwin.
I have tried the following tmux configuration:
set-option -gw xterm-keys on
bind-key -n C-Tab next-window
bind-key -n "^[[1;5I" next-window # tmux doesn't recognize
bind-key -n "\e[1;5I" next-window # tmux doesn't recognize
If I hit CTRL+TAB after launching tmux, I get a bell sound. If I hit it after the tmux prefix, it prints 1;5I.
I am using minTTY 2.2.3 under cygwin/Babun. I have disabled minTTY's handling of this key combo via its options (SwitchShortcuts=no in .minttyrc).
For reference, CTRL+TAB and CTRL+SHIFT+TAB work for cycling screen windows with the following .screenrc:
bindkey "^[[1;5I" next
bindkey "^[[1;6I" prev
I got here because I bumped into the same issue.
tmux now supports custom key bindings via user-keys - since August 2017, so if you can build tmux yourself, or once a new tmux version is released, it's possible like so:
set -s user-keys[0] "\e[1;5I"
set -s user-keys[1] "\e[1;6I"
bind-key -n User0 select-pane -t+
bind-key -n User1 select-pane -t-
Note that you must use double quotes and not single quotes or else it won't interpret \e correctly.
At the time of writing the example in the manual uses single quotes - https://github.com/tmux/tmux/issues/1043 , though it's likely to be fixed soon.

How to send a command to all panes in tmux?

I like to call :clear-history on panes with a huge scrollback. However, I want to script a way to send this command to all the panes in the various windows.
I know how to send a command to all the windows, courtesy of this question, but how do I send a command to all the panes of which window as well?
send-keys and synchronize-panes from the tmux manpage come to mind, but I'm not sure how to marry them together. But maybe there is a simpler way to do this.
Extra Observations:
Thinking about this a little bit, tmux list-panes -a seems to list all the panes in the current session. Pretty useful to start off with. Where do I go from here?
Have you tried following in tmux window with multiple panes
Ctrl-B :
setw synchronize-panes on
clear history
A bit late to the party but I didn't want to set and unset synchronize-panes just to send one command so I created a wrapper function around tmux and added a custom function called send-keys-all-panes.
_tmux_send_keys_all_panes_ () {
for _pane in $(tmux list-panes -F '#P'); do
tmux send-keys -t ${_pane} "$#"
done
}
I also create a wrapper around the tmux command to simplify calling this function (for convenience). The wrapper and the above code are all here.
This allows me to run tmux send-keys-all-panes <command> or tmux skap <command to send <command> to all panes.
Note that tmux is aliased to my wrapper function tmux_pp.
Update June 2019
Quick illustration on how to configure your own binding for synchronize panes.
Added the following into my tmux.conf (the comments certainly apply to my overall configuration):
# synchronize all panes in a window
# don't use control S, too easily confused
# with navigation key sequences in tmux (show sessions)
unbind C-S
bind C-Y set-window-option synchronize-panes
Now, I can toggle the ability to synchronize commands across multiple panes with <C-a><C-y>.
(Yes, I remapped the bind key to Ctrl a).
my tmux version is 1.9a, and this works for me, one key is enough for both on and off
bind-key X set-window-option synchronize-panes\; display-message "synchronize-panes is now #{?pane_synchronized,on,off}"
None of the above answers worked for me (tmux v2.3), but this did, from the bash command line:
for _pane in $(tmux list-panes -a -F '#{pane_id}'); do \
tmux clear-history -t ${_pane} ; done
A more generalized script, for tmux commands other than 'clear-history' would just replace that element with a parameter, eg. $1. Do be careful if you intend to write a script to handle a series of tmux commands, as "-t ${_pane}" will need to be applied to each.
Note that the -a parameter to tmux list-panes is required to cover all panes in all windows in all sessions. Without that, only panes in your current tmux window will be affected. If you have more than one tmux session open and only want to apply the command to panes within the current session, replace -a with -s (It's all in the tmux man page).
I haven't the mod points to comment directly on each of the above answers, so here's why they weren't working for me:
The problem that I had with #shailesh-garg 's answer was that the sync affected only commands issued within the panes, not tmux commands issued using Ctrl-B : which are outside the panes.
The three problems that I had with #kshenoy 's answer were that:
it sends keystrokes to within a pane, not to the tmux operation
of that pane, so for instance, if one had a bash shell running in
the pane and one used the script to send "clear-history", those
would be the keystrokes that would appear in the bash command-line.
A work-around would be to send "tmux clear-history" or to pre-pend
"tmux " to "$#", but I haven't edited the answer because of my other
problems with the answer;
I couldn't figure out how to send a
new-line character without literally breaking the line;
Even when I did that, sending "tmux clear-history" had no effect.
If you want to send your command to every pane in every window in every session, add this to your .bashrc:
send_command_to_every_pane() {
for session in `tmux list-sessions -F '#S'`; do
for window in `tmux list-windows -t $session -F '#P' | sort`; do
for pane in `tmux list-panes -t $session:$window -F '#P' | sort`; do
tmux send-keys -t "$session:$window.$pane" "$*" C-m
done
done
done
}
You can then use it like this:
send_command_to_every_pane source ~/.bash_profile
Change "$*" to "$#" if you want that behavior, but in my experience this is what you want.
tmux send-keys -t <session id> <command> C-m
Replace the "session id" and "command" accordingly.
This is my utility function to do it, only executing the command when there there is nothing running in the pane.
#!/bin/bash
_send_bash_command_to_session() {
if [[ $# -eq 0 || "$1" = "--help" ]] ; then
echo 'Usage: _send_bash_command_to_session $session_name what ever command you want: '
return
fi
input_session="$1"
input_command="${#:2}"
for _pane in $(tmux list-panes -s -t ${input_session} -F '#{window_index}.#{pane_index}'); do
# only apply the command in bash or zsh panes.
_current_command=$(tmux display-message -p -t ${input_session}:${_pane} '#{pane_current_command}')
if [ ${_current_command} = zsh ] || [ ${_current_command} = bash ] ; then
tmux send-keys -t ${_pane} "${input_command}" Enter
fi
done
}
tmux_set_venv() {
_current_session=$(tmux display-message -p '#{session_name}')
_send_bash_command_to_session ${_current_session} workon $1
}
Example targeting a session called dev, enabling a python virtualenv in all panes that are in bash or zsh, avoiding executing the command in panes with vim or any other executable:
_send_bash_command_to_session dev workon myvirtualenv
or easier to remember: to do it in the current session:
tmux_set_venv myvirtualenv
Find my configuration file with this function.
You can combine synchronize-panes and send-keys in a single shortcut to send commands to all the panes:
Predefined tmux command clear-history:
bind-key C set-option -w synchronize-panes on\; clear-history \; set-option -w synchronize-panes off
Prompt an arbitrary tmux command:
bind-key p command-prompt -p "Panes command: " "set-option -w synchronize-panes on; %% ; set-option -w -u synchronize-panes"
Prompt an arbitrary shell command:
bind-key p command-prompt -p "Panes command: " "set-option -w synchronize-panes on; send-keys %%\\n ; set-option -w -u synchronize-panes"
By default, byobu uses tmux as backend. It's a wrapper that make things much easier:
Shift+F9:
Ctrl+F9:
Shift+F1
Admittedly only semi-related, I found I could make the status background red when I toggle synchronize-panes so it's obvious when I switch back to a window with an unknown synchronize-panes state:
bind-key C-x setw synchronize-panes on \; set-window-option status-bg red \; display-message "pane sync on"
bind-key M-x setw synchronize-panes off \; set-window-option status-bg default \; display-message "pane sync off"

Tmux copy mode: how to create your own command?

I love Tmux and its copy mode with Vi commands, but I'm really annoyed by the fact that this mode is very far from being as efficient as real Vim.
For example, there is no keybinding to just copy a word (yw), I must always "go to the beginning of a word" "begin selection", "go to the end of the word" then "finish selection". A lot of operations when I just need to do yw in vim.
I searched a way to create my own "yw" command in Tmux copy mode. Chaining all the operations needed is a good idea, but a simple bind with commands separated by ; just doesn't work (similar thing works in non-copy mode). Is there something I miss? Or is the copy mode of Tmux just limited and not as scriptable as I need it to be?
I have this in my tmux conf:
# vi-style controls in copy mode
set-option -g status-keys vi
set-window-option -g mode-keys vi
# v and y like vi in copy-mode
bind-key -t vi-copy 'v' begin-selection
bind-key -t vi-copy 'y' copy-selection
Now after going copy-mode i can easily select words by:
vw
And copy with
y
In tmux you have to select something to copy. There is nothing like copying in normal mode as you know from usual vi/vim commands. Unfortunately you can only use one key (like v or y) for every tmux argument.
You can find more about tmux's vi movement commands here: https://superuser.com/a/197272/57890
This appears to be a bug in the bind-key command when called with the -t option. I have filed a bug report at https://sourceforge.net/tracker/?func=detail&aid=3533562&group_id=200378&atid=973262.
On upstream (2.4+) tmux version this got changed, in order to create a bindings for begin selection you need to use -T and send-keys with -X.
More info in tmux changelog.
Here my bindings for vi copy mode as an example:
# Bind `v` to trigger selection
bind-key -T copy-mode-vi v send-keys -X begin-selection
# Bind `y` to yank current selection
bind-key -T copy-mode-vi y send-keys -X copy-selection-and-cancel
# Rebind `mouse click + drag button release` to not jump away from context
bind-key -T copy-mode-vi MouseDragEnd1Pane send-keys -X copy-selection
If you are using emacs copy mode, replacing copy-mode-vi with copy-mode should be enough.
There's a patch for tmux allowing to create procedures and bind any number of actions for 'mode' keystrokes: http://ershov.github.io/tmux/

Resources