Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature Request] Undo branches #20889

Open
Zalastax opened this issue Feb 19, 2017 · 47 comments
Open

[Feature Request] Undo branches #20889

Zalastax opened this issue Feb 19, 2017 · 47 comments
Labels
feature-request Request for new features or functionality undo-redo Issues around undo/redo
Milestone

Comments

@Zalastax
Copy link

Undo branches / undo tree allows you to undo some changes,
then make a new change, while keeping all changes available in the undo tree.
The undo tree can therefore prevent awkward scenarios such as:

  • Losing all redo futures by accidentally pressing a button during undo
  • Copying the file or save it with git when trying multiple alternatives

This screen-cap showcases how it works in Emacs with undo-tree.

wpid-undo-tree1

Zalastax@c569971 contains the changes to the model that are needed, but several questions remain to be answered. I'm interested in completing the feature but need further input before proceeding.

  • How should the UI look? Graphics / ASCII, clickable?
  • Should the tree be formatted like in Emacs undo-tree (as short tree as possible) or like Vim's Gundo http://screenr.com/M9l (one state per line sorted by time)?
  • What unit-tests should be added?

You can try out the current changes by compiling my fork and you'll find 'History Tree' in the Edit menu. Clicking the menu item will console.log a function that changes what redo future is selected (just like in the gif).

@ferhtgoldaraz
Copy link

This would be extremely useful.

@alexdima
Copy link
Member

Quite cool!

Perhaps I'm biased from looking at git branches too often, but I sort of like Gundo's approach to rendering the undo tree (especially the top->bottom -- present->past sort order).

I'm not sure what the nodes should be, should they be undo stops (perhaps a bit too many of them), should they be time-based, should we change the undo stops themselves to be time based... I think these are a bit too hard to decide upfront. I also think this feature could be useful for linear undo histories (I'd use it even if the undo tree has no "forks" as a way to look back at what I've done)

