diff --git a/autoload/unite/sources/help.vim b/autoload/unite/sources/help.vim index 55bc2a5..2bed2f6 100644 --- a/autoload/unite/sources/help.vim +++ b/autoload/unite/sources/help.vim @@ -1,6 +1,6 @@ " help source for unite.vim " Version: 0.0.3 -" Last Change: 15 Nov 2010 +" Last Change: 14 Feb 2014. " Author: tsukkee " Licence: The MIT License {{{ " Permission is hereby granted, free of charge, to any person obtaining a copy @@ -24,26 +24,36 @@ " define source function! unite#sources#help#define() - return s:source + return unite#util#has_vimproc() ? s:source : {} endfunction +let s:Cache = unite#util#get_vital_cache() " cache let s:cache = [] +let s:cont_number = 0 +let s:cont_max = 0 function! unite#sources#help#refresh() let s:cache = [] + + let cache_dir = unite#get_data_directory() . '/help' + if s:Cache.filereadable(cache_dir, 'help-cache') + " Delete cache file. + call s:Cache.deletefile(cache_dir, 'help-cache') + endif endfunction +let s:vimproc_files = {} " source let s:source = { \ 'name': 'help', \ 'max_candidates': 50, -\ 'required_pattern_length': 1, \ 'action_table': {}, -\ 'default_action': {'common': 'execute'} +\ 'hooks': {}, +\ 'default_action': 'execute', +\ 'filters' : ['matcher_default', 'sorter_word', 'converter_default'], \} -function! s:source.gather_candidates(args, context) - let should_refresh = a:context.is_redraw +function! s:source.hooks.on_init(args, context) let lang_filter = [] for arg in a:args if arg == '!' @@ -55,42 +65,130 @@ function! s:source.gather_candidates(args, context) endif endfor + let a:context.source__lang_filter = lang_filter + + let a:context.source__input = a:context.input + if a:context.source__input == '' + let a:context.source__input = + \ unite#util#input('Please input search word: ', '', 'help') + endif + + call unite#print_source_message('Search word: ' + \ . a:context.source__input, s:source.name) +endfunction +function! s:source.gather_candidates(args, context) + let should_refresh = a:context.is_redraw + if should_refresh call unite#sources#help#refresh() + let a:context.is_async = 1 + endif + + let cache_dir = unite#get_data_directory() . '/help' + if s:Cache.filereadable(cache_dir, 'help-cache') + " Use cache file. + let s:cache = eval(get(s:Cache.readfile( + \ cache_dir, 'help-cache'), 0, '[]')) + + let a:context.is_async = 0 + call unite#print_source_message('Completed.', s:source.name) endif - if empty(s:cache) - for tagfile in split(globpath(&runtimepath, 'doc/{tags,tags-*}'), "\n") - if !filereadable(tagfile) | continue | endif - - let lang = matchstr(tagfile, 'tags-\zs[a-z]\{2\}') - let place = fnamemodify(expand(tagfile), ':p:h:h:t') - - for line in readfile(tagfile) - let name = split(line, "\t")[0] - let word = name . '@' . (!empty(lang) ? lang : 'en') - let abbr = printf( - \ "%s%s (in %s)", name, !empty(lang) ? '@' . lang : '', place) - - " if not comment line - if stridx(name, "!") != 0 - call add(s:cache, { - \ 'word': word, - \ 'abbr': abbr, - \ 'kind': 'common', - \ 'source': 'help', - \ 'action__command': 'help ' . word, - \ 'source__lang' : !empty(lang) ? lang : 'en' - \}) - endif - endfor + if !empty(s:cache) + let list = copy(s:cache) + + return s:filter_list(list, a:context) + endif + + " load files. + let s:vimproc_files = {} + for tagfile in s:globpath(&runtimepath, 'doc/{tags,tags-*}', 1, 1) + if !filereadable(tagfile) | continue | endif + + let file = { + \ 'proc' : vimproc#fopen(tagfile, 'O_RDONLY'), + \ 'lang' : matchstr(tagfile, 'tags-\zs[a-z]\{2\}'), + \ 'path': fnamemodify(expand(tagfile), ':p:h:h:t'), + \ 'max' : len(readfile(tagfile)), + \ 'lnum' : 0, + \ } + let s:vimproc_files[tagfile] = file + endfor + + let s:cont_number = 1 + let s:cont_max = len(s:vimproc_files) + + return [] +endfunction +function! s:source.async_gather_candidates(args, context) + let list = [] + for [key, file] in items(s:vimproc_files) + let lines = file.proc.read_lines(1000, 2000) + + " Show progress. + let file.lnum += len(lines) + let progress = (file.lnum * 100) / file.max + if progress > 100 + let progress = 100 + endif + + call unite#clear_message() + + call unite#print_source_message( + \ printf('[%2d/%2d] Making cache of "%s"...%d%%', + \ s:cont_number, s:cont_max, + \ file.path, progress), s:source.name) + + for line in lines + if line == '' || line[0] == '!' + continue + endif + + let name = split(line, "\t")[0] + let word = name . '@' . (file.lang != '' ? file.lang : 'en') + let abbr = printf("%s%s (in %s)", + \ name, ((file.lang != '') ? '@' . file.lang : ''), file.path) + + call add(list, { + \ 'word': word, + \ 'abbr': abbr, + \ 'action__command': 'help ' . word, + \ 'source__lang' : file.lang != '' ? file.lang : 'en' + \}) endfor + + if file.proc.eof + call file.proc.close() + call remove(s:vimproc_files, key) + let s:cont_number += 1 + endif + endfor + + let s:cache += list + if empty(s:vimproc_files) + let a:context.is_async = 0 + call unite#print_source_message('Completed.', s:source.name) + + " Save cache file. + let cache_dir = unite#get_data_directory() . '/help' + call s:Cache.writefile(cache_dir, 'help-cache', + \ [string(s:cache)]) endif - return filter(copy(s:cache), - \ 'empty(lang_filter) || index(lang_filter, v:val.source__lang) != -1') + return s:filter_list(list, a:context) +endfunction +function! s:source.hooks.on_close(args, context) endfunction +function! s:filter_list(list, context) + call filter(a:list, 'stridx(v:val.word, a:context.source__input) >= 0') + if !empty(a:context.source__lang_filter) + call filter(a:list, 'index(a:context.source__lang_filter, + \ v:val.source__lang) != -1') + endif + + return a:list +endfunction " action let s:action_table = {} @@ -115,5 +213,19 @@ function! s:action_table.tabopen.func(candidate) let &ignorecase = save_ignorecase endfunction +function! s:globpath(path, expr, suf, list) abort + if has('patch-7.4.279') + return globpath(a:path, a:expr, a:suf, a:list) + else + let rst = globpath(a:path, a:expr, a:suf) + if a:list + return split(rst, "\n") + else + return rst + endif + endif +endfunction + let s:source.action_table.common = s:action_table +" vim: expandtab:ts=4:sts=4:sw=4