I want to create a mapping that will changed the ins-completion depending on the character just before the cursor. If the character is {
then I want tag completion, if its :
i want normal completion (that depends on the complete option) and if the characters is a backslash plus some word (\w+
) I want dictionary completion. I have the following in my ftplugin/tex/latex_settings.vim
file:
setlocal dictionary=$DOTVIM/ftplugin/tex/tex_dictionary
setlocal complete=.,k
setlocal tags=./bibtags;
function! MyLatexComplete()
let character = strpart(getline('.'), col('.') - 1, col('.'))
if character == '{'
return "\<C-X>\<C-]>"
elseif character == ':'
return "\<C-X>\<C-N>"
else
return "\<C-X>\<C-K>"
endif
endfunction
inoremap <C-n> <c-r>=MyLatexComplete()<CR>
This doesn't work and I don't know how to fix it.
Edit: This seems to work but I'm want a conditional that checks for \w+ (backslash plus any word) and a final one that gives a message "No match found".
function! MyLatexComplete()
let line = getline('.')
let pos = col('.') - 1
" Citations (comma for multiple ones)
if line[pos - 1] == '{' || line[pos - 1] == ','
return "\<C-X>\<C-]>"
" Sections, equations, etc
elseif line[pos - 1] == ':'
return "\<C-X>\<C-N>"
else
" Commands (such as \delta)
return "\<C-X>\<C-K>"
endif
endfunction
In your original function you have mistakes:
strpart()
takes string, offset and length arguments, while you supplied two offsets.col('.')
is one character past the end-of-line. I.e. len(getline('.'))==col('.')+1
meaning that strpart(getline('.'), col('.')-1)
is always empty.You have fixed these issues in the second variant. But if you want conditional check for \command
you need not just last character. Thus I would suggest matching slice
let line=getline('.')[:col('.')-2]
if line[-1:] is# '{' || line[-1:] is# ','
return "\<C-X>\<C-]>"
elseif line[-1:] is# ':'
return "\<C-X>\<C-N>"
elseif line =~# '\v\\\w+$'
return "\<C-X>\<C-K>"
else
echohl ErrorMsg
echomsg 'Do not know how to complete: use after {, comma or \command'
echohl None
return ''
endif
. Note some things:
==
for string comparison without #
or ?
attached. This does not matter in this case, but you should make yourself used. ==#
and ==?
both ignore value of 'ignorecase'
setting (first acts as if 'noignorecase'
was set, second as if 'ignorecase'
was set). I use even stricter is#
: a is# b
is like type(a)==type(b) && a ==# b
.=~
: use =~#
.Due to backwards compatibility string[-1]
(string[any_negative_integer]
) is always empty. Thus I have to use line[-1:]
.
Never use plain :echoerr
. It is unstable: in terms that you cannot say for sure whether or not this will break execution flaw (:echoerr
breaks execution if put inside :try
block and does not do so otherwise). echohl ErrorMsg|echomsg …|echohl None
never breaks execution, throw …
and try|echoerr …|endtry
break always.
To spot preceding LaTeX commands you can use the following regular expression on your line
variable:
line =~ '\\\w\+$'
(as you can see, the regex is similar to the Perl expression you guessed at, but requires some the characters to be escaped).
To echo a "No match found"
message, you could return an appropriate :echoerr
command:
return "\<C-o>:echoerr 'No match found'\<CR>"
But this has the side-effect of hijacking insert-mode for a moment... maybe it's cleaner just to return no matches as an empty string?
So your final function would look something like this:
function! MyLatexComplete()
let line = getline('.')
let pos = col('.') - 1
" Citations (comma for multiple ones)
if line[pos - 1] == '{' || line[pos - 1] == ','
return "\<C-X>\<C-]>"
" Sections, equations, etc
elseif line[pos - 1] == ':'
return "\<C-X>\<C-N>"
elseif line =~ '\\\w\+$'
" Commands (such as \delta)
return "\<C-X>\<C-K>"
else
" Echo an error:
return "\<C-o>:echoe 'No match found'\<CR>"
endif
endfunction
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With