cache.vim 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. "=============================================================================
  2. " FILE: cache.vim
  3. " AUTHOR: Shougo Matsushita <Shougo.Matsu@gmail.com>
  4. " License: MIT license {{{
  5. " Permission is hereby granted, free of charge, to any person obtaining
  6. " a copy of this software and associated documentation files (the
  7. " "Software"), to deal in the Software without restriction, including
  8. " without limitation the rights to use, copy, modify, merge, publish,
  9. " distribute, sublicense, and/or sell copies of the Software, and to
  10. " permit persons to whom the Software is furnished to do so, subject to
  11. " the following conditionneocomplete#cache#
  12. "
  13. " The above copyright notice and this permission notice shall be included
  14. " in all copies or substantial portions of the Software.
  15. "
  16. " THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  17. " OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  18. " MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  19. " IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  20. " CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  21. " TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  22. " SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  23. " }}}
  24. "=============================================================================
  25. let s:save_cpo = &cpo
  26. set cpo&vim
  27. let s:Cache = neocomplete#util#get_vital().import('System.Cache.Deprecated')
  28. " Cache loader.
  29. function! neocomplete#cache#load_from_cache(cache_dir, filename, ...) abort "{{{
  30. let is_string = get(a:000, 0, 0)
  31. try
  32. " Note: For neocomplete.
  33. let list = []
  34. if is_string
  35. lua << EOF
  36. do
  37. local ret = vim.eval('list')
  38. local list = {}
  39. for line in io.lines(vim.eval(
  40. 'neocomplete#cache#encode_name(a:cache_dir, a:filename)')) do
  41. list = (loadstring) and loadstring('return ' .. line)()
  42. or load('return ' .. line)()
  43. end
  44. for i = 1, #list do
  45. ret:add(list[i])
  46. end
  47. end
  48. EOF
  49. else
  50. let list = eval(get(neocomplete#cache#readfile(
  51. \ a:cache_dir, a:filename), 0, '[]'))
  52. endif
  53. if !empty(list) && is_string && type(list[0]) != type('')
  54. " Type check.
  55. throw 'Type error'
  56. endif
  57. return list
  58. catch
  59. " echomsg string(v:errmsg)
  60. " echomsg string(v:exception)
  61. " Delete old cache file.
  62. let cache_name =
  63. \ neocomplete#cache#encode_name(a:cache_dir, a:filename)
  64. if filereadable(cache_name)
  65. call delete(cache_name)
  66. endif
  67. return []
  68. endtry
  69. endfunction"}}}
  70. " New cache loader.
  71. function! neocomplete#cache#check_cache(cache_dir, key, async_cache_dictionary, keyword_cache, is_string) abort "{{{
  72. if !has_key(a:async_cache_dictionary, a:key)
  73. return
  74. endif
  75. let cache_list = a:async_cache_dictionary[a:key]
  76. if !has_key(a:keyword_cache, a:key)
  77. let a:keyword_cache[a:key] = []
  78. endif
  79. for cache in filter(copy(cache_list), 'filereadable(v:val.cachename)')
  80. let a:keyword_cache[a:key] += neocomplete#cache#load_from_cache(
  81. \ a:cache_dir, cache.filename, a:is_string)
  82. endfor
  83. call filter(cache_list, '!filereadable(v:val.cachename)')
  84. if empty(cache_list)
  85. " Delete from dictionary.
  86. call remove(a:async_cache_dictionary, a:key)
  87. return
  88. endif
  89. endfunction"}}}
  90. " For buffer source cache loader.
  91. function! neocomplete#cache#get_cache_list(cache_dir, async_cache_list) abort "{{{
  92. let cache_list = a:async_cache_list
  93. let loaded_keywords = []
  94. let loaded = 0
  95. for cache in filter(copy(cache_list), 'filereadable(v:val.cachename)')
  96. let loaded = 1
  97. let loaded_keywords = neocomplete#cache#load_from_cache(
  98. \ a:cache_dir, cache.filename, 1)
  99. endfor
  100. call filter(cache_list, '!filereadable(v:val.cachename)')
  101. return [loaded, loaded_keywords]
  102. endfunction"}}}
  103. function! neocomplete#cache#save_cache(cache_dir, filename, keyword_list) abort "{{{
  104. if neocomplete#util#is_sudo()
  105. return
  106. endif
  107. " Output cache.
  108. let string = substitute(substitute(substitute(
  109. \ string(a:keyword_list), '^[', '{', ''),
  110. \ ']$', '}', ''), '\\', '\\\\', 'g')
  111. call neocomplete#cache#writefile(
  112. \ a:cache_dir, a:filename, [string])
  113. endfunction"}}}
  114. " Cache helper.
  115. function! neocomplete#cache#getfilename(cache_dir, filename) abort "{{{
  116. let cache_dir = neocomplete#get_data_directory() . '/' . a:cache_dir
  117. return s:Cache.getfilename(cache_dir, a:filename)
  118. endfunction"}}}
  119. function! neocomplete#cache#filereadable(cache_dir, filename) abort "{{{
  120. let cache_dir = neocomplete#get_data_directory() . '/' . a:cache_dir
  121. return s:Cache.filereadable(cache_dir, a:filename)
  122. endfunction"}}}
  123. function! neocomplete#cache#readfile(cache_dir, filename) abort "{{{
  124. let cache_dir = neocomplete#get_data_directory() . '/' . a:cache_dir
  125. return s:Cache.readfile(cache_dir, a:filename)
  126. endfunction"}}}
  127. function! neocomplete#cache#writefile(cache_dir, filename, list) abort "{{{
  128. if neocomplete#util#is_sudo()
  129. return
  130. endif
  131. let cache_dir = neocomplete#get_data_directory() . '/' . a:cache_dir
  132. return s:Cache.writefile(cache_dir, a:filename, a:list)
  133. endfunction"}}}
  134. function! neocomplete#cache#encode_name(cache_dir, filename) abort
  135. " Check cache directory.
  136. let cache_dir = neocomplete#get_data_directory() . '/' . a:cache_dir
  137. return s:Cache.getfilename(cache_dir, a:filename)
  138. endfunction
  139. function! neocomplete#cache#check_old_cache(cache_dir, filename) abort "{{{
  140. let cache_dir = neocomplete#get_data_directory() . '/' . a:cache_dir
  141. return s:Cache.check_old_cache(cache_dir, a:filename)
  142. endfunction"}}}
  143. function! neocomplete#cache#make_directory(directory) abort "{{{
  144. let directory =
  145. \ neocomplete#get_data_directory() .'/'.a:directory
  146. if !isdirectory(directory)
  147. if neocomplete#util#is_sudo()
  148. call neocomplete#print_error(printf(
  149. \ 'Cannot create Directory "%s" in sudo session.', directory))
  150. else
  151. call mkdir(directory, 'p')
  152. endif
  153. endif
  154. endfunction"}}}
  155. let s:sdir = neocomplete#util#substitute_path_separator(
  156. \ fnamemodify(expand('<sfile>'), ':p:h'))
  157. function! neocomplete#cache#async_load_from_file(cache_dir, filename, pattern, mark) abort "{{{
  158. if !neocomplete#cache#check_old_cache(a:cache_dir, a:filename)
  159. \ || neocomplete#util#is_sudo()
  160. return neocomplete#cache#encode_name(a:cache_dir, a:filename)
  161. endif
  162. let pattern_file_name =
  163. \ neocomplete#cache#encode_name('keyword_patterns', a:filename)
  164. let cache_name =
  165. \ neocomplete#cache#encode_name(a:cache_dir, a:filename)
  166. " Create pattern file.
  167. call neocomplete#cache#writefile(
  168. \ 'keyword_patterns', a:filename, [a:pattern])
  169. " args: funcname, outputname, filename pattern mark
  170. " minlen maxlen encoding
  171. let fileencoding =
  172. \ &fileencoding == '' ? &encoding : &fileencoding
  173. let argv = [
  174. \ 'load_from_file', cache_name, a:filename, pattern_file_name, a:mark,
  175. \ g:neocomplete#min_keyword_length, fileencoding
  176. \ ]
  177. return s:async_load(argv, a:cache_dir, a:filename)
  178. endfunction"}}}
  179. function! neocomplete#cache#async_load_from_tags(cache_dir, filename, filetype, pattern, mark) abort "{{{
  180. if !neocomplete#cache#check_old_cache(a:cache_dir, a:filename)
  181. \ || neocomplete#util#is_sudo()
  182. return neocomplete#cache#encode_name(a:cache_dir, a:filename)
  183. endif
  184. let cache_name =
  185. \ neocomplete#cache#encode_name(a:cache_dir, a:filename)
  186. let pattern_file_name =
  187. \ neocomplete#cache#encode_name('tags_patterns', a:filename)
  188. let tags_file_name = '$dummy$'
  189. let filter_pattern =
  190. \ get(g:neocomplete#tags_filter_patterns, a:filetype, '')
  191. call neocomplete#cache#writefile('tags_patterns', a:filename,
  192. \ [a:pattern, tags_file_name, filter_pattern, a:filetype])
  193. " args: funcname, outputname, filename
  194. " pattern mark minlen encoding
  195. let fileencoding = &fileencoding == '' ? &encoding : &fileencoding
  196. let argv = [
  197. \ 'load_from_tags', cache_name, a:filename, pattern_file_name, a:mark,
  198. \ g:neocomplete#min_keyword_length, fileencoding
  199. \ ]
  200. return s:async_load(argv, a:cache_dir, a:filename)
  201. endfunction"}}}
  202. function! s:async_load(argv, cache_dir, filename) abort "{{{
  203. let vim_path = s:search_vim_path()
  204. if vim_path == '' || !executable(vim_path)
  205. call neocomplete#async_cache#main(a:argv)
  206. else
  207. let args = [vim_path, '-u', 'NONE', '-i', 'NONE', '-n',
  208. \ '-N', '-S', s:sdir.'/async_cache.vim']
  209. \ + a:argv
  210. call vimproc#system_bg(args)
  211. " call vimproc#system(args)
  212. " call system(join(args))
  213. endif
  214. return neocomplete#cache#encode_name(a:cache_dir, a:filename)
  215. endfunction"}}}
  216. function! s:search_vim_path() abort "{{{
  217. if exists('s:vim_path')
  218. return s:vim_path
  219. endif
  220. if !neocomplete#has_vimproc()
  221. return ''
  222. endif
  223. let paths = vimproc#get_command_name(v:progname, $PATH, -1)
  224. if empty(paths)
  225. if has('gui_macvim')
  226. " MacVim check.
  227. if !executable('/Applications/MacVim.app/Contents/MacOS/Vim')
  228. call neocomplete#print_error(
  229. \ 'You installed MacVim in not default directory!'.
  230. \ ' You must add MacVim installed path in $PATH.')
  231. let g:neocomplete#use_vimproc = 0
  232. return ''
  233. endif
  234. let s:vim_path = '/Applications/MacVim.app/Contents/MacOS/Vim'
  235. else
  236. call neocomplete#print_error(
  237. \ printf('Vim path : "%s" is not found.'.
  238. \ ' You must add "%s" installed path in $PATH.',
  239. \ v:progname, v:progname))
  240. let g:neocomplete#use_vimproc = 0
  241. return ''
  242. endif
  243. else
  244. let base_path = neocomplete#util#substitute_path_separator(
  245. \ fnamemodify(paths[0], ':p:h'))
  246. let s:vim_path = base_path . '/vim'
  247. if !executable(s:vim_path) && neocomplete#util#is_mac()
  248. " Note: Search "Vim" instead of vim.
  249. let s:vim_path = base_path. '/Vim'
  250. endif
  251. endif
  252. return s:vim_path
  253. endfunction"}}}
  254. let &cpo = s:save_cpo
  255. unlet s:save_cpo
  256. " vim: foldmethod=marker