Fork of vim-tmux-navigator made
in order to make the keybindings consistent with the ones used by the default vim
configuration, i.e. Ctrl-W + [hjkl].
<ctrl-w>h=> Left<ctrl-w>j=> Down<ctrl-w>k=> Up<ctrl-w>l=> Right<ctrl-w>p=> Previous split
use {
'some0necoding/vim-tmux-navigator'
}Then run
:PackerSync
Add the following lines to your ~/.tmux.conf:
set -g @plugin 'some0necoding/vim-tmux-navigator'
run '~/.tmux/plugins/tpm/tpm'If you don't want the plugin to create any mappings, you can use the five provided functions to define your own custom maps. You will need to define custom mappings in your vim configuration as well as update the bindings in tmux to match.
let g:tmux_navigator_no_mappings = 1
noremap <silent> {Left-Mapping} :<C-U>TmuxNavigateLeft<cr>
noremap <silent> {Down-Mapping} :<C-U>TmuxNavigateDown<cr>
noremap <silent> {Up-Mapping} :<C-U>TmuxNavigateUp<cr>
noremap <silent> {Right-Mapping} :<C-U>TmuxNavigateRight<cr>
noremap <silent> {Previous-Mapping} :<C-U>TmuxNavigatePrevious<cr>vim.g.tmux_navigator_no_mappings = 1
vim.api.nvim_set_keymap("n", "{Left-Mapping}", ":<C-U>TmuxNavigateLeft<cr>", { silent = true })
vim.api.nvim_set_keymap("n", "{Down-Mapping}", ":<C-U>TmuxNavigateDown<cr>", { silent = true })
vim.api.nvim_set_keymap("n", "{Up-Mapping}", ":<C-U>TmuxNavigateUp<cr>", { silent = true })
vim.api.nvim_set_keymap("n", "{Right-Mapping}", ":<C-U>TmuxNavigateRight<cr>", { silent = true })
vim.api.nvim_set_keymap("n", "{Previous-Mapping}", ":<C-U>TmuxNavigatePrevious<cr>", { silent = true })You can configure the plugin to write the current buffer, or all buffers, when
navigating from Vim to tmux. This functionality is exposed via the
g:tmux_navigator_save_on_switch variable, which can have either of the
following values:
| Value | Behavior |
|---|---|
| 1 | :update (write the current buffer, but only if changed) |
| 2 | :wall (write all buffers) |
To enable this, add the following (with the desired value) to your ~/.vimrc:
" Write all buffers before navigating from Vim to tmux pane
let g:tmux_navigator_save_on_switch = 2By default, if you zoom the tmux pane running Vim and then attempt to navigate "past" the edge of the Vim session, tmux will unzoom the pane. This is the default tmux behavior, but may be confusing if you've become accustomed to navigation "wrapping" around the sides due to this plugin.
We provide an option, g:tmux_navigator_disable_when_zoomed, which can be used
to disable this unzooming behavior, keeping all navigation within Vim until the
tmux pane is explicitly unzoomed.
To disable navigation when zoomed, add the following to your ~/.vimrc:
" Disable tmux navigator when zooming the Vim pane
let g:tmux_navigator_disable_when_zoomed = 1As noted above, navigating from a Vim pane to another tmux pane normally causes
the window to be unzoomed. Some users may prefer the behavior of tmux's -Z
option to select-pane, which keeps the window zoomed if it was zoomed. To
enable this behavior, set the g:tmux_navigator_preserve_zoom option to 1:
" If the tmux window is zoomed, keep it zoomed when moving from Vim to another pane
let g:tmux_navigator_preserve_zoom = 1Naturally, if g:tmux_navigator_disable_when_zoomed is enabled, this option
will have no effect.
Alter each of the five lines of the tmux configuration listed above to use your custom mappings. Note each line contains two references to the desired mapping.
In interactive programs such as FZF, Ctrl+hjkl can be used instead of the arrow keys to move the selection up and down. If vim-tmux-navigator is getting in your way trying to change the active window instead, you can make it be ignored and work as if this plugin were not enabled. Just modify the is_vim variable(that you have either on the snipped you pasted on ~/.tmux.conf or on the vim-tmux-navigator.tmux file). For example, to add the program foobar:
- is_vim="ps -o state= -o comm= -t '#{pane_tty}' | grep -iqE '^[^TXZ ]+ +(\\S+\\/)?g?(view|l?n?vim?x?|fzf)(diff)?$'"
+ is_vim="ps -o state= -o comm= -t '#{pane_tty}' | grep -iqE '^[^TXZ ]+ +(\\S+\\/)?g?(view|l?n?vim?x?|fzf|foobar)(diff)?$'"By default, if you try to move past the edge of the screen, tmux/vim will "wrap" around to the opposite side. To disable this, you'll need to configure both tmux and vim:
For vim, you only need to enable this option:
let g:tmux_navigator_no_wrap = 1Tmux doesn't have an option, so whatever key bindings you have need to be set to conditionally wrap based on position on screen:
is_vim="ps -o state= -o comm= -t '#{pane_tty}' \
| grep -iqE '^[^TXZ ]+ +(\\S+\\/)?g?(view|l?n?vim?x?|fzf)(diff)?$'"
bind-key -n 'C-h' if-shell "$is_vim" { send-keys C-h } { if-shell -F '#{pane_at_left}' {} { select-pane -L } }
bind-key -n 'C-j' if-shell "$is_vim" { send-keys C-j } { if-shell -F '#{pane_at_bottom}' {} { select-pane -D } }
bind-key -n 'C-k' if-shell "$is_vim" { send-keys C-k } { if-shell -F '#{pane_at_top}' {} { select-pane -U } }
bind-key -n 'C-l' if-shell "$is_vim" { send-keys C-l } { if-shell -F '#{pane_at_right}' {} { select-pane -R } }
bind-key -T copy-mode-vi 'C-h' if-shell -F '#{pane_at_left}' {} { select-pane -L }
bind-key -T copy-mode-vi 'C-j' if-shell -F '#{pane_at_bottom}' {} { select-pane -D }
bind-key -T copy-mode-vi 'C-k' if-shell -F '#{pane_at_top}' {} { select-pane -U }
bind-key -T copy-mode-vi 'C-l' if-shell -F '#{pane_at_right}' {} { select-pane -R }If you like to nest your tmux sessions, this plugin is not going to work properly. It probably never will, as it would require detecting when Tmux would wrap from one outermost pane to another and propagating that to the outer session.
By default this plugin works on the outermost tmux session and the vim sessions it contains, but you can customize the behaviour by adding more commands to the expression used by the grep command.
When nesting tmux sessions via ssh or mosh, you could extend it to look like
'(^|\/)g?(view|vim|ssh|mosh?)(diff)?$', which makes this plugin work within
the innermost tmux session and the vim sessions within that one. This works
better than the default behaviour if you use the outer Tmux sessions as relays
to different hosts and have all instances of vim on remote hosts.
Similarly, if you like to nest tmux locally, add |tmux to the expression.
This behaviour means that you can't leave the innermost session with Ctrl-hjkl
directly. These following fallback mappings can be targeted to the right Tmux
session by escaping the prefix (Tmux' send-prefix command).
bind -r C-h run "tmux select-pane -L"
bind -r C-j run "tmux select-pane -D"
bind -r C-k run "tmux select-pane -U"
bind -r C-l run "tmux select-pane -R"
bind -r C-\ run "tmux select-pane -l"Another workaround is to configure tmux on the outer machine to send keys to the inner tmux session:
bind-key -n 'M-h' 'send-keys c-h'
bind-key -n 'M-j' 'send-keys c-j'
bind-key -n 'M-k' 'send-keys c-k'
bind-key -n 'M-l' 'send-keys c-l'
Here we bind "meta" key (aka "alt" or "option" key) combinations for each of
the four directions and send those along to the innermost session via
send-keys. You use the normal C-h,j,k,l while in the outermost session and
the alternative bindings to navigate the innermost session. Note that if you
use the example above on a Mac, you may need to configure your terminal app to
get the option key to work like a normal meta key. Consult your terminal app's
manual for details.
A third possible solution is to manually prevent the outermost tmux session from intercepting the navigation keystrokes by disabling the prefix table:
set -g pane-active-border-style 'fg=#000000,bg=#ffff00'
bind -T root F12 \
set prefix None \;\
set key-table off \;\
if -F '#{pane_in_mode}' 'send-keys -X cancel' \;\
set -g pane-active-border-style 'fg=#000000,bg=#00ff00'
refresh-client -S \;\
bind -T off F12 \
set -u prefix \;\
set -u key-table \;\
set -g pane-active-border-style 'fg=#000000,bg=#ffff00'
refresh-client -S
This code, added to the machine running the outermost tmux session, toggles the
outermost prefix table on and off with the F12 key. When off, the active
pane's border changes to green to indicate that the inner session receives
navigation keystrokes. When toggled back on, the border returns to yellow and
normal operation resumes and the outermost responds to the nav keystrokes.
The code example above also toggles the prefix key (ctrl-b by default) for the outer session so that same prefix can be temporarily used on the inner session instead of having to use a different prefix (ctrl-a by default) which you may find convenient. If not, simply remove the lines that set/unset the prefix key from the code example above.
This is likely due to conflicting key mappings in your ~/.vimrc. You can use
the following search pattern to find conflicting mappings
\v(nore)?map\s+\<c-[hjkl]\>. Any matching lines should be deleted or
altered to avoid conflicting with the mappings from the plugin.
Another option is that the pattern matching included in the .tmux.conf is
not recognizing that Vim is active. To check that tmux is properly recognizing
Vim, use the provided Vim command :TmuxNavigatorProcessList. The output of
that command should be a list like:
Ss -zsh
S+ vim
S+ tmux
If you encounter a different output please open an issue with as much info about your OS, Vim version, and tmux version as possible.
This functionality requires tmux version 1.8 or higher. You can check your version to confirm with this shell command:
tmux -V # should return 'tmux 1.8'If you find that navigation within Vim (from split to split) is fine, but Vim
to a non-Vim tmux pane is delayed, it might be due to a slow shell startup.
Consider moving code from your shell's non-interactive rc file (e.g.,
~/.zshenv) into the interactive startup file (e.g., ~/.zshrc) as Vim only
sources the non-interactive config.
Terminal mode is currently unsupported as adding this plugin's mappings there causes conflict with movement mappings for FZF (it also uses terminal mode). There's a conversation about this in christoomey#172
tmate is a tmux fork that aids in setting up remote pair programming sessions. It is designed to run alongside tmux without issue, but occasionally there are hiccups. Specifically, if the versions of tmux and tmate don't match, you can have issues. See this issue for more detail.
Images built from minimalist OSes may not have the ps command or have a
simpler version of the command that is not compatible with this plugin.
Try installing the procps package using the appropriate package manager
command. For Alpine, you would do apk add procps.
If this doesn't solve your problem, you can also try the following:
Replace the is_vim variable in your ~/.tmux.conf file with:
if-shell '[ -f /.dockerenv ]' \
"is_vim=\"ps -o state=,comm= -t '#{pane_tty}' \
| grep -iqE '^[^TXZ ]+ +(\\S+\\/)?g?(view|l?n?vim?x?)(diff)?$'\""
# Filter out docker instances of nvim from the host system to prevent
# host from thinking nvim is running in a pseudoterminal when its not.
"is_vim=\"ps -o state=,comm=,cgroup= -t '#{pane_tty}' \
| grep -ivE '^.+ +.+ +.+\\/docker\\/.+$' \
| grep -iqE '^[^TXZ ]+ +(\\S+\\/)?g?(view|l?n?vim?x?)(diff)? +'\""Details: The output of the ps command on the host system includes processes running within containers, but containers have their own instances of /dev/pts/*. vim-tmux-navigator relies on /dev/pts/* to determine if vim is running, so if vim is running in say /dev/pts/ in a container and there is a tmux pane (not running vim) in /dev/pts/ on the host system, then without the patch above vim-tmux-navigator will think vim is running when its not.
The tmux configuration uses an inlined grep pattern match to help determine if the current pane is running Vim. If you run into any issues with the navigation not happening as expected, you can try using Mislav's original external script which has a more robust check.