let s:movestate = 0 au CursorHold * call AbortCombo() function! AbortCombo() let s:movestate = 0 endfunction function! MoveCombo(axis, direction, normal_move, window_move, tab_move) let l:startpos = getpos('.') " Check if the combo was interrupted. Horizontal moves are interrupted when " moving between lines. There is no extra condition for vertical moves. if s:movestate > 0 && \ ( (s:moveaxis == 1 && bufnr('') == s:combostartbuffer && \ s:combostart[1] != l:startpos[1]) || \ a:axis != s:moveaxis || a:direction != s:movedireciotn ) let s:movestate = 0 endif if s:movestate == 0 let s:combostart = l:startpos let s:combostartbuffer = bufnr('') let s:moveaxis = a:axis let s:movedireciotn = a:direction exe 'normal! ' . a:normal_move " Assume moving in the buffer is to an extreme position. So the next " move should always be between windows or tabs. let s:movestate = s:movestate + 1 elseif s:movestate == 1 " Moving between windows. Since we may be leaving this window, restore " the position of the cursor at the start of the combo. call setpos('.', s:combostart) let l:start = winnr() exe 'wincmd ' . a:window_move if winnr() == l:start " Didn't move to different windows. Try moving between tabs (still " done in this call). let s:movestate = s:movestate + 1 endif endif " Note that moving between tabs is always evaluated. This means the if a " move between windows was unsuccesful we can try moving between tabs " immediately. if s:movestate == 2 let l:start = tabpagenr() exe 'silent! ' . a:tab_move if tabpagenr() == l:start call setpos('.', l:startpos) endif endif endfunction function! ComboMove_Left() call MoveCombo(1, -1, '_', 'h', 'tabprev') endfunction function! ComboMove_Right() call MoveCombo(1, 1, '$l', 'l', 'tabnext') endfunction function! ComboMove_Up() call MoveCombo(2, -1, 'gg', 'k', 'tabnew') endfunction function! ComboMove_Down() call MoveCombo(2, 1, 'G', 'j', 'tabclose') endfunction