Vim Tips Wiki
Vim Tips Wiki
Advertisement
Tip 1202 Printable Monobook Previous Next

created 2006 · complexity basic · author inetic · version 6.0


The following script will save your settings (see :help :mksession) on Vim exit, and load those settings when you enter Vim again.

The settings are associated (by this script) to the directory from where you've started Vim. For example, if you start Vim from directory /home/mynick/project/foo, edit multiple buffers and then exit without closing the buffers, when you next run Vim from the same directory, all the buffers, mappings and other settings will be loaded back as they were when you left.

Just paste the following into your vimrc:

function! MakeSession()
  let b:sessiondir = $HOME . "/.vim/sessions" . getcwd()
  if (filewritable(b:sessiondir) != 2)
    exe 'silent !mkdir -p ' b:sessiondir
    redraw!
  endif
  let b:filename = b:sessiondir . '/session.vim'
  exe "mksession! " . b:filename
endfunction

function! LoadSession()
  let b:sessiondir = $HOME . "/.vim/sessions" . getcwd()
  let b:sessionfile = b:sessiondir . "/session.vim"
  if (filereadable(b:sessionfile))
    exe 'source ' b:sessionfile
  else
    echo "No session loaded."
  endif
endfunction
au VimEnter * nested :call LoadSession()
au VimLeave * :call MakeSession()

Without corrections this script will work only on Unix like systems.

Comments[]

Why not just use script#69?


Problem with editing crontab, /etc/passwd, and the like.

If you are in $HOME and edit the crontab via crontab -e and then quit Vim without first closing the buffer explicitly, and do this again from $HOME, you will look at an empty crontab.

Why? When you enter crontab -e, crontab essentially copies the current crontab to /tmp/<random_filename> and opens this temporary file in $EDITOR, which is of course Vim. The next time, crontab creates a new temporary file, but Vim restores the last session from $HOME. Hence, you end up editing an empty temporary file. What's more, if you save this file, it won't be activated afterwards because you made no changes to the current temporary crontab file.

The same goes for vipw and vigr and more utilities.

I think the tip would be more useful if it did only restore a session when Vim is started without a filename argument.


Yes, I agree, after a while I didn't like the behaviour of autoloading a session on VimEnter for similar reasons. I've changed line:

au VimEnter * nested :call LoadSession()

to:

map ,l :call LoadSession()<CR>

i.e. loading sesion on ",l" shortcut request.


I've since modified this script myself to only autoload when no file arguments are provided:

" automatically load and save session on start/exit.
" Modified by robin burchell <w00t@inspircd.org> to only load/save sessions if started with no arguments.
function! MakeSession()
  if g:sessionfile != ""
    echo "Saving."
    if (filewritable(g:sessiondir) != 2)
      exe 'silent !mkdir -p ' g:sessiondir
      redraw!
    endif
    exe "mksession! " . g:sessionfile
  endif
endfunction

function! LoadSession()
  if argc() == 0
    let g:sessiondir = $HOME . "/.vim/sessions" . getcwd()
    let g:sessionfile = g:sessiondir . "/session.vim"
    if (filereadable(g:sessionfile))
      exe 'source ' g:sessionfile
    else
      echo "No session loaded."
    endif
  else
    let g:sessionfile = ""
    let g:sessiondir = ""
  endif
endfunction

au VimEnter * nested :call LoadSession()
au VimLeave * :call MakeSession()

I didn't like that a session is created every time you leave Vim. I've changed it in two ways:

  • Vim never creates the session.vim, it only updates it.
  • The user must manually create the first session.vim, after that Vim will update and load as necessary.

The idea is that I didn't want session files for every file I casually edit.

" Creates a session
function! MakeSession()
  let b:sessiondir = $HOME . "/.vim_sessions" . getcwd()
  if (filewritable(b:sessiondir) != 2)
    exe 'silent !mkdir -p ' b:sessiondir
    redraw!
  endif
  let b:filename = b:sessiondir . '/session.vim'
  exe "mksession! " . b:filename
endfunction

