casouri / vundo

Visualize the undo tree.
413 stars 20 forks source link

Highlighting nodes of saves - extend? #72

Open michael-heerdegen opened 1 year ago

michael-heerdegen commented 1 year ago

Hello,

to get the nodes corresponding to saves highlighted - do I have to save from the vundo buffer to get this?

Because I am using vundo-highlight-saved-nodes -> t I and never saw such highlights. Would you consider to allow to get the highlights when the user is saving normally?

I made it work in my config, but I had to duplicate a lot of quite internal vundo code. It would be nice if you could factor out a function that does the job. So that one could use it in or as an advice of save-buffer. Would that make sense?

TIA - Michael.

jdtsmith commented 1 year ago

No, it does not require saving via vundo (or even undoing via vundo) to work, since undo itself encodes "undo modified a saved buffer state" timestamps into the undo stream. Are you working from the git master branch, or an ELPA version?

michael-heerdegen commented 1 year ago

JD Smith @.***> writes:

No, it does not require saving via vundo (or even undoing via vundo) to work, since undo itself encodes "undo modified a saved buffer state" timestamps into the undo stream. Are you working from the git master branch, or an ELPA version?

Interesting. I am using the current version 2.1.0 from Gnu Elpa.

How does vundo normally know/notice when a buffer (state) has been saved?

michael-heerdegen commented 1 year ago

Oh my! The issue is gone. And I think the reason was that I had some older version in my load-path that just shadowed the elpa package. I'm sorry for this distraction.

jdtsmith commented 1 year ago

OK. There are a few kinks to work out but it mostly works well. Vundo knows about saved states because the undo system itself injects timestamps into the buffer-undo-list list whenever it's modifying a saved buffer state. This is how it's able to reset the buffer modified status when you "return" to a former saved buffer.

michael-heerdegen commented 1 year ago

Yes, it works very well indeed!

So I only have some small text improvement suggestions for you does it work when I just paste it here?

From 02d2161ac788620a1df79710ad5c37dc2b174b9c Mon Sep 17 00:00:00 2001
From: Michael Heerdegen <michael_heerdegen@web.de>
Date: Tue, 5 Apr 2022 05:32:42 +0200
Subject: [PATCH] Some typos

Three more tyos
---
 vundo.el | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/vundo.el b/vundo.el
index 29bd659..f45389d 100644
--- a/vundo.el
+++ b/vundo.el
@@ -79,7 +79,7 @@
 ;;
 ;; Your default font needs to contain these Unicode characters, otherwise
 ;; they look terrible and don’t align. You can find a font that covers
