Files

154 lines
6.3 KiB
VimL

" ingo/cmdargs/glob.vim: Functions for expanding file glob arguments.
"
" DEPENDENCIES:
" - ingo/cmdargs/file.vim autoload script
" - ingo/compat.vim autoload script
" - ingo/os.vim autoload script
"
" Copyright: (C) 2012-2016 Ingo Karkat
" The VIM LICENSE applies to this script; see ':help copyright'.
"
" Maintainer: Ingo Karkat <ingo@karkat.de>
"
" REVISION DATE REMARKS
" 1.025.004 08-Jul-2016 ENH: Add second optional flag
" a:isKeepDirectories to
" ingo#cmdargs#glob#Expand() /
" ingo#cmdargs#glob#ExpandSingle().
" 1.022.003 22-Sep-2014 Use ingo#compat#glob().
" 1.013.002 13-Sep-2013 Use operating system detection functions from
" ingo/os.vim.
" 1.007.001 01-Jun-2013 file creation from ingofileargs.vim
function! ingo#cmdargs#glob#ExpandSingle( fileglob, ... )
"******************************************************************************
"* PURPOSE:
" Expand any file wildcards in a:fileglob to a list of normal filespecs.
"* ASSUMPTIONS / PRECONDITIONS:
" None.
"* EFFECTS / POSTCONDITIONS:
" None.
"* INPUTS:
" a:fileglob File glob (already processed by
" ingo#cmdargs#file#Unescape()).
" a:isKeepNoMatch Optional flag that lets globs that have no matches be kept
" and returned as-is, instead of being removed. Set this when
" you want to support creating new files.
" a:isKeepDirectories Optional flag that keeps directories in the list.
"* RETURN VALUES:
" List of normal filespecs; globs have been expanded. To consume this in
" another Vim command, use:
" join(map(l:filespecs, 'fnameescape(v:val)))
"******************************************************************************
" XXX: Special Vim variables are expanded by -complete=file, but (in Vim
" 7.3), escaped special names are _not_ correctly re-escaped, and a
" following glob() or expand() will mistakenly expand them. Because of the
" auto-expansion, any unescaped special Vim variable that gets here is in
" fact a literal special filename. We don't even need to re-escape and
" glob() it, just return it verbatim.
if a:fileglob =~# '^\%(%\|#\d\?\)\%(:\a\)*$\|^<\%(cfile\|cword\|cWORD\)>\%(:\a\)*$'
return [a:fileglob]
else
" Filter out directories; we're usually only interested in files.
let l:specs = (a:0 && a:1 ? split(expand(a:fileglob), '\n') : ingo#compat#glob(a:fileglob, 0, 1))
return (a:0 >= 2 && a:2 ? l:specs : filter(l:specs, '! isdirectory(v:val)'))
endif
endfunction
function! ingo#cmdargs#glob#Expand( fileglobs, ... )
"******************************************************************************
"* PURPOSE:
" Expand any file wildcards in a:fileglobs to a list of normal filespecs.
"* ASSUMPTIONS / PRECONDITIONS:
" None.
"* EFFECTS / POSTCONDITIONS:
" None.
"* INPUTS:
" a:fileglobs Either space-separated arguments string (from a :command
" -complete=file ... <q-args> custom command), or a list of
" fileglobs (already processed by
" ingo#cmdargs#file#Unescape()).
" a:isKeepNoMatch Optional flag that lets globs that have no matches be kept
" and returned as-is, instead of being removed. Set this when
" you want to support creating new files.
" a:isKeepDirectories Optional flag that keeps directories in the list.
"* RETURN VALUES:
" List of filespecs; globs have been expanded. To consume this in another Vim
" command, use:
" join(map(l:filespecs, 'fnameescape(v:val)))
"******************************************************************************
let l:fileglobs = (type(a:fileglobs) == type([]) ? a:fileglobs : ingo#cmdargs#file#SplitAndUnescape(a:fileglobs))
let l:filespecs = []
for l:fileglob in l:fileglobs
call extend(l:filespecs, call('ingo#cmdargs#glob#ExpandSingle', [l:fileglob] + a:000))
endfor
return l:filespecs
endfunction
function! s:ContainsNoWildcards( fileglob )
" Note: This is only an empirical approximation; it is not perfect.
if ingo#os#IsWinOrDos()
return a:fileglob !~ '[*?]'
else
return a:fileglob !~ '\\\@<![*?{[]'
endif
endfunction
function! ingo#cmdargs#glob#Resolve( fileglobs )
"*******************************************************************************
"* PURPOSE:
" Expand any file wildcards in a:fileglobs, convert to normal filespecs
" and assemble file statistics. Like ingo#cmdargs#glob#Expand(), but
" additionally returns statistics.
"* ASSUMPTIONS / PRECONDITIONS:
" None.
"* EFFECTS / POSTCONDITIONS:
" None.
"* INPUTS:
" a:fileglobs Raw list of file patterns.
"* RETURN VALUES:
" [l:filespecs, l:statistics] First element is a list of the resolved
" filespecs (in normal, not Ex syntax), second element is a dictionary
" containing the file statistics.
"*******************************************************************************
let l:statistics = { 'files': 0, 'removed': 0, 'nonexisting': 0 }
let l:filespecs = []
for l:fileglob in a:fileglobs
let l:resolvedFilespecs = ingo#cmdargs#glob#ExpandSingle(l:fileglob)
if empty(l:resolvedFilespecs)
" To treat the file pattern as a filespec, we must emulate one
" effect of glob(): It removes superfluous escaping of spaces in the
" filespec (but leaves other escaped characters like 'C:\\foo'
" as-is). Without this substitution, the filereadable() check won't
" work.
let l:normalizedPotentialFilespec = substitute(l:fileglob, '\\\@<!\\ ', ' ', 'g')
" The globbing yielded no files; however:
if filereadable(l:normalizedPotentialFilespec)
" a) The file pattern itself represents an existing file. This
" happens if a file is passed that matches one of the
" 'wildignore' patterns. In this case, as the file has been
" explicitly passed to us, we include it.
let l:filespecs += [l:normalizedPotentialFilespec]
elseif s:ContainsNoWildcards(l:fileglob)
" b) The file pattern contains no wildcards and represents a
" to-be-created file.
let l:filespecs += [l:fileglob]
let l:statistics.nonexisting += 1
else
" Nothing matched this file pattern, or whatever matched is
" covered by the 'wildignore' patterns and not a file itself.
let l:statistics.removed += 1
endif
else
" We include whatever the globbing returned; 'wildignore' patterns
" are filtered out.
let l:filespecs += l:resolvedFilespecs
endif
endfor
let l:statistics.files = len(l:filespecs)
return [l:filespecs, l:statistics]
endfunction
" vim: set ts=8 sts=4 sw=4 noexpandtab ff=unix fdm=syntax :