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

How do I run a command without moving the cursor or changing the scroll position?

Answer

:let view=winsaveview() | {cmd} | call winrestview(view)

Explanation

When writing Vimscript functions or mappings, commands like :substitute, gg, or :%normal will move the cursor and change the scroll position. The winsaveview() and winrestview() functions let you save and restore the exact window state — cursor line, column, scroll offset, and more — so the user sees no visible jump after your command runs.

How it works

  • winsaveview() — returns a dictionary containing the cursor position, topline (scroll position), and other window state
  • {cmd} — any Ex command that would normally move the cursor
  • winrestview(view) — restores the saved window state exactly

The saved dictionary includes keys like lnum (cursor line), col (cursor column), topline (first visible line), and leftcol (horizontal scroll offset).

Example

Strip trailing whitespace from the entire file without moving the cursor:

:let view=winsaveview() | %s/\s\+$//e | call winrestview(view)

Wrap it in a function for reuse:

function! StripTrailingWhitespace()
  let l:view = winsaveview()
  %s/\s\+$//e
  call winrestview(l:view)
endfunction
nnoremap <leader>w :call StripTrailingWhitespace()<CR>

Tips

  • This pattern is essential for any mapping or autocommand that modifies the buffer globally
  • The view dictionary can be inspected with :echo winsaveview() to see all saved fields
  • Unlike using marks to save position, winsaveview() also preserves the exact scroll offset

Next

How do I use PCRE-style regex in Vim without escaping every special character?