Vim Tips Wiki
Advertisement
Tip 1569 Printable Monobook Previous Next

created June 4, 2008 · complexity basic · author Dfishburn · version 7.0


I often have more than one Vim (gui on Windows) running. Quite often I will have one per project, each instance editing multiple buffers. When I start Vim, I name it (based on the project or tool I launched it from).

gvim --servername VS_NET filename

When I re-open Vim I like its screen position and size to be the same as they were when Vim was closed.

Version 1 (win32 and only one Vim instance)

Add the following to your vimrc to accomplish this.

" Restore screen size and position
" Saves data in viminfo in a global variable based on gvim servername.
" BUG: When more than one instance of Vim is running, the last to exit
"      overwrites the data saved by the previous instances.
if has("gui_running") && has('win32')
  function! Screen_init()
    " - Remembers and restores winposition, columns and lines stored in
    "   global variables written to viminfo
    " - Must follow font settings so that columns and lines are accurate
    "   based on font size.
    if ! has("gui_running") || ! has('win32')
      return
    endif
    if &viminfo !~ '!'
      echoerr 'Screen_init: The viminfo setting must have a "!".  :h viminfo  :set viminfo+=!'
      return
    endif
    " initialize
    if !exists("g:COLS_".v:servername)
      let g:COLS_{v:servername} = &columns
    endif
    if !exists("g:LINES_".v:servername)
      let g:LINES_{v:servername} = &lines
    endif
    if !exists("g:WINPOSX_".v:servername)
      " don't set to 0, let window manager decide
      let g:WINPOSX_{v:servername} = ""
    endif
    if !exists("g:WINPOSY_".v:servername)
      " don't set to 0, let window manager decide
      let g:WINPOSY_{v:servername} = ""
    endif
    " set
    execute "set columns=".g:COLS_{v:servername}
    execute "set lines=".g:LINES_{v:servername}
    execute "winpos ".g:WINPOSX_{v:servername}." ".g:WINPOSY_{v:servername}
  endfunction

  function! Screen_get()
    " used on exit to retain window position and size
    let g:COLS_{v:servername} = &columns
    let g:LINES_{v:servername} = &lines
    let g:WINPOSX_{v:servername} = getwinposx()
    " filter negative error condition
    if g:WINPOSX_{v:servername} < 0
      let g:WINPOSX_{v:servername} = 0
    endif
    let g:WINPOSY_{v:servername} = getwinposy()
    " filter negative error condition
    if g:WINPOSY_{v:servername} < 0
      let g:WINPOSY_{v:servername} = 0
    endif
  endfunction

  let g:restore_screen_size_pos = 1
  " autocmd VimEnter * breakadd func Screen_init
  autocmd VimEnter * if g:restore_screen_size_pos == 1 | call Screen_init() | endif
  autocmd VimLeavePre * if g:restore_screen_size_pos == 1 | call Screen_get() | endif
endif

Version 2 (all systems and multiple Vim instances)

Here is an alternative script that is being tried that uses a file (vimsize) instead of viminfo. This version access the file used to save the size/position using a Vim buffer.

