mirror of
https://github.com/inkarkat/vim-ingo-library.git
synced 2026-05-29 11:18:51 +02:00
129 lines
4.7 KiB
VimL
129 lines
4.7 KiB
VimL
" ingo/fs/traversal.vim: Functions for traversal of the file system.
|
|
"
|
|
" DEPENDENCIES:
|
|
" - ingo/actions.vim autoload script
|
|
" - ingo/compat.vim autoload script
|
|
" - ingo/fs/path.vim autoload script
|
|
" - ingo/os.vim autoload script
|
|
"
|
|
" Copyright: (C) 2013-2016 Ingo Karkat
|
|
" The VIM LICENSE applies to this script; see ':help copyright'.
|
|
"
|
|
" Maintainer: Ingo Karkat <ingo@karkat.de>
|
|
"
|
|
" REVISION DATE REMARKS
|
|
" 1.029.006 05-Dec-2016 Add
|
|
" ingo#fs#traversal#FindFirstContainedInUpDir().
|
|
" 1.022.005 22-Sep-2014 Use ingo#compat#globpath().
|
|
" 1.013.004 13-Sep-2013 Use operating system detection functions from
|
|
" ingo/os.vim.
|
|
" 1.011.003 01-Aug-2013 Make a:path argument optional and default to the
|
|
" current buffer's directory (as all existing
|
|
" clients use that).
|
|
" Add ingo#fs#traversal#FindDirUpwards().
|
|
" 1.003.002 26-Mar-2013 Rename to
|
|
" ingo#fs#traversal#FindLastContainedInUpDir()
|
|
" 001 22-Mar-2013 file creation
|
|
let s:save_cpo = &cpo
|
|
set cpo&vim
|
|
|
|
function! ingo#fs#traversal#FindDirUpwards( Predicate, ... )
|
|
"******************************************************************************
|
|
"* PURPOSE:
|
|
" Find directory where a:Predicate matches in a:path, searching upwards. Like
|
|
" |finddir()|, but supports not just fixed directory names, but only upwards
|
|
" search.
|
|
"* ASSUMPTIONS / PRECONDITIONS:
|
|
" None.
|
|
"* EFFECTS / POSTCONDITIONS:
|
|
" None.
|
|
"* INPUTS:
|
|
" a:Predicate Either a Funcref that gets invoked with a dirspec, or an
|
|
" expression where "v:val" is replaced with a dirspec.
|
|
" a:dirspec Optional starting directory. Should be absolute or at least in a
|
|
" format that allows upward traversal via :h. If omitted, the
|
|
" search starts from the current buffer's directory.
|
|
"* RETURN VALUES:
|
|
" First dirspec where a:Predicate returns true.
|
|
" Empty string when that never happens until the root directory is reached.
|
|
"******************************************************************************
|
|
let l:dir = (a:0 ? a:1 : expand('%:p:h'))
|
|
let l:prevDir = ''
|
|
while l:dir !=# l:prevDir
|
|
if ingo#actions#EvaluateWithValOrFunc(a:Predicate, l:dir)
|
|
return l:dir
|
|
endif
|
|
|
|
" Stop iterating after reaching the file system root.
|
|
if ingo#os#IsWindows() && ingo#fs#path#IsUncPathRoot(l:dir)
|
|
break
|
|
endif
|
|
let l:prevDir = l:dir
|
|
let l:dir = fnamemodify(l:dir, ':h')
|
|
endwhile
|
|
|
|
return ''
|
|
endfunction
|
|
|
|
function! ingo#fs#traversal#FindFirstContainedInUpDir( expr, ... )
|
|
"******************************************************************************
|
|
"* PURPOSE:
|
|
" Traversing upwards from the current buffer's directory, find the first
|
|
" directory that yields a match for the a:expr glob.
|
|
"* ASSUMPTIONS / PRECONDITIONS:
|
|
" None.
|
|
"* EFFECTS / POSTCONDITIONS:
|
|
" None.
|
|
"* INPUTS:
|
|
" a:expr File glob that must match in the target upwards directory.
|
|
" a:dirspec Optional starting directory. Should be absolute or at least in a
|
|
" format that allows upward traversal via :h. If omitted, the
|
|
" search starts from the current buffer's directory.
|
|
"* RETURN VALUES:
|
|
" Dirspec of the first parent directory that matches a:expr.
|
|
" Empty string if a:expr every matches up to the filesytem's root.
|
|
"******************************************************************************
|
|
return call(
|
|
\ function('ingo#fs#traversal#FindDirUpwards'),
|
|
\ [printf('! empty(ingo#compat#glob(ingo#fs#path#Combine(v:val, %s), 1))', string(a:expr))] + a:000
|
|
\)
|
|
endfunction
|
|
|
|
function! ingo#fs#traversal#FindLastContainedInUpDir( expr, ... )
|
|
"******************************************************************************
|
|
"* PURPOSE:
|
|
" Traversing upwards from the current buffer's directory, find the last
|
|
" directory that yields a match for the a:expr glob.
|
|
"* ASSUMPTIONS / PRECONDITIONS:
|
|
" None.
|
|
"* EFFECTS / POSTCONDITIONS:
|
|
" None.
|
|
"* INPUTS:
|
|
" a:expr File glob that must match in each upwards directory.
|
|
" a:dirspec Optional starting directory. Should be absolute or at least in a
|
|
" format that allows upward traversal via :h. If omitted, the
|
|
" search starts from the current buffer's directory.
|
|
"* RETURN VALUES:
|
|
" Dirspec of the highest directory that still matches a:expr.
|
|
" Empty string if a:expr doesn't even match in the starting directory.
|
|
"******************************************************************************
|
|
let l:dir = (a:0 ? a:1 : expand('%:p:h'))
|
|
let l:prevDir = ''
|
|
while l:dir !=# l:prevDir
|
|
if empty(ingo#compat#globpath(l:dir, a:expr, 1))
|
|
return l:prevDir
|
|
endif
|
|
let l:prevDir = l:dir
|
|
let l:dir = fnamemodify(l:dir, ':h')
|
|
if ingo#os#IsWindows() && ingo#fs#path#IsUncPathRoot(l:dir)
|
|
break
|
|
endif
|
|
endwhile
|
|
|
|
return l:dir
|
|
endfunction
|
|
|
|
let &cpo = s:save_cpo
|
|
unlet s:save_cpo
|
|
" vim: set ts=8 sts=4 sw=4 noexpandtab ff=unix fdm=syntax :
|