Skip to content

Instantly share code, notes, and snippets.

@Arnie97
Last active August 29, 2022 08:19
Show Gist options
  • Save Arnie97/8d578ab793bb9b3f35394f416c85103c to your computer and use it in GitHub Desktop.
Save Arnie97/8d578ab793bb9b3f35394f416c85103c to your computer and use it in GitHub Desktop.
Neovim 0.5+ undo file version bumping script. Fixes "E824: Incompatible undo file"
#!/usr/bin/env python3
"""
Neovim undo file version bumping script
This python script backups and converts Vim undo files generated by
vanilla Vim 7.2.444 - 9.0 or Neovim 0.1.0 - 0.4.4 (UF_VERSION=2) to
reuse them on Neovim 0.5.0+ (UF_VERSION=3) without the error message
"E824: Incompatible undo file".
See https://github.com/neovim/neovim/pull/13973 for more information.
Example usage w/ undodir:
$ ./ufbump ~/.local/share/nvim/undo/*
Alternative form if the shell complains about "too many arguments":
$ find ~/.local/share/nvim/undo -type f -exec ./ufbump '{}' +
Example usage w/o undodir:
$ find /code/path -name '*.un~' -type f -exec ./ufbump '{}' +
USE AT YOUR OWN RISK!
The author disclaims copyright to this source code.
In place of a legal notice, here is a blessing:
* May you do good and not evil.
* May you find forgiveness for yourself and forgive others.
* May you share freely, never taking more than you give.
"""
import os
import shutil
import struct
import sys
UF_START_MAGIC = b"Vim\237UnDo\345"
UF_ENTRY_END_MAGIC = b"\x35\x81"
UF_OLD_VERSION = 2
UF_NEW_VERSION = 3
def main(path):
path_tmp = path + ".tmp"
path_bak = path + ".bak"
with open(path, "rb") as src:
magic = src.read(len(UF_START_MAGIC))
if magic != UF_START_MAGIC:
print("%s: not a vim undo file, skipped" % path)
return
version, *_ = struct.unpack(">h", src.read(2))
if version != UF_OLD_VERSION:
print("%s: undo file version was %d, skipped" % (path, version))
return
with open(path_tmp, "wb") as dest:
dest.write(UF_START_MAGIC)
dest.write(struct.pack(">h", UF_NEW_VERSION))
dest.write(src.read().replace(UF_ENTRY_END_MAGIC, UF_ENTRY_END_MAGIC * 2))
os.rename(path, path_bak)
os.rename(path_tmp, path)
print("%s: added empty extmark section" % path)
if __name__ == "__main__":
script, *argv = sys.argv
if not argv:
print(__doc__.strip())
for path in argv:
main(path)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment