Files
Ingo Karkat 03cf81bd51
2017-05-26 17:51:05 +02:00

174 lines
6.7 KiB
VimL

" ingo/window/locate.vim: Functions to locate a window.
"
" DEPENDENCIES:
" - ingo/actions.vim autoload script
"
" Copyright: (C) 2016 Ingo Karkat
" The VIM LICENSE applies to this script; see ':help copyright'.
"
" Maintainer: Ingo Karkat <ingo@karkat.de>
"
" REVISION DATE REMARKS
" 1.028.001 25-Nov-2016 file creation
function! s:Match( winVarName, Predicate, winNr, ... )
if a:0 >= 2 && a:winNr == a:2
return 0
endif
let l:tabNr = (a:0 ? a:1 : tabpagenr())
let l:value = gettabwinvar(l:tabNr, a:winNr, a:winVarName)
return !! ingo#actions#EvaluateWithValOrFunc(a:Predicate, l:value)
endfunction
function! s:CheckTabPageNearest( tabNr, winVarName, Predicate, ... )
let l:skipWinNr = (a:0 ? a:1 : 0)
let [l:currentWinNr, l:previousWinNr, l:lastWinNr] = [tabpagewinnr(a:tabNr), tabpagewinnr(a:tabNr, '#'), tabpagewinnr(a:tabNr, '$')]
if s:Match(a:winVarName, a:Predicate, l:currentWinNr, a:tabNr, l:skipWinNr)
return [a:tabNr, l:currentWinNr]
elseif s:Match(a:winVarName, a:Predicate, l:previousWinNr, a:tabNr, l:skipWinNr)
return [a:tabNr, l:previousWinNr]
endif
let l:offset = 1
while l:currentWinNr - l:offset > 0 || l:currentWinNr + l:offset <= l:lastWinNr
if s:Match(a:winVarName, a:Predicate, l:currentWinNr - l:offset, a:tabNr, l:skipWinNr)
return [a:tabNr, l:currentWinNr - l:offset]
elseif s:Match(a:winVarName, a:Predicate, l:currentWinNr + l:offset, a:tabNr, l:skipWinNr)
return [a:tabNr, l:currentWinNr + l:offset]
endif
let l:offset += 1
endwhile
return [0, 0]
endfunction
function! ingo#window#locate#NearestByPredicate( isSearchOtherTabPages, winVarName, Predicate )
"******************************************************************************
"* PURPOSE:
" Locate the window closest to the current one where the window variable a:winVarName makes
" a:Predicate (passed in as argument or v:val) true.
"* ASSUMPTIONS / PRECONDITIONS:
" None.
"* EFFECTS / POSTCONDITIONS:
" None.
"* INPUTS:
" a:isSearchOtherTabPages Flag whether windows in other tab pages should also
" be considered.
" a:winVarName Name of the window-local variable, like in
" |gettabwinvar()|
" a:Predicate Either a Funcref or an expression to be eval()ed.
" Gets the value of a:winVarName passed, should return
" a boolean value.
"* RETURN VALUES:
" [tabpagenr, winnr] if a:isSearchOtherTabPages and the found window is on a
" different tab page
" [0, winnr] if the window is on the current tab page
" [0, 0] if a:Predicate did not yield true in any other window
"******************************************************************************
let l:lastWinNr = winnr('#')
if l:lastWinNr != 0 && s:Match(a:winVarName, a:Predicate, l:lastWinNr)
return [tabpagenr(), l:lastWinNr]
endif
let l:result = s:CheckTabPageNearest(tabpagenr(), a:winVarName, a:Predicate, winnr())
if l:result != [0, 0] || ! a:isSearchOtherTabPages
return l:result
endif
let [l:currentTabPageNr, l:lastTabPageNr] = [tabpagenr(), tabpagenr('$')]
let l:offset = 1
while l:currentTabPageNr - l:offset > 0 || l:currentTabPageNr + l:offset <= l:lastTabPageNr
let l:result = s:CheckTabPageNearest(l:currentTabPageNr - l:offset, a:winVarName, a:Predicate)
if l:result != [0, 0] | return l:result | endif
let l:result = s:CheckTabPageNearest(l:currentTabPageNr + l:offset, a:winVarName, a:Predicate)
if l:result != [0, 0] | return l:result | endif
let l:offset += 1
endwhile
return [0, 0]
endfunction
function! ingo#window#locate#FirstByPredicate( isSearchOtherTabPages, winVarName, Predicate )
"******************************************************************************
"* PURPOSE:
" Locate the first window (in this tab page, or with a:isSearchOtherTabPages
" in other tabs) where the window variable a:winVarName makes a:Predicate
" (passed in as argument or v:val) true.
"* ASSUMPTIONS / PRECONDITIONS:
" None.
"* EFFECTS / POSTCONDITIONS:
" None.
"* INPUTS:
" a:isSearchOtherTabPages Flag whether windows in other tab pages should also
" be considered.
" a:winVarName Name of the window-local variable, like in
" |gettabwinvar()|
" a:Predicate Either a Funcref or an expression to be eval()ed.
" Gets the value of a:winVarName passed, should return
" a boolean value.
"* RETURN VALUES:
" [tabpagenr, winnr] if a:isSearchOtherTabPages and the found window is on a
" different tab page
" [0, winnr] if the window is on the current tab page
" [0, 0] if a:Predicate did not yield true in any other window
"******************************************************************************
for l:winNr in range(1, winnr('$'))
if s:Match(a:winVarName, a:Predicate, l:winNr)
return [0, l:winNr]
endif
endfor
if ! a:isSearchOtherTabPages
return [0, 0]
endif
for l:tabPageNr in filter(range(1, tabpagenr('$')), 'v:val != ' . tabpagenr())
let l:lastWinNr = tabpagewinnr(l:tabPageNr, '$')
for l:winNr in range(1, l:lastWinNr)
if s:Match(a:winVarName, a:Predicate, l:winNr, l:tabPageNr)
return [l:tabPageNr, l:winNr]
endif
endfor
endfor
return [0, 0]
endfunction
function! ingo#window#locate#ByPredicate( strategy, isSearchOtherTabPages, winVarName, Predicate )
"******************************************************************************
"* PURPOSE:
" Locate a window (in this tab page, or with a:isSearchOtherTabPages in other
" tabs), with a:strategy to determine precedences, where the window variable
" a:winVarName makes a:Predicate (passed in as argument or v:val) true.
"* ASSUMPTIONS / PRECONDITIONS:
" None.
"* EFFECTS / POSTCONDITIONS:
" None.
"* INPUTS:
" a:strategy One of "first" or "nearest".
" a:isSearchOtherTabPages Flag whether windows in other tab pages should also
" be considered.
" a:winVarName Name of the window-local variable, like in
" |gettabwinvar()|
" a:Predicate Either a Funcref or an expression to be eval()ed.
" Gets the value of a:winVarName passed, should return
" a boolean value.
"* RETURN VALUES:
" [tabpagenr, winnr] if a:isSearchOtherTabPages and the found window is on a
" different tab page
" [0, winnr] if the window is on the current tab page
" [0, 0] if a:Predicate did not yield true in any other window
"******************************************************************************
if a:strategy ==# 'first'
return ingo#window#locate#FirstByPredicate(a:isSearchOtherTabPages, a:winVarName, a:Predicate)
elseif a:strategy ==# 'nearest'
return ingo#window#locate#NearestByPredicate(a:isSearchOtherTabPages, a:winVarName, a:Predicate)
else
throw 'ASSERT: Unknown strategy ' . string(a:strategy)
endif
endfunction
" vism: set ts=8 sts=4 sw=4 noexpandtab ff=unix fdm=syntax :