As for implementing it, I think you're on the right path w.r.t. the data model to represent the undo tree. For the UI, I'd start a new folder in editor/contrib/ and start easy with an editor widget (perhaps an overlay widget). I'd look into rendering the tree using a <canvas>, and I'd try to make the editor core API (what will eventually make it to IModel in editorCommon) as slim as possible -- the idea is the editor can work just fine without any of the /contrib/ (they're sort of plugins) and this should be a plugin in that sense.

Definitely a nice idea!

@alexdima alexdima added the feature-request Request for new features or functionality label Feb 22, 2017
@alexdima alexdima added this to the Backlog milestone Feb 22, 2017
@Zalastax
Copy link
Author

Zalastax commented Mar 26, 2017

@alexandrudima I'd like some new feedback or hand the code over. Zalastax@d7f0b84 implements the model changes and a contrib plugin with nice rendering. Things I know need to be improved are:

  • No tests have been added (old tests pass though)
  • Strings are not internationalized
  • The canvas has to be focused to move between items (arrow up/down)
  • History Tree can only be opened using a right click menu
  • History Tree can only be closed using the ESC key
  • Positioning of the tree in the x-dimension is hard-coded

I have completed the parts I find interesting so I'd be happy to let someone else finish this up, but there would be no problem if I have to do that myself. Let me know what you think and what the next step is!

Render of the history tree using a light theme:
image

@Zalastax
Copy link
Author

Zalastax commented Apr 8, 2017

Small improvements and keeping up with upstream in Zalastax@83359d5.
Added:

  • Strings are internationalizable
  • Positioning of the tree in the x-dimension is now dynamic

@stevencl
Copy link
Member

Thanks for your hard work on this @Zalastax, we really appreciate the effort you have put into this. Please accept my apologies for not getting back to you earlier.

I think this is a great idea and it is one that I think most people would react positively to when it was described to them.

Crucially though, I wonder if it is something that many people would modify their behaviour to start to use. The UX and UI for this would have to integrate well with current behaviour, otherwise I expect many people just wouldn’t adjust. For example, if, in order to take advantage of this, you had to learn another keybinding on top of ctrl-Z, most people would just keep using ctrl-Z because that is such a habit.

On the other hand, if it was integrated with the undo command today, that would increase usage, but we would need to do it in such a way that people don’t notice it most of the time. Ctrl-Z would continue to work as expected until there is a branch when we would need to get them to tell us which branch to take. This is a challenging UX to design.

So I think if we make it a separate feature to undo, a small number of people might adjust their regular behaviour to start using it. If we worked on the UX so that it integrated with existing usage patterns, more people would use it, but we would run a higher risk of breaking a fundamental editor experience if we didn’t get the UX right.

Unfortunately we do not have the capacity to focus on designing this user experience. So given this, sadly we will have to decline this feature request. I understand that this is disappointing news and I can only apologise again for not responding earlier.

@Zalastax
Copy link
Author

I'm disappointed and perplexed. These news come after I put the work in after getting greenlit. We already have examples of this working in Vim and Emacs, and it's fairly usable already in my fork.
You don't use this feature all the time, but when you do it's indispensable. Normal undo is undisturbed and when you need it you bring up the undo tree. I think we would only need to polish the mouse and keyboard interaction of what is already there in the fork to provide good value with a small effort.
I really hope you will reconsider.

@chuckdries
Copy link

@stevencl Any way to get you to reconsider? How about a pep talk.

Frankly, I believe you misinterpreted how it might work.

UI wise:

  • normal C-z and C-r work just as most people expect, they simply stick to the immediate path between the newest leaf and the source. Leaves are only created when changes are made mid-tree, so it would be relatively simple to rearrange the tree to keep the current path on the far left or something to make traversal easier
  • You've implemented non-standard conventions that stay out of the way by default before. Take multiple cursor support: certainly not a standard feature on most text editors, it's a feature that has to be used explicitly and has keyboard shortcuts to memorize, but now that I use it I can't imagine living without it. It's a true power user feature that differentiates VScode from its competition. I don't know if you came up with it but you implemented it well when others didn't, and you pushed text editing forward. This is what makes you a great editor, your focus on refined and useful tools for putting letters in a text file is the core of who you are. This tool, which few may use at first, is primed to make the leap to GUI text editing. Let it happen.

What if we work more heavily on the UI? I gather this wouldn't be very doable as a plugin, right? I'm actually willing to help maintain and update a fork if @Zalastax's is okay with that. This is the one big feature I've been waiting for. The VSCodeVim plugin maintains its own undo/redo history that diverges from VSCodes, and I know that they have valid reasons for doing so, but it's so occasionally annoying.

even if this doesn't work out, I still love VSCode and all the work the team puts in. Thank you for this beautiful piece of software.

@Zalastax
Copy link
Author

@chuckdries you're very welcome to do so, and I'll be happy to help you maintain a fork. I'll fix my fork so it works on top of master. You can email me if you want to get in touch on some other platform.

@stevencl
Copy link
Member

I'd be more than happy to chat. As I said, I think this is a great idea.

@qix
Copy link

qix commented Dec 3, 2017

@stevencl What about exposing the undo tree for extensions and keeping the current UX inside standard vscode unchanged?

I understand from a UX perspective this is a very hard change to make, and there possibly might not be one correct solution to the problem.

The API though (as far as I understand it) is actually rather simple. All that is needed is a getTree() and setState(node). With a little more thought (and chatting to the vscode-vim group) it might even allow a solution to the VSCodeVim/Vim#1490 regarding syncing their undo stacks.

The VS editor can always walk the right-most edge (which is equivalent to how undo/redo works at the moment) and it'd allow experimentation with the UI from extensions.

Motivation:
For some of us though this undo tree's mean not losing work. Personally I'm using a voice programming system and mistakes are frequent though very rarely destructive. Without having an undo-tree in the editor a mistake during any kind of undo operation runs the risk of being destructive and losing history.

@Zalastax
Copy link
Author

I won't have time to maintain my fork for several months but if anyone wants to step up to make this happen I'll help. There are further details for what needs to be done in the issue section of my fork. I think it's important to have a team member help at least design the API, since the details are quite intricate. For this to get done there needs to be clear and fast communication from all parties, which is not happening now.

@WickyNilliams
Copy link

WickyNilliams commented Feb 14, 2018

I'd like to voice my support for this. It would be an excellent addition to the editor (we've all accidentally blown away our undo history!). As mentioned above, it in no way affects how current undo stack works - it is transparent. And finally, @Zalastax has kindly implemented the foundations of the feature!

