‹ BackHN Continuity

Thread

On caring for user data: NeoVim caused Vim undo files to be deleted

384 points · 346 comments · jandeboevrie

  1. gavinhoward · · focus · HN ↗
    As a Neovim user, this stopped me dead with painful realization: I may have suffered the same thing but didn't realize it. There was a time when I could not undo something, and it was after a Neovim upgrade.

    Unlike Dr. Chisnall, I started my editor journey on Neovim, so it wasn't a transition that bit me. However, if the format of the persistent undo file is unstable, and Neovim just deletes it when it doesn't recognize the previous format, then it seems conceivable (to me) that an upgrade after changing the format would delete the file too.

    Ouch. This is making me think about getting off of Neovim. Yes, FOSS comes as-is, but if there's an alternative...

    1. antonkochubey · · focus · HN ↗
      Sorry for my ignorance, but what is the usefulness of undo persistence after a IDE restart? Don't you normally save your changes and finish a piece of work before exiting an DE?

      Edit: some great examples in the replies here, thanks! Perhaps I should start using it in editors that support it, never gave it a thought before.

      1. traverseda · · focus · HN ↗
        I often use it to edit system config files, often on embedded devices where I don't have my git credentials setup, or on servers. In these cases we're already not in an ideal world, I don't have good reliable version control or change management in place. In those less-than-ideal worlds, having proper undo history is nice.
        1. Joker_vD · · focus · HN ↗

              #!/bin/sh
              
              errecho() {
                  >&2 printf '%s\n' "$@"
              }
              
              if [ "$#" != 1 ] || [ -z "$1" ]
              then
                  errecho 'Requires a single filename as the argument'
                  exit 1
              fi
              
              ORIGINAL=$1
              if [ "${ORIGINAL#./}" == "$ORIGINAL" ] && [ "${ORIGINAL#/}" == "$ORIGINAL" ]
              then
                  ORIGINAL=./"$ORIGINAL"
              fi
              
              # because of course the output of dirname can't be blindly joined with slash and the basename
              DIRNAME=$(dirname -- "$ORIGINAL")
              if [ "$DIRNAME" = / ]
              then
                  DIRNAME=
              fi
              
              FILENAME=$(basename -- "$ORIGINAL")
              # because of course extracting the filename's extension is not supported out of the box
              case "$FILENAME" in
                  .*.* )
                      EXTENSION=.${FILENAME#.*.}
                      BASENAME=$(printf '%s' "$FILENAME" | cut -c-$((${#FILENAME} - ${#EXTENSION})) )
                      ;;
                  .* )
                      EXTENSION=
                      BASENAME=$FILENAME
                      ;;
                  *.[^.]* )
                      BASENAME=${FILENAME%%.*}
                      EXTENSION=${FILENAME#*.}
                      ;;
                  * )
                      BASENAME=${FILENAME%%.*}
                      EXTENSION=$(printf '%s' "$FILENAME" | cut -c$((${#BASENAME} + 1))- )
                      ;;
              esac
              
              if [ "$FILENAME" != "$BASENAME$EXTENSION" ] || [ -z "$BASENAME" ]
              then
                  errecho 'Failed to properly split the extension from the filename:' "$FILENAME"
                  exit 1
              fi
              
              TIMESTAMP=$(date --utc --date=@"$(stat --format %Y "$ORIGINAL")" +'_%Y-%m-%d_%H%M%S')
              if [ -z "$TIMESTAMP" ]
              then
                  errecho 'Failed to get the timestamp of the file:' "$ORIGINAL"
                  exit 1
              fi
              
              NEW_FILENAME=$(printf '%s/%s_%s%s' "$DIRNAME" "$BASENAME" "$TIMESTAMP" "$EXTENSION")
              
              if [ "$NEW_FILENAME" = "$ORIGINAL" ]
              then
                  errecho 'Somehow the name for the backup is the same as the original file'
                  exit 1
              fi
              
              # this preserves the timestamps somewhat better
              if ! mv --no-clobber --no-copy -- "$ORIGINAL" "$NEW_FILENAME"
              then
                  errecho 'Failed to backup the file: ' "$ORIGINAL" "$NEW_FILENAME"
                  exit 1
              fi
              
              if ! cp -- "$NEW_FILENAME" "$ORIGINAL"
              then
                  errecho 'Failed to backup the file: ' "$ORIGINAL" "$NEW_FILENAME"
                  mv --no-clobber --no-copy -- "$NEW_FILENAME" "$ORIGINAL"
              fi
          
          Actually, nevermind that bullshit, you know what? I think I'd prefer to have an editor with locally persisted edit history instead.
        2. PunchyHamster · · focus · HN ↗
          First, you need backups

          Second (for servers), etckeeper

          1. traverseda · · focus · HN ↗
            I mean I already responded to the comment

            > In these cases we're already not in an ideal world, I don't have good reliable version control or change management in place.

            Most of the stuff I work on is properly scripted idempotent deploys, with good backups and all that. Or it's a one-off demo, or a prototype. Not having full undo history is never going to actually kill a project, it's just going to make early stage projects and one-offs more inconvenient.

Open on Hacker News to reply ↗

Unofficial Hacker News client; not affiliated with Y Combinator.