" Restore screen size and position
" Saves data in a separate file, and so works with multiple instances of Vim.
if has("gui_running")
  function! Screen_filename()
    if has('amiga')
      return "s:.vimsize"
    elseif has('win32')
      return $HOME."\\_vimsize"
    else
      return $HOME."/.vimsize"
    endif
  endfunction

  function! Screen_load()
    " - Remembers and restores winposition, columns and lines stored in
    "   a .vimsize file
    " - Must follow font settings so that columns and lines are accurate
    "   based on font size.
    if !has("gui_running")
      return
    endif
    if !g:restore_screen_size_pos
      return
    endif
    " read any existing variables from .vimsize file
    silent! execute "sview " . escape(Screen_filename(),'%#\ $')
    silent! execute "0/^" . v:servername . " /"
    let sizepos = split(getline('.'))
    if len(sizepos) != 0 && sizepos[0] == v:servername
      execute "set columns=".sizepos[1]
      execute "set lines=".sizepos[2]
      silent! execute "winpos ".sizepos[3]." ".sizepos[4]
    endif
    silent! q
  endfunction

  function! Screen_save()
    " used on exit to retain window position and size
    if !has("gui_running")
      return
    endif
    if !g:restore_screen_size_pos
      return
    endif
    silent! execute "split " . escape(Screen_filename(),'%#\ $')
    silent! execute "0/^" . v:servername . " /"
    let sizepos = split(getline('.'))
    if len(sizepos) != 0 && sizepos[0] == v:servername
      delete _
    endif
    $put = v:servername . ' ' . &columns . ' ' . &lines . ' ' .
          \ (getwinposx()<0?0:getwinposx()) . ' ' .
          \ (getwinposy()<0?0:getwinposy())
    silent! x!
  endfunction

  if !exists('g:restore_screen_size_pos')
    let g:restore_screen_size_pos = 1
  endif
  autocmd VimEnter * call Screen_load()
  autocmd VimLeavePre * call Screen_save()
endif

Version 3 (like Version 2, but uses file read/write)

Here is an alternative script that is being tried that uses a file (vimsize) instead of viminfo. This version uses Vim's readfile/writefile functions to access the file used to save the size/position.

" Restore screen size and position.
if has("gui_running")
  function! ScreenFilename()
    if has('amiga')
      return "s:.vimsize"
    elseif has('win32')
      return $HOME."\\_vimsize"
    else
      return $HOME."/.vimsize"
    endif
  endfunction

  function! ScreenRestore()
    " Restore window size (columns and lines) and position
    " from values stored in vimsize file.
    " Must set font first so columns and lines are based on font size.
    let f = ScreenFilename()
    if has("gui_running") && g:restore_screen_size_pos && filereadable(f)
      for line in readfile(f)
        let sizepos = split(line)
        if len(sizepos) == 5 && sizepos[0] == v:servername
          silent! execute "set columns=".sizepos[1]." lines=".sizepos[2]
          silent! execute "winpos ".sizepos[3]." ".sizepos[4]
          return
        endif
      endfor
    endif
  endfunction

  function! ScreenSave()
    " Save window size and position.
    if has("gui_running") && g:restore_screen_size_pos
      let data = v:servername . ' ' . &columns . ' ' . &lines . ' ' .
            \ (getwinposx()<0?0:getwinposx()) . ' ' .
            \ (getwinposy()<0?0:getwinposy())
      let f = ScreenFilename()
      if filereadable(f)
        let lines = readfile(f)
        call filter(lines, "v:val !~ '^" . v:servername . "\\>'")
        call add(lines, data)
      else
        let lines = [data]
      endif
      call writefile(lines, f)
    endif
  endfunction

  if !exists('g:restore_screen_size_pos')
    let g:restore_screen_size_pos = 1
  endif
  autocmd VimEnter * call ScreenRestore()
  autocmd VimLeavePre * call ScreenSave()
endif

Comments

As Sightless said on the June new tips page, version 1 can't work with more than one Vim instance. I just finished writing version 3 which has the advantage that the data file does not get read into a buffer, and so doesn't influence MRU file or buffer lists. Please add any thoughts below. --JohnBeckett 11:51, 9 September 2008 (UTC)

 TO DO 
I think my above comment, and the following which I added to version 1 are totally wrong. :help viminfo-write

BUG: When more than one instance of Vim is running, the last to exit overwrites the data saved by the previous instances.

Need to investigate and prune the tip.

In version 2, the silent! q probably should be silent! bwipeout. With 'q', the .vimsize file is visible in the buffer list, which is irritating, and which causes trouble if another Vim instance changes the file. --JohnBeckett 04:00, 13 February 2009 (UTC)

Advertisement