" Updates a session, BUT ONLY IF IT ALREADY EXISTS
function! UpdateSession()
  let b:sessiondir = $HOME . "/.vim_session" . getcwd()
  let b:sessionfile = b:sessiondir . "session.vim"
  if (filereadable(b:sessionfile))
    exe "mksession! " . b:filename
  endif
endfunction

" Loads a session if it exists
function! LoadSession()
  let b:sessiondir = $HOME . "/.vim_sessions" . getcwd()
  let b:sessionfile = b:sessiondir . "/session.vim"
  if (filereadable(b:sessionfile))
    exe 'source ' b:sessionfile
  else
    echo "No session loaded."
  endif
endfunction

au VimEnter * nested :call LoadSession()
au VimLeave * :call UpdateSession()
map <leader>m :call MakeSession()<CR>

Combining the previous two ideas then results in having no sessions by default or when called with commandline arguments. After executing :call MakeSession() ( or using its mapping ) that directory then has session autoloading and saving activated. So starting (g)vim without arguments in that directory results in loading the session. And when exiting it is autosaved again. (Note: If you're using Windows, you intend to keep, make sure to exit with :qa not multiple :q otherwise only the last window is saved naturally)

" Creates a session
function! MakeSession()
  let b:sessiondir = $HOME . "/.vim/sessions" . getcwd()
  if (filewritable(b:sessiondir) != 2)
    exe 'silent !mkdir -p ' b:sessiondir
    redraw!
  endif
  let b:sessionfile = b:sessiondir . '/session.vim'
  exe "mksession! " . b:sessionfile
endfunction

" Updates a session, BUT ONLY IF IT ALREADY EXISTS
function! UpdateSession()
  let b:sessiondir = $HOME . "/.vim/sessions" . getcwd()
  let b:sessionfile = b:sessiondir . "/session.vim"
  if (filereadable(b:sessionfile))
    exe "mksession! " . b:sessionfile
    echo "updating session"
  endif
endfunction

" Loads a session if it exists
function! LoadSession()
  if argc() == 0
    let b:sessiondir = $HOME . "/.vim/sessions" . getcwd()
    let b:sessionfile = b:sessiondir . "/session.vim"
    if (filereadable(b:sessionfile))
      exe 'source ' b:sessionfile
    else
      echo "No session loaded."
    endif
  else
    let b:sessionfile = ""
    let b:sessiondir = ""
  endif
endfunction

au VimEnter * nested :call LoadSession()
au VimLeave * :call UpdateSession()
map <leader>m :call MakeSession()<CR>

To avoid your session to be overwritten when Vim is called with commandline argument add:

if argc()==0

at the beginning of the update function and

endif

at the end.


A simplified version which simply autosaves the current session on exit, if one exists.

function! SaveSession()
  if v:this_session != ""
    echo "Saving."
    exe 'mksession! ' . '"' . v:this_session . '"'
  else
    echo "No Session."
  endif
endfunction

au VimLeave * :call SaveSession()

If you omit 'options' from 'sessionoptions', you might want to use nested flag from VimEnter autocmd. Syntax highlighting and mappings might not be restored otherwise.

autocmd VimEnter * nested call RestoreSession()


I always use server mode in my vim (for the multimon plugin, essentially), so I have modified the save/load functions to be tied to the servername:

function! MakeSession()
  if ! exists("v:servername")
        return
  endif
  let b:sessiondir = $HOME . "/.vim/sessions"
  if (filewritable(b:sessiondir) != 2)
    exe 'silent !mkdir -p ' b:sessiondir
    redraw!
  endif
  let b:filename = b:sessiondir . '/' . v:servername
  exe "mksession! " . b:filename
endfunction

function! LoadSession()
  if ! exists("v:servername")
        return
  endif
  let b:sessiondir = $HOME . "/.vim/sessions"
  let b:sessionfile = b:sessiondir . "/" . v:servername
  if (filereadable(b:sessionfile))
    exe 'source ' b:sessionfile
  else
    echo "No session loaded."
  endif
endfunction

au VimEnter * nested :call LoadSession()
au VimLeave * :call MakeSession()

I wrote another session plugin from the comments here that autosaves/loads based on the git projects and branches called gitsessions.vim.

Advertisement