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,Oinsert 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
:stopinsertwithCursorHoldI(the insert-mode variant ofCursorHold) for insert-mode timeouts - In Neovim,
vim.cmd('stopinsert')orvim.api.nvim_command('stopinsert')works from Lua callbacks