tags:

views:

1215

answers:

4

When a previous Vim session crashed, you are greeted with the "Swap file ... already exists!" for each and every file that was open in the previous session.

Can you make this Vim recovery prompt smarter? (Without switching off recovery!) Specifically, I'm thinking of:

  • If the swapped version does not contain unsaved changes and the editing process is no longer running, can you make Vim automatically delete the swap file?
  • Can you automate the suggested process of saving the recovered file under a new name, merging it with file on disk and then deleting the old swap file, so that minimal interaction is required? Especially when the swap version and the disk version are the same, everything should be automatic.

I discovered the SwapExists autocommand but I don't know if it can help with these tasks.

+10  A: 

I have vim store my swap files in a single local directory, by having this in my .vimrc:

set directory=~/.vim/swap,.

Among other benefits, this makes the swap files easy to find all at once. Now when my laptop loses power or whatever and I start back up with a bunch of swap files laying around, I just run my cleanswap script:

TMPDIR=$(mktemp -d) || exit 1
RECTXT="$TMPDIR/vim.recovery.$USER.txt"
RECFN="$TMPDIR/vim.recovery.$USER.fn"
trap 'rm -f "$RECTXT" "$RECFN"; rmdir "$TMPDIR"' 0 1 2 3 15
for q in ~/.vim/swap/.*sw? ~/.vim/swap/*; do
  [[ -f $q ]] || continue
  rm -f "$RECTXT" "$RECFN"
  vim -X -r "$q" \
      -c "w! $RECTXT" \
      -c "let fn=expand('%')" \
      -c "new $RECFN" \
      -c "exec setline( 1, fn )" \
      -c w\! \
      -c "qa"
  if [[ ! -f $RECFN ]]; then
    echo "nothing to recover from $q"
    rm -f "$q"
    continue
  fi
  CRNT="$(cat $RECFN)"
  if diff --strip-trailing-cr --brief "$CRNT" "$RECTXT"; then
      echo "removing redundant $q"
      echo "  for $CRNT"
      rm -f "$q"
  else
      echo $q contains changes
      vim -n -d "$CRNT" "$RECTXT"
      rm -i "$q" || exit
  fi
done

This will remove any swap files that are up-to-date with the real files. Any that don't match are brought up in a vimdiff window so I can merge in my unsaved changes.

--Chouser

Chouser
What if you edit two files of the same name, for instance in two branches of an SVN repository
Nathan Fellman
When editing more than one file with the same name, Vim will go backwards in the alphabet for the extensions (*.swp, *.swo, *.swn, etc.).It should be noted that using this method disables the "swap file exists" feature. So you will *need* to use the `cleanswap` script provided above.
sirlancelot
+5  A: 

I just discovered this:

http://vimdoc.sourceforge.net/htmldoc/diff.html#:DiffOrig

I copied and pasted the DiffOrig command into my .vimrc file and it works like a charm. This greatly eases the recovery of swap files. I have no idea why it isn't included by default in VIM.

Here's the command for those who are in a hurry:

 command DiffOrig vert new | set bt=nofile | r # | 0d_ | diffthis
  \ | wincmd p | diffthis
Jack Senechal
A: 

This is just what i was looking for too! If you use it: recover the file when prompted and then run :DiffOrig

+1  A: 

Great tip DiffOrig is perfect. Here is a bash script I use to run it on each swap file under the current directory:

#!/bin/bash

swap_files=`find . -name "*.swp"`

for s in $swap_files ; do
        orig_file=`echo $s | perl -pe 's!/\.([^/]*).swp$!/$1!' `
        echo "Editing $orig_file"
        sleep 1
        vim -r $orig_file -c "DiffOrig"
        echo -n "  Ok to delete swap file? [y/n] "
        read resp
        if [ "$resp" == "y" ] ; then
                echo "  Deleting $s"
                rm $s
        fi
done

Probably could use some more error checking and quoting but has worked so far.

-Mark