"=============================================================================
" FILE: helper.vim
" AUTHOR: Shougo Matsushita <Shougo.Matsu@gmail.com>
" License: MIT license {{{
" Permission is hereby granted, free of charge, to any person obtaining
" a copy of this software and associated documentation files (the
" "Software"), to deal in the Software without restriction, including
" without limitation the rights to use, copy, modify, merge, publish,
" distribute, sublicense, and/or sell copies of the Software, and to
" permit persons to whom the Software is furnished to do so, subject to
" the following conditions:
"
" The above copyright notice and this permission notice shall be included
" in all copies or substantial portions of the Software.
"
" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
" IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
" CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
" TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
" SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
" }}}
"=============================================================================
function! vimshell#complete#helper#files(cur_keyword_str, ...) abort "{{{
" vimshell#complete#helper#files(cur_keyword_str [, path])
if a:0 > 1
call vimshell#echo_error('Too many arguments.')
endif
let path = (a:0 == 1 ? a:1 : '.')
let list = vimshell#complete#helper#get_files(path, a:cur_keyword_str)
" Extend pseudo files.
if a:cur_keyword_str =~ '^/dev/'
for word in vimshell#complete#helper#keyword_simple_filter(
\ ['/dev/null', '/dev/clip', '/dev/quickfix'],
\ a:cur_keyword_str)
let dict = {
\ 'word' : word, 'menu' : 'file'
\}
" Escape word.
let dict.orig = vimshell#util#expand(dict.word)
let dict.word = escape(dict.word, ' *?[]"={}')
call add(list, dict)
endfor
endif
return list
endfunction"}}}
function! vimshell#complete#helper#directories(cur_keyword_str) abort "{{{
let ret = []
for keyword in filter(vimshell#complete#helper#files(a:cur_keyword_str),
\ 'isdirectory(v:val.orig) ||
\ (vimshell#util#is_windows() && fnamemodify(v:val.orig, ":e") ==? "LNK"
\ && isdirectory(resolve(v:val.orig)))')
let dict = keyword
let dict.menu = 'directory'
call add(ret, dict)
endfor
return ret
endfunction"}}}
function! vimshell#complete#helper#cdpath_directories(cur_keyword_str) abort "{{{
" Check dup.
let check = {}
for keyword in filter(vimshell#complete#helper#files(a:cur_keyword_str, &cdpath),
\ 'isdirectory(v:val.orig) || (vimshell#util#is_windows()
\ && fnamemodify(v:val.orig, ":e") ==? "LNK"
\ && isdirectory(resolve(v:val.orig)))')
if !has_key(check, keyword.word) && keyword.word =~ '/'
let check[keyword.word] = keyword
endif
endfor
let ret = []
for keyword in values(check)
let dict = keyword
let dict.menu = 'cdpath'
call add(ret, dict)
endfor
return ret
endfunction"}}}
function! vimshell#complete#helper#directory_stack(cur_keyword_str) abort "{{{
if !exists('b:vimshell')
return []
endif
let ret = []
for keyword in vimshell#complete#helper#keyword_simple_filter(
\ range(len(b:vimshell.directory_stack)), a:cur_keyword_str)
let dict = { 'word' : keyword, 'menu' : b:vimshell.directory_stack[keyword] }
call add(ret, dict)
endfor
return ret
endfunction"}}}
function! vimshell#complete#helper#aliases(cur_keyword_str) abort "{{{
if !exists('b:vimshell')
return []
endif
let ret = []
for keyword in vimshell#complete#helper#keyword_simple_filter(
\ keys(b:vimshell.alias_table), a:cur_keyword_str)
let dict = { 'word' : keyword }
if len(b:vimshell.alias_table[keyword]) > 15
let dict.menu = 'alias ' .
\ printf("%s..%s",
\ b:vimshell.alias_table[keyword][:8],
\ b:vimshell.alias_table[keyword][-4:])
else
let dict.menu = 'alias ' .
\ b:vimshell.alias_table[keyword]
endif
call add(ret, dict)
endfor
return ret
endfunction"}}}
function! vimshell#complete#helper#internals(cur_keyword_str) abort "{{{
let commands = vimshell#available_commands(a:cur_keyword_str)
let ret = []
for keyword in vimshell#complete#helper#keyword_simple_filter(
\ keys(commands), a:cur_keyword_str)
let dict = { 'word' : keyword, 'menu' : commands[keyword].kind }
call add(ret, dict)
endfor
return ret
endfunction"}}}
function! vimshell#complete#helper#executables(cur_keyword_str, ...) abort "{{{
if a:cur_keyword_str =~ '[/\\]'
let files = vimshell#complete#helper#files(a:cur_keyword_str)
else
let path = a:0 > 1 ? a:1 :
\ vimshell#util#is_windows() ? substitute($PATH, '\\\?;', ',', 'g') :
\ substitute($PATH, '/\?:', ',', 'g')
let files = vimshell#complete#helper#files(a:cur_keyword_str, path)
endif
if vimshell#util#is_windows()
let exts = escape(substitute($PATHEXT, ';', '\\|', 'g'), '.')
let pattern = (a:cur_keyword_str =~ '[/\\]')?
\ 'isdirectory(v:val.orig) || "." .
\ fnamemodify(v:val.orig, ":e") =~? '.string(exts) :
\ '"." . fnamemodify(v:val.orig, ":e") =~? '.string(exts)
else
let pattern = (a:cur_keyword_str =~ '[/\\]')?
\ 'isdirectory(v:val.orig) || executable(v:val.orig)'
\ : 'executable(v:val.orig)'
endif
call filter(files, pattern)
let ret = []
for keyword in files
let dict = keyword
let dict.menu = 'command'
if a:cur_keyword_str !~ '[/\\]'
let dict.word = fnamemodify(keyword.word, ':t')
let dict.abbr = fnamemodify(keyword.abbr, ':t')
endif
call add(ret, dict)
endfor
return ret
endfunction"}}}
function! vimshell#complete#helper#buffers(cur_keyword_str) abort "{{{
let ret = []
let bufnumber = 1
while bufnumber <= bufnr('$')
if buflisted(bufnumber) &&
\ vimshell#util#head_match(bufname(bufnumber), a:cur_keyword_str)
let keyword = bufname(bufnumber)
let dict = { 'word' : escape(keyword, ' *?[]"={}'), 'menu' : 'buffer' }
call add(ret, dict)
endif
let bufnumber += 1
endwhile
return ret
endfunction"}}}
function! vimshell#complete#helper#args(command, args) abort "{{{
let commands = vimshell#available_commands(a:command)
" Get complete words.
if has_key(get(commands, a:command, {}), 'complete')
let complete_words = commands[a:command].complete(a:args)
elseif empty(a:args)
return []
else
let complete_words = vimshell#complete#helper#files(a:args[-1])
endif
if a:args[-1] =~ '^--\?[[:alnum:]._-]\+=\f\+$\|[<>]\+\f\+$'
" Complete file.
let prefix = matchstr(a:args[-1],
\'^--[[:alnum:]._-]\+=\|^[<>]\+')
let complete_words += vimshell#complete#helper#files(
\ a:args[-1][len(prefix): ])
endif
return complete_words
endfunction"}}}
function! vimshell#complete#helper#command_args(args) abort "{{{
" command args...
if len(a:args) == 1
" Commands.
return vimshell#complete#helper#executables(a:args[0])
else
" Args.
return vimshell#complete#helper#args(a:args[0], a:args[1:])
endif
endfunction"}}}
function! vimshell#complete#helper#variables(cur_keyword_str) abort "{{{
let _ = []
let _ += map(copy(vimshell#complete#helper#environments(
\ a:cur_keyword_str[1:])), "'$' . v:val")
if a:cur_keyword_str =~ '^$\l'
let _ += map(keys(b:vimshell.variables), "'$' . v:val")
elseif a:cur_keyword_str =~ '^$$'
let _ += map(keys(b:vimshell.system_variables), "'$$' . v:val")
endif
return vimshell#complete#helper#keyword_simple_filter(_, a:cur_keyword_str)
endfunction"}}}
function! vimshell#complete#helper#environments(cur_keyword_str) abort "{{{
if !exists('s:envlist')
" Get environment variables list.
let s:envlist = map(split(system('set'), '\n'),
\ "toupper(matchstr(v:val, '^\\h\\w*'))")
endif
return vimshell#complete#helper#keyword_simple_filter(
\ copy(s:envlist), a:cur_keyword_str)
endfunction"}}}
function! vimshell#complete#helper#call_omnifunc(omnifunc) abort "{{{
" Set complete function.
let &l:omnifunc = a:omnifunc
return "\<C-x>\<C-o>\<C-p>"
endfunction"}}}
function! vimshell#complete#helper#restore_omnifunc(omnifunc) abort "{{{
if &l:omnifunc !=# a:omnifunc
let &l:omnifunc = a:omnifunc
endif
endfunction"}}}
function! vimshell#complete#helper#compare_rank(i1, i2) abort "{{{
return a:i1.rank < a:i2.rank ? 1 : a:i1.rank == a:i2.rank ? 0 : -1
endfunction"}}}
function! vimshell#complete#helper#keyword_filter(list, cur_keyword_str) abort "{{{
let cur_keyword = substitute(a:cur_keyword_str, '\\\zs.', '\0', 'g')
if &ignorecase
let expr = printf('stridx(tolower(v:val.word), %s) == 0',
\ string(tolower(cur_keyword)))
else
let expr = printf('stridx(v:val.word, %s) == 0',
\ string(cur_keyword))
endif
return filter(a:list, expr)
endfunction"}}}
function! vimshell#complete#helper#keyword_simple_filter(list, cur_keyword_str) abort "{{{
let cur_keyword = substitute(a:cur_keyword_str, '\\\zs.', '\0', 'g')
let expr = &ignorecase ?
\ printf('stridx(tolower(v:val), %s) == 0',
\ string(tolower(cur_keyword))) :
\ printf('stridx(v:val, %s) == 0',
\ string(cur_keyword))
return filter(a:list, expr)
endfunction"}}}
function! vimshell#complete#helper#get_files(path, complete_str) abort "{{{
let candidates = s:get_glob_files(a:path, a:complete_str)
if a:path == ''
let candidates = vimshell#complete#helper#keyword_filter(
\ candidates, a:complete_str)
endif
return sort(filter(copy(candidates),
\ 'v:val.action__is_directory')) +
\ sort(filter(copy(candidates),
\ '!v:val.action__is_directory'))
endfunction"}}}
function! s:get_glob_files(path, complete_str) abort "{{{
let path = ',,' . substitute(a:path, '\.\%(,\|$\)\|,,', '', 'g')
let complete_str = vimshell#util#substitute_path_separator(
\ substitute(a:complete_str, '\\\(.\)', '\1', 'g'))
let glob = (complete_str !~ '\*$')?
\ complete_str . '*' : complete_str
if a:path == ''
let files = vimshell#util#glob(glob)
else
try
let globs = globpath(path, glob)
catch
return []
endtry
let files = split(vimshell#util#substitute_path_separator(globs), '\n')
endif
let files = filter(files, "v:val !~ '/.$'")
let files = map(
\ files, "{
\ 'word' : v:val,
\ 'orig' : v:val,
\ 'action__is_directory' : isdirectory(v:val),
\ }")
if a:complete_str =~ '^\$\h\w*'
let env = matchstr(a:complete_str, '^\$\h\w*')
let env_ev = eval(env)
if env_ev == ''
return []
endif
if vimshell#util#is_windows()
let env_ev = substitute(env_ev, '\\', '/', 'g')
endif
let len_env = len(env_ev)
else
let env = ''
let env_ev = ''
let len_env = 0
endif
let home_pattern = '^'.
\ vimshell#util#substitute_path_separator(
\ expand('~')).'/'
let exts = escape(substitute($PATHEXT, ';', '\\|', 'g'), '.')
let candidates = []
for dict in files
let dict.orig = dict.word
if len_env != 0 && dict.word[: len_env-1] == env_ev
let dict.word = env . dict.word[len_env :]
endif
let abbr = dict.word
if dict.action__is_directory && dict.word !~ '/$'
let abbr .= '/'
if vimshell#util#is_auto_delimiter()
let dict.word .= '/'
endif
elseif vimshell#util#is_windows()
if '.'.fnamemodify(dict.word, ':e') =~ exts
let abbr .= '*'
endif
elseif executable(dict.word)
let abbr .= '*'
endif
let dict.abbr = abbr
if a:complete_str =~ '^\~/'
let dict.word = substitute(dict.word, home_pattern, '\~/', '')
let dict.abbr = substitute(dict.abbr, home_pattern, '\~/', '')
endif
" Escape word.
let dict.word = escape(dict.word, ' ;*?[]"={}''')
call add(candidates, dict)
endfor
return candidates
endfunction"}}}
" vim: foldmethod=marker