I've been trying to write a simple complete function for Vim that tries
multiple values for the
Here is a version that works but which I find unsatisfactory:
function! CompleteFunc(findstart, base) if a:findstart let start = AmbitiousFindStart() " -1 to exclude cursor, -1 again to convert column to index let fake_base = getline('.')[start:col('.')-2] if empty(GetCompletions(fake_base)) let start = FallbackFindStart() endif return start else return GetCompletions(a:base) endif endfunction set completefunc=CompleteFunc
Specifically in my case,
AmbitiousFindStart() tries to set
start so as to
consume all non-whitespace characters, but if this fails, I want to use
FallbackFindStart(), which only tries to consume word characters.
Here are the problems I see with this approach:
- Even in the case when
AmbitiousFindStart()succeeds (i.e. produces matches when calling
GetCompletions()is called twice.
fake_baseapproach seems inelegant to me; Vim is the one who is suppose to provide me with
base, rather than me going out of my way to try to calculate what
basewould be. Additionally I'm not even sure if my
basecalculation is correct (it seems to work in the cases I've tried, but there might be problems with e.g. multi-byte characters). I've therefore called it the "fake"
baseto distinguish it from the "real"
basethat Vim would provide.
My first approach to fix problem (1) was the following, which does not work:
function! BadCompleteFunc(findstart, base) if a:findstart let start = AmbitiousFindStart() return start else let compl_lst = GetCompletions(a:base) if empty(compl_lst) let fake_base = getline('.')[start:col('.')-2] let compl_lst = GetCompletions(fake_base) endif return compl_lst endif endfunction
The problem with this is that Vim uses the
start value returned from the
BadCompleteFunc() is called to decide what to replace the
completion with, rather than the string value of
The second approach I came up with is to use
complete(), which has problems
of its own:
function! Complete() let startidx = AmbitiousFindStart() let startcol = startidx + 1 let currcol = col('.') let curridx = currcol - 1 let fake_base = getline('.')[startidx:curridx-1] let matches = GetCompletions(fake_base) if !empty(matches) call complete(startcol, matches) else let startidx = FallbackFindStart() let startcol = startidx + 1 let fake_base = getline('.')[startidx:curridx-1] let matches = GetCompletions(fake_base) call complete(startcol, matches) endif return '' endfunction
The problem here is that this assumes a usage through a custom insert mode
mapping, such as
inoremap <C-X><C-U> <C-R>=Complete()<CR>, rather than being
able to set
What is the right way to approach this sort of complete function?