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>

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
    Oct 20 '16 at 5:30
  • Also, I added &l:buftype == '' && to both ifs as this prevents errors in command and other special windows.
    – Walf
    Aug 22 '17 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
    Oct 20 '16 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
    Oct 20 '16 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
    Oct 20 '16 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
    Oct 20 '16 at 15:01

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.