-
Notifications
You must be signed in to change notification settings - Fork 18
/
mucomplete.vim
215 lines (193 loc) · 7.81 KB
/
mucomplete.vim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
" Chained completion that works as I want!
" Maintainer: Lifepillar <lifepillar@lifepillar.me>
" License: This file is placed in the public domain
let s:save_cpo = &cpo
set cpo&vim
" Note: In 'c-n' and 'c-p' below we use the fact that pressing <c-x> while in
" ctrl-x submode doesn't do anything and any key that is not valid in ctrl-x
" submode silently ends that mode (:h complete_CTRL-Y) and inserts the key.
" Hence, after <c-x><c-b>, we are surely out of ctrl-x submode. The subsequent
" <bs> is used to delete the inserted <c-b>. We use <c-b> because it is not
" mapped (:h i_CTRL-B-gone). This trick is needed to have <c-p> (and <c-n>)
" trigger keyword completion under all circumstances, in particular when the
" current mode is the ctrl-x submode. (pressing <c-p>, say, immediately after
" <c-x><c-o> would do a different thing).
let s:cnp = "\<c-x>" . get(g:, 'mucomplete#exit_ctrlx_keys', "\<c-b>\<bs>")
let s:compl_mappings = extend({
\ 'c-n' : s:cnp."\<c-n>", 'c-p' : s:cnp."\<c-p>",
\ 'cmd' : "\<c-x>\<c-v>", 'defs': "\<c-x>\<c-d>",
\ 'dict': "\<c-x>\<c-k>", 'file': "\<c-x>\<c-f>",
\ 'incl': "\<c-x>\<c-i>", 'keyn': "\<c-x>\<c-n>",
\ 'keyp': "\<c-x>\<c-p>", 'line': s:cnp."\<c-x>\<c-l>",
\ 'omni': "\<c-x>\<c-o>", 'spel': "\<c-x>s" ,
\ 'tags': "\<c-x>\<c-]>", 'thes': "\<c-x>\<c-t>",
\ 'user': "\<c-x>\<c-u>", 'ulti': "\<c-r>=mucomplete#ultisnips#complete()\<cr>",
\ 'path': "\<c-r>=mucomplete#path#complete()\<cr>",
\ 'uspl': "\<c-r>=mucomplete#spel#complete()\<cr>"
\ }, get(g:, 'mucomplete#user_mappings', {}), 'error')
unlet s:cnp
let s:select_entry = { 'c-p' : "\<c-p>\<down>", 'keyp': "\<c-p>\<down>" }
let s:pathsep = exists('+shellslash') && !&shellslash ? '\\' : '/'
" Internal state
let s:compl_methods = [] " Current completion chain
let s:N = 0 " Length of the current completion chain
let s:i = 0 " Index of the current completion method in the completion chain
let s:compl_text = '' " Text to be completed
let s:auto = 0 " Is autocompletion enabled?
let s:dir = 1 " Direction to search for the next completion method (1=fwd, -1=bwd)
let s:cycle = 0 " Should µcomplete treat the completion chain as cyclic?
let s:i_history = [] " To detect loops when using <c-h>/<c-l>
let s:pumvisible = 0 " Has the pop-up menu become visible?
if exists('##TextChangedI') && exists('##CompleteDone')
fun! s:act_on_textchanged()
if s:completedone
let s:completedone = 0
let g:mucomplete_with_key = 0
if get(s:compl_methods, s:i, '') ==# 'path' && getline('.')[col('.')-2] =~# '\m\f'
silent call mucomplete#path#complete()
elseif get(s:compl_methods, s:i, '') ==# 'file' && getline('.')[col('.')-2] =~# '\m\f'
silent call feedkeys("\<c-x>\<c-f>", 'i')
endif
elseif !&g:paste && match(strpart(getline('.'), 0, col('.') - 1),
\ get(g:mucomplete#trigger_auto_pattern, getbufvar("%", "&ft"),
\ g:mucomplete#trigger_auto_pattern['default'])) > -1
silent call feedkeys("\<plug>(MUcompleteAuto)", 'i')
endif
endf
fun! mucomplete#enable_auto()
let s:completedone = 0
let g:mucomplete_with_key = 0
augroup MUcompleteAuto
autocmd!
autocmd TextChangedI * noautocmd call s:act_on_textchanged()
autocmd CompleteDone * noautocmd let s:completedone = 1
augroup END
let s:auto = 1
endf
fun! mucomplete#disable_auto()
if exists('#MUcompleteAuto')
autocmd! MUcompleteAuto
augroup! MUcompleteAuto
endif
let s:auto = 0
endf
fun! mucomplete#toggle_auto()
if exists('#MUcompleteAuto')
call mucomplete#disable_auto()
echomsg '[MUcomplete] Auto off'
else
call mucomplete#enable_auto()
echomsg '[MUcomplete] Auto on'
endif
endf
endif
" Patterns to decide when automatic completion should be triggered.
let g:mucomplete#trigger_auto_pattern = extend({
\ 'default' : '\k\k$'
\ }, get(g:, 'mucomplete#trigger_auto_pattern', {}))
" Completion chains
let g:mucomplete#chains = extend({
\ 'default' : ['file', 'omni', 'keyn', 'dict']
\ }, get(g:, 'mucomplete#chains', {}))
" Conditions to be verified for a given method to be applied.
if has('lambda')
let s:yes_you_can = { _ -> 1 } " Try always
let g:mucomplete#can_complete = extend({
\ 'default' : extend({
\ 'dict': { t -> strlen(&l:dictionary) > 0 },
\ 'file': { t -> t =~# '\m\%('.s:pathsep.'\|\~\)\f*$' },
\ 'omni': { t -> strlen(&l:omnifunc) > 0 },
\ 'spel': { t -> &l:spell && !empty(&l:spelllang) },
\ 'tags': { t -> !empty(tagfiles()) },
\ 'thes': { t -> strlen(&l:thesaurus) > 0 },
\ 'user': { t -> strlen(&l:completefunc) > 0 },
\ 'path': { t -> t =~# '\m\%('.s:pathsep.'\|\~\)\f*$' },
\ 'uspl': { t -> &l:spell && !empty(&l:spelllang) },
\ 'ulti': { t -> get(g:, 'did_plugin_ultisnips', 0) }
\ }, get(get(g:, 'mucomplete#can_complete', {}), 'default', {}))
\ }, get(g:, 'mucomplete#can_complete', {}), 'keep')
else
let s:yes_you_can = function('mucomplete#compat#yes_you_can')
let g:mucomplete#can_complete = mucomplete#compat#can_complete()
endif
fun! s:act_on_pumvisible()
let s:pumvisible = 0
return s:auto || index(['spel','uspl'], get(s:compl_methods, s:i, '')) > - 1
\ ? ''
\ : (stridx(&l:completeopt, 'noselect') == -1
\ ? (stridx(&l:completeopt, 'noinsert') == - 1 ? '' : "\<up>\<c-n>")
\ : get(s:select_entry, s:compl_methods[s:i], "\<c-n>\<up>")
\ )
endf
fun! s:can_complete()
return get(get(g:mucomplete#can_complete, getbufvar("%","&ft"), {}),
\ s:compl_methods[s:i],
\ get(g:mucomplete#can_complete['default'], s:compl_methods[s:i], s:yes_you_can)
\ )(s:compl_text)
endf
fun! mucomplete#yup()
let s:pumvisible = 1
return ''
endf
fun! s:next_completion()
return s:compl_mappings[s:compl_methods[s:i]] . "\<c-r>\<c-r>=pumvisible()?mucomplete#yup():''\<cr>\<plug>(MUcompleteNxt)"
endf
" Precondition: pumvisible() is false.
fun! s:next_method()
let s:i += s:dir
while (s:i+1) % (s:N+1) != 0 && !s:can_complete()
let s:i += s:dir
endwhile
return (s:i+1) % (s:N+1) != 0 ? s:next_completion() : ''
endf
" Precondition: pumvisible() is false.
fun! s:next_method_cyclic()
while 1
let s:i = (s:i + s:dir + s:N) % s:N
if index(s:i_history, s:i) > -1
return ''
endif
call add(s:i_history, s:i)
if s:can_complete()
break
endif
endwhile
return s:next_completion()
endf
fun! mucomplete#verify_completion()
return s:pumvisible ? s:act_on_pumvisible() : (s:cycle ? s:next_method_cyclic() : s:next_method())
endf
" Precondition: pumvisible() is true.
fun! mucomplete#cycle(dir)
let [s:dir, s:cycle, s:i_history] = [a:dir, 1, []]
return "\<c-e>" . s:next_method_cyclic()
endf
" Precondition: pumvisible() is true.
fun! mucomplete#cycle_or_select(dir)
return get(g:, 'mucomplete#cycle_with_trigger', 0)
\ ? mucomplete#cycle(a:dir)
\ : (a:dir > 0 ? "\<c-n>" : "\<c-p>")
endf
" Precondition: pumvisible() is false.
fun! mucomplete#complete(dir)
let s:compl_text = matchstr(getline('.'), '\S\+\%'.col('.').'c')
if strlen(s:compl_text) == 0
return (a:dir > 0 ? "\<plug>(MUcompleteTab)" : "\<plug>(MUcompleteCtd)")
endif
let [s:dir, s:cycle] = [a:dir, 0]
let s:compl_methods = get(b:, 'mucomplete_chain',
\ get(g:mucomplete#chains, getbufvar("%", "&ft"), g:mucomplete#chains['default']))
let s:N = len(s:compl_methods)
let s:i = s:dir > 0 ? -1 : s:N
return s:next_method()
endf
fun! mucomplete#tab_complete(dir)
if pumvisible()
return mucomplete#cycle_or_select(a:dir)
else
let g:mucomplete_with_key = 1
return mucomplete#complete(a:dir)
endif
endf
let &cpo = s:save_cpo
unlet s:save_cpo