Vim Tips Wiki
Advertisement

Autocapitalizing the start of every sentence, a common function in cell phones, is unexpectedly nontrivial. The usual candidates, mapping ". a" to ". A" in insert mode, using abbreviate, don't work, produce unexpected delay, or require extra keypresses. The strategy here is to map a function to "." and CR in insert mode and to use getchar() to detect subsequent keypresses.

The key Vim functions here are:

  • getchar -- wait for a single keypress, return the numeric key code
  • n2char -- convert keycode back to a character
  • startinsert -- start insert mode after the function call as to not disrupt flow

The basic idea is fairly simple, but some logical manipulations are required to handle the beginnings and the endings of lines because of how exiting from input mode works (cursor sometimes moves back one character).

The vimrc file

function! WaitForKey(triggeredByCR)
 let isFirstChar = !(col(".")-1)
 let input=getchar()
 "Space=32 .=46 CR=13
 if input==32 || input==46 || input==13 || a:triggeredByCR
   while input==32 || input==46 || input==13
     if isFirstChar && input==13
        exe "normal i" . nr2char(13)
        redraw
     else
        exe "normal a" . nr2char(input)
        redraw
     endif
     let isFirstChar = !(col(".")-1)
     let input=getchar()
   endwhile
   if isFirstChar  
      if (input>=97 && input<=122)     "a=97 A=65
        exe "normal i" . nr2char(input-32)
        redraw
      else
        exe "normal i" . nr2char(input)
        redraw
      endif
   else
      if (input>=97 && input<=122)     "a=97 A=65
        exe "normal a" . nr2char(input-32)
        redraw
      else
        exe "normal a" . nr2char(input)
        redraw
      endif
   endif
 else
   exe "normal a" . nr2char(input)
   redraw
 endif
 normal l
 if (col("$")-1)==col(".")
    startinsert!
 else
    startinsert
 endif

endfu imap <silent> . .<Esc>:call WaitForKey(0)<CR> imap <silent> <CR> <CR><Esc>:call WaitForKey(1)<CR>

Advertisement