[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)