Seems like a no-brainer?

@nickserv
Copy link

nickserv commented Feb 14, 2018

@stevencl I use undo-tree in Emacs on a daily basis, and the key thing to understand about this feature is that when your editor already has a normal undo stack (as VSCode already does), adding a tree based undo UI on top of it is completely compatible and transparent with the standard undo and redo commands. If the tree is not open, an undo will go up a node in the tree, and a redo will go down the most recently chosen branch. Because the most recently chosen branch is the most recently created branch by default, the default branch chosen will be exactly the same whether or not a tree based undo stack is used in the implementation, even if the undo tree is never used and the user is unaware that it exists. This is not a UX problem because if the undo tree is not opened the editor will behave exactly the same with undo/tree, but an internal undo tree implementation is necessary to allow for this new undo tree UX to be added. Please reconsider.

@gralpli
Copy link

gralpli commented Mar 4, 2018

I'd really like to have this.

One idea for the UI:

When undoing multiple changes I hold Ctrl pressed and press Z as often as necessary.

So when pressing Z we could show an overlay (maybe over the Explorer) that is as simple as the Emacs one and keep it visible as long as Ctrl is held. Pressing Z and Y works as always and navigates through the tree. Using the cursor keys allows selecting alternative branches.

Example:

Pressing Ctrl + Z undoes the last change and shows the undo tree. Still holding Ctrl pressed and pressing the arrow down key undoes another change. Still holding Ctrl pressed and pressing the arrow right key highlights an alternative branch in the undo tree. Still holding Ctrl pressed and pressing the arrow up key redoes the first change from the new branch.

Z and arrow down as well as Y and arrow up can be used interchangeably.

@Zalastax
Copy link
Author

Zalastax commented Mar 4, 2018

@gralphi that's not a bad idea. I really like how holding control is what keeps the ui open. However, isn't there a risk that it will feel like the UI is flickering if you just do a normal undo? Having a special key combo to open the UI seems preferable to me, perhaps ctrl+alt+z?
Keep the good ideas coming and we'll have a good base once all parties have time to get involved again!

@gralpli
Copy link

gralpli commented Mar 4, 2018

Flickering is a valid point.

Maybe it should pop up when one of the following conditions is met (pressing Ctrl+Z and holding Ctrl down is precondition to all of them):

  • Z is pressed a second time
  • Ctrl is held for more than one second
  • the arrow keys are used

Would have two advantages: Users wouldn't need to memorize a new combination and they will sooner or later discover the new functionality by accident.

@nickserv
Copy link

nickserv commented Mar 5, 2018

Having a tree overlay that pops up after a normal undo/redo is an interesting idea, but I don't think it should be enabled by default because undo trees can be confusing and it's not obvious that normal undo/redo works the same in a tree, as per my previous explanation. I also don't think the user should have to hold ctrl to get related undo commands, that would get confusing when the other binds do things unrelated to undo because the keybinds would become modal, and I think that's less intuitive.

By default, the undo-tree Emacs package does not override the main undo bind, instead it only replaces one of the less common keybinds for undo so you can still use both. The alternative keybind then opens the tree without starting an undo yet. I think we should do something similar and add a new keybind for the undo tree to avoid confusing existing users. This would make the feature harder to find, but it could always be added to the documentation and following the principle of least surprise is more important than enabling more advanced features by default in my opinion. We could also add a separate command for the tree based undo so if a user searches the commands for undo, they would see both standard undo/redo and the command that opens the tree based UI.

@Zalastax
Copy link
Author

Zalastax commented Mar 5, 2018

@nickmccurdy I totally agree.
The biggest question marks when I stopped working were:

  • What APIs do other extensions need? E.g. VSCodeVim.
  • What APIs can the UI use? previewHTML seems most natural, but is difficult to use.

See https://github.com/Zalastax/vscode/issues for more details.

@Zalastax
Copy link
Author

Zalastax commented Mar 8, 2018

With the new webview API coming up, the view API seems to be solved. The view can now be a webpage that listens to commands from the main editor and updates the view accordingly.
Thus, the biggest remaining hurdle is designing the API for the undo tree information.
I still don't have much time to commit to this, but I can help discuss your ideas if someone steps up.

