complete.vim 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. "=============================================================================
  2. " FILE: complete.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 conditions:
  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. function! neocomplete#complete#_get_results(cur_text, ...) abort "{{{
  28. call neocomplete#print_debug('start get_complete_sources')
  29. let neocomplete = neocomplete#get_current_neocomplete()
  30. let neocomplete.start_time = reltime()
  31. " Comment check.
  32. let neocomplete.within_comment =
  33. \ neocomplete#helper#get_syn_name(1) ==# 'Comment'
  34. let complete_sources = call(
  35. \ 'neocomplete#complete#_set_results_pos', [a:cur_text] + a:000)
  36. if empty(complete_sources)
  37. call neocomplete#print_debug('Skipped.')
  38. return []
  39. endif
  40. if neocomplete#is_auto_complete()
  41. let complete_pos =
  42. \ neocomplete#complete#_get_complete_pos(complete_sources)
  43. call neocomplete#complete#_set_previous_position(a:cur_text, complete_pos)
  44. endif
  45. call neocomplete#complete#_set_results_words(complete_sources)
  46. return filter(copy(complete_sources),
  47. \ '!empty(v:val.neocomplete__context.candidates)')
  48. endfunction"}}}
  49. function! neocomplete#complete#_get_complete_pos(sources) abort "{{{
  50. if empty(a:sources)
  51. return -1
  52. endif
  53. return min([col('.')] + map(copy(a:sources),
  54. \ 'v:val.neocomplete__context.complete_pos'))
  55. endfunction"}}}
  56. function! neocomplete#complete#_get_words(sources, complete_pos, complete_str) abort "{{{
  57. let frequencies = neocomplete#variables#get_frequencies()
  58. if exists('*neocomplete#sources#buffer#get_frequencies')
  59. let frequencies = extend(copy(
  60. \ neocomplete#sources#buffer#get_frequencies()),
  61. \ frequencies)
  62. endif
  63. " Append prefix.
  64. let candidates = []
  65. let len_words = 0
  66. for source in sort(filter(deepcopy(a:sources),
  67. \ '!empty(v:val.neocomplete__context.candidates)'),
  68. \ 's:compare_source_rank')
  69. let context = source.neocomplete__context
  70. let words = type(context.candidates[0]) == type('') ?
  71. \ map(copy(context.candidates), "{'word': v:val}") :
  72. \ deepcopy(context.candidates)
  73. let context.candidates = words
  74. call neocomplete#helper#call_hook(
  75. \ source, 'on_post_filter', {})
  76. if context.complete_pos > a:complete_pos
  77. let prefix = a:complete_str[: context.complete_pos
  78. \ - a:complete_pos - 1]
  79. " Fix complete position.
  80. let context.complete_pos = a:complete_pos
  81. let context.complete_str = prefix
  82. for candidate in words
  83. let candidate.word = prefix . candidate.word
  84. endfor
  85. endif
  86. lua << EOF
  87. do
  88. local frequencies = vim.eval('frequencies')
  89. local candidates = vim.eval('words')
  90. for i = 0, #candidates-1 do
  91. if frequencies[candidates[i].word] ~= nil then
  92. candidates[i].rank = frequencies[candidates[i].word]
  93. end
  94. end
  95. end
  96. EOF
  97. let words = neocomplete#helper#call_filters(
  98. \ source.neocomplete__sorters, source, {})
  99. if empty(words)
  100. continue
  101. endif
  102. let words = neocomplete#helper#call_filters(
  103. \ source.neocomplete__converters, source, {})
  104. if empty(words)
  105. continue
  106. endif
  107. if source.max_candidates > 0
  108. let words = words[: source.max_candidates -1]
  109. endif
  110. " Set default menu.
  111. if get(words[0], 'menu', '') !~ '^\[.*\]'
  112. call s:set_default_menu(words, source)
  113. endif
  114. let candidates += words
  115. let len_words += len(words)
  116. if g:neocomplete#max_list > 0
  117. \ && len_words > g:neocomplete#max_list
  118. break
  119. endif
  120. if neocomplete#complete_check()
  121. return []
  122. endif
  123. endfor
  124. call filter(candidates, 'v:val.word !=# a:complete_str')
  125. if g:neocomplete#max_list > 0
  126. let candidates = candidates[: g:neocomplete#max_list]
  127. endif
  128. " Check dup and set icase.
  129. let icase = g:neocomplete#enable_ignore_case &&
  130. \ !((g:neocomplete#enable_smart_case
  131. \ || g:neocomplete#enable_camel_case) && a:complete_str =~ '\u')
  132. if icase
  133. for candidate in candidates
  134. let candidate.icase = 1
  135. endfor
  136. endif
  137. if neocomplete#complete_check()
  138. return []
  139. endif
  140. return candidates
  141. endfunction"}}}
  142. function! neocomplete#complete#_set_results_pos(cur_text, ...) abort "{{{
  143. " Initialize sources.
  144. let neocomplete = neocomplete#get_current_neocomplete()
  145. let filetype = neocomplete#get_context_filetype()
  146. let sources = (a:0 > 0) ? a:1 :
  147. \ (filetype ==# neocomplete.sources_filetype) ?
  148. \ neocomplete.sources : neocomplete#helper#get_sources_list()
  149. let pos = winsaveview()
  150. " Try source completion. "{{{
  151. let complete_sources = []
  152. for source in filter(values(sources),
  153. \ 'neocomplete#helper#is_enabled_source(v:val, filetype)')
  154. if !source.loaded
  155. call neocomplete#helper#call_hook(source, 'on_init', {})
  156. let source.loaded = 1
  157. endif
  158. let context = source.neocomplete__context
  159. let context.input = a:cur_text
  160. let context.filetype = filetype
  161. let context.filetypes = neocomplete#context_filetype#filetypes()
  162. try
  163. let complete_pos = s:use_previous_result(source, context) ?
  164. \ context.prev_complete_pos :
  165. \ has_key(source, 'get_complete_position') ?
  166. \ source.get_complete_position(context) :
  167. \ neocomplete#helper#match_word(context.input,
  168. \ neocomplete#get_keyword_pattern_end(filetype, source.name))[0]
  169. catch
  170. call neocomplete#print_error(v:throwpoint)
  171. call neocomplete#print_error(v:exception)
  172. call neocomplete#print_error(
  173. \ 'Error occurred in source''s get_complete_position()!')
  174. call neocomplete#print_error(
  175. \ 'Source name is ' . source.name)
  176. return complete_sources
  177. finally
  178. if winsaveview() != pos
  179. call winrestview(pos)
  180. endif
  181. endtry
  182. if complete_pos < 0
  183. let context.complete_pos = -1
  184. let context.complete_str = ''
  185. continue
  186. endif
  187. let complete_str = context.input[complete_pos :]
  188. if neocomplete#is_auto_complete() &&
  189. \ (source.input_pattern == '' ||
  190. \ context.input !~# '\%(' . source.input_pattern.'\m\)$') &&
  191. \ len(complete_str) < source.min_pattern_length
  192. " Skip.
  193. let context.complete_pos = -1
  194. let context.complete_str = ''
  195. continue
  196. endif
  197. let context.complete_pos = complete_pos
  198. let context.complete_str = complete_str
  199. call add(complete_sources, source)
  200. endfor
  201. "}}}
  202. return complete_sources
  203. endfunction"}}}
  204. function! neocomplete#complete#_set_results_words(sources) abort "{{{
  205. " Try source completion.
  206. " Save options.
  207. let ignorecase_save = &ignorecase
  208. let pos = winsaveview()
  209. try
  210. for source in a:sources
  211. if neocomplete#complete_check()
  212. return
  213. endif
  214. let context = source.neocomplete__context
  215. let &ignorecase = (g:neocomplete#enable_smart_case
  216. \ || g:neocomplete#enable_camel_case) ?
  217. \ context.complete_str !~ '\u'
  218. \ : g:neocomplete#enable_ignore_case
  219. if s:use_previous_result(source, context)
  220. " Use previous candidates.
  221. let context.candidates = deepcopy(context.prev_candidates)
  222. else
  223. try
  224. let winwidth = winwidth(0)
  225. let type_string = type('')
  226. let context.candidates = filter(source.gather_candidates(context),
  227. \ 'len((type(v:val) == type_string) ?
  228. \ v:val : v:val.word) < winwidth')
  229. catch
  230. call neocomplete#print_error(v:throwpoint)
  231. call neocomplete#print_error(v:exception)
  232. call neocomplete#print_error(
  233. \ 'Source name is ' . source.name)
  234. call neocomplete#print_error(
  235. \ 'Error occurred in source''s gather_candidates()!')
  236. return
  237. finally
  238. if winsaveview() != pos
  239. call winrestview(pos)
  240. endif
  241. endtry
  242. let context.prev_line = context.input
  243. let context.prev_candidates = copy(context.candidates)
  244. let context.prev_complete_pos = context.complete_pos
  245. endif
  246. if !empty(context.candidates)
  247. let matchers = empty(source.neocomplete__matchers) ?
  248. \ neocomplete#get_current_neocomplete().default_matchers
  249. \ : source.neocomplete__matchers
  250. let context.candidates = neocomplete#helper#call_filters(
  251. \ matchers, source, {})
  252. endif
  253. call neocomplete#print_debug(source.name)
  254. endfor
  255. finally
  256. let &ignorecase = ignorecase_save
  257. endtry
  258. endfunction"}}}
  259. function! neocomplete#complete#_check_previous_position(cur_text, complete_pos) abort "{{{
  260. let neocomplete = neocomplete#get_current_neocomplete()
  261. return a:complete_pos == neocomplete.old_complete_pos
  262. \ && line('.') == neocomplete.old_linenr
  263. \ && a:cur_text ==# neocomplete.old_cur_text
  264. endfunction"}}}
  265. function! neocomplete#complete#_set_previous_position(cur_text, complete_pos) abort "{{{
  266. let neocomplete = neocomplete#get_current_neocomplete()
  267. let neocomplete.old_complete_pos = a:complete_pos
  268. let neocomplete.old_linenr = line('.')
  269. let neocomplete.old_cur_text = a:cur_text
  270. endfunction"}}}
  271. " Source rank order. "{{{
  272. function! s:compare_source_rank(i1, i2) abort
  273. return a:i2.rank - a:i1.rank
  274. endfunction"}}}
  275. function! s:set_default_menu(words, source) abort "{{{
  276. lua << EOF
  277. do
  278. local candidates = vim.eval('a:words')
  279. local mark = vim.eval('a:source.mark') .. ' '
  280. for i = 0, #candidates-1 do
  281. candidates[i].menu = mark .. (candidates[i].menu ~= nil and
  282. candidates[i].menu or '')
  283. end
  284. end
  285. EOF
  286. endfunction"}}}
  287. function! s:use_previous_result(source, context) abort "{{{
  288. let neocomplete = neocomplete#get_current_neocomplete()
  289. return !a:source.is_volatile
  290. \ && substitute(a:context.input, '\k\+$', '', '')
  291. \ ==# substitute(a:context.prev_line, '\k\+$', '', '')
  292. \ && stridx(a:context.input, a:context.prev_line) == 0
  293. \ && !empty(a:context.prev_candidates)
  294. \ && line('.') == neocomplete.old_linenr
  295. endfunction"}}}
  296. let &cpo = s:save_cpo
  297. unlet s:save_cpo
  298. " vim: foldmethod=marker