I know I can :set ignorecase smartcase to get autompletion to be case-insensitive but this has the side-effect of making all searches case-insensitive unless they contain an uppercase character.

I have tried the following to attempt a per-command setting of ignorecase, but had no luck:

inoremap <C-N> <C-\><C-O>:let b:last_ic = &ignorecase \| set ignorecase<CR><C-N><C-\><C-O>:let &ignorecase=b:last_ic \| unlet b:last_ic<CR>

2 Answers 2


It's not straight-forward, but it's possible to do this with :h map-<expr> and some script:

augroup toggle_compl_ignorecase
  autocmd CompleteDone,InsertLeave *
        \ if exists('s:ignorecase') |
        \   let &ignorecase = s:ignorecase |
        \   unlet! s:ignorecase |
        \ endif
augroup END

function! s:before_complete(key) abort
  if !exists('s:ignorecase')
    let s:ignorecase = &ignorecase
    set ignorecase
  return a:key

for s:key in ["\<c-n>", "\<c-p>", "\<c-x>"]
  execute 'inoremap <expr> '.s:key.' <sid>before_complete("'.s:key.'")'

Note: The double quotes and slashes are significant.

The keys <c-n>, <c-p>, and <c-x> are mapped to an expression that returns the final keys to be interpreted by Vim. In this case all you're doing is using s:before_complete() as a passthrough to set ignorecase.

To restore ignorecase, the autocmd CompleteDone is used. If a menu isn't displayed when pressing any of those keys, CompleteDone should still be triggered. InsertLeave is included since it's the ultimate indication that you're not doing anything with completions. Sanity is always a good thing :>

  • Thank you. I modified it a little, but wouldn't have gotten the result without your help.
    – Walf
    Commented Oct 20, 2016 at 5:30
  • Also, I added &l:buftype == '' && to both ifs as this prevents errors in command and other special windows.
    – Walf
    Commented Aug 22, 2017 at 2:22

What I actually used:

" case insensitive auto-complete
function! BeforeComplete(key) abort
    if !exists('g:last_ic')
        let g:last_ic = &ignorecase
        set ignorecase
    return a:key
for s:key in ['<c-n>', '<c-p>', '<c-x>']
    execute 'inoremap <expr> '.s:key.' BeforeComplete('''.s:key.''')'
autocmd CompleteDone,InsertLeave * if exists('g:last_ic') | let &ignorecase=g:last_ic | unlet g:last_ic | endif

(Because I got a couple of errors and wanted the variable to use the same scope as the option's.)

  • What were the errors? The scope should be just fine in the original script.
    – Tommy A
    Commented Oct 20, 2016 at 5:50
  • @TommyA Something like <SNR>_8s:before_complete function not found, then another error about an invalid expression that was likely caused by the first. It may have been my mistake from a stray keystroke.
    – Walf
    Commented Oct 20, 2016 at 9:20
  • If it wasn't copied verbatim, you might've typed it out as <sid>s:before_complete(...). In any case, doesn't matter if you got it working. I just prefer to keep utility non-user functions out of the global scope.
    – Tommy A
    Commented Oct 20, 2016 at 14:39
  • 1
    Couldn't tell you, that's reconstructed from vague memory. I did go over it, typing some, mostly because I wanted to understand it and tinker, not just copy & paste.
    – Walf
    Commented Oct 20, 2016 at 15:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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