1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-01-23 07:10:06 +08:00

feat(tmux): use bundle vim-tmux-navigator

This commit is contained in:
wsdjeg 2022-05-30 00:45:17 +08:00
parent 5ac713041d
commit a892272616
9 changed files with 570 additions and 1 deletions

View File

@ -45,7 +45,7 @@ let s:enable_tmux_clipboard = 0
function! SpaceVim#layers#tmux#plugins() abort
let plugins = [
\ ['christoomey/vim-tmux-navigator', { 'on_cmd': [
\ [g:_spacevim_root_dir . 'bundle/vim-tmux-navigator', { 'on_cmd': [
\ 'TmuxNavigateLeft', 'TmuxNavigateDown', 'TmuxNavigateUp',
\ 'TmuxNavigateRight'] }],
\ ]

5
bundle/README.md vendored
View File

@ -8,6 +8,7 @@ In `bundle/` directory, there are two kinds of plugins: forked plugins without c
- [No changed plugins](#no-changed-plugins)
- [`lang#ruby` layer](#langruby-layer)
- [`lang#python` layer](#langpython-layer)
- [`tmux` layer](#tmux-layer)
<!-- vim-markdown-toc -->
@ -52,3 +53,7 @@ In `bundle/` directory, there are two kinds of plugins: forked plugins without c
- [jeetsukumaran/vim-pythonsense@9200a57](https://github.com/jeetsukumaran/vim-pythonsense/tree/9200a57629c904ed2ab8c9b2e8c5649d311794ba)
- [alfredodeza/coveragepy.vim@afcef30](https://github.com/alfredodeza/coveragepy.vim/tree/afcef301b723048c25250d2d539b9473a8e4f747)
- [Vimjas/vim-python-pep8-indent@60ba5e](https://github.com/Vimjas/vim-python-pep8-indent/tree/60ba5e11a61618c0344e2db190210145083c91f8)
#### `tmux` layer
- [christoomey/vim-tmux-navigator@9ca5bfe5b](https://github.com/christoomey/vim-tmux-navigator/tree/9ca5bfe5bd274051b5dd796cc150348afc993b80)

1
bundle/vim-tmux-navigator/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
doc/tags

21
bundle/vim-tmux-navigator/License.md vendored Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Chris Toomey
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

305
bundle/vim-tmux-navigator/README.md vendored Normal file
View File

@ -0,0 +1,305 @@
Vim Tmux Navigator
==================
This plugin is a repackaging of [Mislav Marohnić's](https://mislav.net/) tmux-navigator
configuration described in [this gist][]. When combined with a set of tmux
key bindings, the plugin will allow you to navigate seamlessly between
vim and tmux splits using a consistent set of hotkeys.
**NOTE**: This requires tmux v1.8 or higher.
Usage
-----
This plugin provides the following mappings which allow you to move between
Vim panes and tmux splits seamlessly.
- `<ctrl-h>` => Left
- `<ctrl-j>` => Down
- `<ctrl-k>` => Up
- `<ctrl-l>` => Right
- `<ctrl-\>` => Previous split
**Note** - you don't need to use your tmux `prefix` key sequence before using
the mappings.
If you want to use alternate key mappings, see the [configuration section
below][].
Installation
------------
### Vim
If you don't have a preferred installation method, I recommend using [Vundle][].
Assuming you have Vundle installed and configured, the following steps will
install the plugin:
Add the following line to your `~/.vimrc` file
``` vim
Plugin 'christoomey/vim-tmux-navigator'
```
Then run
```
:PluginInstall
```
If you are using Vim 8+, you don't need any plugin manager. Simply clone this repository inside `~/.vim/pack/plugin/start/` directory and restart Vim.
```
git clone git@github.com:christoomey/vim-tmux-navigator.git ~/.vim/pack/plugins/start/vim-tmux-navigator
```
### tmux
To configure the tmux side of this customization there are two options:
#### Add a snippet
Add the following to your `~/.tmux.conf` file:
``` tmux
# Smart pane switching with awareness of Vim splits.
# See: https://github.com/christoomey/vim-tmux-navigator
is_vim="ps -o state= -o comm= -t '#{pane_tty}' \
| grep -iqE '^[^TXZ ]+ +(\\S+\\/)?g?(view|n?vim?x?)(diff)?$'"
bind-key -n 'C-h' if-shell "$is_vim" 'send-keys C-h' 'select-pane -L'
bind-key -n 'C-j' if-shell "$is_vim" 'send-keys C-j' 'select-pane -D'
bind-key -n 'C-k' if-shell "$is_vim" 'send-keys C-k' 'select-pane -U'
bind-key -n 'C-l' if-shell "$is_vim" 'send-keys C-l' 'select-pane -R'
tmux_version='$(tmux -V | sed -En "s/^tmux ([0-9]+(.[0-9]+)?).*/\1/p")'
if-shell -b '[ "$(echo "$tmux_version < 3.0" | bc)" = 1 ]' \
"bind-key -n 'C-\\' if-shell \"$is_vim\" 'send-keys C-\\' 'select-pane -l'"
if-shell -b '[ "$(echo "$tmux_version >= 3.0" | bc)" = 1 ]' \
"bind-key -n 'C-\\' if-shell \"$is_vim\" 'send-keys C-\\\\' 'select-pane -l'"
bind-key -T copy-mode-vi 'C-h' select-pane -L
bind-key -T copy-mode-vi 'C-j' select-pane -D
bind-key -T copy-mode-vi 'C-k' select-pane -U
bind-key -T copy-mode-vi 'C-l' select-pane -R
bind-key -T copy-mode-vi 'C-\' select-pane -l
```
#### TPM
If you'd prefer, you can use the Tmux Plugin Manager ([TPM][]) instead of
copying the snippet.
When using TPM, add the following lines to your ~/.tmux.conf:
``` tmux
set -g @plugin 'christoomey/vim-tmux-navigator'
run '~/.tmux/plugins/tpm/tpm'
```
Thanks to Christopher Sexton who provided the updated tmux configuration in
[this blog post][].
Configuration
-------------
### Custom Key Bindings
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 `~/.vimrc` as well as update the bindings in tmux to
match.
#### Vim
Add the following to your `~/.vimrc` to define your custom maps:
``` vim
let g:tmux_navigator_no_mappings = 1
nnoremap <silent> {Left-Mapping} :TmuxNavigateLeft<cr>
nnoremap <silent> {Down-Mapping} :TmuxNavigateDown<cr>
nnoremap <silent> {Up-Mapping} :TmuxNavigateUp<cr>
nnoremap <silent> {Right-Mapping} :TmuxNavigateRight<cr>
nnoremap <silent> {Previous-Mapping} :TmuxNavigatePrevious<cr>
```
*Note* Each instance of `{Left-Mapping}` or `{Down-Mapping}` must be replaced
in the above code with the desired mapping. Ie, the mapping for `<ctrl-h>` =>
Left would be created with `nnoremap <silent> <c-h> :TmuxNavigateLeft<cr>`.
##### Autosave on leave
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:
```vim
" Write all buffers before navigating from Vim to tmux pane
let g:tmux_navigator_save_on_switch = 2
```
##### Disable While Zoomed
By 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:
```vim
" Disable tmux navigator when zooming the Vim pane
let g:tmux_navigator_disable_when_zoomed = 1
```
##### Preserve Zoom
As 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`:
```vim
" If the tmux window is zoomed, keep it zoomed when moving from Vim to another pane
let g:tmux_navigator_preserve_zoom = 1
```
Naturally, if `g:tmux_navigator_disable_when_zoomed` is enabled, this option
will have no effect.
#### Tmux
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.
### Additional Customization
#### Restoring Clear Screen (C-l)
The default key bindings include `<Ctrl-l>` which is the readline key binding
for clearing the screen. The following binding can be added to your `~/.tmux.conf` file to provide an alternate mapping to `clear-screen`.
``` tmux
bind C-l send-keys 'C-l'
```
With this enabled you can use `<prefix> C-l` to clear the screen.
Thanks to [Brian Hogan][] for the tip on how to re-map the clear screen binding.
#### Nesting
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).
``` tmux
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"
```
Troubleshooting
---------------
### Vim -> Tmux doesn't work!
This is likely due to conflicting key mappings in your `~/.vimrc`. You can use
the following search pattern to find conflicting mappings
`\vn(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.
[open an issue]: https://github.com/christoomey/vim-tmux-navigator/issues/new
### Tmux Can't Tell if Vim Is Active
This functionality requires tmux version 1.8 or higher. You can check your
version to confirm with this shell command:
``` bash
tmux -V # should return 'tmux 1.8'
```
### Switching out of Vim Is Slow
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.
### It doesn't work in Vim's `terminal` mode
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 https://github.com/christoomey/vim-tmux-navigator/pull/172
### It Doesn't Work in tmate
[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](https://github.com/christoomey/vim-tmux-navigator/issues/27) for more
detail.
[tmate]: http://tmate.io/
### It Still Doesn't Work!!!
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.
[Brian Hogan]: https://twitter.com/bphogan
[Mislav's original external script]: https://github.com/mislav/dotfiles/blob/master/bin/tmux-vim-select-pane
[Vundle]: https://github.com/gmarik/vundle
[TPM]: https://github.com/tmux-plugins/tpm
[configuration section below]: #custom-key-bindings
[this blog post]: http://www.codeography.com/2013/06/19/navigating-vim-and-tmux-splits
[this gist]: https://gist.github.com/mislav/5189704

View File

@ -0,0 +1,39 @@
*tmux-navigator.txt* Plugin to allow seamless navigation between tmux and vim
==============================================================================
CONTENTS *tmux-navigator-contents*
==============================================================================
INTRODUCTION *tmux-navigator*
Vim-tmux-navigator is a little plugin which enables seamless navigation
between tmux panes and vim splits. This plugin is a repackaging of Mislav
Marohinc's tmux=navigator configuration. When combined with a set of tmux key
bindings, the plugin will allow you to navigate seamlessly between vim and
tmux splits using a consistent set of hotkeys.
NOTE: This requires tmux v1.8 or higher.
==============================================================================
CONFIGURATION *tmux-navigator-configuration*
* Activate autoupdate on exit
let g:tmux_navigator_save_on_switch = 1
* Disable vim->tmux navigation when the Vim pane is zoomed in tmux
let g:tmux_navigator_disable_when_zoomed = 1
* If the Vim pane is zoomed, stay zoomed when moving to another tmux pane
let g:tmux_navigator_preserve_zoom = 1
* Custom Key Bindings
let g:tmux_navigator_no_mappings = 1
nnoremap <silent> {Left-mapping} :TmuxNavigateLeft<cr>
nnoremap <silent> {Down-Mapping} :TmuxNavigateDown<cr>
nnoremap <silent> {Up-Mapping} :TmuxNavigateUp<cr>
nnoremap <silent> {Right-Mapping} :TmuxNavigateRight<cr>
nnoremap <silent> {Previous-Mapping} :TmuxNavigatePrevious<cr>
vim:tw=78:ts=8:ft=help:norl:

42
bundle/vim-tmux-navigator/pattern-check vendored Normal file
View File

@ -0,0 +1,42 @@
#!/usr/bin/env bash
#
# Collection of various test strings that could be the output of the tmux
# 'pane_current_comamnd' message. Included as regression test for updates to
# the inline grep pattern used in the `.tmux.conf` configuration
set -e
RED=$(tput setaf 1)
GREEN=$(tput setaf 2)
YELLOW=$(tput setaf 3)
NORMAL=$(tput sgr0)
vim_pattern='(^|\/)g?(view|n?vim?x?)(diff)?$'
match_tests=(vim Vim VIM vimdiff /usr/local/bin/vim vi gvim view gview nvim vimx)
no_match_tests=( /Users/christoomey/.vim/thing /usr/local/bin/start-vim )
display_matches() {
for process_name in "$@"; do
printf "%s %s\n" "$(matches_vim_pattern $process_name)" "$process_name"
done
}
matches_vim_pattern() {
if echo "$1" | grep -iqE "$vim_pattern"; then
echo "${GREEN}match${NORMAL}"
else
echo "${RED}fail${NORMAL}"
fi
}
main() {
echo "Testing against pattern: ${YELLOW}$vim_pattern${NORMAL}\n"
echo "These should all ${GREEN}match${NORMAL}\n----------------------"
display_matches "${match_tests[@]}"
echo "\nThese should all ${RED}fail${NORMAL}\n---------------------"
display_matches "${no_match_tests[@]}"
}
main

View File

@ -0,0 +1,131 @@
" Maps <C-h/j/k/l> to switch vim splits in the given direction. If there are
" no more windows in that direction, forwards the operation to tmux.
" Additionally, <C-\> toggles between last active vim splits/tmux panes.
if exists("g:loaded_tmux_navigator") || &cp || v:version < 700
finish
endif
let g:loaded_tmux_navigator = 1
function! s:VimNavigate(direction)
try
execute 'wincmd ' . a:direction
catch
echohl ErrorMsg | echo 'E11: Invalid in command-line window; <CR> executes, CTRL-C quits: wincmd k' | echohl None
endtry
endfunction
if !get(g:, 'tmux_navigator_no_mappings', 0)
nnoremap <silent> <c-h> :TmuxNavigateLeft<cr>
nnoremap <silent> <c-j> :TmuxNavigateDown<cr>
nnoremap <silent> <c-k> :TmuxNavigateUp<cr>
nnoremap <silent> <c-l> :TmuxNavigateRight<cr>
nnoremap <silent> <c-\> :TmuxNavigatePrevious<cr>
endif
if empty($TMUX)
command! TmuxNavigateLeft call s:VimNavigate('h')
command! TmuxNavigateDown call s:VimNavigate('j')
command! TmuxNavigateUp call s:VimNavigate('k')
command! TmuxNavigateRight call s:VimNavigate('l')
command! TmuxNavigatePrevious call s:VimNavigate('p')
finish
endif
command! TmuxNavigateLeft call s:TmuxAwareNavigate('h')
command! TmuxNavigateDown call s:TmuxAwareNavigate('j')
command! TmuxNavigateUp call s:TmuxAwareNavigate('k')
command! TmuxNavigateRight call s:TmuxAwareNavigate('l')
command! TmuxNavigatePrevious call s:TmuxAwareNavigate('p')
if !exists("g:tmux_navigator_save_on_switch")
let g:tmux_navigator_save_on_switch = 0
endif
if !exists("g:tmux_navigator_disable_when_zoomed")
let g:tmux_navigator_disable_when_zoomed = 0
endif
if !exists("g:tmux_navigator_preserve_zoom")
let g:tmux_navigator_preserve_zoom = 0
endif
function! s:TmuxOrTmateExecutable()
return (match($TMUX, 'tmate') != -1 ? 'tmate' : 'tmux')
endfunction
function! s:TmuxVimPaneIsZoomed()
return s:TmuxCommand("display-message -p '#{window_zoomed_flag}'") == 1
endfunction
function! s:TmuxSocket()
" The socket path is the first value in the comma-separated list of $TMUX.
return split($TMUX, ',')[0]
endfunction
function! s:TmuxCommand(args)
let cmd = s:TmuxOrTmateExecutable() . ' -S ' . s:TmuxSocket() . ' ' . a:args
let l:x=&shellcmdflag
let &shellcmdflag='-c'
let retval=system(cmd)
let &shellcmdflag=l:x
return retval
endfunction
function! s:TmuxNavigatorProcessList()
echo s:TmuxCommand("run-shell 'ps -o state= -o comm= -t ''''#{pane_tty}'''''")
endfunction
command! TmuxNavigatorProcessList call s:TmuxNavigatorProcessList()
let s:tmux_is_last_pane = 0
augroup tmux_navigator
au!
autocmd WinEnter * let s:tmux_is_last_pane = 0
augroup END
function! s:NeedsVitalityRedraw()
return exists('g:loaded_vitality') && v:version < 704 && !has("patch481")
endfunction
function! s:ShouldForwardNavigationBackToTmux(tmux_last_pane, at_tab_page_edge)
if g:tmux_navigator_disable_when_zoomed && s:TmuxVimPaneIsZoomed()
return 0
endif
return a:tmux_last_pane || a:at_tab_page_edge
endfunction
function! s:TmuxAwareNavigate(direction)
let nr = winnr()
let tmux_last_pane = (a:direction == 'p' && s:tmux_is_last_pane)
if !tmux_last_pane
call s:VimNavigate(a:direction)
endif
let at_tab_page_edge = (nr == winnr())
" Forward the switch panes command to tmux if:
" a) we're toggling between the last tmux pane;
" b) we tried switching windows in vim but it didn't have effect.
if s:ShouldForwardNavigationBackToTmux(tmux_last_pane, at_tab_page_edge)
if g:tmux_navigator_save_on_switch == 1
try
update " save the active buffer. See :help update
catch /^Vim\%((\a\+)\)\=:E32/ " catches the no file name error
endtry
elseif g:tmux_navigator_save_on_switch == 2
try
wall " save all the buffers. See :help wall
catch /^Vim\%((\a\+)\)\=:E141/ " catches the no file name error
endtry
endif
let args = 'select-pane -t ' . shellescape($TMUX_PANE) . ' -' . tr(a:direction, 'phjkl', 'lLDUR')
if g:tmux_navigator_preserve_zoom == 1
let l:args .= ' -Z'
endif
silent call s:TmuxCommand(args)
if s:NeedsVitalityRedraw()
redraw!
endif
let s:tmux_is_last_pane = 1
else
let s:tmux_is_last_pane = 0
endif
endfunction

View File

@ -0,0 +1,25 @@
#!/usr/bin/env bash
version_pat='s/^tmux[^0-9]*([.0-9]+).*/\1/p'
is_vim="ps -o state= -o comm= -t '#{pane_tty}' \
| grep -iqE '^[^TXZ ]+ +(\\S+\\/)?g?(view|n?vim?x?)(diff)?$'"
tmux bind-key -n C-h if-shell "$is_vim" "send-keys C-h" "select-pane -L"
tmux bind-key -n C-j if-shell "$is_vim" "send-keys C-j" "select-pane -D"
tmux bind-key -n C-k if-shell "$is_vim" "send-keys C-k" "select-pane -U"
tmux bind-key -n C-l if-shell "$is_vim" "send-keys C-l" "select-pane -R"
tmux_version="$(tmux -V | sed -En "$version_pat")"
tmux setenv -g tmux_version "$tmux_version"
#echo "{'version' : '${tmux_version}', 'sed_pat' : '${version_pat}' }" > ~/.tmux_version.json
tmux if-shell -b '[ "$(echo "$tmux_version < 3.0" | bc)" = 1 ]' \
"bind-key -n 'C-\\' if-shell \"$is_vim\" 'send-keys C-\\' 'select-pane -l'"
tmux if-shell -b '[ "$(echo "$tmux_version >= 3.0" | bc)" = 1 ]' \
"bind-key -n 'C-\\' if-shell \"$is_vim\" 'send-keys C-\\\\' 'select-pane -l'"
tmux bind-key -T copy-mode-vi C-h select-pane -L
tmux bind-key -T copy-mode-vi C-j select-pane -D
tmux bind-key -T copy-mode-vi C-k select-pane -U
tmux bind-key -T copy-mode-vi C-l select-pane -R
tmux bind-key -T copy-mode-vi C-\\ select-pane -l