2

I am very used to the shell autocompletion, which uses the <tab> character. Therefore I tried to build something similar into my .vimrc. I'm aware of the super popular YCM plugin but let's face this as an exercise in learning.

I have built the following piece of vimscript to: first, allow me to use different types of <c-x> completions by changing a variable; second, do not fire a completion if the cursor is not after a cword character.

let g:tab_completion_keys = "\<c-x>\<c-p>"
function! TabCompletion1()
  let l:char = matchstr(getline('.'), '\%' . col('.') . 'c.')
  if l:char =~# '\k'
    execute "normal! a" . g:tab_completion_keys . "\<esc>"
  else
    execute "normal! a\<tab>\<esc>"
  endif
endfunction
inoremap <tab> <esc>:call TabCompletion1()<cr>a

The problem is that I cannot leave normal! in insert-mode. i.e. I cannot enter insert-mode in normal! and finish the command without exiting the insert-mode. Thanks to that, the code above opens the completion list and always selects the first completion, because I leave the insert mode.

How can I make an insert-mode mapping that leaves me in insert-mode for some time (to select one word from the completion list) and then continues the mapping?

Or, maybe, there is a better way to deal with exe normal!?

  • 1
    Didn't you try supertab plugin? – SibiCoder Jul 16 '16 at 4:03
  • 3
    I second the recommendation for supertab. To answer your question: see :h :map-<expr>. Most imap maps are easier to write with <expr>. – Sato Katsura Jul 16 '16 at 4:16
  • 1
    Take a look at how VimCompletesMe does that. – romainl Jul 16 '16 at 7:43
  • @SatoKatsura - Yup :h map-<expr> clarified a lot of things for me. Thanks – grochmal Jul 16 '16 at 16:02
0

Just like Sato Katsura said, this is a job for the map modifier <expr>. With <expr> you can return the key combination from the function. The final code looks as this:

let g:tab_completion_keys = "\<c-x>\<c-p>"
function! TabCompletion()
  let l:col = max([col('.')-1, 1])
  let l:char = matchstr(getline('.'), '\%' . l:col . 'c.')
  if l:char =~# '\k'
    return g:tab_completion_keys
  else
    return "\<tab>"
  endif
endfunction
inoremap <expr> <tab> TabCompletion()

In practice it is much better to use a full plugin. I am now using supertab suggested by SibiCoder.

supertab has many more configuration options than the code above, including: defined patterns for which no completion shall be attempted, different completion contexts based on the text around the cursor and even an option to use a different key than <tab>.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.