christoomey.vim-tmux-navigator/plugin/tmux_navigator.vim
2018-05-16 23:21:36 +02:00

140 lines
4.2 KiB
VimL

" 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
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
function! s:TmuxOrTmateExecutable()
return (match($TMUX, 'tmate') != -1 ? 'tmate' : 'tmux')
endfunction
function! s:UseTmuxNavigatorMappings()
return !get(g:, 'tmux_navigator_no_mappings', 0)
endfunction
function! s:InTmuxSession()
return $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:GetTmuxCommand(args)
return [s:TmuxOrTmateExecutable(), '-S', s:TmuxSocket()] + a:args
endfunction
if has('nvim')
function! s:TmuxCommand(args)
return substitute(system(s:GetTmuxCommand(a:args)), '\n$', '', '')
endfunction
else
function! s:TmuxCommand(args)
" Vim does not support a list for `system()`.
let cmd = join(map(s:GetTmuxCommand(a:args), 'fnameescape(v:val)'))
return substitute(system(cmd), '\n$', '', '')
endfunction
endif
function! s:TmuxPaneCurrentCommand()
echo s:TmuxCommand(['display-message', '-p', '#{pane_current_command}'])
endfunction
command! TmuxPaneCurrentCommand call s:TmuxPaneCurrentCommand()
let s:tmux_is_last_pane = 0
augroup tmux_navigator
au!
autocmd WinEnter * let s:tmux_is_last_pane = 0
augroup END
" Like `wincmd` but also change tmux panes instead of vim windows when needed.
function! s:TmuxWinCmd(direction)
if s:InTmuxSession()
call s:TmuxAwareNavigate(a:direction)
else
call s:VimNavigate(a:direction)
endif
endfunction
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', $TMUX_PANE, '-'.tr(a:direction, 'phjkl', 'lLDUR')]
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
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
command! TmuxNavigateLeft call s:TmuxWinCmd('h')
command! TmuxNavigateDown call s:TmuxWinCmd('j')
command! TmuxNavigateUp call s:TmuxWinCmd('k')
command! TmuxNavigateRight call s:TmuxWinCmd('l')
command! TmuxNavigatePrevious call s:TmuxWinCmd('p')
if s:UseTmuxNavigatorMappings()
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