1. let s:movestate = 0
  2. au CursorHold * call <SID>AbortCombo()
  3. function! <SID>AbortCombo()
  4.     let s:movestate = 0
  5. endfunction
  6.  
  7. function! <SID>MoveCombo(axis, direction, normal_move, window_move, tab_move)
  8.     let l:startpos = getpos('.')
  9.  
  10.     " Check if the combo was interrupted. Horizontal moves are interrupted when
  11.     " moving between lines. There is no extra condition for vertical moves.
  12.     if s:movestate > 0 &&
  13.                 \ ( (s:moveaxis == 1 && bufnr('') == s:combostartbuffer &&
  14.                 \    s:combostart[1] != l:startpos[1]) ||
  15.                 \      a:axis != s:moveaxis || a:direction != s:movedireciotn )
  16.         let s:movestate = 0
  17.     endif
  18.  
  19.     if s:movestate == 0
  20.         let s:combostart = l:startpos
  21.         let s:combostartbuffer = bufnr('')
  22.         let s:moveaxis = a:axis
  23.         let s:movedireciotn = a:direction
  24.         exe 'normal! ' . a:normal_move
  25.         " Assume moving in the buffer is to an extreme position. So the next
  26.         " move should always be between windows or tabs.
  27.         let s:movestate = s:movestate + 1
  28.     elseif s:movestate == 1
  29.         " Moving between windows. Since we may be leaving this window, restore
  30.         " the position of the cursor at the start of the combo.
  31.         call setpos('.', s:combostart)
  32.         let l:start = winnr()
  33.         exe 'wincmd ' . a:window_move
  34.         if winnr() == l:start
  35.             " Didn't move to different windows. Try moving between tabs (still
  36.             " done in this call).
  37.             let s:movestate = s:movestate + 1
  38.         endif
  39.     endif
  40.  
  41.     " Note that moving between tabs is always evaluated. This means the if a
  42.     " move between windows was unsuccesful we can try moving between tabs
  43.     " immediately.
  44.     if s:movestate == 2
  45.         let l:start = tabpagenr()
  46.         exe 'silent! ' . a:tab_move
  47.         if tabpagenr() == l:start
  48.             call setpos('.', l:startpos)
  49.         endif
  50.     endif
  51. endfunction
  52.  
  53. function! ComboMove_Left()
  54.     call <SID>MoveCombo(1, -1, '_', 'h', 'tabprev')
  55. endfunction
  56.  
  57. function! ComboMove_Right()
  58.     call <SID>MoveCombo(1, 1, '$l', 'l', 'tabnext')
  59. endfunction
  60.  
  61. function! ComboMove_Up()
  62.     call <SID>MoveCombo(2, -1, 'gg', 'k', 'tabnew')
  63. endfunction
  64.  
  65. function! ComboMove_Down()
  66.     call <SID>MoveCombo(2, 1, 'G', 'j', 'tabclose')
  67. endfunction