[HN Gopher] Resolving the great undo-redo quandary
       ___________________________________________________________________
        
       Resolving the great undo-redo quandary
        
       Author : kerblang
       Score  : 392 points
       Date   : 2022-11-11 12:59 UTC (10 hours ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | low_tech_punk wrote:
       | Wow, the article nailed the UX.
       | 
       | On the implementation side, I think the article implies that you
       | might need to model the edits by Operation, rather than State?
       | Otherwise, the cost of the undo scales O(N) of the content size,
       | which is not viable.
       | 
       | It works well for Git, which models content by State, using
       | Structural Sharing. But Git has built-in delta compression so the
       | memory footprint is roughly O(1) per operation. I don't think
       | implementing this on the web for a <textarea>, or
       | [contenteditable="true"] is a "minimum" effort.
       | 
       | Challenges I can think of:
       | 
       | 1. DOM api exposes state, not operations. You need manual diffing
       | 
       | 2. When applying the operations, you need to manually restore
       | cursor positions
       | 
       | 3. CJK language IME might inject unwanted intermediate states
       | that must be ignored
        
       | [deleted]
        
       | sharikous wrote:
       | My way is a a ugly undo - copy - redo - paste.
       | 
       | Not efficient, sure, but I'm used to it and it solves my problem
       | most of the time
        
         | twodave wrote:
         | Honestly IMO it's a bit better--often times I find myself
         | wanting neither _this_ nor _that_, but some of each. I get to a
         | point in a function where I realize changes I made elsewhere
         | are no longer needed, but I want to keep my function the same.
         | So I usually just copy the function (and paste it someplace so
         | I don't for real lose it), undo everything, then just splice
         | the function back in how I want it.
        
         | somebodythere wrote:
         | The main issue with this I find is a stray keystroke before you
         | redo wiping your redo stack .
        
       | indosauros wrote:
       | FYI if you use Jetbrains/PyCharm, it also provides this (and has
       | saved me many times)
       | 
       | Just right click your file and view "Local History"
        
         | jasonjmcghee wrote:
         | Yup. And it's full-text searchable, which I've found people
         | generally don't realize. Fantastic feature.
        
       | randomsearch wrote:
       | Relatedly, have you ever thought about how undo works with text?
       | 
       | Open your mail client, compose a message, type a few words. What
       | do you expect cmd-z to do? How much of the words will it undo?
       | All the line? Try it.
       | 
       | Then after undo, type a bit more. Hit enter and cursor back. Type
       | again.
       | 
       | Undoing typing is no trivial matter.
        
       | 323 wrote:
       | Many times I want to undo to a previous state, but then apply
       | again a few of the changes I just reverted, basically cherry-
       | picking from the future (from the redo stack).
       | 
       | It would be interesting to be able to see all edits as individual
       | patches/diffs that you can commit/discard individually. Like a
       | mini automatic git inside the editor, automatic in the sense that
       | every "edit" creates a commit, undo/redo move HEAD.
       | 
       | This would be entirely optional, you can continue using Undo/Redo
       | as usual, but if you need to do a more complex history operation
       | you can open this "git" view and operate on the edit tree
       | directly.
       | 
       | Photoshop has this nice undo panel where you can see individual
       | edits and click your way to the desired point in history:
       | 
       | https://www.bwillcreative.com/wp-content/uploads/2020/08/how...
       | 
       | One can imagine such a view in a text editor, where each entry
       | shows a diff of what that step did.
        
         | twobitshifter wrote:
         | This is what I thought the undo redo quandary would be. The
         | fact that you can undo an undo seems like tablestakes to me.
        
         | nwatson wrote:
         | In Atlassian Sourcetree you can stage the full current file,
         | undo live changes in your editor, make different changes to
         | your live document, and then reapply chunks of your prior
         | changes from staging to live document (actually looks like
         | undoing unstaged chunks).
        
         | spullara wrote:
         | Use local history in any JetBrains IDE.
        
           | JackFr wrote:
           | And with the diff panel you can easily cherry pick selected
           | changes to apply.
        
           | bitslayer wrote:
           | I am not a JetBrains user, but it looks like that only
           | applies to saved versions? Undo normally holds every typed
           | change. https://www.jetbrains.com/help/idea/local-
           | history.html#resto...
        
             | travisjungroth wrote:
             | You're usually autosaving. So it's not every character, but
             | maybe every minute and lots of other logical triggers like
             | running the file. I've found it works very well.
        
           | jasonlotito wrote:
           | Seriously. This is one of those features I forget other
           | people don't have access to. Anything less is just
           | uninspired.
        
             | 323 wrote:
             | VS Code has this feature too, it's just not known.
        
         | perlgeek wrote:
         | Agreed.
         | 
         | When I write "foobar", delete the last three characters (so
         | that now I have "foo", then I write a "t", I would like to be
         | able to undo the previous deletion (giving me "footbar"), not
         | just adding the last character.
         | 
         | Seems to me that would work especially well in editors that
         | have the concept of verbs + objects, like vim's "delete until
         | the end of the line" or "replace current word with...", but
         | maybe it would work with all kinds of editors?
        
           | chongli wrote:
           | Should it be "footbar"? Or "foobart"? I could see a case
           | being made for either.
        
             | mananaysiempre wrote:
             | foo<<<bar===t>>>
             | 
             | I'm kidding, but only a bit: the (in hindsight, reasonable)
             | lesson of the Pijul paper[1] is that if you want to do the
             | most general merge and (therefore) avoid any arbitrary
             | choices, you're forced to extend your model from consistent
             | files as sequences to files potentially containing
             | conflicts as DAGs (or something even more complicated if
             | you have data more complex than a single flat sequence or
             | edits other than insertions). Or you can _very carefully_
             | make a consistent set of arbitrary choices, like
             | implementations of operational transformation usually do.
             | 
             | [1] https://doi.org/10.1016/j.entcs.2013.09.018
        
             | perlgeek wrote:
             | Depends on where the cursor is when you press redo, because
             | it was originally inserted at the cursor position.
        
               | chongli wrote:
               | I would definitely not want the behaviour of undo/redo to
               | depend on the current position of the cursor; that's what
               | paste is for.
        
         | Chris2048 wrote:
         | If the changes "conflict" it might be best to use a "smart"
         | editor that can somewhat figure out changes on a higher level.
        
       | advisedwang wrote:
       | So, like Google Doc's document history? When you revert to an old
       | version, it creates a new version with the old contents, it
       | doesn't delete all the intermediate states. (although ctrl-z
       | ctrl-y doesn't do this)
        
       | unholiness wrote:
       | Feels like I'm missing something...
       | 
       | If I press ctrl-z ctrl-z, I expect the last 2 things typed to be
       | undone. Based on what he's saying, the first ctrl-z undoes one
       | step, and the second ctrl-z _undoes the undo_ i.e. puts me back
       | where I started, with no way to get back further.
       | 
       | Is there a special case for multiple undo's in a row? If so it
       | seems unclear where to draw the line. If not it sounds
       | nonfunctional.
        
         | rando14775 wrote:
         | In Emacs, undo makes an undo pointer go down in the undo stack.
         | Pressing undo again goes back another step. If you do any other
         | regular edit, the pointer starts over at the top of the undo
         | stack. Undo puts its own edits on top of the stack like any
         | other command.
         | 
         | So if you "undo, undo" you undo two things. If you "undo, edit,
         | undo", you're keeping the first undo but reverse the edit. If
         | you "undo, edit, undo, undo", you're back to where you started
         | (except your undo stack has now grown).
        
         | dmix wrote:
         | True, at what point do you include the undo itself in the undo
         | history or do you skip it entirely?
         | 
         | Never considered that.
        
           | osrec wrote:
           | I feel things work most intuitively if the undo/redo
           | functions simply navigate the history, but do not themselves
           | form part of the history.
        
             | kqr wrote:
             | That means silently killing off potentially large amounts
             | of editing history every time you edit after an undo.
             | That's the problem this article is about.
        
               | dmix wrote:
               | I was thinking maybe you ignore it for the first 10
               | seconds or even better until the cursor changes to a new
               | position, thqt way quick rewinds work in the moment. But
               | later on you can restore the state with undos factored
               | in.
        
             | unholiness wrote:
             | That's how every other undo works. The whole GRUQ is caused
             | by undos not themselves forming a part of history...
        
               | TuringTest wrote:
               | That's it. You can think of an undo operation U at time
               | (t) as a new simple command that rolls back the content
               | to a previous version (t-x). If you undo that U
               | operation, it's a new command U' that restores content
               | again to version (t).
               | 
               | The history sequence would then be:
               | 
               | (t) --U-> (t-x) --U'-> (t)
               | 
               | And if you add (A) some new content (c) when in state
               | (t-x), it becomes command , which can itself be undone
               | with commands U'' (to remove A), U''' (to remove U):
               | 
               | (t) --U-> (t-x) --A-> (t+c) --U''--> (t-x) --U'''--> (t)
        
               | hackmiester wrote:
               | >every other undo
               | 
               | Ahhhhh, some time you should try a little app called
               | Adobe Photoshop.
        
         | jefftk wrote:
         | The way this approach is implemented in Emacs is that it
         | depends on whether your previous action was an undo.
         | A: A         A B: AB         A B C: ABC         A B C undo: AB
         | A B C undo undo: A         A B C undo undo D: AD         A B C
         | undo undo D undo: A         A B C undo undo D undo undo: AB
        
           | unholiness wrote:
           | Interesting. So basically the last chain of undo doesn't
           | enter the history until you do something else.
           | 
           | I often use undo as a faster delete when making edits, so I
           | think I would still be annoyed by this (why am I seeing this
           | crap I undid reappearing?) Now after a long undo chain I'm
           | afraid to type for a new reason: it will pollute my undo
           | stack. But it might be reasonable if my brain was used to it.
           | Can't knock something I've never tried.
        
             | jefftk wrote:
             | How is undo a faster delete?
        
               | TuringTest wrote:
               | If you're only adding content, undo removes the most
               | recent content inserted. But that's a very limited case
               | of everything that undo can achieve.
        
               | a_e_k wrote:
               | Like the GP, I also use undo as a faster delete. The key
               | is that undo in Emacs doesn't just go one keystroke at a
               | time. By default it will basically quash a whole chunk of
               | similar operations and undo/redo them together:
               | 
               | > amalgamating-undo-limit is a variable defined in
               | 'simple.el'.
               | 
               | > Its value is 20
               | 
               | > The maximum number of changes to possibly amalgamate
               | when undoing changes. The 'undo' command will normally
               | consider "similar" changes (like inserting characters) to
               | be part of the same change. This is called "amalgamating"
               | the changes. This variable says what the maximum number
               | of changes considered is when amalgamating. A value of 1
               | means that nothing is amalgamated.
               | 
               | There's also a hidden 10s idle timer that will insert a
               | boundary to break up the amalgamation. So if you type,
               | pause and think, and then start typing again, the chunked
               | undo/redo will always stop at the point that you started
               | typing again. Taken together, it's usually quite
               | effective at guessing how much to delete.
        
             | TuringTest wrote:
             | Note that if you delete something and press Undo, it
             | restores the content that was there before removing it.
             | 
             | The "branching undo" in the article extends the concept to
             | being able to recover things that were at some point in
             | your "redo" pile, but which in other editors would been
             | have lost when you typed something else while in that
             | state.
             | 
             | As the article explains, the simplest mental model is
             | "rewind in time to the point I was 5 minutes, 10, 15, 20
             | minutes in the past". If you've been undoing and redoing
             | things, going through that point in the past will retrieve
             | those removals and retrievals.
        
         | pjungwir wrote:
         | No, Ctrl-Z Ctrl-Z still undoes the last two edits.
         | 
         | Basically Ctrl-Z is now "rewind" and Ctrl-Y is now "fast
         | forward". Instead of a stack you have an append-only list. Even
         | Ctrl-Z appends to the list. (I'm eliding the optimizations he
         | mentions.) So if you Ctrl-Z then edit, you can still get back
         | to the state before your Ctrl-Z.
        
         | ctrlmeta wrote:
         | > If so it seems unclear where to draw the line. If not it
         | sounds nonfunctional.
         | 
         | There is no line. It is just one long linear list. An undo
         | operation is an edit to the text after all. So the edit made by
         | the undo operation also goes as a text edit operation in the
         | undo list.
         | 
         | This is the way undo has always been in Emacs. I wouldn't say
         | it is nonfunctional. I use this in Emacs undo, redo (which is
         | undo-of-undo) and it feels okay most of the time. It is good to
         | know that Emacs will never lose any edit even if I have
         | performed a confusing series of undos and redos. But it can get
         | confusing pretty soon if we are undoing and redoing on the same
         | edit too many times.
         | 
         | That is why many people don't like linear undo history and
         | install an undo-tree plugin which makes undos easy to navigate
         | in a tree. Yet another reason to design some computer/software
         | history lessons so that devs can learn from the existing
         | techniques, their adoption, benefits and complaints.
        
         | jrmg wrote:
         | The article says:
         | 
         |  _The act of undoing need only become part of our linear
         | history if we squash the proverbial butterfly and thus alter
         | "the past"; in that case the act of undoing itself is instantly
         | recorded as a series of changes, by replaying the redo stack
         | onto the undo stack twice: 1) Forwards, for the original
         | changes 2) and then backwards, to record the history of our
         | undoing._
         | 
         | By _squash the proverbial butterfly and thus alter "the past"_
         | they mean make an edit after undoing.
        
         | IshKebab wrote:
         | Yeah for something that is supposedly intuitive this is the
         | worst explanation I have ever read. I _think_ what he 's saying
         | is that:
         | 
         | It works exactly like normal undo/redo, but if you make an edit
         | that would normally wipe your "redo stack", then instead that
         | redo stack is moved into the undo stack.
         | 
         | So:                 Type "hello"       Type "world"       Type
         | "!"       Undo       Undo       (Editor is "hello", with
         | "world" and "!" on the redo stack)       Type "dave"
         | (This would normally wipe the redo stack but instead it moves
         | it to the undo stack)       Undo       (Editor is "hello")
         | Undo       (Editor is "helloworld")       Undo       (Editor is
         | "helloworld!")       Undo       (Editor is "helloworld")
         | Undo       (Editor is "hello")
         | 
         | I like the idea. It's a little weird that typing changes the
         | undo stack but it already can change the redo stack so I don't
         | think it matters.
         | 
         | It needs an understandable explanation and ideally a web demo
         | to gain traction though.
        
           | TuringTest wrote:
           | I think the best strategy to make it intuitive would be to
           | flatten the redo stack as a single command, so that the pile
           | of successive 'undo's gets redone as a single step. In your
           | example:                 Type "hello"       Type "world"
           | Type "!"       Undo       Undo       (Editor is "hello", with
           | "world!" on the redo stack)            Type "dave"
           | (Editor is "hellodave")       (This would normally wipe the
           | redo stack but instead it moves it to the undo stack)
           | Undo       (Editor is "hello")       Undo       (Editor is
           | "helloworld!")       Undo       (Editor is "helloworld")
           | Undo       (Editor is "hello")
        
             | IshKebab wrote:
             | Yeah maybe, I'd have to play around with both to see which
             | is less annoying.
        
             | feintruled wrote:
             | I get what you are saying, but I think it is confusing to
             | refer to a 'redo' stack at all. There is only ever one
             | stack, and you are always at the end of it. To go back
             | through time you copy the states onto the stack (stack
             | isn't even the right word, I guess but I'll stick with it)
             | 
             | Consider typing the alphabet
             | 
             | Stack:                 1.a       2.ab       3.abc
             | 4.abcd
             | 
             | Now you 'undo' back to place 2 and type 'x'. But while you
             | are conceptually travelling back in time, what the stack
             | really looks like now is:                 1.a       2.ab
             | 3.abc       4.abcd       5.abc       6.ab       7.abx
             | 
             | A conventional undo stack would leave you stuck at a new
             | place 3: abx, all redos gone. Undos from that point can
             | only take you back to place 1 or 0. (Just tested this out
             | on OS X TextEdit, it does this). With the linear stack,
             | there is no redo, only undo.
             | 
             | I _think_ that is what the article means at least...
        
               | thelightherder wrote:
               | Photoshop has nonlinear history. When this option is
               | tunred on, you can undo several times, make a change, and
               | not lose all the states you've undid - isn't this what
               | he's talking about?
        
               | IshKebab wrote:
               | Yeah that's the same thing and is probably how you'd
               | actually implement it, but conceptually you can think of
               | there being an undo and redo stack.
        
           | [deleted]
        
       | cratermoon wrote:
       | As soon as I started reading the author's solution, I thought of
       | git. Good to see it acknowledged later on.
        
       | adrianmsmith wrote:
       | The !Edit text editor in RISC OS used this algorithm in the late
       | 80s. https://www.databasesandlife.com/risc-os-edit-undo/
       | 
       | I must admit I found it a bit confusing at first. Took me quite a
       | while to form a mental model of how it worked.
        
       | pencilguin wrote:
       | It always astonishes me that undo, redo, and auto-save are
       | implemented without relying on a logging mechanism akin to
       | databases' "write-ahead logs".
       | 
       | To me the main problem of maintaining "redo" actions is of
       | identifying them. They are unnamed, and presenting and
       | recognizing an alteration is hard.
        
       | stevebmark wrote:
       | Plug for the Vim undotree plugin, which exposes Vim's undo tree
       | in a navigable UI. It's saved my butt in the rare occasion I need
       | it. https://github.com/mbbill/undotree
        
       | hamilyon2 wrote:
       | Intellij enables multifile changes, renames, file moves with
       | multiple files as single operation, as well as reload from disk,
       | which breaks this simple linear history model afaiu. There is
       | also a separate linear time-based local history in case you screw
       | up. How intellij handles this is the best, in my mind, because of
       | simplicity and separate "I screwed up" mode.
        
         | qw wrote:
         | "Local history" in IntelliJ has saved me several times. The
         | diff mode is very useful when working on a piece of code and
         | suddenly your tests starts failing and you need to find out
         | what changes you made in the last hour.
        
       | dsp_person wrote:
       | My biggest gripe with undo is in cases where it's unclear what
       | undo will do if anything, and the action is file or email related
       | without a clean redo option.
       | 
       | Thunderbird - oops I just keymashed and did a bunch of random
       | shortcuts. OK great I can Undo infinitely with no indication of
       | what emails are being moved or undeleted, etc.
       | 
       | Windows Explorer, Dolphin etc - undo can be pretty opaque unless
       | you already know what it is that is being undone. And there isn't
       | a redo!
       | 
       | > Of course that tree requires a navigation system for users to
       | pick their way back through the undo-redo history, leading to all
       | sorts of complicated user interfacery that nobody has time to
       | deal with.
       | 
       | I would LOVE the complicated user interfacery to be in all
       | applications to show at least the list of actions! Image editors
       | are great at this.
        
         | mhb wrote:
         | Unbelievably, Solidworks does not even have undo for some
         | things and undo/redo are terribly broken.
        
       | im3w1l wrote:
       | I absolutely detest emacs' default undo behavior. I find it worse
       | and more confusing than the normal simple stupid algorithm. With
       | undo-tree, it becomes better than normal, but only very
       | marginally so. I use the linear undo and redo it provides every
       | day but only go looking at the tree a few times a year.
        
       | riccardomc wrote:
       | TL;DR
       | 
       | So much cognitive load.
       | 
       | Just configure Vim to put everything you delete in your clipboard
       | and use a clipboard manager like diodon[1] with 1000 items.
       | 
       | Of course works also outside of Vim, you just have to copy the
       | part you might want to reuse before deleting/modifying.
       | 
       | [1]https://github.com/diodon-dev/diodon
        
       | heeen2 wrote:
       | I implemented something similar for a interactive whiteboard
       | project once. The undo operation would simply be appended as
       | another action that itself could be undone by re-doing it.
       | 
       | However, as you played with it, it became confusing because it
       | ran counter to ingrained expected behavior of an undo/redo dual
       | stack implementation. Eventually I implemented the classic
       | approach.
        
       | asciimov wrote:
       | > No, there is no undo "tree"[...]
       | 
       | This is still a tree, it's just implemented in an array.
        
         | vitiral wrote:
         | This is still an acyclic node graph, it's just implemented as a
         | tree.
        
           | preordained wrote:
           | yep, it's graphs all the way down
        
         | andybak wrote:
         | Wll, it's a tree that is collapsed into an array - which makes
         | it an array to all intents and purposes.
         | 
         | The point is that the "tree-ness" is never exposed to the user.
         | This is the problem OP is claiming to have solved - the
         | cognitive burden that the tree solution introduces.
        
         | rdez6173 wrote:
         | The point is that the "tree" is not exposed to the user. I feel
         | the author makes this extremely clear.
        
         | guipsp wrote:
         | Yes a linked list is a degenerate tree, but was this worth
         | pointing out?
        
       | Veuxdo wrote:
       | Sounds like the Braid version of undo-redo.
        
         | adrianmsmith wrote:
         | Could you elaborate or provide a link? I haven't heard of the
         | "Braid version of undo-redo" before.
        
           | aidenn0 wrote:
           | Braid is a video game with time travel as a core mechanic
        
           | pmarreck wrote:
           | Even if you think you don't like games, Braid was really
           | different
        
           | vitiral wrote:
           | Braid is a game about time travel.
           | 
           | This is not like Braid at all, since the game works by
           | "overwriting" your past actions (with a few other mechanics).
           | 
           | The Braid editor would be like "Normal" undo except a ghost
           | cursor continues to make the edits you just undid. Would be a
           | hilarious April fool's feature.
        
           | Kwpolska wrote:
           | I guess they're referring to
           | https://en.wikipedia.org/wiki/Braid_(video_game)
        
         | DonHopkins wrote:
         | Game Helpin' Squad: Time Travel Understander
         | 
         | https://www.youtube.com/watch?v=1fABGyVzVwI
         | 
         | [Braid parody tutorial]
        
       | quartz wrote:
       | Semi-related: What I really wish all my editors and IDEs would
       | have is some kind of "delete history" view into my deleted text
       | (especially blocks of text).
       | 
       | I'll often delete something, then work for a while, then realize
       | I need that thing back again so I have to VERY carefully undo
       | everything after the delete until I get to a point in history
       | before it, copy the deleted text, then re-do everything back to
       | my original state while making sure not to accidentally execute
       | any inputs which would burn down the redo stack.
        
         | headPoet wrote:
         | A lot of IDEs (I know Eclipse and VSCode both do this) will
         | create a copy of the file you're working on each time you hit
         | save. You can then navigate back through the local history of
         | the file.
         | 
         | I'm conditioned to hit Ctrl+S with almost every change, so this
         | gives me a very detailed history of my revisions.
        
         | lelanthran wrote:
         | Vim stores all deleted text automatically, up to a max of 10, I
         | think.
         | 
         | Probably very possible to extend that with some advanced
         | vimscripting.
        
           | cpcallen wrote:
           | In this thread: people discussing all the excellent features
           | they wish their text editor had that emacs (and/or vim) has
           | had for literally decades.
        
             | JackFr wrote:
             | And/or JetBrains.
             | 
             | Makes me wonder honestly what tool in widespread use
             | doesn't have this? Notepad?
        
           | nouveaux wrote:
           | Vim supports practically unlimited undo with branching
           | history. You can visualize it and hop to any undo with a
           | plugin.
           | 
           | https://github.com/simnalamburt/vim-mundo
        
             | lelanthran wrote:
             | Yes, but GP wanted something that would just keep all
             | deleted text.
             | 
             | Sort of, anytime you delete something, that text gets
             | stored somewhere in case, 2 hours later, you realised you
             | wanted it.
        
               | quag wrote:
               | Yes, vim's "set undofile" will create a persistent undo
               | file that stores all changes to the file indefinitely.
               | You can undo changes made months ago over reboots. If you
               | move the undo file between machines, you can undo on
               | different computers.
               | 
               | Undoing a change from 2 hours ago in the same editing
               | session is the trivial use case for undofile.
        
               | lelanthran wrote:
               | But undoing is not what the original commenter wanted.
        
         | vvillena wrote:
         | Jetbrains IDEs can do this using the local history feature.
         | Browse through time on a separate tab, copy what you need, and
         | paste it back into the present.
        
           | Larrikin wrote:
           | Whats even more amazing is that you can right click the
           | package/folder and get local history and see entire files
           | that you previously deleted.
           | 
           | Took me a while to discover this but has saved me almost as
           | many times as local history in a file. Also makes me feel
           | much better when refactoring and deleting tons of old code.
        
         | xixixao wrote:
         | You can use "cut" instead of "delete" and clipboard with
         | history tracking, for example Alfred on macOS.
         | 
         | Then you cut, do some changes, and later on realize you wanted
         | something from the cut code, bring out the clipboard history
         | and fish out what you need.
        
           | chrisshroba wrote:
           | Maccy is a great free and open source clipboard history tool
           | with a nice interface (Alfred requires the power pack
           | purchase for this feature)
        
           | quartz wrote:
           | Oh cool-- are you saying Alfred will let me override the
           | delete key in the case of highlighted text so it always
           | executes a cut instead?
        
             | lyjackal wrote:
             | I think they're just referring to a clipboard history
             | offered by Alfred, not remapping the delete key
        
           | jorams wrote:
           | Emacs does this by default. Anything you delete ends up in
           | the "kill ring", and you can cycle through that when pasting
           | ("yanking") something. Packages like Consult[1] provide
           | version of the yank-pop command that, instead of cycling
           | through the kill ring, make it searchable.
           | 
           | [1]: https://github.com/minad/consult
        
           | tartoran wrote:
           | Yes, but having thousands of snippets in a bucket can be
           | quite confusing too, where do the pieces go back and so on.
           | 
           | For this reason I comment out code then keep it until I'm
           | sure I no longer need it. This works in sessions, and do the
           | final delete, clean up etc at the end of the session before
           | committing the changes to the repo. I see devs keeping
           | commented out code in repos but that adds too much noise,
           | makes the code a real mess..
        
         | [deleted]
        
         | tezza wrote:
         | Eclipse has "local history" for each file save operation.
         | 
         | You can even do a graphical diff against each candidate
         | timestamp in a gui wizard
         | 
         | As others have mentioned JetBrains cloned this feature too
        
         | sporedro wrote:
         | Just a list of tools that have this, in case you use any of
         | them and didn't know: Vim - has this with undo tree Emacs - has
         | this as well Jetbrains - IDE's have this with local history
         | they show changes made. VScode has this I'm pretty sure by
         | default otherwise there's a plug-in for it since I remember
         | doing it. Also just want to add something really cool about vim
         | and undo/redos that relates to this post. With vim your able to
         | "block" or "bunch" your changes which allows you to control
         | what an undo will do. For example, going into insert mode and
         | typing a sentence than exiting insert mode would be one "bunch"
         | and undo would undo that entire sentence. If you wanted to you
         | can control it by leaving insert mode after a adding a single
         | word or making a single edit and that will be what the undo
         | will revert. Probably rambling a bit here, but the concept of
         | controlling what will be undone/redone is a really neat feature
         | of vim.
        
         | [deleted]
        
       | Strilanc wrote:
       | > _you can use up all available memory in approx. 64 quick steps
       | by: Type 1 character; Undo to beginning; Type 1 character; Undo
       | to beginning; etc_
       | 
       | This is fine because "undo to beginning" isn't a single action.
       | Each time this loop runs, the user spends more and more time
       | mashing undo to get back to the beginning. The number of actions
       | in the history is only increasing by a constant amount per user
       | action.
        
       | xg15 wrote:
       | Have to applaud the author on their naming game. GURQ is
       | definitely one of the best worst acronyms.
        
       | giancarlostoro wrote:
       | This reminds me of the time I nuked all my code by mistake (rm
       | -rf *) and I still had PyCharm open, and I opened their "Code
       | History" tool and un-deleted all my code, immediately proceeded
       | to commit and push whatever state it was in because I was about
       | to freak out.
       | 
       | I think all IDE's should have their own internal copies of code
       | that are housed elsewhere, it has saved me hours of turmoil
       | trying to re-write already solved for code.
        
       | gandalfff wrote:
       | Alternatively, use Vim undotree:
       | 
       | https://github.com/mbbill/undotree
        
         | andybak wrote:
         | I found the article interesting because it's an approach that I
         | could apply to tools other than text editors - it explains the
         | general concept. I wouldn't have discovered it if someone just
         | posted a link to a Vim add-on.
        
         | Asooka wrote:
         | Or the earlier / later commands which function exactly as the
         | article describes and are part of vanilla vim. You can even
         | give them a time argument, for example :earlier 10m to go back
         | ten minutes.
        
       | jovial_cavalier wrote:
       | Vim supports this out of the box with :earlier and :later
        
         | maxk42 wrote:
         | And g+ / g-
        
       | ec109685 wrote:
       | In this methodology, without exposing the tree, how does the user
       | select between the two branches created after the butterfly is
       | squashed?
       | 
       | It seems like Google Docs does it in an intuitive way where undo
       | / redo works normally, but there's another time ordered history
       | of the document to select from.
       | 
       | Is this what the author's approach is advocating?
        
         | zwkrt wrote:
         | In the author's algorithm there is no two branches. The
         | following diagram is an undo tree where we made change B, went
         | back to A, then made C                     C ------ now
         | /      ---- A          \           B
         | 
         | But time doesn't branch, so our history shouldn't /have to/
         | branch. What if our undo was itself part of the linear history?
         | Then we could build up the history like this:                 A
         | A ---- B       A ---- B --- undo_B       A ---- B ---- undo_B
         | ---- C
         | 
         | For complex undo/redo scenarios this could get out of hand.
         | A -- B -- undo_B -- C -- undo_C -- undo_undo_B --undo_B --
         | undo_A...
         | 
         | But the author (I think correctly) states that for the average
         | user this behavior is intuitive and desired.
         | 
         | They also added the optimization that undoing and then redoing
         | a set of changes doesn't make it into the history, as it's
         | basically a no-op.
        
         | kdmccormick wrote:
         | Nope, the author's solution is to consider the original undo
         | (the "time travelling") to be an undo-able change in itself. No
         | branching history. So you end up with:                 state 1
         | * change A       state 2        * change B       state 3
         | * undo B       state 2        * change C (the "butterfly
         | squashing")       state 3a        * undo C       state 2
         | * undo <undo B>       state 3 (!)        * undo B       state 2
         | * undo A       state 1
         | 
         | The traditional editor would differ by putting you right at
         | state 1 at (!), blocking your access to state 3.
        
       | colanderman wrote:
       | JOE [1] has worked this way as long as I remember (which is close
       | to 20 years).
       | 
       | [1] https://joe-editor.sourceforge.io/
        
       | bo1024 wrote:
       | Cool! What about a model based completely on the "history" as a
       | list of states of the document over time?
       | 
       | There is no "undo" or "redo" operation, we only have "browse
       | backward/forward in time".
       | 
       | If you are browsing at a point in the past history, you can just
       | start editing. Then the document state is copied to the end of
       | the history (i.e. the current point in time), followed by your
       | edits, etc.
       | 
       | This removes the 2^n problem. It could be a bit inconvenient if
       | you want to do a lot of tree-like changes, but could also better
       | balance convenience+usability+power.
        
         | jsmith45 wrote:
         | That is basically the same as the proposed skipping of B in
         | navigation. It does however require the ability to put "make
         | document look like X" (where X is the old state) as a single
         | undo stack entry. If your app design allows that, great,
         | squashing all of B into a single entry would work fine.
         | 
         | Such an implementation would be: if you go back and try to make
         | a change, it moves everything from the redo stack to the undo
         | stack (to return the the "present"), adds one entry in that
         | represents atomically changing the document to match the old
         | state you were looking at, and then finally adds the change you
         | attempted to make as a new entry in the undo stack.
        
       | pierrebai wrote:
       | This doesn't solve the problem of wanting to redo from another
       | "do history branch" while preserving the changes you've done in
       | your current history branch. Using the notation of the article,
       | you have done:
       | 
       | A -> B -> C -> rewound to B -> D -> E
       | 
       | Now at that E point, you'd want to have C too. (I'm assumikng
       | there is no conflict between C and E.) There is no point in the
       | linear history where you have both E and C. Sure you can go back
       | to C, or go back to E. Or go back to C then decide to go back to
       | E again. But you can't have both.
       | 
       | In vim, I use the fact that the yank buffers are not part of the
       | undo/redo history, only changes to the file are. So I undo to the
       | point I had the change I want back, yank them in a named buffer,
       | redo and put the yanked buffer. You cannot go to an alternate
       | history, but at least you can get back stuff you've deleted.
       | 
       | In git, what I describe is pretty-close to cherry-pick from a
       | commit in a branch you deleted that you find using the ref-log.
        
       | Izkata wrote:
       | Vim has this, it's :earlier and :later
       | 
       | https://vimtricks.com/p/vimtrick-time-travel-in-vim/
       | :earlier 3 - Undo the last 3 changes         :earlier 5m - Go
       | back to the state of the file 5 minutes ago         :later 2 -
       | After undoing something, redo the next 2 changes         :later
       | 1h - Travel forward through the change history 1 hour
       | 
       | Vim also stores the tree of changes, but it's a pain to access
       | without plugins.
        
         | chrisshroba wrote:
         | I think what vim has is different and better than what OP
         | describes - it's two separate change logs, one for undo/redo
         | and one for time-based jumping. Trying to fit both of those
         | constructs into one list gets messy.
        
         | fnfontana wrote:
         | I have started to learn Vim about a year ago and still learning
         | new tricks each day
        
           | hackmiester wrote:
           | Wait until you say this after 10 years.
        
             | vintermann wrote:
             | After 10 years he might even be as fast as with a non-modal
             | editor.
        
               | Ar-Curunir wrote:
               | Every non-modal editor I've used is significantly slower
               | at editing text than Vim
        
             | pletnes wrote:
             | I'm at 15 soon.
        
               | aidenn0 wrote:
               | 25, with 5 years of other vi editors previous to that.
               | Vim is pretty great.
        
         | bigfatfrock wrote:
         | Using strictly vim for years, I'm still mind blown by the sheer
         | amount of "don't knows" within the tool that I miss like this.
         | 
         | Thank you!
        
         | TylerE wrote:
         | Wait until you see what intellij can do. It can do that, while
         | also layering it in a logical, graphical diff viewer
        
           | shepherdjerred wrote:
           | https://www.jetbrains.com/help/idea/local-history.html
        
           | Lio wrote:
           | Vim has plugins for that. ;)
           | 
           | I use https://github.com/mbbill/undotree but if that's not to
           | your taste there are many others.
           | 
           | e.g. https://docs.stevelosh.com/gundo.vim/
        
             | HellsMaddy wrote:
             | I rarely have to use it, but Undotree is so amazing when
             | you need it.
        
             | semi-extrinsic wrote:
             | F** right off. How have I used Vim for fifteen years and
             | not learned about this.
        
               | Lio wrote:
               | Haha, that made me spit my drink. :D
        
           | nequo wrote:
           | I don't doubt that IntelliJ overall is more user-friendly.
           | But just to note, Emacs' undo-tree can also show the diff for
           | each change.
           | 
           | Edit: Screenshot (with an unusually blue Emacs theme):
           | https://www.emacswiki.org/emacs/UndoTree#h5o-5
        
           | squeaky-clean wrote:
           | Visual Studio Code offers something similar in the timeline
           | view. It's not as fine-grained, but still can be a life
           | saver.
        
         | omoikane wrote:
         | Came here to look for comments about VIM's `g-` and `g+`
         | feature, was not disappointed :)
        
           | dm319 wrote:
           | Are those the shortcuts for it? I can't believe I didn't
           | realise vim had this.
        
         | jancsika wrote:
         | What a great feature!
         | 
         | Is the author of that feature here?
         | 
         | If so, I want to know how they could develop such a feature and
         | be so quiet about it.
         | 
         | It's like someone baking a birthday cake and then dropping it
         | down an abandoned well.
         | 
         | Just imagine how much more productive we'd all be if Vim bros
         | were as loud as the crypto bros over the past decade!
        
           | TheRealPomax wrote:
           | You just need to get vim bros going. Just go "omg I hate vi
           | so much" at a tech meetup and sit back for the fire hose of
           | vim features to start.
        
           | kzrdude wrote:
           | Another great Vim feature is persistent undo. You open a
           | file, make modifications, save and close. You open again and
           | the undo history is still there. You'll just have to enable
           | that feature.. don't think it's on by default, unfortunately.
           | Find a ~/.cache directory to store the undo history in.
        
             | samtheprogram wrote:
             | This would make my life so much easier -- constantly
             | accidentally closing a file when I want to hold on to the
             | undo history to redo something. Do you know the name of the
             | feature/flag/setting?
        
               | pjungwir wrote:
               | This is what I have in my ~/.vimrc:                   "
               | https://vi.stackexchange.com/questions/6/how-can-i-use-
               | the-undofile         if !isdirectory($HOME."/.vim")
               | call mkdir($HOME."/.vim", "", 0770)         endif
               | if !isdirectory($HOME."/.vim/undo-dir")             call
               | mkdir($HOME."/.vim/undo-dir", "", 0700)         endif
               | set undodir=~/.vim/undo-dir         set undofile
        
           | Avshalom wrote:
           | It's at least 16 years old https://github.com/vim/vim/blob/1f
           | 4d4de1ba52d0a9f1310e1026d9...
        
             | jancsika wrote:
             | And in that 16 years, where was the Vim-sponsored nascar
             | with ":earlier 39" printed on the hood in Courier New?
             | 
             | Shameful.
             | 
             | (I'm actually afraid to continue making jokes on the non-
             | zero probability that someone here reads this and tries to
             | start a Vimcoin...)
        
       | jasonjmcghee wrote:
       | I haven't seen `set undofile` mentioned yet- vim supports
       | persistent undo. You can close a buffer, restart etc and when you
       | reopen, you can still undo. I'm a huge fan.
        
       | NelsonMinar wrote:
       | Lifestreams was based on the same core idea of keeping all past
       | versions of a thing. Only with Lifestreams you keep all past
       | versions of _everything_. I constantly find myself thinking back
       | on these ideas from the 90s, there 's a lot in Eric Freeman and
       | David Gelernter's work that is worth revisiting now that storage
       | is so cheap.
        
       | dahart wrote:
       | > Second of all, there's no need to include "window shopping" in
       | our recorded history; this is when you undo a ways, take a look
       | around, then skedaddle out of there back to "the present" without
       | changing anything. This is just a matter of moving information
       | back and forth from undo-stack to redo-stack.
       | 
       | Usually the whole reason I might undo for a while is to get back
       | _part_ of something I was working on and merge it into other
       | changes I've made since then. I'm curious why the author
       | dismisses this, personally cherry picking old history is my
       | primary workflow with undo. In editors that support the undo
       | history they're advocating here, like emacs, I'm usually undoing
       | a long way so that I can put something in the clipboard, then
       | redo all the way back and cut-and-paste the previous partial
       | state.
       | 
       | It is nice in emacs that typing after undo doesn't lose my undone
       | edits, that is handy and is a nice little safety net, but it
       | doesn't actually solve the problem I normally want to solve.
        
         | dullcrisp wrote:
         | It doesn't sound like you have a problem though. Just keep
         | doing what you're doing.
        
           | dahart wrote:
           | Hehe, sure, but there _are_ better ways to do this, and it's
           | a common need. If the best thing we have is hitting undo 45
           | times to find something, copy it, try not to accidentally
           | type anything and try not to accidentally lose the clipboard,
           | then redo 45 times, then do a bunch of manual editing... now
           | repeat the entire process for every file, when there are
           | several involved... if that's sufficient, then SVN is
           | sufficient for source control, and we have no need for Git,
           | right? ;)
           | 
           | My real point is that the "Great Undo-Redo Quandary" is
           | broader than what's in the article, and the solution
           | discussed is incomplete, doesn't solve a big chunk of the
           | reason people are using undo multiple times.
        
             | remram wrote:
             | In the proposed article, it sounds like if you accidentally
             | typed anything you would have to hit "undo" twice instead
             | of "redo" N times to get back. Still seems confusing.
        
               | somishere wrote:
               | But if you accidentally type something now you can't just
               | hit redo N times to get back. It's gone.
        
             | TheRealPomax wrote:
             | Is it though? If you really just needed part of what you
             | had and hour ago, then there's nothing wrong with scrolling
             | back to an hour ago, copying that one bit you needed,
             | scrolling back some more to where you were a minute ago,
             | and integrate it as desired?
             | 
             | (which, note, is not window shopping: you didn't go back to
             | have a look and skedaddle; the past is a data store, and
             | you're accessing that data store for productivity reasons)
        
               | dahart wrote:
               | I feel like it is, so I'm not sure what you're asking.
               | It's sometimes error prone depending on editor, and
               | sometimes a lengthy and manual hassle to undo many times
               | & copy old state, and then to merge if it's not a single
               | contiguous block and not a single file. It's way easier
               | to do what I'm talking about if I've committed changes in
               | git every 5 minutes, but I don't always do that in
               | advance (most people don't), and therefore could be nice
               | to have a non-linear undo UI that addresses the workflow
               | example I'm talking about, which happens to be a common
               | reason that people even think about what happens in
               | multiple undo-redo scenarios in the first place. What's
               | wrong with pointing out that 1- we can make better tools
               | if we want, and 2- linear undo/redo doesn't solve the
               | whole problem?
        
               | vidarh wrote:
               | Doesn't sound like linear undo/redo is the problem, but
               | rather ability to navigate it. Timestamp the actions and
               | you could offer "undo to 1h ago". Or you could allow
               | searching the undo history.
               | 
               | But I may be having a hard time understanding why you
               | need this as your description just does not fit my
               | typical workflow.
        
         | crdrost wrote:
         | I might be understanding you poorly here...
         | 
         | The author is not dismissing this in the sense of saying "it's
         | impossible and that's okay" but rather "it's possible and it
         | never generated the ambiguity in the first place, so it needs
         | no special logic."
         | 
         | So you probably actually use undo-redo in _two_ big ways:
         | 
         | 1. I just pasted the wrong thing or modified the wrong file or
         | the kid grabbed the keyboard etc, I want to quickly erase N
         | changes.
         | 
         | 2. I want to grab info from the past and surface it back to the
         | present. I cut something and then lost my clipboard contents,
         | or so. This is what you described.
         | 
         | The problem in the article is, basically imagine that you get
         | the key wrong. You do your browsing thing, you are N levels
         | back in time, but instead of Cmd-c to copy this block of code,
         | you accidentally either Cmd-x which deletes it, or Cmd-v or
         | Opt-c or so which overwrites it. You were trying to do (2) but
         | now the dominant heuristic suggests to the computer that you
         | are actually doing (1). Because in the usual implementation of
         | undo-redo, undos push changes off the history onto a stack,
         | redos pop changes off the stack onto the history... And any new
         | change clears the redo stack! That stack clear is the heuristic
         | providing the difference between (1) and (2). When the
         | heuristic misfires, it misfires in really dangerous ways,
         | potentially eating hours of work.
         | 
         | So (2) is not being dismissed as "who cares" but rather as
         | "that's fine because our heuristic has not yet led us astray,
         | every implementation of undo that has redo will solve
         | obvious-(2) and obvious-(1) correctly."
         | 
         | This is where I might be misunderstanding you, I am not clear
         | if you are saying that your editor is cooler than this default
         | interpretation in some way that does not require "redo all the
         | way back and cut-and-paste the previous partial state"...? If
         | so then I would have to hear more before I could know if the
         | article's "history is always chronological, but browsing
         | history is different than undoing it: undoing it only happens
         | on an edit to an old browsed copy and saves a history-rollback
         | into the modern chronological history, rather than fussing with
         | undo graphs or whatever" approach works that way.
         | 
         | Edit: actually, the article's approach of having a browse mode
         | solves your problem automatically in a counterintuitive way...
         | Cut instead of copy, you will get launched out of browse-mode,
         | then undo twice to get to the tip of your history.
         | Counterintuitive but definitely saves some keystrokes.
        
           | dahart wrote:
           | Fundamentally, the example I'm bringing up requires a tree
           | structure conceptually, mixing some older history with some
           | newer history. The solution in the article doesn't address
           | this, and it seems to dismiss the need for this use case, but
           | I'm saying the whole reason I get into a situation where
           | knowing how undo and redo work, and when I might care about
           | whether typing after redo will lose history, is because I'm
           | trying to merge old state with recent edits. I want both
           | changes, not just one or the other.
        
             | somishere wrote:
             | Have to disagree here. "History mix" is a super common use
             | case for me, as is a "clip slip" scenario - where I fumble
             | and erase the future.
             | 
             | The technique as described works fine for this. I use it in
             | the terminal all the time (an interface where state is
             | saved on execution rather than keystroke). You go up
             | through the history, copy the part of the command you need
             | and head back to the present to use it.
             | 
             | I think it just comes down to the point at which state is
             | modified. I wouldn't expect an implementation to modify
             | state just by viewing the history, only by editing it.
             | Suffice it to say your use case is fine.
             | 
             | Edit: tho, reading some of your other comments I agree that
             | a better interface for this use case (e.g. a "revert to
             | last meaningful edit" action) would be useful. Tho its
             | slightly tangential to the discussion.
        
         | joemi wrote:
         | The author isn't dismissing "window shopping". They're just
         | dismissing the need to keep track of the "window shopping" in
         | the history, since you're not changing anything in the history.
         | 
         | If you have state1, edit it and get state2, edit that and get
         | state3, then go back to state2 and copy something and then go
         | forward again to state3 to paste that something, why should the
         | history from state3 (in reverse chronological order) then be
         | [state2,state3,state2,state1] when it could just be
         | [state2,state1]? This is what the author claims, and it makes
         | sense to be. If I undo, don't make any changes, then redo, I
         | don't want that undo-redo to then be part of the undo history.
        
       | lichtenberger wrote:
       | You can do this with a tree-based persistent/functional data-
       | structure, too.
       | 
       | For instance the single writer (per resource) in the
       | evolutionary, append-only database system[1], I'm working on in
       | my spare time, can simply revert the whole resource (resource is
       | like a table in the relational DB jargon) to a past revision.
       | Once a new commit is issued a new revision gets appended and the
       | whole history in-between is preserved. Thus, you can, for
       | instance, retrieve individual changes and cherry pick these from
       | the revisions in-between.
       | 
       | [1] https://github.com/sirixdb
        
       | samatman wrote:
       | There's an interesting parallel here: the system proposed in the
       | post is concatenative, and the undo tree style is, well, a tree.
       | Sort of a Forth v. Lisp thing.
       | 
       | Here the big disadvantage of Forth, the implicit stack state, is
       | less obviously balanced by something good. The UX of undo trees
       | could certainly use improvement, it would be great if undo/redo
       | behaved as expected, but any pivot point would automatically pop
       | up the tree view. Then there's cherry-picking, but I have a
       | solution to that.
       | 
       | This is in fact the thing I want most from an editor: select a
       | region and then undo/redo changes _only in that region_. Search
       | and replace tends to work this way, but I 've never seen it in an
       | undo/redo system.
       | 
       | How many times have you modified a function, broke it
       | accidentally, and just didn't notice and made more changes? So
       | the tests go red, you run a diff, and you see exactly what needs
       | fixing: but you copy and paste out of the diff, because you can't
       | just undo within the offending function.
        
       | chrisshroba wrote:
       | I disagree that undo and redo are the only two actions needed to
       | support this behavior. For example, if I'm performing the
       | following three actions:
       | 
       | - insert A
       | 
       | - insert B
       | 
       | - insert C
       | 
       | And then I undo, I would expect to be be back at having AB. If I
       | then undo, I would be undoing my undo and have ABC. Then undoing
       | again would get me back to AB. And I remain in this 2-cycle.
       | 
       | Instead I propose the best solution is to be able to "step out"
       | of the editing experience and see your history in a separate UI,
       | and be able to choose a specific past version to revert to.
       | _This_ revert would be an atomic operation that could then be
       | undone.
       | 
       | This is how most versioned consumer systems I know of work today
       | (e.g. Google Docs, Figma, MS Office) and it feels intuitive to me
       | as a user.
        
       | jtaft wrote:
       | Sounds similar to vim's time travel command
       | 
       | :earlier 30m
        
       | [deleted]
        
       | aliswe wrote:
       | Genius.
        
       | siraben wrote:
       | I've been using undo-tree[0] in Emacs for several years now, and
       | it's amazingly intuitive and fast to use and shows your undo
       | history as a tree.
       | 
       | [0] https://elpa.gnu.org/packages/undo-tree.html
        
       | pwpwp wrote:
       | Would be useful if this had a comparison with Emacs, which also
       | resolves the GURQ.
        
         | jefftk wrote:
         | Emacs already implements exactly what they are proposing: an
         | undo operation is just another action added to the chain of
         | states, which can itself be undone.
        
       | [deleted]
        
       | rcthompson wrote:
       | This is exactly how undo works in Emacs out of the box.
       | Personally, I prefer to install the undo-tree package and
       | manually browse through the tree of undo paths. I'm not sure why
       | this author finds a tree unacceptable for this purpose.
        
         | gpvos wrote:
         | And it is exactly why I find Emacs undo so hard to work with.
         | But maybe I will get it now I've read this article.
        
           | BeetleB wrote:
           | Note that Emacs undo is _not_ tree based, but works as
           | described in the article. The tree based undo is a separate
           | package one has to install.
        
           | b3morales wrote:
           | Two suggestions that might make it easier for you. There's a
           | package called `undo-fu` that puts a thin layer on top of the
           | undo system to keep the behavior strictly linear.
           | 
           | And built in, there are the `undo-only` and `undo-redo`
           | commands. Unlike the base `undo` they will only walk in one
           | direction.
        
           | jonathannerat wrote:
           | See `:h undo-persistance` for that feature. In particular you
           | want to do `set undofile` in your vim config
        
           | tmtvl wrote:
           | You can, if you like, install the 'vundo' package, which
           | gives you a tree-based overview of your undo history, making
           | it easy to switch between branches and go backward and
           | forward. It's basically like the undo-tree view for the
           | default undo mechanism.
        
         | sulam wrote:
         | He literally says why at the top of the post. People find it
         | too complicated.
        
           | fuckstick wrote:
           | No they don't. The method they are praising is already the
           | base implementation for emacs.
        
           | 0xCMP wrote:
           | No, he says most people do not actually implement the
           | interface to make it make sense. So they have to make ctrl-z
           | and ctrl-shift-z do the logical linear thing which requires
           | all sorts of craziness which is what is complicated to do
           | correctly (e.g. without breaking user expectations).
        
           | taeric wrote:
           | I confess I didn't get that the post was about emacs. Reading
           | the intro, it sounds more like it assumes nobody ever
           | implemented something. And then goes on to describe what
           | sounds a lot like how emacs works.
        
             | db48x wrote:
             | That's the impression I got as well, since it never
             | mentions Emacs at all and then describes exactly how Emacs
             | works.
        
         | rtpg wrote:
         | Because it requires more than two commands
        
         | Chris2048 wrote:
         | Sounds like this solution would best be implemented _with_ an
         | undo-tree, but also a linear history mapping with pointers to
         | that tree - the linear history would just log movement within
         | the tree over time e.g. undo-redo would just be a backwards-
         | forwards movement.
        
           | rcthompson wrote:
           | That's exactly what you get with undo-tree. The regular
           | undo/redo commands continue working as normal, but you can
           | also manually browse the tree if things get too nonlinear for
           | you.
        
             | Chris2048 wrote:
             | The one I saw had you browsing the tree, rather than a
             | linear history representation of a tree.
        
         | wging wrote:
         | Yeah, I spent a long while (years) using pretty much exactly
         | the solution he describes, as implemented in emacs. It's not as
         | good as a tree, because undo/redo cycles make it very annoying
         | to traverse through the history. I greatly prefer undo-tree.
        
         | marcinreal wrote:
         | Make sure to check the value of `undo-limit`, as the low
         | default value greatly (and needlessly, on modern machines)
         | nerfs undo. It also applies to extensions like undo-tree and
         | vundo I believe.
         | 
         | > undo-limit is a variable defined in 'C source code'.
         | 
         | > Its value is 10000000
         | 
         | > Original value was 160000
         | 
         | Speaking of extensions, I find undo-tree pretty buggy. I might
         | be one of a dozen people who actually love the default
         | undo/redo mechanism.
        
         | onedognight wrote:
         | Additionally, emacs will filter undo/redo's to changes within a
         | region. If you select a region (no new command to learn) and
         | use undo/redo, it will only perform those that affect text
         | completely within the region. This is a superpower that
         | delights me each time use it.
        
           | a_e_k wrote:
           | That region based undo is fantastic and has saved my bacon so
           | many times! I really wish more apps had it, though I shudder
           | to think of the implementation complexity.
        
           | nickcw wrote:
           | I did not know this, despite having used emacs for > 20 years
           | - thank you!
        
           | jerry1979 wrote:
           | Do you know a way to keep the region selected after undoing
           | so as to continually undo within the region?
        
             | db48x wrote:
             | That's the default behavior; perhaps you have customized
             | something that changed it.
        
           | randlet wrote:
           | Yes! Having regional undo is super useful sometimes. I
           | switched from emacs to vim a long time ago, but still miss
           | this feature (although not enough to go searching to find an
           | equivalent vim plug in I guess). Lazy web?
        
             | _huayra_ wrote:
             | Well if you want to return to Emacs, I can attest as a
             | former long-time vim user that the emulation layers for vim
             | modes in Emacs are fantastic! They're really the only good
             | part of vim, as the configuration language was always a bit
             | less desirable than elisp, imo.
        
               | randlet wrote:
               | I've tried in past but always found the vim modes to be a
               | bit lacking. My last attempt was probably 6 or 7 years
               | ago though so maybe worth another shot!
        
               | comfypotato wrote:
               | Evil mode is the modern standard I believe. Not a user
               | myself, but I hear good things.
        
               | fiddlerwoaroof wrote:
               | I ported my vim configuration to Evil Mode seven years
               | ago and haven't looked back. Evil Mode is the best done
               | vi emulation layer I've seen and I think it even improves
               | on vim in at least one area (the behavior of `I` in
               | visual line mode).
        
             | ilyt wrote:
             | I switched from Emacs to IDEA because IDE features are
             | frankly unrivalled but I still think Emacs does the text
             | editing part plainly better
        
       | ctrlmeta wrote:
       | > No, there is no undo "tree", nor any complicated graphical user
       | interface to go with. ... You've got your undos, your redos, and
       | that's it. The underlying data structure is strictly linear, but
       | all edit states are preserved and reachable ...
       | 
       | This is exactly how Emacs works!
       | 
       | Emacs has worked like this since its beginning in 1980s. It was
       | even documented in the first manual (1981):
       | 
       |  _This might seem to pile one disaster on another, but it doesn
       | 't, because vou can always Undo the Undo if it didn't help._
       | (page 137 of manual)
       | 
       | I think there needs to be some sort of computing and software
       | history lessons. It can offer great value in the current world of
       | software development. It will save you from the trouble of
       | rediscovering techniques that are already in use in classic
       | battle-tested software.
       | 
       | (And really? You need to invent a cheesy acronym for this? If
       | that's what it takes to sell the obvious these days, how about
       | SLUR - Simple Linear Undo Redo?)
        
         | nerdponx wrote:
         | Vim also has an undo tree, although you need a plugin to work
         | with it easily (called "Undotree").
        
           | zwkrt wrote:
           | Yes but the article is specially calling out that using an
           | undo tree is something no one wants.
        
             | lostcolony wrote:
             | And that you still want a linear path through your undos
             | and redos...and that's something that Emacs does.
        
             | cwillu wrote:
             | It's more of an implementation detail that is available to
             | users. The article's simplification is also available via
             | :earlier and :later, with the added bonus that they can
             | take _time_ as a parameter as well as a simple revision
             | count. ":earlier 1h" has been handy more than once.
        
         | vitiral wrote:
         | Of course emacs implements it as just a long linked list.
        
           | coldacid wrote:
           | It doesn't need to be anything else.
        
         | coldacid wrote:
         | I blame CADT.
        
         | [deleted]
        
         | mananaysiempre wrote:
         | Kakoune, like the more logical Vim it is, has both in a
         | sensible arrangement: an undo tree with a current branch, which
         | you can navigate up and down (u/U), and a linear history of the
         | path you took through that tree, which you can navigate
         | backwards and forwards (<a-u>/<a-U>). Unlike a single undo
         | branch, you're never afraid you're going to lose your work when
         | you need to go rescue a piece from a previous version; unlike a
         | plain linear history like TFA proposes and Emacs uses, you're
         | not punished with a quadratic number of undo/redo pairs if you
         | need a point behind several parallel do-overs of the same part.
         | Unfortunately, without any sort of visible representation of
         | all that I frequently find myself getting lost in the whole
         | thing.
         | 
         | (Now that I'm thinking about it, Git's commit tree and reflog
         | play a similar pair of complementary roles locally.)
        
         | db48x wrote:
         | In Anathem there were academics who spent their entire lives
         | learning the history of academic scholarship for the express
         | purpose of reminding everyone how often things are reinvented
         | and preventing people from getting too excited when they have
         | discovered something that was already known. I'm drawing a
         | blank on their name, but it was one of the things about the
         | book that I really enjoyed. It really helped to sell the
         | setting, where the scientific method has been known and used
         | continuously for 5,000 years or more.
        
         | kleiba wrote:
         | _> This is exactly how Emacs works!_
         | 
         | ...and has been since forever. Thus I don 't understand what
         | the fuss is?!
        
       | cletus wrote:
       | The best form of history, undo and redo I've used is on hte
       | various Jetbrains editors. It's a feature called Local History
       | and is insanely useful.
       | 
       | 1. It's always on. It never requires an explicit save or commit;
       | 
       | 2. It automatically saves any changes and timestamps them;
       | 
       | 3. You can view the state of a file or a tree at any moment in
       | time and then pull out that file (or tree).
       | 
       | 4. If you do that, it becomes part of the temporal history so you
       | can always go back.
       | 
       | I find this completely natural because usually when it's
       | necessary you think "Oh I need to unwind most of what I did in
       | the last hour" or "I changed something I shouldn't have
       | yesterday". You're not thinking about a line (or a tree) of
       | changes. You're thinking about times and possibly ordering ("I
       | changed X right before I changed Y").
        
         | adrianmsmith wrote:
         | Yep, I use Apple Time Machine for much the same purpose. Once
         | you've set it up, it's always on, you can just go back in time
         | (the granularity is once per hour, but that's been enough every
         | time I've needed to use it) and restore (or make a copy of) any
         | file or folder. Saved me quite a few times when Git has let me
         | down.
        
         | cwillu wrote:
         | > "Oh I need to unwind most of what I did in the last hour" or
         | "I changed something I shouldn't have yesterday"
         | 
         | Vim's :earlier and :later can take a time parameter (i.e., 30m,
         | 2h, 1d) which does exactly that.
        
         | jansan wrote:
         | Local History is hidden in the File Menu and does not have a
         | shortcut. It is one of the most useful features in the
         | Jetbrains editors, so I set Alt+Z as a keyboard shortcut
         | (because Ctrl+Z is undo), which after a few years of using it
         | still seems like a good idea.
         | 
         | One point that is missing from your description is that it
         | always shows the previous state in the diff view, which also
         | feels really natural to use (I only sometimes whish the diff
         | markers were more distinguishable from the inspection and ToDo
         | markers).
        
         | 323 wrote:
         | VS Code has that feature too, but only for individual files.
        
           | alisonatwork wrote:
           | I wish VS Code would expand on that feature, coming from
           | IntelliJ. It's really annoying that you need to type the name
           | of the file you want to see the local history of, even when
           | it's the currently active file in the editor. There should be
           | a sidebar widget for it that's active for whatever the
           | current file is.
           | 
           | The cool thing with IntelliJ is if you accidentally deleted a
           | file you can just touch a blank version of the file and the
           | history comes back. Not sure if VS Code does that yet.
        
             | 323 wrote:
             | There is a sidebar widget. But it starts merged in the File
             | Explorer view, and you need to drag it over from there to
             | the sidebar to make it independent -
             | https://stackoverflow.com/a/71522634
             | 
             | The widget is called "Timeline".
             | 
             | > _The cool thing with IntelliJ is if you accidentally
             | deleted a file you can just touch a blank version of the
             | file and the history comes back. Not sure if VS Code does
             | that yet._
             | 
             | VS Code does keep the history after file deletion, but I'm
             | not sure how to access it from inside.
             | 
             | I had to manually rummage through the storage directory to
             | find a file I accidentally deleted, but it was an file
             | which was never saved (think Untitled), so it didn't had a
             | path that I could try creating a blank file at.
        
               | alisonatwork wrote:
               | Fantastic! Thank you so much.
               | 
               | I think it's a fairly common situation that people using
               | programming tools (VS Code, git, vim etc) can go for
               | years without realizing there is a built-in feature that
               | can solve exactly a problem they always struggled to
               | solve. I'm not sure how to surface that sort of
               | functionality in the tool, but I'm glad HN is here to
               | point it out. One similarly cool thing I learned in a
               | recent comment is that if you press dot (.) on Github web
               | interface, it will launch an in-browser VS Code instance
               | to edit the file you are viewing. Nifty!
        
               | 323 wrote:
               | It helps to read the VS Code monthly update release
               | notes, it takes about 3 min, but you'll be aware of all
               | new features they introduce.
        
             | cletus wrote:
             | Or you can just look at the history of the folder.
        
       | [deleted]
        
       | bigmattystyles wrote:
       | So Back to The Future II basically :-)
       | 
       | (edit below)
       | 
       | (1985 Marty + Doc) => 2015
       | 
       | (2015 Biff) => 1955 => 2015 (he shouldn't be able to return here)
       | 
       | (1985 Marty + Doc) 2015 => 1985' => 1955 => 1985
        
       | bhawks wrote:
       | Google's internal source repository client CitC (client in the
       | cloud) behaves this way for your entire workspace, forever.
       | 
       | It was so freeing - every single file save, delete, move and so
       | on was saved without user intervention.
       | 
       | Realize that you were barking up the wrong tree for 2 days?
       | Simply go into .snapshots and the entire workspace from before
       | would be there.
       | 
       | This interface composed so well with other tools you could do a
       | parallel bisection test across every prior state of your
       | workspace and find the minute where you made an edit that broke
       | some functionality. All on the cloud.
       | 
       | I miss this tool very much. No amount of git commit discipline
       | can emulate it.
        
         | ray__ wrote:
         | I'm surprised that tools like this aren't more common (even in
         | non-commercial settings) given the tiny amount of space that
         | code/text takes to store.
        
       | DonHopkins wrote:
       | Then there's Undo/Redo for navigating relationships (1994,
       | interactive music video, Macromedia Director, Mark Canter, Meet
       | MediaBand, UnDo Me):
       | 
       | Meet MediaBand (2/5) - UnDo Me
       | 
       | https://www.youtube.com/watch?v=8E-Sc9XafmE
       | 
       | >The second of two interactive music videos on Canter
       | Technology's Meet MediaBand CD-ROM, UnDo Me could very well be
       | considered the "Choose Your Own Adventure" of music videos - in
       | that MediaBand's lead singer, Kelly Gabriel, has to choose from
       | one of four different relationships. YOU help Kelly decide which
       | one to try, and navigate her way through each relationship.
       | 
       | >At the end of each chorus, you are asked to make a branching
       | decision based on whether Kelly should be passive (ice) or
       | aggressive (fire) with the guy she's going out with. Things not
       | turning out well for her? At any time you could "UnDo the past"
       | and choose a different guy, or even jump back to a certain point
       | in the relationship and change your decisions.
       | 
       | >Four separate videos were produced for each relationship
       | (concluding in a total of 16 possible outcomes), connected
       | together with an intro, a home chorus and reverse/"UnDoing"
       | sections. As you could probably tell each section has a different
       | musical style, reflecting the mood and personalities of the
       | relationship that section represents. A version of the song can
       | also be found as a separate CD audio track on the Meet MediaBand
       | CD-ROM.
       | 
       | Meet MediaBand by Marc Canter (1994):
       | 
       | https://www.youtube.com/watch?v=0dRZ52wM84Q
       | 
       | https://www.ebay.com/itm/325099461299
        
       | SWEETCANDY wrote:
       | I am new player
        
       ___________________________________________________________________
       (page generated 2022-11-11 23:00 UTC)