Vim Tips Wiki
Tip 1109 Printable Monobook Previous Next

created 2006 · complexity advanced · author Gerald Lai · version 6.0

This is for script writers who wish to save and restore the position of the normal cursor and its screen.

To save cursor and screen positions: call CurPos("save")

To restore positions: call CurPos("restore")


"Pressing <F2> shouldn't change a thing! try with special characters and such
nmap <F2> :call Test()<CR>
function Test()
  call CurPos("save")
  normal gg0
  call CurPos("restore")

function CurPos(action)
  if a:action == "save"
    let b:saveve = &virtualedit
    let b:savesiso = &sidescrolloff
    set virtualedit=all
    set sidescrolloff=0
    let b:curline = line(".")
    let b:curvcol = virtcol(".")
    let b:curwcol = wincol()
    normal! g0
    let b:algvcol = virtcol(".")
    normal! M
    let b:midline = line(".")
    execute "normal! ".b:curline."G".b:curvcol."|"
    let &virtualedit = b:saveve
    let &sidescrolloff = b:savesiso
  elseif a:action == "restore"
    let b:saveve = &virtualedit
    let b:savesiso = &sidescrolloff
    set virtualedit=all
    set sidescrolloff=0
    execute "normal! ".b:midline."Gzz".b:curline."G0"
    let nw = wincol() - 1
    if b:curvcol != b:curwcol - nw
      execute "normal! ".b:algvcol."|zs"
      let s = wincol() - nw - 1
      if s != 0
        execute "normal! ".s."zl"
    execute "normal! ".b:curvcol."|"
    let &virtualedit = b:saveve
    let &sidescrolloff = b:savesiso
    unlet b:saveve b:savesiso b:curline b:curvcol b:curwcol b:algvcol b:midline
  return ""


Benji Fisher's functions (foo.vim?) contain a Mark() function that returns an ex command that, when executed, restores the cursor and screen positions. An example:

:let currPos = Mark()
" Do some stuff
:execute currPos

I tested Benji's Mark() function and found that it doesn't hold the screen position well when the screen has already been scrolled past to the right - which is the original intention for retaining the screen position in the first place.

Here's an example of how it breaks:

fun TestMark()
  let a = Mark()
  "move to the start & end of the file to simulate cursor displacement
  normal gg0G0
  exe a
nmap <F2> :call TestMark()<CR>

Now try pressing <F2> at the end of a long line of a large file (try a binary file) that is longer than the window width. The cursor retains its position, but the screen position shifts.

cecutil.vim's SaveWinPosn() and RestoreWinPosn() functions script#1066 do this too.

I tried cecutil's SaveWinPosn() and RestoreWinPosn() but it does not retain the screen's exact position once the cursor is at the end of a long line and the screen has been scrolled to the right. Perhaps it has to do with the 'scrolloff', 'sidescrolloff' & 'sidescroll' options.

The script above tries to restore the screen middle line number (so line xx will be at the middle screen before and after editing). This is not very reliable, because when the last line of the file is above the bottom of the screen, the cursor position after M is not in the middle of the screen. Save and restore the top of the screen (using H) is more reliable. So

"save line number x
"do something
"go to line number x

should restore the screen better than the solution above. In the case where the last line of the file is below the bottom of the screen, then the two solutions are identical (except for the position of the cursor -- one in middle, one at top).