let s : movestate = 0

au CursorHold * call < SID > AbortCombo ( )

function ! < SID > AbortCombo ( )

let s : movestate = 0

endfunction

function ! < SID > 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 < SID > MoveCombo ( 1 , - 1 , '_' , 'h' , 'tabprev' )

endfunction

function ! ComboMove_Right ( )

call < SID > MoveCombo ( 1 , 1 , '$l' , 'l' , 'tabnext' )

endfunction

function ! ComboMove_Up ( )

call < SID > MoveCombo ( 2 , - 1 , 'gg' , 'k' , 'tabnew' )

endfunction

function ! ComboMove_Down ( )

call < SID > MoveCombo ( 2 , 1 , 'G' , 'j' , 'tabclose' )