vimtricks.wiki Concise Vim tricks, one at a time.

How do I read a single keystroke from the user inside a Vimscript mapping or function?

Answer

getchar()

Explanation

getchar() blocks and waits for the user to press a key, returning its numeric character code. Combined with nr2char(), it lets you build interactive mappings that branch on user input — enabling mini-menus, character-driven operators, and dynamic behavior without a plugin framework.

How it works

let char = getchar()        " blocks until a key is pressed; returns char code
let str  = nr2char(char)    " convert to a string character

Key facts:

  • Returns a number (e.g. 97 for a)
  • For special keys (arrows, function keys), returns a string like "\<Up>"
  • Call inside a mapping with :call or :execute

Example

A mapping that surrounds the word under the cursor with any pair of quotes or brackets you type next:

nnoremap <Leader>q :call SurroundWord()<CR>
function! SurroundWord()
  let open = nr2char(getchar())
  let pairs = {'(': ')', '[': ']', '{': '}', '<': '>'}
  let close = get(pairs, open, open)
  execute 'normal! viw<Esc>a' . close . '\<Esc>bi' . open . '\<Esc>'
endfunction

Press <Leader>q then " to wrap the word in double quotes, or ( to wrap in parentheses.

Tips

  • Use getcharstr() (Vim 8.2+ / Neovim) to get the string directly without nr2char()
  • getchar(1) checks if a char is available without blocking (non-blocking peek)
  • Always guard with if char ==# "\<Esc>" to cancel gracefully
  • For Neovim Lua: vim.fn.getchar() and vim.fn.nr2char() work identically

Next

How do I extract regex capture groups from a string in Vimscript?