674 lines
20 KiB
VimL
674 lines
20 KiB
VimL
|
"=============================================================================
|
||
|
" FILE: helper.vim
|
||
|
" AUTHOR: Shougo Matsushita <Shougo.Matsu@gmail.com>
|
||
|
" License: MIT license
|
||
|
"=============================================================================
|
||
|
|
||
|
if !exists('s:internal_candidates_list')
|
||
|
let s:internal_candidates_list = {}
|
||
|
let s:global_candidates_list = {
|
||
|
\ 'dictionary_variables' : {}, 'runtimepath' : &runtimepath }
|
||
|
let s:script_candidates_list = {}
|
||
|
let s:local_candidates_list = {}
|
||
|
endif
|
||
|
|
||
|
let s:dictionary_path =
|
||
|
\ substitute(fnamemodify(expand('<sfile>'), ':h'), '\\', '/', 'g')
|
||
|
|
||
|
function! necovim#helper#make_cache() abort
|
||
|
if &filetype !=# 'vim'
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
let s:script_candidates_list[bufnr('%')] =
|
||
|
\ s:get_script_candidates(bufnr('%'))
|
||
|
endfunction
|
||
|
|
||
|
function! necovim#helper#augroup(cur_text, complete_str) abort
|
||
|
" Make cache.
|
||
|
if s:check_global_candidates('augroups')
|
||
|
let s:global_candidates_list.augroups = s:get_augrouplist()
|
||
|
endif
|
||
|
|
||
|
return copy(s:global_candidates_list.augroups)
|
||
|
endfunction
|
||
|
function! necovim#helper#colorscheme_args(cur_text, complete_str) abort
|
||
|
return s:make_completion_list(map(split(
|
||
|
\ globpath(&runtimepath, 'colors/*.vim'), '\n'),
|
||
|
\ 'fnamemodify(v:val, ":t:r")'))
|
||
|
endfunction
|
||
|
function! necovim#helper#command(cur_text, complete_str) abort
|
||
|
if a:cur_text == '' ||
|
||
|
\ a:cur_text =~ '^[[:digit:],[:space:][:tab:]$''<>]*\h\w*$'
|
||
|
" Commands.
|
||
|
|
||
|
" Make cache.
|
||
|
if s:check_global_candidates('commands')
|
||
|
let s:global_candidates_list.commands = s:get_cmdlist()
|
||
|
endif
|
||
|
if !has_key(s:internal_candidates_list, 'commands')
|
||
|
let s:internal_candidates_list.commands = s:make_cache_commands()
|
||
|
endif
|
||
|
|
||
|
let list = copy(s:internal_candidates_list.commands)
|
||
|
\ + copy(s:global_candidates_list.commands)
|
||
|
else
|
||
|
" Commands args.
|
||
|
|
||
|
" Expression.
|
||
|
let list = necovim#helper#expression(a:cur_text, a:complete_str)
|
||
|
|
||
|
if s:has_cmdline()
|
||
|
let list += s:make_completion_list(
|
||
|
\ getcompletion(a:cur_text, 'cmdline'))
|
||
|
let list = s:uniq_by(list, 'v:val.word')
|
||
|
endif
|
||
|
endif
|
||
|
|
||
|
return list
|
||
|
endfunction
|
||
|
function! necovim#helper#environment(cur_text, complete_str) abort
|
||
|
" Make cache.
|
||
|
if s:check_global_candidates('environments')
|
||
|
let s:global_candidates_list.environments = s:get_envlist()
|
||
|
endif
|
||
|
|
||
|
return copy(s:global_candidates_list.environments)
|
||
|
endfunction
|
||
|
function! necovim#helper#expand(cur_text, complete_str) abort
|
||
|
return s:make_completion_list(
|
||
|
\ ['<cfile>', '<afile>', '<abuf>', '<amatch>',
|
||
|
\ '<sfile>', '<cword>', '<cWORD>', '<client>'])
|
||
|
endfunction
|
||
|
function! necovim#helper#expression(cur_text, complete_str) abort
|
||
|
return necovim#helper#function(a:cur_text, a:complete_str)
|
||
|
\+ necovim#helper#var(a:cur_text, a:complete_str)
|
||
|
endfunction
|
||
|
function! necovim#helper#feature(cur_text, complete_str) abort
|
||
|
if !has_key(s:internal_candidates_list, 'features')
|
||
|
let s:internal_candidates_list.features = s:make_cache_features()
|
||
|
endif
|
||
|
return copy(s:internal_candidates_list.features)
|
||
|
endfunction
|
||
|
function! necovim#helper#filetype(cur_text, complete_str) abort
|
||
|
if !has_key(s:internal_candidates_list, 'filetypes')
|
||
|
let s:internal_candidates_list.filetypes =
|
||
|
\ s:make_completion_list(map(
|
||
|
\ split(globpath(&runtimepath, 'syntax/*.vim'), '\n') +
|
||
|
\ split(globpath(&runtimepath, 'indent/*.vim'), '\n') +
|
||
|
\ split(globpath(&runtimepath, 'ftplugin/*.vim'), '\n')
|
||
|
\ , "matchstr(fnamemodify(v:val, ':t:r'), '^[[:alnum:]-]*')"))
|
||
|
endif
|
||
|
|
||
|
return copy(s:internal_candidates_list.filetypes)
|
||
|
endfunction
|
||
|
function! necovim#helper#function(cur_text, complete_str) abort
|
||
|
" Make cache.
|
||
|
if s:check_global_candidates('functions')
|
||
|
let s:global_candidates_list.functions = s:get_functionlist()
|
||
|
endif
|
||
|
if !has_key(s:internal_candidates_list, 'functions')
|
||
|
let s:internal_candidates_list.functions = s:make_cache_functions()
|
||
|
endif
|
||
|
|
||
|
let script_functions = values(s:get_cached_script_candidates().functions)
|
||
|
if a:complete_str =~ '^s:'
|
||
|
let list = script_functions
|
||
|
elseif a:complete_str =~ '^\a:'
|
||
|
let list = deepcopy(script_functions)
|
||
|
for keyword in list
|
||
|
let keyword.word = '<SID>' . keyword.word[2:]
|
||
|
let keyword.abbr = '<SID>' . keyword.abbr[2:]
|
||
|
endfor
|
||
|
else
|
||
|
let list = copy(s:internal_candidates_list.functions)
|
||
|
\ + copy(s:global_candidates_list.functions)
|
||
|
\ + script_functions
|
||
|
for functions in map(values(s:script_candidates_list), 'v:val.functions')
|
||
|
let list += values(filter(copy(functions), 'v:val.word[:1] !=# "s:"'))
|
||
|
endfor
|
||
|
endif
|
||
|
|
||
|
return list
|
||
|
endfunction
|
||
|
function! necovim#helper#let(cur_text, complete_str) abort
|
||
|
if a:cur_text !~ '='
|
||
|
return necovim#helper#var(a:cur_text, a:complete_str)
|
||
|
elseif a:cur_text =~# '\<let\s\+&\%([lg]:\)\?filetype\s*=\s*'
|
||
|
" FileType.
|
||
|
return necovim#helper#filetype(a:cur_text, a:complete_str)
|
||
|
else
|
||
|
return necovim#helper#expression(a:cur_text, a:complete_str)
|
||
|
endif
|
||
|
endfunction
|
||
|
function! necovim#helper#option(cur_text, complete_str) abort
|
||
|
" Make cache.
|
||
|
if !has_key(s:internal_candidates_list, 'options')
|
||
|
let s:internal_candidates_list.options = s:make_cache_options()
|
||
|
endif
|
||
|
|
||
|
if a:cur_text =~ '\<set\%[local]\s\+\%(filetype\|ft\)='
|
||
|
return necovim#helper#filetype(a:cur_text, a:complete_str)
|
||
|
else
|
||
|
return copy(s:internal_candidates_list.options)
|
||
|
endif
|
||
|
endfunction
|
||
|
function! necovim#helper#var_dictionary(cur_text, complete_str) abort
|
||
|
let var_name = matchstr(a:cur_text,
|
||
|
\'\%(\a:\)\?\h\w*\ze\.\%(\h\w*\%(()\?\)\?\)\?$')
|
||
|
let list = []
|
||
|
if a:cur_text =~ '[btwg]:\h\w*\.\%(\h\w*\%(()\?\)\?\)\?$'
|
||
|
let list = has_key(s:global_candidates_list.dictionary_variables, var_name) ?
|
||
|
\ values(s:global_candidates_list.dictionary_variables[var_name]) : []
|
||
|
elseif a:cur_text =~ 's:\h\w*\.\%(\h\w*\%(()\?\)\?\)\?$'
|
||
|
let list = values(get(s:get_cached_script_candidates().dictionary_variables,
|
||
|
\ var_name, {}))
|
||
|
endif
|
||
|
|
||
|
return list
|
||
|
endfunction
|
||
|
function! necovim#helper#var(cur_text, complete_str) abort
|
||
|
" Make cache.
|
||
|
if s:check_global_candidates('variables')
|
||
|
let s:global_candidates_list.variables =
|
||
|
\ s:get_variablelist(g:, 'g:') + s:get_variablelist(v:, 'v:')
|
||
|
\ + s:make_completion_list(['v:val'])
|
||
|
endif
|
||
|
|
||
|
if a:complete_str =~ '^[swtb]:'
|
||
|
let list = values(s:get_cached_script_candidates().variables)
|
||
|
if a:complete_str !~ '^s:'
|
||
|
let prefix = matchstr(a:complete_str, '^[swtb]:')
|
||
|
let list += s:get_variablelist(eval(prefix), prefix)
|
||
|
endif
|
||
|
elseif a:complete_str =~ '^[vg]:'
|
||
|
let list = copy(s:global_candidates_list.variables)
|
||
|
else
|
||
|
let list = s:get_local_variables()
|
||
|
endif
|
||
|
|
||
|
return list
|
||
|
endfunction
|
||
|
|
||
|
function! s:get_local_variables() abort
|
||
|
" Get local variable list.
|
||
|
|
||
|
let keyword_dict = {}
|
||
|
" Search function.
|
||
|
let line_num = line('.') - 1
|
||
|
let end_line = (line('.') > 100) ? line('.') - 100 : 1
|
||
|
while line_num >= end_line
|
||
|
let line = getline(line_num)
|
||
|
if line =~ '\<endf\%[unction]\>'
|
||
|
break
|
||
|
elseif line =~ '\<fu\%[nction]!\?\s\+'
|
||
|
" Get function arguments.
|
||
|
call s:analyze_variable_line(line, keyword_dict)
|
||
|
break
|
||
|
endif
|
||
|
|
||
|
let line_num -= 1
|
||
|
endwhile
|
||
|
let line_num += 1
|
||
|
|
||
|
let end_line = line('.') - 1
|
||
|
while line_num <= end_line
|
||
|
let line = getline(line_num)
|
||
|
|
||
|
if line =~ '\<\%(let\|for\)\s\+'
|
||
|
if line =~ '\<\%(let\|for\)\s\+s:' &&
|
||
|
\ has_key(s:script_candidates_list, bufnr('%'))
|
||
|
\ && has_key(s:script_candidates_list[bufnr('%')], 'variables')
|
||
|
let candidates_list = s:script_candidates_list[bufnr('%')].variables
|
||
|
else
|
||
|
let candidates_list = keyword_dict
|
||
|
endif
|
||
|
|
||
|
call s:analyze_variable_line(line, candidates_list)
|
||
|
endif
|
||
|
|
||
|
let line_num += 1
|
||
|
endwhile
|
||
|
|
||
|
return values(keyword_dict)
|
||
|
endfunction
|
||
|
|
||
|
function! s:get_cached_script_candidates() abort
|
||
|
return has_key(s:script_candidates_list, bufnr('%')) ?
|
||
|
\ s:script_candidates_list[bufnr('%')] : {
|
||
|
\ 'functions' : {}, 'variables' : {},
|
||
|
\ 'function_prototypes' : {}, 'dictionary_variables' : {} }
|
||
|
endfunction
|
||
|
function! s:get_script_candidates(bufnumber) abort
|
||
|
" Get script candidate list.
|
||
|
|
||
|
let function_dict = {}
|
||
|
let variable_dict = {}
|
||
|
let dictionary_variable_dict = {}
|
||
|
let function_prototypes = {}
|
||
|
let var_pattern = '\a:[[:alnum:]_:]*\.\h\w*\%(()\?\)\?'
|
||
|
|
||
|
for line in getbufline(a:bufnumber, 1, '$')
|
||
|
if line =~ '\<fu\%[nction]!\?\s\+'
|
||
|
call s:analyze_function_line(
|
||
|
\ line, function_dict, function_prototypes)
|
||
|
elseif line =~ '\<let\s\+'
|
||
|
" Get script variable.
|
||
|
call s:analyze_variable_line(line, variable_dict)
|
||
|
elseif line =~ var_pattern
|
||
|
while line =~ var_pattern
|
||
|
let var_name = matchstr(line, '\a:[[:alnum:]_:]*\ze\.\h\w*')
|
||
|
let candidates_dict = dictionary_variable_dict
|
||
|
if !has_key(candidates_dict, var_name)
|
||
|
let candidates_dict[var_name] = {}
|
||
|
endif
|
||
|
|
||
|
call s:analyze_dictionary_variable_line(
|
||
|
\ line, candidates_dict[var_name], var_name)
|
||
|
|
||
|
let line = line[matchend(line, var_pattern) :]
|
||
|
endwhile
|
||
|
endif
|
||
|
endfor
|
||
|
|
||
|
return { 'functions' : function_dict, 'variables' : variable_dict,
|
||
|
\ 'function_prototypes' : function_prototypes,
|
||
|
\ 'dictionary_variables' : dictionary_variable_dict }
|
||
|
endfunction
|
||
|
|
||
|
function! s:make_cache_options() abort
|
||
|
let options = map(filter(split(s:redir('set all'), '\s\{2,}\|\n')[1:],
|
||
|
\ "!empty(v:val) && v:val =~ '^\\h\\w*=\\?'"),
|
||
|
\ "substitute(v:val, '^no\\|=\\zs.*$', '', '')")
|
||
|
for option in copy(options)
|
||
|
if option[-1:] != '='
|
||
|
call add(options, 'no'.option)
|
||
|
endif
|
||
|
endfor
|
||
|
|
||
|
return map(filter(options, "v:val =~ '^\\h\\w*=\\?'"), "{
|
||
|
\ 'word' : substitute(v:val, '=$', '', ''), 'kind' : 'o',
|
||
|
\ }")
|
||
|
endfunction
|
||
|
function! s:make_cache_features() abort
|
||
|
let helpfile = expand(findfile('doc/eval.txt', &runtimepath))
|
||
|
|
||
|
if !filereadable(helpfile)
|
||
|
return []
|
||
|
endif
|
||
|
|
||
|
let features = []
|
||
|
let lines = readfile(helpfile)
|
||
|
let start = match(lines,
|
||
|
\ ((v:version > 704 || v:version == 704 && has('patch11')) ?
|
||
|
\ 'acl' : '^all_builtin_terms'))
|
||
|
let end = match(lines, '^x11')
|
||
|
for l in lines[start : end]
|
||
|
let _ = matchlist(l, '^\(\k\+\)\t\+\(.\+\)$')
|
||
|
if !empty(_)
|
||
|
call add(features, {
|
||
|
\ 'word' : _[1],
|
||
|
\ 'menu' : '; ' . _[2],
|
||
|
\ })
|
||
|
endif
|
||
|
endfor
|
||
|
|
||
|
call add(features, {
|
||
|
\ 'word' : 'patch',
|
||
|
\ 'menu' : '; Included patches Ex: patch123',
|
||
|
\ })
|
||
|
if has('patch-7.4.237')
|
||
|
call add(features, {
|
||
|
\ 'word' : 'patch-',
|
||
|
\ 'menu' : '; Version and patches Ex: patch-7.4.237'
|
||
|
\ })
|
||
|
endif
|
||
|
|
||
|
return features
|
||
|
endfunction
|
||
|
function! s:make_cache_functions() abort
|
||
|
let helpfile = expand(findfile('doc/eval.txt', &runtimepath))
|
||
|
if !filereadable(helpfile)
|
||
|
return []
|
||
|
endif
|
||
|
|
||
|
let lines = readfile(helpfile)
|
||
|
let functions = []
|
||
|
let start = match(lines, '^abs')
|
||
|
let end = match(lines, '^abs', start, 2)
|
||
|
for i in range(end-1, start, -1)
|
||
|
let func = matchstr(lines[i], '^\s*\zs\w\+(.\{-})')
|
||
|
if func != ''
|
||
|
call insert(functions, {
|
||
|
\ 'word' : substitute(func, '(\zs.\+)', '', ''),
|
||
|
\ 'abbr' : substitute(func, '(\zs\s\+', '', ''),
|
||
|
\ })
|
||
|
endif
|
||
|
endfor
|
||
|
|
||
|
return functions
|
||
|
endfunction
|
||
|
function! s:make_cache_commands() abort
|
||
|
let helpfile = expand(findfile('doc/index.txt', &runtimepath))
|
||
|
if !filereadable(helpfile)
|
||
|
return []
|
||
|
endif
|
||
|
|
||
|
let lines = readfile(helpfile)
|
||
|
let commands = []
|
||
|
let start = match(lines, '^|:!|')
|
||
|
let end = match(lines, '^|:\~|', start)
|
||
|
for lnum in range(end, start, -1)
|
||
|
let desc = substitute(lines[lnum], '^\s\+\ze', '', 'g')
|
||
|
let _ = matchlist(desc, '^|:\(.\{-}\)|\s\+\S\+')
|
||
|
if !empty(_)
|
||
|
call add(commands, {
|
||
|
\ 'word' : _[1], 'kind' : 'c',
|
||
|
\ })
|
||
|
endif
|
||
|
endfor
|
||
|
|
||
|
return commands
|
||
|
endfunction
|
||
|
function! s:make_cache_autocmds() abort
|
||
|
let helpfile = expand(findfile('doc/autocmd.txt', &runtimepath))
|
||
|
if !filereadable(helpfile)
|
||
|
return []
|
||
|
endif
|
||
|
|
||
|
let lines = readfile(helpfile)
|
||
|
let autocmds = []
|
||
|
let start = match(lines, '^|BufNewFile|')
|
||
|
let end = match(lines, '^|User|', start)
|
||
|
let desc = ''
|
||
|
for lnum in range(end, start, -1)
|
||
|
let desc = substitute(lines[lnum], '^\s\+\ze', '', 'g') . ' ' . desc
|
||
|
let _ = matchlist(desc, '^|\(.\{-}\)|\s\+\S\+')
|
||
|
if !empty(_)
|
||
|
call add(autocmds, { 'word' : _[1], })
|
||
|
let desc = ''
|
||
|
endif
|
||
|
endfor
|
||
|
|
||
|
return autocmds
|
||
|
endfunction
|
||
|
|
||
|
function! s:get_cmdlist() abort
|
||
|
let list = exists('*getcompletion') ?
|
||
|
\ getcompletion('', 'command') :
|
||
|
\ split(s:redir('command'), '\n')[1:]
|
||
|
return s:make_completion_list(list)
|
||
|
endfunction
|
||
|
function! s:get_variablelist(dict, prefix) abort
|
||
|
let kind_dict =
|
||
|
\ ['0', '""', '()', '[]', '{}', '.', 'b', 'no', 'j', 'ch']
|
||
|
return values(map(copy(a:dict), "{
|
||
|
\ 'word' : a:prefix.v:key,
|
||
|
\ 'kind' : kind_dict[type(v:val)],
|
||
|
\}"))
|
||
|
endfunction
|
||
|
function! s:get_functionlist() abort
|
||
|
let keyword_dict = {}
|
||
|
let function_prototypes = {}
|
||
|
for line in split(s:redir('function'), '\n')
|
||
|
let line = line[9:]
|
||
|
if line =~ '^<SNR>'
|
||
|
continue
|
||
|
endif
|
||
|
let orig_line = line
|
||
|
|
||
|
let word = matchstr(line, '\h[[:alnum:]_:#.]*()\?')
|
||
|
if word != ''
|
||
|
let keyword_dict[word] = {
|
||
|
\ 'word' : word, 'abbr' : line,
|
||
|
\}
|
||
|
|
||
|
let function_prototypes[word] = orig_line[len(word):]
|
||
|
endif
|
||
|
endfor
|
||
|
|
||
|
let s:global_candidates_list.function_prototypes = function_prototypes
|
||
|
|
||
|
return values(keyword_dict)
|
||
|
endfunction
|
||
|
function! s:get_augrouplist() abort
|
||
|
let list = exists('*getcompletion') ?
|
||
|
\ getcompletion('', 'augroup') :
|
||
|
\ split(s:redir('augroup') . ' END', '\s\|\n')
|
||
|
return s:make_completion_list(list)
|
||
|
endfunction
|
||
|
function! s:get_mappinglist() abort
|
||
|
let keyword_list = []
|
||
|
for line in split(s:redir('map'), '\n')
|
||
|
let map = matchstr(line, '^\a*\s*\zs\S\+')
|
||
|
if map !~ '^<' || map =~ '^<SNR>'
|
||
|
continue
|
||
|
endif
|
||
|
call add(keyword_list, { 'word' : map })
|
||
|
endfor
|
||
|
return keyword_list
|
||
|
endfunction
|
||
|
function! s:get_envlist() abort
|
||
|
let keyword_list = []
|
||
|
for line in split(system('set'), '\n')
|
||
|
let word = '$' . toupper(matchstr(line, '^\h\w*'))
|
||
|
call add(keyword_list, { 'word' : word, 'kind' : 'e' })
|
||
|
endfor
|
||
|
return keyword_list
|
||
|
endfunction
|
||
|
|
||
|
function! s:make_completion_list(list) abort
|
||
|
return map(copy(a:list), "{ 'word' : v:val }")
|
||
|
endfunction
|
||
|
function! s:analyze_function_line(line, keyword_dict, prototype) abort
|
||
|
" Get script function.
|
||
|
let line = substitute(matchstr(a:line,
|
||
|
\ '\<fu\%[nction]!\?\s\+\zs.*)'), '".*$', '', '')
|
||
|
let orig_line = line
|
||
|
let word = matchstr(line, '^\h[[:alnum:]_:#.]*()\?')
|
||
|
if word != '' && !has_key(a:keyword_dict, word)
|
||
|
let a:keyword_dict[word] = {
|
||
|
\ 'word' : word, 'abbr' : line, 'kind' : 'f'
|
||
|
\}
|
||
|
let a:prototype[word] = orig_line[len(word):]
|
||
|
endif
|
||
|
endfunction
|
||
|
function! s:analyze_variable_line(line, keyword_dict) abort
|
||
|
if a:line =~ '\<\%(let\|for\)\s\+\a[[:alnum:]_:]*'
|
||
|
" let var = pattern.
|
||
|
let word = matchstr(a:line, '\<\%(let\|for\)\s\+\zs\a[[:alnum:]_:]*')
|
||
|
let expression = matchstr(a:line, '\<let\s\+\a[[:alnum:]_:]*\s*=\s*\zs.*$')
|
||
|
if !has_key(a:keyword_dict, word)
|
||
|
let a:keyword_dict[word] = {
|
||
|
\ 'word' : word,
|
||
|
\ 'kind' : s:get_variable_type(expression)
|
||
|
\}
|
||
|
elseif expression != '' && a:keyword_dict[word].kind == ''
|
||
|
" Update kind.
|
||
|
let a:keyword_dict[word].kind = s:get_variable_type(expression)
|
||
|
endif
|
||
|
elseif a:line =~ '\<\%(let\|for\)\s\+\[.\{-}\]'
|
||
|
" let [var1, var2] = pattern.
|
||
|
let words = split(matchstr(a:line,
|
||
|
\'\<\%(let\|for\)\s\+\[\zs.\{-}\ze\]'), '[,[:space:]]\+')
|
||
|
let expressions = split(matchstr(a:line,
|
||
|
\'\<let\s\+\[.\{-}\]\s*=\s*\[\zs.\{-}\ze\]$'), '[,[:space:];]\+')
|
||
|
|
||
|
let i = 0
|
||
|
while i < len(words)
|
||
|
let expression = get(expressions, i, '')
|
||
|
let word = words[i]
|
||
|
|
||
|
if !has_key(a:keyword_dict, word)
|
||
|
let a:keyword_dict[word] = {
|
||
|
\ 'word' : word,
|
||
|
\ 'kind' : s:get_variable_type(expression)
|
||
|
\}
|
||
|
elseif expression != '' && a:keyword_dict[word].kind == ''
|
||
|
" Update kind.
|
||
|
let a:keyword_dict[word].kind = s:get_variable_type(expression)
|
||
|
endif
|
||
|
|
||
|
let i += 1
|
||
|
endwhile
|
||
|
elseif a:line =~ '\<fu\%[nction]!\?\s\+'
|
||
|
" Get function arguments.
|
||
|
for arg in split(matchstr(a:line, '^[^(]*(\zs[^)]*'), '\s*,\s*')
|
||
|
let word = 'a:' . (arg == '...' ? '000' : arg)
|
||
|
let a:keyword_dict[word] = {
|
||
|
\ 'word' : word,
|
||
|
\ 'kind' : (arg == '...' ? '[]' : '')
|
||
|
\}
|
||
|
|
||
|
endfor
|
||
|
if a:line =~ '\.\.\.)'
|
||
|
" Extra arguments.
|
||
|
for arg in range(5)
|
||
|
let word = 'a:' . arg
|
||
|
let a:keyword_dict[word] = {
|
||
|
\ 'word' : word,
|
||
|
\ 'kind' : (arg == 0 ? '0' : '')
|
||
|
\}
|
||
|
endfor
|
||
|
endif
|
||
|
endif
|
||
|
endfunction
|
||
|
function! s:analyze_dictionary_variable_line(line, keyword_dict, var_name) abort
|
||
|
let let_pattern = '\<let\s\+'.a:var_name.'\.\h\w*'
|
||
|
let call_pattern = '\<call\s\+'.a:var_name.'\.\h\w*()\?'
|
||
|
|
||
|
if a:line =~ let_pattern
|
||
|
let word = matchstr(a:line, a:var_name.'\zs\.\h\w*')
|
||
|
let kind = ''
|
||
|
elseif a:line =~ call_pattern
|
||
|
let word = matchstr(a:line, a:var_name.'\zs\.\h\w*()\?')
|
||
|
let kind = '()'
|
||
|
else
|
||
|
let word = matchstr(a:line, a:var_name.'\zs.\h\w*\%(()\?\)\?')
|
||
|
let kind = s:get_variable_type(
|
||
|
\ matchstr(a:line, a:var_name.'\.\h\w*\zs.*$'))
|
||
|
endif
|
||
|
|
||
|
if !has_key(a:keyword_dict, word)
|
||
|
let a:keyword_dict[word] = { 'word' : word, 'kind' : kind }
|
||
|
elseif kind != '' && a:keyword_dict[word].kind == ''
|
||
|
" Update kind.
|
||
|
let a:keyword_dict[word].kind = kind
|
||
|
endif
|
||
|
endfunction
|
||
|
function! s:split_args(cur_text, complete_str) abort
|
||
|
let args = split(a:cur_text)
|
||
|
if a:complete_str == ''
|
||
|
call add(args, '')
|
||
|
endif
|
||
|
|
||
|
return args
|
||
|
endfunction
|
||
|
|
||
|
" Initialize return types.
|
||
|
function! s:set_dictionary_helper(variable, keys, value) abort
|
||
|
for key in split(a:keys, ',')
|
||
|
let a:variable[key] = a:value
|
||
|
endfor
|
||
|
endfunction
|
||
|
let s:function_return_types = {}
|
||
|
call s:set_dictionary_helper(
|
||
|
\ s:function_return_types,
|
||
|
\ 'len,match,matchend',
|
||
|
\ '0')
|
||
|
call s:set_dictionary_helper(
|
||
|
\ s:function_return_types,
|
||
|
\ 'input,matchstr',
|
||
|
\ '""')
|
||
|
call s:set_dictionary_helper(
|
||
|
\ s:function_return_types,
|
||
|
\ 'expand,filter,sort,split',
|
||
|
\ '[]')
|
||
|
|
||
|
function! s:get_variable_type(expression) abort
|
||
|
" Analyze variable type.
|
||
|
if a:expression =~ '^\%(\s*+\)\?\s*\d\+\.\d\+'
|
||
|
return '.'
|
||
|
elseif a:expression =~ '^\%(\s*+\)\?\s*\d\+'
|
||
|
return '0'
|
||
|
elseif a:expression =~ '^\%(\s*\.\)\?\s*["'']'
|
||
|
return '""'
|
||
|
elseif a:expression =~ '\<function('
|
||
|
return '()'
|
||
|
elseif a:expression =~ '^\%(\s*+\)\?\s*\['
|
||
|
return '[]'
|
||
|
elseif a:expression =~ '^\s*{\|^\.\h[[:alnum:]_:]*'
|
||
|
return '{}'
|
||
|
elseif a:expression =~ '\<\h\w*('
|
||
|
" Function.
|
||
|
let func_name = matchstr(a:expression, '\<\zs\h\w*\ze(')
|
||
|
return has_key(s:function_return_types, func_name) ? s:function_return_types[func_name] : ''
|
||
|
else
|
||
|
return ''
|
||
|
endif
|
||
|
endfunction
|
||
|
|
||
|
function! s:set_dictionary_helper(variable, keys, pattern) abort
|
||
|
for key in split(a:keys, '\s*,\s*')
|
||
|
if !has_key(a:variable, key)
|
||
|
let a:variable[key] = a:pattern
|
||
|
endif
|
||
|
endfor
|
||
|
endfunction
|
||
|
|
||
|
function! s:check_global_candidates(key) abort
|
||
|
if s:global_candidates_list.runtimepath !=# &runtimepath
|
||
|
let s:global_candidates_list.runtimepath = &runtimepath
|
||
|
return 1
|
||
|
endif
|
||
|
|
||
|
return !has_key(s:global_candidates_list, a:key)
|
||
|
endfunction
|
||
|
function! s:redir(command) abort
|
||
|
if exists('*execute')
|
||
|
return execute(a:command)
|
||
|
endif
|
||
|
|
||
|
redir => r
|
||
|
execute 'silent!' a:command
|
||
|
redir END
|
||
|
|
||
|
return r
|
||
|
endfunction
|
||
|
|
||
|
function! s:has_cmdline() abort
|
||
|
if !exists('*getcompletion')
|
||
|
return 0
|
||
|
endif
|
||
|
|
||
|
try
|
||
|
call getcompletion('', 'cmdline')
|
||
|
catch
|
||
|
return 0
|
||
|
endtry
|
||
|
|
||
|
return 1
|
||
|
endfunction
|
||
|
|
||
|
" Removes duplicates from a list.
|
||
|
function! s:uniq(list) abort
|
||
|
return s:uniq_by(a:list, 'v:val')
|
||
|
endfunction
|
||
|
|
||
|
" Removes duplicates from a list.
|
||
|
function! s:uniq_by(list, f) abort
|
||
|
let list = map(copy(a:list), printf('[v:val, %s]', a:f))
|
||
|
let i = 0
|
||
|
let seen = {}
|
||
|
while i < len(list)
|
||
|
let key = string(list[i][1])
|
||
|
if has_key(seen, key)
|
||
|
call remove(list, i)
|
||
|
else
|
||
|
let seen[key] = 1
|
||
|
let i += 1
|
||
|
endif
|
||
|
endwhile
|
||
|
return map(list, 'v:val[0]')
|
||
|
endfunction
|