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

How do I programmatically exit insert mode from an autocommand or Vimscript function?

Answer

:stopinsert

Explanation

:stopinsert is an Ex command that immediately exits insert (or replace) mode and returns to normal mode. Unlike pressing <Esc>, which requires simulating a keypress, :stopinsert works reliably from autocommands and Vimscript functions where injecting keystrokes is awkward or unsafe. This makes it the correct tool for mode-switching logic driven by events or timers.

How it works

  • :stopinsert — transitions from insert or replace mode to normal mode
  • It is equivalent to <Esc> but callable from any Vimscript context
  • Safe to call even if already in normal mode (it is a no-op then)
  • Works with both i, I, a, A, o, O insert entry points and replace mode (R)

Example

Auto-leave insert mode after 30 seconds of idle typing:

set updatetime=30000
autocmd CursorHoldI * stopinsert

Return to normal mode when the cursor leaves the current window:

autocmd WinLeave * if mode() =~# 'i' | stopinsert | endif

Exit insert mode at the end of a function called from a mapping:

function! InsertAndReturn(text)
  execute 'normal! a' . a:text
  stopinsert
endfunction

Tips

  • Always guard with mode() when calling from generic autocmds to avoid side effects in normal mode
  • mode() returns 'i' in insert mode and 'R' in replace mode; use =~# for case-sensitive matching
  • Pair :stopinsert with CursorHoldI (the insert-mode variant of CursorHold) for insert-mode timeouts
  • In Neovim, vim.cmd('stopinsert') or vim.api.nvim_command('stopinsert') works from Lua callbacks

Next

How do I autocomplete macro-defined identifiers from header files while in insert mode?