Undo in Vi and its successors
13 points by runxiyu
13 points by runxiyu
previously, previously
Fair enough, especially since the first previously is by the same author less than a week earlier.
On the other hand, this post goes into more detail about a very specific point. I think that point deserves discussion on its own.
The original Bill Joy vi famously only had a single level of undo (which is part of what makes it a product of its time). The 'u' command either undid your latest change or it redid the change, undo'ing your undo. When POSIX and the Single Unix Specification wrote vi into the standard, they required this behavior; the vi specification requires 'u' to work the same as it does in ex, where it is specified as:
Reverse the changes made by the last command that modified the contents of the edit buffer, including undo.
This is one particular piece of POSIX compliance that I think everyone should ignore.
Vim and its derivatives ignore the POSIX requirement and implement multi-level undo and redo in the usual and relatively obvious way. The vim 'u' command only undoes changes but it can undo lots of them, and to redo changes you use Ctrl-r ('r' and 'R' were already taken).
He then reviews undo/redo in nvi, Evil mode for Emacs, and Busybox vi. (Tl;dr: nvi is POSIX compliant and (original) vi-style, but it adds the . command to allow for a limited version of multi-level undo; Evil is sort of like Vim, but seems not to support multi-level undo with other actions interspersed; and also its version of redo is more Emacs than Vi/Vim-like; Busybox vi can be built to support multi-level undo, and on some systems this is the default; but it doesn't support redo at all (!).) In a parenthetical final paragraph, he adds nextvi, neatvi, vile, and vis, but he discusses them in less detail.
He concludes:
My personal view is that the vim undo and redo behavior is the best and most human friendly option. Undo and redo are predictable and you can predictably intersperse undo and redo operations with other operations that don't modify the buffer, such as moving the cursor, searching, and yanking portions of text.
Obviously this is deep into personal preferences and highly subjective opinions, but I agree 100% with him. After playing with antirez's kilo and working through the (excellent!) Build your own text editor based on kilo, I tried porting kilo to be vilo. If all you want is to open and edit a single file at a time, save changes to that file, save the file under a new name, basic movements and scrolling (including things like f/F and t/T), (very!) simplistic auto-indentation, and simple regex searching, it's easy. (I was genuinely shocked how easy.) My next question was "How much more would I need for this to be an editor I can actually use every day?"
I'm continuing to play with all this, both by using my own hyper-minimal vilo and by trying out heirloom-vi, nvi, neatvi, and nextvi. Here's what I found out about my needs and preferences.
:cq (essential for backing out of Git commits, which I apparently do at least a couple of times a week), gg (not essential but muscle memory for me), hybrid line numbers, and some text objects. I also added options to allow the user to delete more freely using backspace. No doubt it is inefficient to use the backspace key too much, but Vi's limitations on the backspace key drive me crazy. I've been using this fork happily, but I'd love to add Vim-like undo and redo (and dot-repeat).All of which is a long (long) way of saying that I like the idea of a much smaller editor than Vim or Neovim, but some things from Vi would have to change for me. Undo and redo is definitely one of them.
(My “previously” links are for sharing context when lobsters doesn’t do so automatically; they aren’t criticism and I’m not implying you shouldn’t have posted. I’m not a deletionist.)
In vim you can actually traverse the undo tree and also make it persistent: https://vimdoc.sourceforge.net/htmldoc/undo.html
Practically unlimited persistent undo is my favourite feature of vim. I never got the hang of the UI for the branching undo, but being able to undo to a state from before I rebooted the machine is great. My vimrc pops all of these files under ~/.cache, so the FS doesn't get cluttered with them. My laptop has 115MB of files there, which is trivial in comparison to modern disk sizes.
This is also the reason I don't use NeoVim. The first time I tried NeoVim, I discovered that they had changed the format of the undo files. They deleted the existing one (did not auto-upgrade, so NeoVim saw no undo history) and the new one was then not readable in vim. I raised an issue about this and was told that (in spite of the fact that I'd been using persistent undo for 20 years in vim and it had never lost data) persistent undo history was not something you should ever rely on and they would destroy it whenever they felt like it. Vim has always respected Raskin's First Law: A program may not harm a user's data, or through inaction allow a user's data to come to harm. If it crashes, I lose a few seconds of data at a time. I don't lose undo history at all. The NeoVim developers' attitude made me never want to trust them with my data.
uu meaning undo undo and not undo redo in vim is the primary reason why nvi is usually the first thing I install on a system new to me (if it isn't part of base, in f.e. OpenBSD)