@alexdima alexdima removed their assignment Apr 17, 2018
@YoshiWalsh
Copy link

I really hope we will see this functionality in VSCode in the near future. @stevencl, since you have expressed your willingness to chat about this, could you offer a response to the points chuckdries made? This seems to me to be an extra feature that doesn't break existing user behaviours, and can simply be used in addition to them for users who would benefit from this feature. Even if a significant proportion of VSCode developers remain unaware of this feature, undo trees have the potential to recover large quantities of accidentally deleted work. Even if only a few % of vscode users ever use this feature, that would still be saving many many hours of lost work.

Further, this exact functionality is already present in many popular competing editors/IDEs, such as JetBrains' products, Brackets, Vim and Emacs. With the inclusion of undo-tree support, there would be few remaining compelling reasons to choose anything other than VSCode.

@stevencl
Copy link
Member

Sorry for not responding earlier.

I understand how this can work in addition to regular undo (indeed, I used zalastax's fork to play with the experience before responding back in September last year so I have seen how it might work). And I understand the value that undo branches provides. My reluctance to take on this work is not based on a lack of understanding of undo branches or their value.

As the UX researcher on the team, my goal is to optimise the experience that we ship out of the box for as many users as we possibly can. Adding extra commands and functionality always comes at a cost, no matter how useful the command and functionality is (at the very least, extra commands increase the search space that new users must search through when looking for functionality). So we are always very careful about adding anything to the product. Consequently, my point about investigating how or if this could integrate with the regular undo experience was motivated by this goal.

That being said, I think that the comparison to single cursor/multi cursor is fair and I do believe that undo branches could live alongside regular undo. However, we would need to spend time carefully designing the UX for undo branches. For example, how should they be made visible (in a document/a viewlet/an overlay/a panel/something else)? How can we integrate them in a way that is consistent with other UI in the product? Additionally, we would need to spend time designing the UX for undo branches so that the user is always very clear about the changes that will be made as they navigate the undo tree. We would also need to consider how this would work with other extensions (such as LiveShare: see this issue for example microsoft/live-share#7).

This isn't a trivial amount of UX work although none of it is impossibly difficult UX work of course. It's just that we do not have resources to do this work as we are focused on other tasks. In addition, I think that it's not a trivial amount of engineering work to integrate this, although that is not my area of expertise. So unfortunately this is just not something that we are in a position to work on.

@alexdima alexdima added editor-textbuffer Editor text buffer and removed editor labels Sep 20, 2018
@amelio-vazquez-reina
Copy link

amelio-vazquez-reina commented Oct 6, 2019

As a long-time Emacs and undo-tree user, and someone who really misses the ability to easily navigate the undo tree, I'm extremely interested in this and support this feature as well.

@wmayner
Copy link

wmayner commented Nov 17, 2019

This is one of the killer features of Vim; it would be great to have it in VSCode. Sorry for the noise, but I want to add my voice to the chorus.

@amelio-vazquez-reina
Copy link

amelio-vazquez-reina commented Feb 7, 2020

Could the the new Timeline view be used to support this feature? Or does it only support "path graphs" (aka "linear graphs"), i.e. graphs where nodes can have at most one predecessor and at most one successor?

Note that the "undo graph" (aka "history graph" aka "undo branches") is usually at least a tree, if not a general graph (if we assume a graph where any nodes with the same text collapse into one node)

@thijsbro
Copy link

Ohhhh yes, please do consider adding the tree view like in Emacs as mentioned by @Zalastax and @amelio-vazquez-reina . It's super intuitive and allows you write and rewrite code much more easily, because you know that what you wrote before can always be retrieved. It's a bit like a git commit for every keystroke. :-) :-) :-)

@amelio-vazquez-reina
Copy link

amelio-vazquez-reina commented Feb 14, 2020

@thijsbro If you are interested in this feature, I recommend watching / following up / upvoting on #84297 as well since the new Timeline view as I mentioned here could potentially help here :)

@alexdima alexdima added the undo-redo Issues around undo/redo label Feb 26, 2020
@vegerot
Copy link

vegerot commented Apr 21, 2020

@amelio-vazquez-reina thanks. Really wanting this feature

@Zalastax
Copy link
Author

