277 lines
7.9 KiB
VimL
277 lines
7.9 KiB
VimL
|
"=============================================================================
|
||
|
" FILE: async_cache.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 condition
|
||
|
"
|
||
|
" 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.
|
||
|
" }}}
|
||
|
"=============================================================================
|
||
|
|
||
|
let s:save_cpo = &cpo
|
||
|
set cpo&vim
|
||
|
|
||
|
function! s:main(argv) abort "{{{
|
||
|
" args: funcname, outputname filename pattern_file_name mark minlen fileencoding
|
||
|
let [funcname, outputname, filename, pattern_file_name, mark, minlen, fileencoding]
|
||
|
\ = a:argv
|
||
|
|
||
|
if funcname ==# 'load_from_file'
|
||
|
let keyword_list = s:load_from_file(
|
||
|
\ filename, pattern_file_name, mark, minlen, fileencoding, 1)
|
||
|
|
||
|
let string = '{' . escape(string(keyword_list)[1 : -2], '\\') . '}'
|
||
|
else
|
||
|
let keyword_list = s:load_from_tags(
|
||
|
\ filename, pattern_file_name, mark, minlen, fileencoding)
|
||
|
let string = string(keyword_list)
|
||
|
endif
|
||
|
|
||
|
if empty(keyword_list)
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
" For neocomplete.
|
||
|
" Output cache.
|
||
|
call writefile([string], outputname)
|
||
|
endfunction"}}}
|
||
|
|
||
|
function! s:load_from_file(filename, pattern_file_name, mark, minlen, fileencoding, is_string) abort "{{{
|
||
|
if !filereadable(a:filename)
|
||
|
" File not found.
|
||
|
return []
|
||
|
endif
|
||
|
|
||
|
let lines = readfile(a:filename)
|
||
|
if a:fileencoding !=# &encoding
|
||
|
let lines = map(lines, 's:iconv(v:val, a:fileencoding, &encoding)')
|
||
|
endif
|
||
|
|
||
|
let pattern = get(readfile(a:pattern_file_name), 0, '\h\w*')
|
||
|
let pattern2 = '^\%('.pattern.'\m\)'
|
||
|
let keyword_list = []
|
||
|
let dup_check = {}
|
||
|
|
||
|
for line in lines "{{{
|
||
|
let match = match(line, pattern)
|
||
|
while match >= 0 "{{{
|
||
|
let match_str = matchstr(line, pattern2, match)
|
||
|
|
||
|
if !has_key(dup_check, match_str) && len(match_str) >= a:minlen
|
||
|
" Append list.
|
||
|
call add(keyword_list, match_str)
|
||
|
let dup_check[match_str] = 1
|
||
|
endif
|
||
|
|
||
|
if match_str == ''
|
||
|
break
|
||
|
endif
|
||
|
|
||
|
let match += len(match_str)
|
||
|
|
||
|
let match = match(line, pattern, match)
|
||
|
endwhile"}}}
|
||
|
endfor"}}}
|
||
|
|
||
|
if !a:is_string
|
||
|
call map(keyword_list, "{'word' : match_str}")
|
||
|
endif
|
||
|
|
||
|
return keyword_list
|
||
|
endfunction"}}}
|
||
|
|
||
|
function! s:load_from_tags(filename, pattern_file_name, mark, minlen, fileencoding) abort "{{{
|
||
|
let keyword_lists = []
|
||
|
let dup_check = {}
|
||
|
|
||
|
let [tags_file_name, filter_pattern] =
|
||
|
\ readfile(a:pattern_file_name)[1 : 2]
|
||
|
if tags_file_name !=# '$dummy$'
|
||
|
" Check output.
|
||
|
let tags_list = []
|
||
|
|
||
|
let i = 0
|
||
|
while i < 2
|
||
|
if filereadable(tags_file_name)
|
||
|
" Use filename.
|
||
|
let tags_list = map(readfile(tags_file_name),
|
||
|
\ 's:iconv(v:val, a:fileencoding, &encoding)')
|
||
|
break
|
||
|
endif
|
||
|
|
||
|
sleep 500m
|
||
|
let i += 1
|
||
|
endwhile
|
||
|
else
|
||
|
if !filereadable(a:filename)
|
||
|
return []
|
||
|
endif
|
||
|
|
||
|
" Use filename.
|
||
|
let tags_list = map(readfile(a:filename),
|
||
|
\ 's:iconv(v:val, a:fileencoding, &encoding)')
|
||
|
endif
|
||
|
|
||
|
if empty(tags_list)
|
||
|
return s:load_from_file(a:filename, a:pattern_file_name,
|
||
|
\ a:mark, a:minlen, a:fileencoding, 0)
|
||
|
endif
|
||
|
|
||
|
for line in tags_list
|
||
|
let tag = split(substitute(line, "\<CR>", '', 'g'), '\t', 1)
|
||
|
|
||
|
" Add keywords.
|
||
|
if line =~ '^!' || len(tag) < 3 || len(tag[0]) < a:minlen
|
||
|
\ || has_key(dup_check, tag[0])
|
||
|
continue
|
||
|
endif
|
||
|
|
||
|
let opt = join(tag[2:], "\<TAB>")
|
||
|
let cmd = matchstr(opt, '.*/;"')
|
||
|
|
||
|
let option = {
|
||
|
\ 'cmd' : substitute(substitute(substitute(cmd,
|
||
|
\'^\%([/?]\^\?\)\?\s*\|\%(\$\?[/?]\)\?;"$', '', 'g'),
|
||
|
\ '\\\\', '\\', 'g'), '\\/', '/', 'g'),
|
||
|
\ 'kind' : ''
|
||
|
\}
|
||
|
if option.cmd =~ '\d\+'
|
||
|
let option.cmd = tag[0]
|
||
|
endif
|
||
|
|
||
|
for opt in split(opt[len(cmd):], '\t', 1)
|
||
|
let key = matchstr(opt, '^\h\w*\ze:')
|
||
|
if key == ''
|
||
|
let option['kind'] = opt
|
||
|
else
|
||
|
let option[key] = matchstr(opt, '^\h\w*:\zs.*')
|
||
|
endif
|
||
|
endfor
|
||
|
|
||
|
if has_key(option, 'file')
|
||
|
\ || (has_key(option, 'access') && option.access != 'public')
|
||
|
continue
|
||
|
endif
|
||
|
|
||
|
let abbr = has_key(option, 'signature')? tag[0] . option.signature :
|
||
|
\ (option['kind'] == 'd' || option['cmd'] == '') ?
|
||
|
\ tag[0] : option['cmd']
|
||
|
let abbr = substitute(abbr, '\s\+', ' ', 'g')
|
||
|
" Substitute "namespace foobar" to "foobar <namespace>".
|
||
|
let abbr = substitute(abbr,
|
||
|
\'^\(namespace\|class\|struct\|enum\|union\)\s\+\(.*\)$',
|
||
|
\'\2 <\1>', '')
|
||
|
" Substitute typedef.
|
||
|
let abbr = substitute(abbr,
|
||
|
\'^typedef\s\+\(.*\)\s\+\(\h\w*\%(::\w*\)*\);\?$',
|
||
|
\'\2 <typedef \1>', 'g')
|
||
|
" Substitute extends and implements.
|
||
|
let abbr = substitute(abbr,
|
||
|
\'\<\%(extends\|implements\)\s\+\S\+\>', '', '')
|
||
|
" Substitute marker.
|
||
|
let abbr = substitute(abbr, '"\s*{{{', '', '')
|
||
|
|
||
|
let keyword = {
|
||
|
\ 'word' : tag[0], 'abbr' : abbr, 'menu' : '',
|
||
|
\ 'kind' : option['kind'],
|
||
|
\ }
|
||
|
if has_key(option, 'struct')
|
||
|
let keyword.menu = option.struct
|
||
|
elseif has_key(option, 'class')
|
||
|
let keyword.menu = option.class
|
||
|
elseif has_key(option, 'enum')
|
||
|
let keyword.menu = option.enum
|
||
|
elseif has_key(option, 'union')
|
||
|
let keyword.menu = option.union
|
||
|
endif
|
||
|
|
||
|
call add(keyword_lists, keyword)
|
||
|
let dup_check[tag[0]] = 1
|
||
|
endfor"}}}
|
||
|
|
||
|
if filter_pattern != ''
|
||
|
call filter(keyword_lists, filter_pattern)
|
||
|
endif
|
||
|
|
||
|
return keyword_lists
|
||
|
endfunction"}}}
|
||
|
|
||
|
function! s:truncate(str, width) abort "{{{
|
||
|
" Original function is from mattn.
|
||
|
" http://github.com/mattn/googlereader-vim/tree/master
|
||
|
|
||
|
if a:str =~# '^[\x00-\x7f]*$'
|
||
|
return len(a:str) < a:width ?
|
||
|
\ printf('%-'.a:width.'s', a:str) : strpart(a:str, 0, a:width)
|
||
|
endif
|
||
|
|
||
|
let ret = a:str
|
||
|
let width = strdisplaywidth(a:str)
|
||
|
if width > a:width
|
||
|
let ret = s:strwidthpart(ret, a:width)
|
||
|
let width = strdisplaywidth(ret)
|
||
|
endif
|
||
|
|
||
|
if width < a:width
|
||
|
let ret .= repeat(' ', a:width - width)
|
||
|
endif
|
||
|
|
||
|
return ret
|
||
|
endfunction"}}}
|
||
|
|
||
|
function! s:strwidthpart(str, width) abort "{{{
|
||
|
let ret = a:str
|
||
|
let width = strdisplaywidth(a:str)
|
||
|
while width > a:width
|
||
|
let char = matchstr(ret, '.$')
|
||
|
let ret = ret[: -1 - len(char)]
|
||
|
let width -= strwidth(char)
|
||
|
endwhile
|
||
|
|
||
|
return ret
|
||
|
endfunction"}}}
|
||
|
|
||
|
function! s:iconv(expr, from, to) abort
|
||
|
if a:from == '' || a:to == '' || a:from ==? a:to
|
||
|
return a:expr
|
||
|
endif
|
||
|
let result = iconv(a:expr, a:from, a:to)
|
||
|
return result != '' ? result : a:expr
|
||
|
endfunction
|
||
|
|
||
|
if argc() == 7 &&
|
||
|
\ (argv(0) ==# 'load_from_file' || argv(0) ==# 'load_from_tags')
|
||
|
try
|
||
|
call s:main(argv())
|
||
|
catch
|
||
|
call writefile([v:throwpoint, v:exception],
|
||
|
\ fnamemodify(argv(1), ':h:h').'/async_error_log')
|
||
|
endtry
|
||
|
|
||
|
qall!
|
||
|
else
|
||
|
function! neocomplete#async_cache#main(argv) abort "{{{
|
||
|
call s:main(a:argv)
|
||
|
endfunction"}}}
|
||
|
endif
|
||
|
|
||
|
let &cpo = s:save_cpo
|
||
|
unlet s:save_cpo
|
||
|
|
||
|
" vim: foldmethod=marker
|