Permalink
Browse files

Seamless window, pane switching in vim inside tmux

  • Loading branch information...
1 parent e73e515 commit 1a0c1aaea2a1cf05290b290faf0644d54e64975b @pengwynn committed Mar 22, 2013
Showing with 55 additions and 5 deletions.
  1. +17 −0 bin/tmux-vim-select-pane
  2. +7 −5 tmux/tmux.conf.symlink
  3. +30 −0 vim/vim.symlink/tmux.vim
  4. +1 −0 vim/vimrc.symlink
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+# Like `tmux select-pane`, but if Vim is running in the current pane it sends a
+# keystroke to Vim instead to let it decide whether it's going to switch windows
+# internally or switch tmux panes.
+set -e
+
+# gets the tty of active tmux pane
+active_tty="$(tmux list-panes -F '#{pane_active}#{pane_tty}' | grep '^1')"
+
+# checks if there's a foreground Vim process in attached to that tty
+if ps c -o 'state=,command=' -t "${active_tty#1}" | grep '+' | grep -iE '\bvim?\b' >/dev/null ; then
+ direction="$(echo "${1#-}" | tr 'lLDUR' '\\hjkl')"
+ # forward the keystroke to Vim
+ tmux send-keys C-$direction
+else
+ tmux select-pane "$@"
+fi
@@ -20,7 +20,7 @@ bind-key C-a last-window
# ssh-friendly splits
bind-key | run-shell 'exec tmux-ssh-split -h'
-bind-key \ run-shell 'exec tmux-ssh-split -h'
+#bind-key \ run-shell 'exec tmux-ssh-split -h'
@mislav
mislav Mar 22, 2013 Contributor

Why commented this out? C-\ shouldn't interfere with it I think

@pengwynn
pengwynn Mar 22, 2013 Owner

Ha, yeah, adding that back, it works fine. I was debugging my application of your gist before I realized I hadn't reloaded tmux.conf. facepalm

bind-key - run-shell 'exec tmux-ssh-split -v'
# windows and panes
@@ -34,10 +34,12 @@ bind-key , previous-window # <
bind-key . next-window # >
bind-key < swap-window -t :-
bind-key > swap-window -t :+
-bind-key C-h resize-pane -L 5
-bind-key C-l resize-pane -R 5
-bind-key C-j resize-pane -D 5
-bind-key C-k resize-pane -U 5
+# Smart pane switching with awareness of vim splits
+bind -n C-k run-shell 'tmux-vim-select-pane -U'
+bind -n C-j run-shell 'tmux-vim-select-pane -D'
+bind -n C-h run-shell 'tmux-vim-select-pane -L'
+bind -n C-l run-shell 'tmux-vim-select-pane -R'
+bind -n "C-\\" run-shell 'tmux-vim-select-pane -l'
bind-key n command-prompt 'rename-window "%%"'
bind-key N command-prompt 'rename-session "%%"'
@@ -0,0 +1,30 @@
+let g:tmux_is_last_pane = 0
+au WinEnter * let g:tmux_is_last_pane = 0
+
+" Like `wincmd` but also change tmux panes instead of vim windows when needed.
+function TmuxWinCmd(direction)
+ let nr = winnr()
+ let tmux_last_pane = (a:direction == 'p' && g:tmux_is_last_pane)
+ if !tmux_last_pane
+ " try to switch windows within vim
+ exec 'wincmd ' . a:direction
+ endif
+ " 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 tmux_last_pane || nr == winnr()
+ let cmd = 'tmux select-pane -' . tr(a:direction, 'phjkl', 'lLDUR')
+ exec 'silent !'.cmd
+ redraw! " because `exec` fucked up the screen. why is this needed?? arrghh
+ let g:tmux_is_last_pane = 1
+ else
+ let g:tmux_is_last_pane = 0
+ endif
+endfunction
+
+" navigate between split windows/tmux panes
+nmap <c-j> :call TmuxWinCmd('j')<cr>
+nmap <c-k> :call TmuxWinCmd('k')<cr>
+nmap <c-h> :call TmuxWinCmd('h')<cr>
+nmap <c-l> :call TmuxWinCmd('l')<cr>
+nmap <c-\> :call TmuxWinCmd('p')<cr>
View
@@ -11,6 +11,7 @@ source ~/.vim/autocmd.vim
source ~/.vim/rails.vim
source ~/.vim/ruby.vim
source ~/.vim/common.vim
+source ~/.vim/tmux.vim
" Per-directory .vimrc files
set exrc

0 comments on commit 1a0c1aa

Please sign in to comment.