@alexdima and @stevencl do we still have technological challenges for implementing this, like LiveShare? I see that microsoft/live-share#7 is closed. Let me know if you want to have a second go at this. I think it would bring a lot of value.

@techsin
Copy link

techsin commented Feb 19, 2021

I'd like propose another shortcut. Undo/Redo shortcuts should work linearly as they do now. Editor should know which branch the user has backtracked from and upon redoing should go back to it. But have additional shortcuts to cycle through branches. So one for up and one for down. Pressing these shortcuts will take you leaf nodes of sibling branches.

Summary of shortcuts:

  1. cmd+z = Undo
  2. cmd+shift+z = Redo
  3. ctrl+alt+cmd+down = Change to previous branch
  4. ctrl+alt+cmd+up = Change to next branch
  5. ctrl+alt+cmd+p = Mark a branch
  6. ctrl+alt+cmd+[ = Jump to marked branch (for easy jumping back to branch you are actually using)

This doesn't require GUI, GUI is nice to have but not required.

Visual Explanation

Web 1920 – 1

Furthermore, it'd be useful for last edited branch to be the most bottom branch. This way when you cycle back you always go in descending order of last modified.

@techsin
Copy link

techsin commented Feb 19, 2021

There is some vagueness in ordering branch by last modified, probably best figured out by testing it

@immjs
Copy link

immjs commented Oct 22, 2021

IMHO I don't think it's needed to get used to any keyboard shortcuts. Maybe add some for the elite who only uses keyboard but really a graph is enough for when I accidentally press a key when trying to get some value back.

@alexdima alexdima removed the editor-textbuffer Editor text buffer label Oct 22, 2021
@AlexDaniel
Copy link

AlexDaniel commented Jan 27, 2022

Just observed my co-worker using vscode lose some of the changes because they rolled back with ctrl+z to see something and then touched some key which dropped all future history. From a perspective of an emacs user who has undo-tree, that was hilarious, sorry 😂. Point is, it's one of the features that you use once and can't even imagine living without it.

As for keyboard shortcuts, there is no need to overthink it. The only shortcut that is needed is something that'd drop you into a tree view (ctrl+shift+z seems like an obvious choice, if that's unused, if it is then maybe alt instead of shift). From there it's arrows only: ↑ to go back, ↓ to go forward, and ← → to switch between the branches that come out of the current point. Esc to close the tree view. Doing it sideways is also fine, but history is more vertical than horizontal (many changes, not so many branches), and vertical scrolling should probably be preferred.

@Pyrolistical
Copy link

Local history is now in the timeline.

I think if we enhanced local history to include undo tree, there is a unified ux.

The undo tree would get collapsed into new local history items periodically

@Zwyx
Copy link

Zwyx commented Sep 21, 2022

Just wanted to add my support for this feature. It's not often used, but very useful when it is.

@orpheuslummis
Copy link

As a potentially helpful reference, this is the code for the undo feature in neovim: https://github.com/neovim/neovim/blob/master/src/nvim/undo.c

@techsin
Copy link

techsin commented Nov 18, 2022

orpheuslummis Gold mine, Thanks

@cwshields
Copy link

I'd like to add my support for this feature. I would argue that this feature would be very widely used for a variety of reasons. I would use this feature multiple times a day, possibly hourly for work and personal use. It's something that not only already exists in other IDEs, but also tools from Serif like Affinity, and it's an incredibly helpful feature when you're debugging, or troubleshooting.

@micimize
Copy link

Given the interest here I wanted to mention an idea I had for implementing undo tree as a standalone utility which I made a a separate gist for. Basic idea is to create an undo tree with some clever git usage.

If anyone wants to discuss the idea please do so there as it is not germane to this thread.

@benediktms
Copy link

Just want to chime in my support for this feature. I think undo trees can be extremely useful!

@vquelque
Copy link

We definitely need this! This is an essential feature found in all good editors.

@ilarramendi
Copy link

+1 for this feature! this is still missing in 2024

@taqiyy
Copy link

taqiyy commented Jun 1, 2024

this the only thing i miss from vim please heavily consider this !

@sammcj
Copy link

sammcj commented Jul 28, 2024

It's been a while but super keen to see this implemented!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-request Request for new features or functionality undo-redo Issues around undo/redo
Projects
None yet
Development

No branches or pull requests