-;; these characters (eg, Symbola, Unifont), and set `vundo-default' face
+;; these characters (e.g. Symbola, Unifont), and set `vundo-default' face
 ;; to use that font:
 ;;
 ;;     (set-face-attribute 'vundo-default nil :family "Symbola")
@@ -112,7 +112,7 @@
 ;; `vundo-m' object corresponding to it. Once we have the mod-list and
 ;; hash table, we connect the nodes in mod-list to form a tree in
 ;; `vundo--build-tree'. We build the tree by a simple observation:
-;; only non-undo modifications creates new unique buffer states and
+;; Only non-undo modifications create new unique buffer states and
 ;; need to be drawn in the tree. For undo modifications, they
 ;; associate equivalent nodes.
 ;;
@@ -1257,7 +1257,7 @@ If ARG < 0, move forward."

 (defun vundo-save (arg)
   "Run `save-buffer' with the current buffer Vundo is operating on.
-Accepts the same interactive arfument ARG as ‘save-buffer’."
+Accepts the same interactive argument ARG as ‘save-buffer’."
   (interactive "p")
   (vundo--check-for-command
    (with-current-buffer vundo--orig-buffer
-- 
2.30.2

The only vundo related thing I feeled I could experiment with so far was to support the following: I hit a key and get a buffer copy of the current buffer in the window above the current one. It is not an indirect buffer but it shares a copy of buffer-undo-list with markers replaces with markers pointing to the new buffer. Then I can use vundo there without touching the original buffer. This is mostly useful when I need to go back to an older state and multiple things have been changed in the meantime. Then I can e.g. use Ediff to get back some parts of the old state and just kill the buffer copy afterwards.

If you are interested in the idea I can post the code, dunno if it could be useful for others.

Thanks, Michael.

jdtsmith commented 1 year ago

@casouri take a look at the typos. For your clone buffer idea, you can leave the vundo buffer open and eventually hit q to cancel any changes. I do this all the time. Browse back, find a bit of what I needed, copy it, then quit vundo. Remember that undo saves everything.

michael-heerdegen commented 1 year ago

JD Smith @.***> writes:

For your clone buffer idea, you can leave the vundo buffer open and eventually hit q to cancel any changes. Also remember that undo save everything.

Sure. But when the history gets large and there are lots of changes, I might need to copy a former state to a different temporary buffer so that I can choose which parts I want to restore (reintroduce) and which not.

Then finding the way back with vundo to the original "HEAD" (undo state) is not trivial in a large undo date tree. That's the problem I want to avoid. Is there a solution for this: get back to the last undo-state after vundo had been left? That would be a nice feature.

It's not easy to implement my original idea btw: AFAIU I have to create copies of buffer-undo-list',undo-equiv-table' and pending-undo-list' with markers treated, but leaving shared structures intact (overarching!). Although I thought I have done that correctly the undo-equiv-table' related part doesn't work correctly.

jdtsmith commented 1 year ago

I might need to copy a former state to a different temporary buffer so that I can choose which parts I want to restore (reintroduce) and which not.

How? By simply copying those parts over into place? If that's the case, then just create a temp buffer, copy whatever you need to it from older buffer states, hit q, and put them in place.

finding the way back with vundo to the original "HEAD" (undo state) is not trivial in a large undo date tree

Sure it is: q! Also see #56 where I threw together simple diff functionality. This could be expanded on to include mark-and-act diff (i.e. diff between two specified nodes). And then you could apply the accumulated diffs to another state of the same buffer, e.g. using ediff-patch-buffer.

michael-heerdegen commented 1 year ago

JD Smith @.***> writes:

[...] then just create a temp buffer, copy whatever you need to it from older buffer states, hit q, and put them in place.

So - it is save to leave the vundo buffer and just do something else? Even when I accidentally edit the base buffer?

Sure it is: q! Also see #56 where I threw together simple diff functionality. This could be expanded on to include mark-and-act diff (i.e. diff between two specified nodes). And then you could apply the accumulated diffs to another state of the same buffer, e.g. using ediff-patch-buffer.

This is definitely useful. I am not yet sure how my favorite interface would look like.

casouri commented 1 year ago

It's not easy to implement my original idea btw: AFAIU I have to create copies of buffer-undo-list',undo-equiv-table' and pending-undo-list' with markers treated, but leaving shared structures intact (overarching!). Although I thought I have done that correctly the undo-equiv-table' related part doesn't work correctly.

It feels like clone-buffer is all you need (it duplicates the undo history), or I'm missing something?

michael-heerdegen commented 1 year ago

Yuan Fu @.***> writes:

It feels like clone-buffer is all you need (it duplicates the undo history), or I'm missing something?

The questions are whether it is reliable, and whether it is save.

The `buffer-undo-list' contains entries with markers pointing to the original buffer. The cloned buffers gets the value of buffer-undo-list

Second: the values of `buffer-undo-list' in the original buffer and in the clone share the same list structure (references to the same list objects). Changes in one buffer might mess up the undo history in the other.

I don't know how problematic these things are in practice.

jdtsmith commented 1 year ago

So - it is save to leave the vundo buffer and just do something else? Even when I accidentally edit the base buffer?

Yes, it is safe. A "rollback" node is saved as a local variable when vundo starts. q takes you back to it.

michael-heerdegen commented 1 year ago

JD Smith @.***> writes:

Yes, it is safe. A "rollback" node is saved as a local variable when vundo starts. q takes you back to it.

I see. Is it save to save these node indices (seems they are just integers) to allow to return to a node later (I mean explictly, a node I choose).

I can code that by myself, but I want to be sure that the association undo-state <-> vundo-node-index does never change.

(Background is: I want to allow to save buffer undo states in registers

casouri commented 6 months ago

Not super safe. If you generate too much undo records, and undo list exceeds undo limit, Emacs will delete the earliest undo records, then the index would be shifted and the number wouldn't point to the intended node.

jdtsmith commented 6 months ago

@michael-heerdegen you can check #81 which enables moving l/r among saved nodes. Give it a try. Do be aware that "late changes to old nodes" are currently trimmed in vundo's buffer-undo-list trimming. Discussing ways to mitigate over there.

michael-heerdegen commented 6 months ago

Thanks, will try it out.

michael-heerdegen commented 6 months ago

Works wonderful - thank you. Bound those new commands to shift-left and shift-right.

For some reason my brain expects that repeating vundo-goto-next-saved ends at the latest state even if that is not a saved state. Such a behavior might be convenient for some, aybe you could make it an optional behavior depending on some new user option.

jdtsmith commented 6 months ago

Those are interesting bindings. The latest saved state is only "saved" if the associated buffer is saved to file and unmodified. Or do you just mean "before falling off the end, go to the end"?

michael-heerdegen commented 6 months ago

I mean that I would want that vundo-goto-next-saved goes where a repeated right key would go: the rightmost state in the chain, even if that one is not a state corresponding to a disk-save. This would be an exception, for symmetry reasons - that's where I came from most of the time. Since it's an exception I would make the behavior optional.

jdtsmith commented 6 months ago

OK will look at adding that. We need to solve (or decide to ignore) some timestamp lossage issues when you navigate back, save a node, then branch from there or navigate away. Let me know if you experience this.