* disabling undo boundaries @ 2015-05-10 21:43 Phillip Lord 2015-05-11 1:42 ` Stefan Monnier 0 siblings, 1 reply; 52+ messages in thread From: Phillip Lord @ 2015-05-10 21:43 UTC (permalink / raw) To: Emacs-Devel devel I am a little confused by undo boundaries and how and when they get set. Consider this, entirely pointless piece of code. (defvar fix-test-on nil) (defun fix-test-after-change-function (&rest _) (when fix-test-on (with-current-buffer (get-buffer "*scratch*") (insert "a")))) (add-hook 'after-change-functions 'fix-test-after-change-function) Now, If I delete buffer-undo-list in the current buffer (not *scratch*) then type "abc", I get a buffer-undo-list something like... (nil (355 . 358)) Now if I set fix-test-on to t and do the same, I get this. (nil (357 . 358) nil (356 . 357) nil (355 . 356)) I am wondering why the "nil" undo-boundaries get inserted when I change *a different* buffer. This does not really make sense to me, and is causing breakage in my package. I can't for the life of me find out where this nil boundary is getting added; it appears to happen *after* the after-change-function ends, as I find by logging buffer-undo-list in my a-c-f, so it's neither the buffer-change nor the insert itself. Unfortunately, this also means I cannot fix the problem in the a-c-f. Any other ideas welcome! Phil ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-05-10 21:43 disabling undo boundaries Phillip Lord @ 2015-05-11 1:42 ` Stefan Monnier 2015-05-11 11:46 ` Phillip Lord 0 siblings, 1 reply; 52+ messages in thread From: Stefan Monnier @ 2015-05-11 1:42 UTC (permalink / raw) To: Phillip Lord; +Cc: Emacs-Devel devel > I am wondering why the "nil" undo-boundaries get inserted when I change > *a different* buffer. This does not really make sense to me, and is > causing breakage in my package. The 3 separate undo entries you're seeing are actually the "normal" outcome (one undo-boundary per buffer-modifying command). self-insert-command has special ad-hoc code to try and merge sequences of single-char insertions by removing the previous undo-boundary. Which is why you normally only see a single undo entry. In your second case, I suspect that this ad-hoc code doesn't get to do what it's intended to do, because it does not recognize the undo-boundary that is candidate for removal as being "an undo-boundary we've auto-inserted". So, self-insert-command thinks that this undo-boundary may have been inserted by an explicit call to `undo-boundary' at the end of the previous command, in which case it should not be removed. The relevant code is in the remove_excessive_undo_boundaries function, in src/cmds.c. Stefan ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-05-11 1:42 ` Stefan Monnier @ 2015-05-11 11:46 ` Phillip Lord 2015-05-11 14:45 ` Stefan Monnier 0 siblings, 1 reply; 52+ messages in thread From: Phillip Lord @ 2015-05-11 11:46 UTC (permalink / raw) To: Stefan Monnier; +Cc: Emacs-Devel devel Stefan Monnier <monnier@iro.umontreal.ca> writes: >> I am wondering why the "nil" undo-boundaries get inserted when I change >> *a different* buffer. This does not really make sense to me, and is >> causing breakage in my package. > > The 3 separate undo entries you're seeing are actually the "normal" > outcome (one undo-boundary per buffer-modifying command). > > self-insert-command has special ad-hoc code to try and merge sequences > of single-char insertions by removing the previous undo-boundary. > Which is why you normally only see a single undo entry. > > In your second case, I suspect that this ad-hoc code doesn't get to do > what it's intended to do, because it does not recognize the > undo-boundary that is candidate for removal as being "an undo-boundary > we've auto-inserted". So, self-insert-command thinks that this > undo-boundary may have been inserted by an explicit call to > `undo-boundary' at the end of the previous command, in which case it > should not be removed. > > The relevant code is in the remove_excessive_undo_boundaries function, > in src/cmds.c. Unfortunately, this is a general problem. Try enabling the a-c-f I sent previously, and then run "fill-paragraph" on an overly long line. With after-change-hook disabled.... Now is the winter of our discontent made glorious summer by the sun over york, whether it is M-q Now is the winter of our discontent made glorious summer by the sun over york, whether it is C-/ Now is the winter of our discontent made glorious summer by the sun over york, whether it is With after-change-hook enabled... Now is the winter of our discontent made glorious summer by the sun over york, whether it is M-q Now is the winter of our discontent made glorious summer by the sun over york, whether it is C-/ Now is the winter of our discontent made glorious summer by the sun over york, whether it is C-/ Now is the winter of our discontent made glorious summer by the sun over york, whether it is So, I have to do two undo's rather than one. The problem seems to come from here in record_point, in undo.c if ((current_buffer != last_undo_buffer) /* Don't call Fundo_boundary for the first change. Otherwise we risk overwriting last_boundary_position in Fundo_boundary with PT of the current buffer and as a consequence not insert an undo boundary because last_boundary_position will equal pt in the test at the end of the present function (Bug#731). */ && (MODIFF > SAVE_MODIFF)) Fundo_boundary (); last_undo_buffer = current_buffer; The a-c-f call causes an undo-able in scratch which means that "current-buffer != last_undo_buffer" succeeds, which forces an Fundo_boundary call on the NEXT call to record_point which is why I cannot see this boundary on a-c-f. The best thing that I can think of at the moment is to use post-command-hook to clean up the excessive undo-boundaries, but I am not sure how I am going to work out which ones are "real" and which ones not. The obvious solution (delete all those adding since the last command) will fail for both self-insert-command's logic and anywhere else that undo-boundary has been explicitly called. Better ideas welcome. Phil ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-05-11 11:46 ` Phillip Lord @ 2015-05-11 14:45 ` Stefan Monnier 2015-05-11 16:31 ` Phillip Lord 0 siblings, 1 reply; 52+ messages in thread From: Stefan Monnier @ 2015-05-11 14:45 UTC (permalink / raw) To: Phillip Lord; +Cc: Emacs-Devel devel > The problem seems to come from here in record_point, in undo.c > if ((current_buffer != last_undo_buffer) > /* Don't call Fundo_boundary for the first change. Otherwise we > risk overwriting last_boundary_position in Fundo_boundary with > PT of the current buffer and as a consequence not insert an > undo boundary because last_boundary_position will equal pt in > the test at the end of the present function (Bug#731). */ > && (MODIFF > SAVE_MODIFF)) > Fundo_boundary (); > last_undo_buffer = current_buffer; Oh, I think you're right, this is even more likely the reason for those boundaries. > The best thing that I can think of at the moment is to use > post-command-hook to clean up the excessive undo-boundaries, but I am > not sure how I am going to work out which ones are "real" and which ones > not. The obvious solution (delete all those adding since the last > command) will fail for both self-insert-command's logic and anywhere > else that undo-boundary has been explicitly called. Indeed, removing those boundaries after the fact seems difficult/tricky/risky. I'm not sure exactly what are your design constraints, but I can see a few alternatives: - disable undo in the "other buffer" (*scratch* in your example, tho I suspect it's a different buffer in your real case). - delay the modification of the other buffer (e.g. record in a-c-f the boundaries of the affected text, and process them later from post-command-hook). Not sure if this would really help. - change your a-c-f so it records the buffer-undo-list at the beginning, and it removes the added boundary (if any) at the end. Stefan ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-05-11 14:45 ` Stefan Monnier @ 2015-05-11 16:31 ` Phillip Lord 2015-05-11 19:30 ` Stefan Monnier 0 siblings, 1 reply; 52+ messages in thread From: Phillip Lord @ 2015-05-11 16:31 UTC (permalink / raw) To: Stefan Monnier; +Cc: Emacs-Devel devel Stefan Monnier <monnier@iro.umontreal.ca> writes: >> The problem seems to come from here in record_point, in undo.c > >> if ((current_buffer != last_undo_buffer) >> /* Don't call Fundo_boundary for the first change. Otherwise we >> risk overwriting last_boundary_position in Fundo_boundary with >> PT of the current buffer and as a consequence not insert an >> undo boundary because last_boundary_position will equal pt in >> the test at the end of the present function (Bug#731). */ >> && (MODIFF > SAVE_MODIFF)) >> Fundo_boundary (); >> last_undo_buffer = current_buffer; > > Oh, I think you're right, this is even more likely the reason for > those boundaries. I'm getting slower better at reading Emacs source code:-) I really need to bite the bullet and learn C. >> The best thing that I can think of at the moment is to use >> post-command-hook to clean up the excessive undo-boundaries, but I am >> not sure how I am going to work out which ones are "real" and which ones >> not. The obvious solution (delete all those adding since the last >> command) will fail for both self-insert-command's logic and anywhere >> else that undo-boundary has been explicitly called. > > Indeed, removing those boundaries after the fact seems > difficult/tricky/risky. > > I'm not sure exactly what are your design constraints, I am trying to address a bug in lentic (available in all good repositories!). Lentic picks up the change in one buffer on the a-c-f and percolates it too another (or potentially any number of others). > but I can see a few alternatives: - disable undo in the "other buffer" > (*scratch* in your example, tho I suspect it's a different buffer in > your real case). This fails for me, unfortunately, the user might want to undo in the other buffer. A priori, though, it seems to be a nice idea. I tried this code for instance: #+BEGIN_SRC emacs-lisp (defvar-local fix-test-on nil) (defun fix-test-after-change-function (&rest _) (when fix-test-on (let ( (undo-inhibit-record-point t) ) (with-current-buffer (get-buffer "*scratch*") (insert "a"))))) (add-hook 'after-change-functions 'fix-test-after-change-function) #+END_SRC And that doesn't have the problem because the inhibit stops record_point from ever setting the undo_boundary. > - delay the modification of the other buffer (e.g. record in a-c-f the > boundaries of the affected text, and process them later from > post-command-hook). Not sure if this would really help. Unfortunately that wont work since there there can be many changes on a-c-f for a single p-c-h call. So, I'd have to amalgamate all the changes. > - change your a-c-f so it records the buffer-undo-list at the beginning, > and it removes the added boundary (if any) at the end. The a-c-f doesn't work, unfortunately because the nil boundary is not present till sometime after the a-c-f has been called (when? not sure). I did think of doing this with the pre/post-command-hook -- so, take the car of the b-u-l on the pre-c-h, then on the post-c-h, scan till I get to the old car and delete all nils placed there. I can see a few problems with this. First, it will also remove any undo-boundaries added by explict calls to undo-boundary; perhaps not a huge problem as there do not appear to be that many of them in the lisp code base. Second, it's still not going to work for self-insert-command because each of these are independent commands. Third, I seem to be reimplementing the undo system which feels ugly. Still, at the moment, this appears to be my only way forward. Phil ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-05-11 16:31 ` Phillip Lord @ 2015-05-11 19:30 ` Stefan Monnier 2015-05-11 20:42 ` Phillip Lord 0 siblings, 1 reply; 52+ messages in thread From: Stefan Monnier @ 2015-05-11 19:30 UTC (permalink / raw) To: Phillip Lord; +Cc: Emacs-Devel devel >> but I can see a few alternatives: - disable undo in the "other buffer" >> (*scratch* in your example, tho I suspect it's a different buffer in >> your real case). > This fails for me, unfortunately, the user might want to undo in the > other buffer. A priori, though, it seems to be a nice idea. I tried this > code for instance: > #+BEGIN_SRC emacs-lisp > (defvar-local fix-test-on nil) > (defun fix-test-after-change-function (&rest _) > (when fix-test-on > (let ( > (undo-inhibit-record-point t) > ) > (with-current-buffer > (get-buffer "*scratch*") > (insert "a"))))) > (add-hook 'after-change-functions 'fix-test-after-change-function) > #+END_SRC > And that doesn't have the problem because the inhibit stops record_point > from ever setting the undo_boundary. So, you're saying that the above let binding fixes your problem? Then, I guess it's a valid option as well. It sounds like an obscure work-around, so it probably deserves a clear comment. >> - delay the modification of the other buffer (e.g. record in a-c-f the >> boundaries of the affected text, and process them later from >> post-command-hook). Not sure if this would really help. > Unfortunately that wont work since there there can be many changes on > a-c-f for a single p-c-h call. So, I'd have to amalgamate all the > changes. Amalgamate is exactly what I meant by "record the boundaries". It's a fairly common approach, typically you only track the beg/end enclosing boundaries. E.g. I use it in diff-mode to avoid modifying the buffer right in the middle of a-c-f, which tends to break all kinds of assumptions. >> - change your a-c-f so it records the buffer-undo-list at the beginning, >> and it removes the added boundary (if any) at the end. > The a-c-f doesn't work, unfortunately because the nil boundary is not > present till sometime after the a-c-f has been called (when? not sure). That is weird. The code you quoted from record_point should be run "right away". Are you sure you didn't check in the wrong buffer by any chance? I'd expect something like (let ((old-ul buffer-undo-list)) (with-current-buffer "*scratch*" <doyourthing>) (and (consp buffer-undo-list) (eq (cdr buffer-undo-list) old-ul) (null (car buffer-undo-list)) (setq buffer-undo-list (cdr buffer-undo-list)))) to do the trick. Or, what am I missing? > I did think of doing this with the pre/post-command-hook -- so, take the > car of the b-u-l on the pre-c-h, then on the post-c-h, scan till I get > to the old car and delete all nils placed there. But at that point you won't know which undo-boundaries were added because of the buffer-switch and which were added for other reasons. > I can see a few problems with this. First, it will also remove any > undo-boundaries added by explict calls to undo-boundary; perhaps not a > huge problem as there do not appear to be that many of them in the lisp > code base. Since `doyourthing' shouldn't touch the source buffer, the source buffer's undo-list has no reason to have a hand-added undo-boundary. Stefan ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-05-11 19:30 ` Stefan Monnier @ 2015-05-11 20:42 ` Phillip Lord 2015-05-11 22:23 ` Stefan Monnier 0 siblings, 1 reply; 52+ messages in thread From: Phillip Lord @ 2015-05-11 20:42 UTC (permalink / raw) To: Stefan Monnier; +Cc: Emacs-Devel devel Stefan Monnier <monnier@iro.umontreal.ca> writes: >> This fails for me, unfortunately, the user might want to undo in the >> other buffer. A priori, though, it seems to be a nice idea. I tried this >> code for instance: >> #+BEGIN_SRC emacs-lisp >> (defvar-local fix-test-on nil) >> (defun fix-test-after-change-function (&rest _) >> (when fix-test-on >> (let ( >> (undo-inhibit-record-point t) >> ) >> (with-current-buffer >> (get-buffer "*scratch*") >> (insert "a"))))) >> (add-hook 'after-change-functions 'fix-test-after-change-function) >> #+END_SRC >> And that doesn't have the problem because the inhibit stops record_point >> from ever setting the undo_boundary. > > So, you're saying that the above let binding fixes your problem? > Then, I guess it's a valid option as well. It sounds like an obscure > work-around, so it probably deserves a clear comment. Sort of. In this particular instance above, it does because inhibit-record-point stops both the recording of point AND the insertion of an undo boundary. >>> - delay the modification of the other buffer (e.g. record in a-c-f the >>> boundaries of the affected text, and process them later from >>> post-command-hook). Not sure if this would really help. >> Unfortunately that wont work since there there can be many changes on >> a-c-f for a single p-c-h call. So, I'd have to amalgamate all the >> changes. > > Amalgamate is exactly what I meant by "record the boundaries". > It's a fairly common approach, typically you only track the beg/end > enclosing boundaries. It's difficult in my case. The problem is I have two buffers which I am keeping in sync. So I need to be able to convert a point location in one with a point location in another. And I have to do this *before* the change happens because otherwise the two buffers will hold content which is not in sync (one has changed, the other hasn't been updated yet). Unfortunately, the scope of the changes reported by the b-c-f and a-c-f are not necessarily in agreement with each other -- subst-char-in-region often gets the before-change region wrong. I have some logic for detecting this, but it can be fouled by changes that both add and remove from the buffer at the same time; in these cases, I have to copy the entire buffer. Amalgamating many changes makes this much more likely to happen. > > E.g. I use it in diff-mode to avoid modifying the buffer right in the > middle of a-c-f, which tends to break all kinds of assumptions. > >>> - change your a-c-f so it records the buffer-undo-list at the beginning, >>> and it removes the added boundary (if any) at the end. >> The a-c-f doesn't work, unfortunately because the nil boundary is not >> present till sometime after the a-c-f has been called (when? not sure). > > That is weird. The code you quoted from record_point should be run > "right away". Are you sure you didn't check in the wrong buffer by > any chance? > > I'd expect something like > > (let ((old-ul buffer-undo-list)) > (with-current-buffer "*scratch*" > <doyourthing>) > (and (consp buffer-undo-list) > (eq (cdr buffer-undo-list) old-ul) > (null (car buffer-undo-list)) > (setq buffer-undo-list (cdr buffer-undo-list)))) > > to do the trick. Or, what am I missing? It's rather more sinister than that. The code is this: if ((current_buffer != last_undo_buffer) && (MODIFF > SAVE_MODIFF)) Fundo_boundary (); last_undo_buffer = current_buffer; So, when the after-change-function runs the buffer-undo-list has *already* been modified. But if the a-c-f function makes an undoable change, then last_undo_buffer gets reset to the other buffer (*scratch* in my case). Now, the *next* change happens, and current_buffer != last_undo_buffer is true, so we add a boundary BEFORE, we add the next undo. So, the buffer change in a-c-f adds a boundary before the next change not after the one that has just been added. >> I did think of doing this with the pre/post-command-hook -- so, take the >> car of the b-u-l on the pre-c-h, then on the post-c-h, scan till I get >> to the old car and delete all nils placed there. > > But at that point you won't know which undo-boundaries were added > because of the buffer-switch and which were added for other reasons. Yep, that's a problem. > >> I can see a few problems with this. First, it will also remove any >> undo-boundaries added by explict calls to undo-boundary; perhaps not a >> huge problem as there do not appear to be that many of them in the lisp >> code base. > > Since `doyourthing' shouldn't touch the source buffer, the source > buffer's undo-list has no reason to have a hand-added undo-boundary. In between the start and end of a command? That can happen. It's the point of making undo-boundary a lisp callable function. I had an evil thought on the way home. Rather than working backwards and trying to remove the undo-boundary that had been added as a result of the undo action in another buffer, why not just remove that logic from undo.c? So, I've tried commenting out the four calls to Fundo_boundary there and now everything works. I haven't used this for my daily emacs yet, so perhaps there are demons lurking, but my question would be, why should a undoable change in *that* buffer cause a marker boundary in *this*? What is the point of these undo-boundaries that are causing me all this grief? Phil ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-05-11 20:42 ` Phillip Lord @ 2015-05-11 22:23 ` Stefan Monnier 2015-05-12 11:52 ` Phillip Lord 0 siblings, 1 reply; 52+ messages in thread From: Stefan Monnier @ 2015-05-11 22:23 UTC (permalink / raw) To: Phillip Lord; +Cc: Emacs-Devel devel [ FWIW, I'm not sure amalgamating would actually help solve this problem. ] > It's difficult in my case. The problem is I have two buffers which I am > keeping in sync. So I need to be able to convert a point location in one > with a point location in another. And I have to do this *before* the > change happens because otherwise the two buffers will hold content which > is not in sync (one has changed, the other hasn't been updated yet). Shouldn't it be sufficient to keep track of the lower bound of the changes, the higher bound of the changes, and the number of chars added/removed? Oh, wait I think I now remember that your two buffers aren't necessarily identical, in which case indeed it's ...hmm... difficult. > It's rather more sinister than that. The code is this: > if ((current_buffer != last_undo_buffer) > && (MODIFF > SAVE_MODIFF)) > Fundo_boundary (); > last_undo_buffer = current_buffer; > So, when the after-change-function runs the buffer-undo-list has > *already* been modified. But if the a-c-f function makes an undoable > change, then last_undo_buffer gets reset to the other buffer (*scratch* > in my case). > Now, the *next* change happens, and current_buffer != last_undo_buffer > is true, so we add a boundary BEFORE, we add the next undo. So, the > buffer change in a-c-f adds a boundary before the next change not after > the one that has just been added. Hmm... so, IIUC the changes in *scratch* done from a-f-c cause the next modification in the main buffer to have an undo-boundary prepended because when the new command is run, last_undo_buffer is *scratch*. Then maybe you could try a hack like: (with-current-buffer "*scratch*" <doyourthing>) (let ((buffer-undo-list)) (undo-boundary)) ; Set last_undo_buffer. >> Since `doyourthing' shouldn't touch the source buffer, the source >> buffer's undo-list has no reason to have a hand-added undo-boundary. > In between the start and end of a command? No: during your a-f-c. > I haven't used this for my daily emacs yet, so perhaps there are demons > lurking, but my question would be, why should a undoable change in > *that* buffer cause a marker boundary in *this*? What is the point of > these undo-boundaries that are causing me all this grief? It's a heuristic, Stefan ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-05-11 22:23 ` Stefan Monnier @ 2015-05-12 11:52 ` Phillip Lord 2015-05-12 20:15 ` Stefan Monnier 0 siblings, 1 reply; 52+ messages in thread From: Phillip Lord @ 2015-05-12 11:52 UTC (permalink / raw) To: Stefan Monnier; +Cc: Emacs-Devel devel Stefan Monnier <monnier@iro.umontreal.ca> writes: > Shouldn't it be sufficient to keep track of the lower bound of the > changes, the higher bound of the changes, and the number of chars > added/removed? > Oh, wait I think I now remember that your two buffers aren't necessarily > identical, in which case indeed it's ...hmm... difficult. Yes, that's the problem. Also, it's not ideal for large changes which span the buffer. > >> It's rather more sinister than that. The code is this: > >> if ((current_buffer != last_undo_buffer) >> && (MODIFF > SAVE_MODIFF)) >> Fundo_boundary (); > >> last_undo_buffer = current_buffer; > >> So, when the after-change-function runs the buffer-undo-list has >> *already* been modified. But if the a-c-f function makes an undoable >> change, then last_undo_buffer gets reset to the other buffer (*scratch* >> in my case). > >> Now, the *next* change happens, and current_buffer != last_undo_buffer >> is true, so we add a boundary BEFORE, we add the next undo. So, the >> buffer change in a-c-f adds a boundary before the next change not after >> the one that has just been added. > > Hmm... so, IIUC the changes in *scratch* done from a-f-c cause the next > modification in the main buffer to have an undo-boundary prepended > because when the new command is run, last_undo_buffer is *scratch*. Yep, that's how I read it. > Then maybe you could try a hack like: > > (with-current-buffer "*scratch*" > <doyourthing>) > (let ((buffer-undo-list)) > (undo-boundary)) ; Set last_undo_buffer. It doesn't unfortunately. An undo-boundary is not actually an undoable action in that sense. I tried: (save-excursion (goto-char (point-min))) but AFAICT that fails also. I guess save-excursion is clever enough to remove last_undo_buffer also. >> I haven't used this for my daily emacs yet, so perhaps there are demons >> lurking, but my question would be, why should a undoable change in >> *that* buffer cause a marker boundary in *this*? What is the point of >> these undo-boundaries that are causing me all this grief? > > It's a heuristic, It is, and one that has been in Emacs for a long time. How wedded to keeping it are you? Would it be possible to optionalize? Phil ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-05-12 11:52 ` Phillip Lord @ 2015-05-12 20:15 ` Stefan Monnier 2015-05-12 20:59 ` Phillip Lord 0 siblings, 1 reply; 52+ messages in thread From: Stefan Monnier @ 2015-05-12 20:15 UTC (permalink / raw) To: Phillip Lord; +Cc: Emacs-Devel devel >> Then maybe you could try a hack like: >> >> (with-current-buffer "*scratch*" >> <doyourthing>) >> (let ((buffer-undo-list)) >> (undo-boundary)) ; Set last_undo_buffer. > It doesn't unfortunately. Oh, indeed when buffer-undo-list, undo-boundary is a no-op, so you need (with-current-buffer "*scratch*" <doyourthing>) (let ((buffer-undo-list '(""))) (undo-boundary)) ; Set last_undo_buffer. > It is, and one that has been in Emacs for a long time. How wedded to > keeping it are you? Would it be possible to optionalize? Not sure, Stefan ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-05-12 20:15 ` Stefan Monnier @ 2015-05-12 20:59 ` Phillip Lord 2015-05-13 12:32 ` Stefan Monnier 0 siblings, 1 reply; 52+ messages in thread From: Phillip Lord @ 2015-05-12 20:59 UTC (permalink / raw) To: Stefan Monnier; +Cc: Emacs-Devel devel Stefan Monnier <monnier@iro.umontreal.ca> writes: >>> Then maybe you could try a hack like: >>> >>> (with-current-buffer "*scratch*" >>> <doyourthing>) >>> (let ((buffer-undo-list)) >>> (undo-boundary)) ; Set last_undo_buffer. >> It doesn't unfortunately. > > Oh, indeed when buffer-undo-list, undo-boundary is a no-op, so you need > > (with-current-buffer "*scratch*" > <doyourthing>) > (let ((buffer-undo-list '(""))) > (undo-boundary)) ; Set last_undo_buffer. My fault for not being clear. AFAICT, undo-boundary does not set last_undo_buffer at all. I can't directly test this because I can't get to last_undo_buffer from lisp, but here is my test code. #+BEGIN_SRC emacs-lisp (defvar-local fix-test-on nil) (defvar fix-test-fudge t) (defun fix-test-after-change-function (&rest _) (when fix-test-on (with-current-buffer (get-buffer "*scratch*") (insert "a")) (when fix-test-fudge (let ((buffer-undo-list '(""))) (undo-boundary))))) (add-hook 'after-change-functions 'fix-test-after-change-function) #+END_SRC Setting `fix-test-on' to t still affects undo in the current-buffer. >> It is, and one that has been in Emacs for a long time. How wedded to >> keeping it are you? Would it be possible to optionalize? > > Not sure, Well I have a fork running without it (with some brutal commenting out), so I'll try running that as my daily emacs, and see if it crashes and how it behaves. I'm still trying to understand the reason behind the logic in the first place; unfortunately, the code seems to predate the earliest VC records. Thanks for the feedback, it's been as helpful as always. Phil ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-05-12 20:59 ` Phillip Lord @ 2015-05-13 12:32 ` Stefan Monnier 2015-05-13 15:40 ` Phillip Lord 0 siblings, 1 reply; 52+ messages in thread From: Stefan Monnier @ 2015-05-13 12:32 UTC (permalink / raw) To: Phillip Lord; +Cc: Emacs-Devel devel > My fault for not being clear. AFAICT, undo-boundary does not set > last_undo_buffer at all. Oh, indeed, it sets last_boundary_buffer but not last_undo_buffer! Duh! > I'm still trying to understand the reason behind the logic in the first > place; unfortunately, the code seems to predate the earliest VC records. IIUC the reason is for modifications in another buffer that take place either within a command or between commands (e.g. process output), so they don't accumulate arbitrarily within a single undo-boundary. E.g. if you have a command "add timestamp to log buffer" which you typically use from another buffer then, without this logic, running this command 100 times would result in all entries in the buffer being lumped together into a single undo-unit, so you couldn't undo them separately. Stefab ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-05-13 12:32 ` Stefan Monnier @ 2015-05-13 15:40 ` Phillip Lord 2015-05-14 15:28 ` Stefan Monnier 0 siblings, 1 reply; 52+ messages in thread From: Phillip Lord @ 2015-05-13 15:40 UTC (permalink / raw) To: Stefan Monnier; +Cc: Emacs-Devel devel Stefan Monnier <monnier@iro.umontreal.ca> writes: >> My fault for not being clear. AFAICT, undo-boundary does not set >> last_undo_buffer at all. > > Oh, indeed, it sets last_boundary_buffer but not last_undo_buffer! > Duh! > >> I'm still trying to understand the reason behind the logic in the first >> place; unfortunately, the code seems to predate the earliest VC records. > > IIUC the reason is for modifications in another buffer that take place > either within a command or between commands (e.g. process output), so > they don't accumulate arbitrarily within a single undo-boundary. > > E.g. if you have a command "add timestamp to log buffer" which you > typically use from another buffer then, without this logic, running this > command 100 times would result in all entries in the buffer being lumped > together into a single undo-unit, so you couldn't undo them separately. In the other buffer? So, you can undo the changes to the log buffer one after the other? I agree that makes sense, but it does seem to me that this could be the responsibility of "add timestamp to log buffer". I'm checking at the moment how often this undo-boundary gets called. So far, it's about 1.5% of the time that an undo event gets added, so it's not very often (obviously this is without an a-c-f entry or it would be much higher!). Phil ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-05-13 15:40 ` Phillip Lord @ 2015-05-14 15:28 ` Stefan Monnier 2015-05-15 12:27 ` Phillip Lord 0 siblings, 1 reply; 52+ messages in thread From: Stefan Monnier @ 2015-05-14 15:28 UTC (permalink / raw) To: Phillip Lord; +Cc: Emacs-Devel devel > In the other buffer? So, you can undo the changes to the log buffer one > after the other? I agree that makes sense, but it does seem to me that > this could be the responsibility of "add timestamp to log buffer". Right. > I'm checking at the moment how often this undo-boundary gets called. So > far, it's about 1.5% of the time that an undo event gets added, so it's > not very often (obviously this is without an a-c-f entry or it would be > much higher!). My guess is that the vast majority of the cases where this code is triggered is for process output (inserted in a buffer different from the one that's current). Stefan ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-05-14 15:28 ` Stefan Monnier @ 2015-05-15 12:27 ` Phillip Lord 2015-05-15 18:08 ` Stefan Monnier 0 siblings, 1 reply; 52+ messages in thread From: Phillip Lord @ 2015-05-15 12:27 UTC (permalink / raw) To: Stefan Monnier; +Cc: Emacs-Devel devel Stefan Monnier <monnier@iro.umontreal.ca> writes: >> In the other buffer? So, you can undo the changes to the log buffer one >> after the other? I agree that makes sense, but it does seem to me that >> this could be the responsibility of "add timestamp to log buffer". > > Right. > >> I'm checking at the moment how often this undo-boundary gets called. So >> far, it's about 1.5% of the time that an undo event gets added, so it's >> not very often (obviously this is without an a-c-f entry or it would be >> much higher!). > > My guess is that the vast majority of the cases where this code is > triggered is for process output (inserted in a buffer different from > the one that's current). That doesn't really make sense to me. Say I am editing a file in this buffer while compiling something in that buffer. Why would I want an update in the compilation buffer to force an undo-boundary in this buffer? I guess I could try and print this-command to see what is happening when the condition comes into affect. Sorry to be persistant about this, but at the moment, changing the code in undo.c is the only good solution I can see to my problem. It would be different if explicitally called and automatic boundaries were distinguishable, but they aren't. Phil ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-05-15 12:27 ` Phillip Lord @ 2015-05-15 18:08 ` Stefan Monnier 2015-05-15 19:49 ` Phillip Lord 0 siblings, 1 reply; 52+ messages in thread From: Stefan Monnier @ 2015-05-15 18:08 UTC (permalink / raw) To: Phillip Lord; +Cc: Emacs-Devel devel > That doesn't really make sense to me. Say I am editing a file in this > buffer while compiling something in that buffer. Why would I want an > update in the compilation buffer to force an undo-boundary in this buffer? It probably won't make any difference in "this buffer" because the process filter will be run *between* commands (at which point the read-eval command loop already inserts undo-boundaries anyway). The difference is in the compilation buffer where it'll insert undo boundaries every time you run a command in "this buffer". > Sorry to be persistant about this, but at the moment, changing the code > in undo.c is the only good solution I can see to my problem. It would be > different if explicitally called and automatic boundaries were > distinguishable, but they aren't. We could make them distinguishable, OTOH (e.g. using a (weak) hash-table where we insert every explicitly added undo-boundary). Stefan ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-05-15 18:08 ` Stefan Monnier @ 2015-05-15 19:49 ` Phillip Lord 2015-05-15 23:45 ` Stefan Monnier 0 siblings, 1 reply; 52+ messages in thread From: Phillip Lord @ 2015-05-15 19:49 UTC (permalink / raw) To: Stefan Monnier; +Cc: Emacs-Devel devel Stefan Monnier <monnier@iro.umontreal.ca> writes: >> That doesn't really make sense to me. Say I am editing a file in this >> buffer while compiling something in that buffer. Why would I want an >> update in the compilation buffer to force an undo-boundary in this buffer? > > It probably won't make any difference in "this buffer" because the > process filter will be run *between* commands (at which point the > read-eval command loop already inserts undo-boundaries anyway). > > The difference is in the compilation buffer where it'll insert undo > boundaries every time you run a command in "this buffer". Yes, I can see that. Although iff this is the reason for the undo-boundary, it would still make more sense to me to have the process code insert this. Aside from being a more discrete effect, it would also avoid the current "do nothing now, but insert an undo-boundary before the next change where ever that is" semantics. > >> Sorry to be persistant about this, but at the moment, changing the code >> in undo.c is the only good solution I can see to my problem. It would be >> different if explicitally called and automatic boundaries were >> distinguishable, but they aren't. > > We could make them distinguishable, OTOH (e.g. using a (weak) hash-table where > we insert every explicitly added undo-boundary). I don't understand how that would that work. undo-boundaries are nil, so surely they are all the same object? Using symbols like: '(boundary . user) '(boundary . internal) would enable this, I think. But it would break code like this: (while (or (null (car buffer-undo-list)) (and discard-pos (integerp (car buffer-undo-list)))) (setq buffer-undo-list (cdr buffer-undo-list))) from undo-tree, and I would guess quite a lot of other places. I have thought of a partial solution -- which is to add a symbol to b-u-l in the pre-command-hook, the delete all the boundaries added since that in the post-command-hook. That gets me to a clean "boundary at every command" semantics. I couldn't work out how to do this before, again, because boundaries are all the same object. Phil ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-05-15 19:49 ` Phillip Lord @ 2015-05-15 23:45 ` Stefan Monnier 2015-05-16 13:31 ` Phillip Lord 0 siblings, 1 reply; 52+ messages in thread From: Stefan Monnier @ 2015-05-15 23:45 UTC (permalink / raw) To: Phillip Lord; +Cc: Emacs-Devel devel >>> That doesn't really make sense to me. Say I am editing a file in this >>> buffer while compiling something in that buffer. Why would I want an >>> update in the compilation buffer to force an undo-boundary in this buffer? >> It probably won't make any difference in "this buffer" because the >> process filter will be run *between* commands (at which point the >> read-eval command loop already inserts undo-boundaries anyway). >> The difference is in the compilation buffer where it'll insert undo >> boundaries every time you run a command in "this buffer". > Yes, I can see that. Although iff this is the reason for the > undo-boundary, it would still make more sense to me to have the process > code insert this. Aside from being a more discrete effect, it would also > avoid the current "do nothing now, but insert an undo-boundary before > the next change where ever that is" semantics. I don't claim it's the best solution, indeed. It's just that if we remove it, we'll have to replace it with other mechanisms. So we need a clear description of the current cases that are considered misbehaviors and those that are considered good (tho not necessarily perfect). > I don't understand how that would that work. undo-boundaries are nil, so > surely they are all the same object? No, we'd record put the cons cell in which the nil is placed. Stefan ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-05-15 23:45 ` Stefan Monnier @ 2015-05-16 13:31 ` Phillip Lord 2015-05-19 11:59 ` Phillip Lord 0 siblings, 1 reply; 52+ messages in thread From: Phillip Lord @ 2015-05-16 13:31 UTC (permalink / raw) To: Stefan Monnier; +Cc: Emacs-Devel devel Stefan Monnier <monnier@iro.umontreal.ca> writes: >> Yes, I can see that. Although iff this is the reason for the >> undo-boundary, it would still make more sense to me to have the process >> code insert this. Aside from being a more discrete effect, it would also >> avoid the current "do nothing now, but insert an undo-boundary before >> the next change where ever that is" semantics. > > I don't claim it's the best solution, indeed. It's just that if we > remove it, we'll have to replace it with other mechanisms. > So we need a clear description of the current cases that are considered > misbehaviors and those that are considered good (tho not necessarily > perfect). I entirely agree with this, of course. This is why I am trying to find positive behaviour. So, I have tested this, and indeed commenting out that code does affect undo behaviour. To test this, I wrote a "countdown" script which, well, counts down, and then ran this in *shell*. Then I typed into *scratch* at defined points. With the undo-boundary code, indeed, the typing in *scratch* does add boundaries -- so that a countdown from 100 say, gets split up into multiple undos. Without this code, the countdown gets undone in one go. So, while it clearly has an effect, I am not sure why this is better. For example, if I launch two shell buffers, then run "countdown 20" in both at the same time, then both buffers now undo in 20 steps, one second at a time, because their output interleaves. Again, the "add an undo boundary because of a change in another buffer" semantics does not seem intuitive to me. >> I don't understand how that would that work. undo-boundaries are nil, so >> surely they are all the same object? > > No, we'd record put the cons cell in which the nil is placed. Oh, yes, of course. That does assume, though, that any operations on buffer-undo-list are destructive. For instance, if I filter the buffer-undo-list with seq.el or dash, do I not get all new cons cells? Still, most of the undo.c code seems to change in place, so I guess it would work in most cases. Phil ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-05-16 13:31 ` Phillip Lord @ 2015-05-19 11:59 ` Phillip Lord 2015-05-19 19:42 ` Stefan Monnier 0 siblings, 1 reply; 52+ messages in thread From: Phillip Lord @ 2015-05-19 11:59 UTC (permalink / raw) To: Stefan Monnier; +Cc: Emacs-Devel devel Phillip Lord <phillip.lord@newcastle.ac.uk> writes: > Stefan Monnier <monnier@iro.umontreal.ca> writes: > >> I don't claim it's the best solution, indeed. It's just that if we >> remove it, we'll have to replace it with other mechanisms. >> So we need a clear description of the current cases that are considered >> misbehaviors and those that are considered good (tho not necessarily >> perfect). > > I entirely agree with this, of course. This is why I am trying to find > positive behaviour. > > So, I have tested this, and indeed commenting out that code does affect > undo behaviour. To test this, I wrote a "countdown" script which, well, > counts down, and then ran this in *shell*. Then I typed into *scratch* > at defined points. With the undo-boundary code, indeed, the typing in > *scratch* does add boundaries -- so that a countdown from 100 say, gets > split up into multiple undos. Without this code, the countdown gets > undone in one go. > > So, while it clearly has an effect, I am not sure why this is better. > For example, if I launch two shell buffers, then run "countdown 20" in > both at the same time, then both buffers now undo in 20 steps, one > second at a time, because their output interleaves. Again, the "add an > undo boundary because of a change in another buffer" semantics does not > seem intuitive to me. Just wanted to bump this. I am still not sure why this is a good behaviour. My own feeling is that the "undo-boundary when a buffer change happens" logic may not have been implemented for this reason, but as a belts-and-braces way of detecting the end of a command -- after all, buffer changes (followed by an undoable event) normally happen between commands rather than within. >>> I don't understand how that would that work. undo-boundaries are nil, so >>> surely they are all the same object? >> >> No, we'd record put the cons cell in which the nil is placed. > > Oh, yes, of course. That does assume, though, that any operations on > buffer-undo-list are destructive. For instance, if I filter the > buffer-undo-list with seq.el or dash, do I not get all new cons cells? > Still, most of the undo.c code seems to change in place, so I guess it > would work in most cases. I did start working on this, but haven't got it functional yet. One problem is that if I record the cons cell at the head of buffer-undo-list, I have to search the whole buffer-undo-list to see if it is there (unless I get a match). A cons cell with a nil gets added for every self-insert-command and then removed again, so this tends to happen quite a lot. Phil ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-05-19 11:59 ` Phillip Lord @ 2015-05-19 19:42 ` Stefan Monnier 2015-05-19 21:48 ` Phillip Lord 0 siblings, 1 reply; 52+ messages in thread From: Stefan Monnier @ 2015-05-19 19:42 UTC (permalink / raw) To: Phillip Lord; +Cc: Emacs-Devel devel >> So, while it clearly has an effect, I am not sure why this is better. >> For example, if I launch two shell buffers, then run "countdown 20" in >> both at the same time, then both buffers now undo in 20 steps, one >> second at a time, because their output interleaves. Again, the "add an >> undo boundary because of a change in another buffer" semantics does not >> seem intuitive to me. Agreed. > Just wanted to bump this. I am still not sure why this is a good > behaviour. My own feeling is that the "undo-boundary when a buffer > change happens" logic may not have been implemented for this reason, but > as a belts-and-braces way of detecting the end of a command -- after > all, buffer changes (followed by an undoable event) normally happen > between commands rather than within. For process filters, I think the "right way" would be to add an undo-boundary every N insertions. > I did start working on this, but haven't got it functional yet. One > problem is that if I record the cons cell at the head of > buffer-undo-list, I have to search the whole buffer-undo-list to see if > it is there (unless I get a match). A cons cell with a nil gets added > for every self-insert-command and then removed again, so this tends to > happen quite a lot. Sounds rather ugly. Let's see how far we can go with the option of changing the current behavior rather than trying to add workarounds in your code. Could you describe the exact case that bothers you, so we could start by thinking what should be the ideal behavior for that one? Stefan ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-05-19 19:42 ` Stefan Monnier @ 2015-05-19 21:48 ` Phillip Lord 2015-05-20 2:00 ` Stefan Monnier 0 siblings, 1 reply; 52+ messages in thread From: Phillip Lord @ 2015-05-19 21:48 UTC (permalink / raw) To: Stefan Monnier; +Cc: Emacs-Devel devel Stefan Monnier <monnier@iro.umontreal.ca> writes: >> Just wanted to bump this. I am still not sure why this is a good >> behaviour. My own feeling is that the "undo-boundary when a buffer >> change happens" logic may not have been implemented for this reason, but >> as a belts-and-braces way of detecting the end of a command -- after >> all, buffer changes (followed by an undoable event) normally happen >> between commands rather than within. > > For process filters, I think the "right way" would be to add an > undo-boundary every N insertions. "undo" for a process filter seems to be quite a difficult one to me. In many cases ("M-x compile") undo is just switched off. For things like M-x shell undo is on and makes sense. My initial guess would be that "undo the last command and all the output from that command" would seem the most intuitive. >> I did start working on this, but haven't got it functional yet. One >> problem is that if I record the cons cell at the head of >> buffer-undo-list, I have to search the whole buffer-undo-list to see if >> it is there (unless I get a match). A cons cell with a nil gets added >> for every self-insert-command and then removed again, so this tends to >> happen quite a lot. > > Sounds rather ugly. Let's see how far we can go with the option of > changing the current behavior rather than trying to add workarounds in > your code. Agreed. I'd rather fix the core Emacs behaviour than workaround it, so it works better for everyone. Of course, I have to acknowledge that my public spirited behaviour is partly motivated by the workaround being a PITA. > Could you describe the exact case that bothers you, so we could start by > thinking what should be the ideal behavior for that one? Yes. Any after-change-function that changes another buffer breaks undo. My "noisy-change" package which just logs the before and after-change-function args is an example of this. https://raw.githubusercontent.com/phillord/lentic/master/noisy-change.el My real use case is lentic. Ideal behaviour: is just not to do it. Uncommenting all the "undo_boundary" calls in undo.c seems to achieve this for me, although obviously that's a blunt fix. Phil ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-05-19 21:48 ` Phillip Lord @ 2015-05-20 2:00 ` Stefan Monnier 2015-05-20 7:45 ` Phillip Lord 0 siblings, 1 reply; 52+ messages in thread From: Stefan Monnier @ 2015-05-20 2:00 UTC (permalink / raw) To: Phillip Lord; +Cc: Emacs-Devel devel >> Could you describe the exact case that bothers you, so we could start by >> thinking what should be the ideal behavior for that one? > Yes. Any after-change-function that changes another buffer breaks undo. > My "noisy-change" package which just logs the before and > after-change-function args is an example of this. > https://raw.githubusercontent.com/phillord/lentic/master/noisy-change.el > My real use case is lentic. > Ideal behaviour: is just not to do it. Uncommenting all the > "undo_boundary" calls in undo.c seems to achieve this for me, although > obviously that's a blunt fix. Could you be more specific. Give a very concrete example of a sequence of commands, and then explain which the undo-boundaries end up being and what they should be instead. Stefan ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-05-20 2:00 ` Stefan Monnier @ 2015-05-20 7:45 ` Phillip Lord 2015-05-20 12:53 ` Stefan Monnier 0 siblings, 1 reply; 52+ messages in thread From: Phillip Lord @ 2015-05-20 7:45 UTC (permalink / raw) To: Stefan Monnier; +Cc: Emacs-Devel devel Stefan Monnier <monnier@iro.umontreal.ca> writes: >>> Could you describe the exact case that bothers you, so we could start by >>> thinking what should be the ideal behavior for that one? >> Yes. Any after-change-function that changes another buffer breaks undo. >> My "noisy-change" package which just logs the before and >> after-change-function args is an example of this. >> https://raw.githubusercontent.com/phillord/lentic/master/noisy-change.el >> My real use case is lentic. >> Ideal behaviour: is just not to do it. Uncommenting all the >> "undo_boundary" calls in undo.c seems to achieve this for me, although >> obviously that's a blunt fix. > > Could you be more specific. Give a very concrete example of a sequence > of commands, and then explain which the undo-boundaries end up being and > what they should be instead. Yes, okay. So, in *scratch* I remove comments from the second and third line and put everything onto one line. ;; This buffer is for notes you don't want to save, and for Lisp evaluation. If you want to create a file, visit that file with C-x C-f, then enter the text in that file's own buffer. I load noisy-change.el (but not enable it). (setq buffer-undo-list nil) M-x fill-paragraph (with point on the one line) (nil (156 . 159) (#(" " 0 1 (fontified nil face (whitespace-line font-lock-comment-face))) . -156) (nil face nil 155 . 156) (155 . 156) (78 . 81) (#(" " 0 1 (fontified nil face font-lock-comment-face)) . -78) (#<marker (moves after insertion) at 81 in *scratch*> . 1) (#<marker (moves after insertion) at 81 in *scratch*> . 1) (#<marker (moves after insertion) at 81 in *scratch*> . 1) (#<marker (moves after insertion) at 81 in *scratch*> . 1) (nil face nil 77 . 78) (77 . 78)) M-x undo (setq noisy-change-undo t) (setq buffer-undo-list nil) M-x fill-paragraph (nil (156 . 159) nil (#(" " 0 1 (fontified nil face (whitespace-line font-lock-comment-face))) . -156) nil (nil face nil 155 . 156) nil (155 . 156) nil (78 . 81) nil (#(" " 0 1 (fontified nil face font-lock-comment-face)) . -78) nil (nil face nil 77 . 78) nil (77 . 78)) At my count it takes 8 undo operations to undo "fill-paragraph". Obviously, a longer paragraph will take more operations. Phil ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-05-20 7:45 ` Phillip Lord @ 2015-05-20 12:53 ` Stefan Monnier 2015-05-21 11:15 ` Phillip Lord 0 siblings, 1 reply; 52+ messages in thread From: Stefan Monnier @ 2015-05-20 12:53 UTC (permalink / raw) To: Phillip Lord; +Cc: Emacs-Devel devel > M-x fill-paragraph [...] > At my count it takes 8 undo operations to undo "fill-paragraph". Good example, thank you. But IIUC just removing the "undo-boundary on buffer-change" code still wouldn't give you the perfect behavior, because you still do want an undo-boundary in the second buffer, right? Stefan ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-05-20 12:53 ` Stefan Monnier @ 2015-05-21 11:15 ` Phillip Lord 2015-05-21 15:44 ` Stefan Monnier 0 siblings, 1 reply; 52+ messages in thread From: Phillip Lord @ 2015-05-21 11:15 UTC (permalink / raw) To: Stefan Monnier; +Cc: Emacs-Devel devel Stefan Monnier <monnier@iro.umontreal.ca> writes: >> M-x fill-paragraph > [...] >> At my count it takes 8 undo operations to undo "fill-paragraph". > > Good example, thank you. But IIUC just removing the "undo-boundary on > buffer-change" code still wouldn't give you the perfect behavior, > because you still do want an undo-boundary in the second buffer, right? Yes, you are right, the second buffer is an issue, although I am not convinced that the behaviour is worse. Below I have described two tasks both of which change another buffer on a-c-f. I'm comparing between an Emacs 24.5 (as released, but built from git by me) and my own Emacs (based on 24.4 actually) with the relevant sections of undo.c commented out. Again, built by me. With the existing logic I get a lot of undo boundaries. Without the existing logic I get a sane number of boundaries. I do not get the same undo-boundaries that I would have got in the other buffer if I had made changes by typing commands rather than using a-c-f. But I could add these programmatically with as much or as little fidelity as I choose. The data I make these conclusions on is below. Phil * Noisy-change ** Task Type "abcdef" into *scratch* with (setq noisy-change-log t), then check buffer-undo-list in the created noisy-change-log buffer. I pick this task because it's about as simple as it gets. ** With existing undo-boundary code (nil (402 . 439) nil (329 . 402) nil (256 . 329) nil (183 . 256) nil (110 . 183) nil (37 . 110) nil (1 . 37) (t . 0)) ** Without existing undo-boundary logic (nil (1 . 439) (t . 0)) ** Conclusion The amalgamation of several events is working. * lentic-view ** Task Use "Create Lentic View" (this creates an exact clone, rather like an indirect-buffer). ** With existing undo-boundary logic (nil (197 . 198) nil (196 . 197) nil (195 . 196) nil (194 . 195) nil (193 . 194) nil (192 . 193)) ** Without existing undo-boundary logic (nil (192 . 198)) ** Conclusion Same as last, but with a simpler set of events. * Task 3 Use lentic-view, type in the entire alphabet ** Without existing undo-boundary logig (nil (192 . 217) nil (1 . 192) (t . 0)) ** Conclusion The "undo-boundary every 20 self-insert-command"s logic is not working or it should be something like this... (nil (212 . 218) nil (192 . 212)) I could add this logic in, although it's a bit of pain and requires effectively duplicating logic from cmds.c in lisp. * Task 4 Using lentic view, type in abcdefghijk abcdefghijk ** In *scratch* (nil (208 . 222) nil (206 . 208) nil (192 . 206)) ** In "*lentic: scratch*" (nil (192 . 222) nil (1 . 193) (t . 0)) ** Conclusion All of the insertion events have been amalgamated, so the undo is much too "lumpy". Again, I can add this logic in, but I have to duplicate the "add an undo-boundary after a command" logic from the command loop. ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-05-21 11:15 ` Phillip Lord @ 2015-05-21 15:44 ` Stefan Monnier 2015-05-21 17:03 ` Phillip Lord 2015-08-07 23:49 ` Davis Herring 0 siblings, 2 replies; 52+ messages in thread From: Stefan Monnier @ 2015-05-21 15:44 UTC (permalink / raw) To: Phillip Lord; +Cc: Emacs-Devel devel > Yes, you are right, the second buffer is an issue, although I am not > convinced that the behaviour is worse. Worse than the ideal or worse than the current one? Right now, I'm trying to understand what the ideal behavior should be. After that, we can try to figure out how to get this ideal behavior, or how close we can get to it, and which part of the work can be made generic in undo.c and which part of the work has to be done manually by each and every particular command/package. > ** Conclusion > All of the insertion events have been amalgamated, so the undo is much > too "lumpy". Again, I can add this logic in, but I have to duplicate > the "add an undo-boundary after a command" logic from the > command loop. [ You only used self-insert-command in your examples, which gives a slightly twisted view of what's going on in general. ] But ideally, we could have undo.c do most of that for you. E.g. instead of adding a boundary every time we switch buffer, undo.c could simply keep track of which buffers have seen changes during the current command, and then push undo-boundaries on all of them at the end of the command. Except for self-insert-command, I think this would give you the ideal behavior (without any manual work on your side) *and* it would mostly preserve the existing behavior. For self-insert-command, it's more tricky, and you'd probably need to do the extra manual work. E.g. add a post-self-insert-hook which checks if this self-insert-command removed the previous undo-boundary and then remove it as well in the sibling buffer. I can't see how undo.c could do that for you magically, since it doesn't know that the insertions in the sibling buffer are "clones" of the insertions in the main buffer, nor that it's done by self-insert-command. Another approach would be for you to arrange such that your a-f-c uses self-insert-command rather than `insert' when cloning the insertion from a self-insert-command, but that's probably just as hard if not harder. Stefan ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-05-21 15:44 ` Stefan Monnier @ 2015-05-21 17:03 ` Phillip Lord 2015-05-27 11:46 ` Phillip Lord 2015-08-07 23:49 ` Davis Herring 1 sibling, 1 reply; 52+ messages in thread From: Phillip Lord @ 2015-05-21 17:03 UTC (permalink / raw) To: Stefan Monnier; +Cc: Emacs-Devel devel Stefan Monnier <monnier@iro.umontreal.ca> writes: >> Yes, you are right, the second buffer is an issue, although I am not >> convinced that the behaviour is worse. > > Worse than the ideal or worse than the current one? The current situation. > Right now, I'm trying to understand what the ideal behavior should be. I don't have a clear handle on this either. For my two use cases, with noisy-change-log, I think the answer is, I don't really care. I don't need undo in a log buffer, and if I had thought about it, I would have switched it off. For lentic, I would like the undo-boundaries to be what they would have been if the commands had been typed manually. > After that, we can try to figure out how to get this ideal behavior, or > how close we can get to it, and which part of the work can be made > generic in undo.c and which part of the work has to be done manually by > each and every particular command/package. That would be good. Another package worth looking at would be gnus, which AFAICT, reimplements undo all for itself, to cope with the fact that it's a multi buffer sort of package. >> ** Conclusion >> All of the insertion events have been amalgamated, so the undo is much >> too "lumpy". Again, I can add this logic in, but I have to duplicate >> the "add an undo-boundary after a command" logic from the >> command loop. > > [ You only used self-insert-command in your examples, which gives > a slightly twisted view of what's going on in general. ] > > But ideally, we could have undo.c do most of that for you. > E.g. instead of adding a boundary every time we switch buffer, undo.c > could simply keep track of which buffers have seen changes during the > current command, and then push undo-boundaries on all of them at the end > of the command. Yeah, thought about that and that would get me most of the way there. I think that should not affect *shell* buffers or equivalent right? They actually only update outside of the command loop, so can't have changed in the middle? > Except for self-insert-command, I think this would give you the ideal > behavior (without any manual work on your side) *and* it would mostly > preserve the existing behavior. > > For self-insert-command, it's more tricky, and you'd probably need to do > the extra manual work. E.g. add a post-self-insert-hook which checks if > this self-insert-command removed the previous undo-boundary and then > remove it as well in the sibling buffer. I can't see how undo.c could > do that for you magically, since it doesn't know that the insertions in > the sibling buffer are "clones" of the insertions in the main buffer, > nor that it's done by self-insert-command. I'd agree with this. One possibility would be to have an undo-boundary command which is implements the same sort of "20 steps" logic as self-insert-command. But, even that is going to be hard, since there can be more changes in *that* buffer than in *this* (the two are not necessarily exactly the same). I think this would all be a little easier if buffer-undo-list didn't use "nil" but allowed the developer to differentiate between different kinds of boundary. > Another approach would be for you to arrange such that your a-f-c uses > self-insert-command rather than `insert' when cloning the insertion > from a self-insert-command, but that's probably just as hard if not > harder. That doesn't sound great to me either, as I have to behave quite differently depending on the last-command. It seems to me, that you are not adverse to the idea of changing undo.c to stop it putting boundaries in. Can I suggest a way forward? I will carry on with my hacked Emacs with removed undo-boundaries in undo.c. I can add the "undo-boundary to all changed buffers" using post-command-hook. This will let me test everything makes sense and works as expected, and I don't mind spending the effort, if emacs will support it later. If you are prepared to implement the "add an undo-boundary to every buffer thats changed" logic into undo.c/cmd.c, then we can do that once the logic works. I would be willing to help with that, but my C programming is very poor, and in practice, I'm likely to learn more than I actually help. Phil ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-05-21 17:03 ` Phillip Lord @ 2015-05-27 11:46 ` Phillip Lord 2015-06-29 0:46 ` Stefan Monnier 0 siblings, 1 reply; 52+ messages in thread From: Phillip Lord @ 2015-05-27 11:46 UTC (permalink / raw) To: Stefan Monnier; +Cc: Emacs-Devel devel Phillip Lord <phillip.lord@newcastle.ac.uk> writes: > Stefan Monnier <monnier@iro.umontreal.ca> writes: >> Another approach would be for you to arrange such that your a-f-c uses >> self-insert-command rather than `insert' when cloning the insertion >> from a self-insert-command, but that's probably just as hard if not >> harder. > > That doesn't sound great to me either, as I have to behave quite > differently depending on the last-command. > > It seems to me, that you are not adverse to the idea of changing undo.c > to stop it putting boundaries in. Can I suggest a way forward? I will > carry on with my hacked Emacs with removed undo-boundaries in undo.c. I > can add the "undo-boundary to all changed buffers" using > post-command-hook. This will let me test everything makes sense and > works as expected, and I don't mind spending the effort, if emacs will > support it later. > > If you are prepared to implement the "add an undo-boundary to every > buffer thats changed" logic into undo.c/cmd.c, then we can do that once > the logic works. I would be willing to help with that, but my C > programming is very poor, and in practice, I'm likely to learn more than > I actually help. Actually, I have been thinking about this. What I worry about with this is that we may be adding the same form of heuristic into undo.c as the "insert an undo-boundary if the buffer has changed". And once is in the C layer it is effectively unfixable from lisp. The existing logic does not seem unsensible, but actually does not work in my (admitted niche) set of circumstances. So, it may be that simply removing the existing logic is the right thing to do! Phil ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-05-27 11:46 ` Phillip Lord @ 2015-06-29 0:46 ` Stefan Monnier 2015-08-04 14:18 ` Phillip Lord 0 siblings, 1 reply; 52+ messages in thread From: Stefan Monnier @ 2015-06-29 0:46 UTC (permalink / raw) To: Phillip Lord; +Cc: Emacs-Devel devel > Actually, I have been thinking about this. What I worry about with this > is that we may be adding the same form of heuristic into undo.c as the > "insert an undo-boundary if the buffer has changed". Yes, because we do want this to happen, pretty much always (having changes accumulate without intervening boundary is actually a problem that can lead to nasty behaviors). There are exceptions, but they're rare. Stefan ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-06-29 0:46 ` Stefan Monnier @ 2015-08-04 14:18 ` Phillip Lord 2015-08-06 21:02 ` Phillip Lord 2015-08-06 22:20 ` Stefan Monnier 0 siblings, 2 replies; 52+ messages in thread From: Phillip Lord @ 2015-08-04 14:18 UTC (permalink / raw) To: Stefan Monnier; +Cc: Emacs-Devel devel Stefan Monnier <monnier@iro.umontreal.ca> writes: >> Actually, I have been thinking about this. What I worry about with this >> is that we may be adding the same form of heuristic into undo.c as the >> "insert an undo-boundary if the buffer has changed". > > Yes, because we do want this to happen, pretty much always (having > changes accumulate without intervening boundary is actually a problem > that can lead to nasty behaviors). > > There are exceptions, but they're rare. Sorry for late reply -- been travelling. The heuristic I was refering to is the "insert an undo-boundary if the current-buffer has changed". Or, rather, insert an undo-boundary if some *other* buffer has changed. I think that the current undo-boundary behaviour wrt a single buffer makes sense. It's the fact that inserting content into *that* buffer forces an undo-boundary into *this* buffer. I don't know why Emacs does this. In most cases, this is irrelevant and doesn't happen anyway, and where you have a p-c-h or a-c-f it changes undo behaviour. I worry that I am missing a good reason for this behaviour, but I have thought about it and failed to come up with a reason; negative conclusions are always worrisome, but what else can you do? I'll write a patch to trunk and send it in, once my life has caught up, then I can happily pass the buck of making the final decision to you:-) Phil ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-08-04 14:18 ` Phillip Lord @ 2015-08-06 21:02 ` Phillip Lord 2015-08-06 22:20 ` Stefan Monnier 1 sibling, 0 replies; 52+ messages in thread From: Phillip Lord @ 2015-08-06 21:02 UTC (permalink / raw) To: Stefan Monnier; +Cc: Emacs-Devel devel Phillip Lord <phillip.lord@newcastle.ac.uk> writes: > Stefan Monnier <monnier@iro.umontreal.ca> writes: > >>> Actually, I have been thinking about this. What I worry about with this >>> is that we may be adding the same form of heuristic into undo.c as the >>> "insert an undo-boundary if the buffer has changed". >> >> Yes, because we do want this to happen, pretty much always (having >> changes accumulate without intervening boundary is actually a problem >> that can lead to nasty behaviors). >> >> There are exceptions, but they're rare. > > > Sorry for late reply -- been travelling. > > The heuristic I was refering to is the "insert an undo-boundary if the > current-buffer has changed". Or, rather, insert an undo-boundary if some > *other* buffer has changed. > > I think that the current undo-boundary behaviour wrt a single buffer > makes sense. It's the fact that inserting content into *that* buffer > forces an undo-boundary into *this* buffer. I don't know why Emacs does > this. In most cases, this is irrelevant and doesn't happen anyway, and > where you have a p-c-h or a-c-f it changes undo behaviour. I worry that > I am missing a good reason for this behaviour, but I have thought about > it and failed to come up with a reason; negative conclusions are always > worrisome, but what else can you do? > > I'll write a patch to trunk and send it in, once my life has caught up, > then I can happily pass the buck of making the final decision to you:-) I have added the change that I am suggesting to: fix/no-undo-boundary-on-secondary-buffer-change The change simplifies undo.c somewhat. I can see no reason for the existing logic, and it is has extremely counter-intuitive consequences when using as discussed when using post-c-h or a-c-f. But clearly it also changes some deep (and old!) logic in undo.c. So, making this my first commit to trunk would clearly be reckless. Let me know what you think. If you are unhappy, I will drop the idea entirely and delete the branch. If you are happy, I will leave you to merge/rebase as you choose. If you don't like my commit message grammar, I can fix and squash on a branch! Cheers Phil ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-08-04 14:18 ` Phillip Lord 2015-08-06 21:02 ` Phillip Lord @ 2015-08-06 22:20 ` Stefan Monnier 2015-08-07 13:40 ` Phillip Lord 1 sibling, 1 reply; 52+ messages in thread From: Stefan Monnier @ 2015-08-06 22:20 UTC (permalink / raw) To: Phillip Lord; +Cc: Emacs-Devel devel > I think that the current undo-boundary behaviour wrt a single buffer > makes sense. It's the fact that inserting content into *that* buffer > forces an undo-boundary into *this* buffer. I don't know why Emacs > does this. I think the reason is not very deep: for reasons of efficiency (back in the days when 8MB was a lot of memory), Emacs keeps track of a few undo-related pieces of information in global variables, so it can only handle a single buffer at a time. If a command touches some other buffer, the C code has to choose between "just switch" and "push a boundary and then switch", and the choice it makes is to err on the "safe" side of adding a potentially unnecessary undo-boundary rather than risking to let the undo-log grow without intervening boundaries. In your cases, this is complicated by the fact that you're concerned about self-insert-command which is very special in that it was the only command that doesn't push a boundary every time, but only once every N repetitions. Stefan ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-08-06 22:20 ` Stefan Monnier @ 2015-08-07 13:40 ` Phillip Lord 2015-08-07 13:59 ` David Kastrup 2015-08-07 17:10 ` Stefan Monnier 0 siblings, 2 replies; 52+ messages in thread From: Phillip Lord @ 2015-08-07 13:40 UTC (permalink / raw) To: Stefan Monnier; +Cc: Emacs-Devel devel Stefan Monnier <monnier@iro.umontreal.ca> writes: >> I think that the current undo-boundary behaviour wrt a single buffer >> makes sense. It's the fact that inserting content into *that* buffer >> forces an undo-boundary into *this* buffer. I don't know why Emacs >> does this. > > I think the reason is not very deep: for reasons of efficiency (back in > the days when 8MB was a lot of memory), Emacs keeps track of a few > undo-related pieces of information in global variables, so it can only > handle a single buffer at a time. If a command touches some other > buffer, the C code has to choose between "just switch" and "push > a boundary and then switch", and the choice it makes is to err on the > "safe" side of adding a potentially unnecessary undo-boundary rather > than risking to let the undo-log grow without intervening boundaries. I meant "deep" in the sense of "deep in version control history" -- or in this case, before the version control system. Still, I didn't know this was the reason. Arguing against this are my experiments which suggest that undo-boundaries are, in practice, rarely inserted in this way (about 1% of times these functions are called, although, of course, it will depend on how you are using Emacs). > In your cases, this is complicated by the fact that you're concerned > about self-insert-command which is very special in that it was the only > command that doesn't push a boundary every time, but only once every > N repetitions. I am slightly concerned about this, but not overly concerned. The main thing that I am worried about is here: https://github.com/phillord/lentic/issues/20 where, for example, a single "fill-paragraph" command takes many undos to undo because of multiple changes in *another* buffer. Anyway, the patch is there. Any chance? If not, anything (further) that I can add (or remove!) to the branch to make it happen? Failing that, I will have to think about how to remove the undo-boundary post-hoc, or give up and accept that lentic will interfere with undo. Haven't decided which yet. BTW, I did a demonstration at a conference last, which pitted Emacs (lagging badly on a badly overloaded netbook) with CIDER, and lentic against several slick websites. We won the best demo prize. You have to laugh... Phil ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-08-07 13:40 ` Phillip Lord @ 2015-08-07 13:59 ` David Kastrup 2015-08-07 21:10 ` Phillip Lord 2015-08-07 17:10 ` Stefan Monnier 1 sibling, 1 reply; 52+ messages in thread From: David Kastrup @ 2015-08-07 13:59 UTC (permalink / raw) To: Phillip Lord; +Cc: Stefan Monnier, Emacs-Devel devel phillip.lord@newcastle.ac.uk (Phillip Lord) writes: > Stefan Monnier <monnier@iro.umontreal.ca> writes: > >>> I think that the current undo-boundary behaviour wrt a single buffer >>> makes sense. It's the fact that inserting content into *that* buffer >>> forces an undo-boundary into *this* buffer. I don't know why Emacs >>> does this. >> >> I think the reason is not very deep: for reasons of efficiency (back in >> the days when 8MB was a lot of memory), Emacs keeps track of a few >> undo-related pieces of information in global variables, so it can only >> handle a single buffer at a time. If a command touches some other >> buffer, the C code has to choose between "just switch" and "push >> a boundary and then switch", and the choice it makes is to err on the >> "safe" side of adding a potentially unnecessary undo-boundary rather >> than risking to let the undo-log grow without intervening boundaries. > > > I meant "deep" in the sense of "deep in version control history" -- or > in this case, before the version control system. Still, I didn't know > this was the reason. The problem _I_ see is that it is in general not just "a command" which may touch another buffer, but also compilation buffers, timer events, font lock and a number of other background activities not immediately caused by key presses. -- David Kastrup ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-08-07 13:59 ` David Kastrup @ 2015-08-07 21:10 ` Phillip Lord 2015-08-08 5:39 ` David Kastrup 0 siblings, 1 reply; 52+ messages in thread From: Phillip Lord @ 2015-08-07 21:10 UTC (permalink / raw) To: David Kastrup; +Cc: Stefan Monnier, Emacs-Devel devel David Kastrup <dak@gnu.org> writes: > phillip.lord@newcastle.ac.uk (Phillip Lord) writes: > >> Stefan Monnier <monnier@iro.umontreal.ca> writes: >> >>>> I think that the current undo-boundary behaviour wrt a single buffer >>>> makes sense. It's the fact that inserting content into *that* buffer >>>> forces an undo-boundary into *this* buffer. I don't know why Emacs >>>> does this. >>> >>> I think the reason is not very deep: for reasons of efficiency (back in >>> the days when 8MB was a lot of memory), Emacs keeps track of a few >>> undo-related pieces of information in global variables, so it can only >>> handle a single buffer at a time. If a command touches some other >>> buffer, the C code has to choose between "just switch" and "push >>> a boundary and then switch", and the choice it makes is to err on the >>> "safe" side of adding a potentially unnecessary undo-boundary rather >>> than risking to let the undo-log grow without intervening boundaries. >> >> >> I meant "deep" in the sense of "deep in version control history" -- or >> in this case, before the version control system. Still, I didn't know >> this was the reason. > > The problem _I_ see is that it is in general not just "a command" which > may touch another buffer, but also compilation buffers, timer events, > font lock and a number of other background activities not immediately > caused by key presses. I don't think this is an issue, because Emacs is single-threaded. So, all of these events happen *between* commands which, in general, means that an undo-boundary has gone onto the current-buffer anyway. So, they don't break the undo behaviour in the current-buffer. If it were not, the current semantics of Emacs undo would have been shown to be problematic a long time ago. As it stands (as I think I mentioned a long time ago!), I've checked how often undo-boundaries are added by the current logic and the answer is hardly ever. The code is almost entirely benign AFAICT, in that it never runs. It just makes undo.c more complex than necessary, and is a total disaster for my use case. As always, it depends on what you do with Emacs and I may be missing something where it is the right thing. I can't tell. Phil ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-08-07 21:10 ` Phillip Lord @ 2015-08-08 5:39 ` David Kastrup 2015-08-08 9:58 ` Phillip Lord 0 siblings, 1 reply; 52+ messages in thread From: David Kastrup @ 2015-08-08 5:39 UTC (permalink / raw) To: Phillip Lord; +Cc: Stefan Monnier, Emacs-Devel devel phillip.lord@newcastle.ac.uk (Phillip Lord) writes: > David Kastrup <dak@gnu.org> writes: >> >> The problem _I_ see is that it is in general not just "a command" which >> may touch another buffer, but also compilation buffers, timer events, >> font lock and a number of other background activities not immediately >> caused by key presses. > > > I don't think this is an issue, because Emacs is single-threaded. So, > all of these events happen *between* commands which, in general, means > that an undo-boundary has gone onto the current-buffer anyway. Not for self-insert-command. Not for stuff like shell-command-on-region that has to wait for material to arrive. -- David Kastrup ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-08-08 5:39 ` David Kastrup @ 2015-08-08 9:58 ` Phillip Lord 0 siblings, 0 replies; 52+ messages in thread From: Phillip Lord @ 2015-08-08 9:58 UTC (permalink / raw) To: David Kastrup; +Cc: Stefan Monnier, Emacs-Devel devel David Kastrup <dak@gnu.org> writes: > phillip.lord@newcastle.ac.uk (Phillip Lord) writes: > >> David Kastrup <dak@gnu.org> writes: >>> >>> The problem _I_ see is that it is in general not just "a command" which >>> may touch another buffer, but also compilation buffers, timer events, >>> font lock and a number of other background activities not immediately >>> caused by key presses. >> >> >> I don't think this is an issue, because Emacs is single-threaded. So, >> all of these events happen *between* commands which, in general, means >> that an undo-boundary has gone onto the current-buffer anyway. > > Not for self-insert-command. Not for stuff like shell-command-on-region > that has to wait for material to arrive. I thought shell-command-on-region still arrives between commands, but I have not looked at the code. You are more likely to be correct than I. My feeling is that my patch is likely to remove problems caused by asynchronicity rather than cause it. The logic is simpler and undo boundaries are not added based on something that has happened in the past. Phil ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-08-07 13:40 ` Phillip Lord 2015-08-07 13:59 ` David Kastrup @ 2015-08-07 17:10 ` Stefan Monnier 2015-08-08 21:28 ` Stefan Monnier 1 sibling, 1 reply; 52+ messages in thread From: Stefan Monnier @ 2015-08-07 17:10 UTC (permalink / raw) To: Phillip Lord; +Cc: Emacs-Devel devel > I am slightly concerned about this, but not overly concerned. The main > thing that I am worried about is here: > https://github.com/phillord/lentic/issues/20 > where, for example, a single "fill-paragraph" command takes many undos > to undo because of multiple changes in *another* buffer. Yes, this is a clear bug. > Anyway, the patch is there. Any chance? If not, anything (further) that > I can add (or remove!) to the branch to make it happen? I'll try and look at it soon, Stefan ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-08-07 17:10 ` Stefan Monnier @ 2015-08-08 21:28 ` Stefan Monnier 2015-08-09 15:39 ` Phillip Lord 0 siblings, 1 reply; 52+ messages in thread From: Stefan Monnier @ 2015-08-08 21:28 UTC (permalink / raw) To: Phillip Lord; +Cc: Emacs-Devel devel >> Anyway, the patch is there. Any chance? If not, anything (further) that >> I can add (or remove!) to the branch to make it happen? > I'll try and look at it soon, IIUC this only removes the code which adds a boundary when we change buffer. IOW it switches from the conservative option of adding a boundary even if it might not be needed, to the risky option of hoping that someone else will add the needed boundary. As explained, this will most likely introduce problems with ever-growing undo-logs in buffers filled by process output and timers. It's an acceptable first step, but it needs to be compensated by a second step which keeps track of all buffers modified during the execution of a command and change the "add a boundary in current-buffer at the end of a command" to "add boundaries in all modified buffers at the end of a command". Stefan ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-08-08 21:28 ` Stefan Monnier @ 2015-08-09 15:39 ` Phillip Lord 2015-08-09 16:30 ` Stefan Monnier 0 siblings, 1 reply; 52+ messages in thread From: Phillip Lord @ 2015-08-09 15:39 UTC (permalink / raw) To: Stefan Monnier; +Cc: Emacs-Devel devel Stefan Monnier <monnier@iro.umontreal.ca> writes: >>> Anyway, the patch is there. Any chance? If not, anything (further) that >>> I can add (or remove!) to the branch to make it happen? >> I'll try and look at it soon, > > IIUC this only removes the code which adds a boundary when we change > buffer. IOW it switches from the conservative option of adding > a boundary even if it might not be needed, to the risky option of hoping > that someone else will add the needed boundary. I'd tend to characterise it as the risky option of disrupting the user experience by added unnecessary boundaries on the off-chance of using too much memory, against the conservative option of not adding a boundary. But, otherwise, yes. > As explained, this will most likely introduce problems with ever-growing > undo-logs in buffers filled by process output and timers. Will buffer-undo-list not be truncated by GC anyway? I can't quite understand where the ever-growing logs come from, nor how the functionality I have removed would prevent it. > It's an acceptable first step, but it needs to be compensated by > a second step which keeps track of all buffers modified during the > execution of a command and change the "add a boundary in current-buffer > at the end of a command" to "add boundaries in all modified buffers > at the end of a command". I'm struggling with understanding this also. I've tried tracing when the code my patch removes actually runs and it is pretty rarely. And, yet, undo works correctly, generally on a per-command basis (except for the self-insert-command special handling). Also, adding boundaries in all modified buffers strikes me as fairly stochastic. Assuming a well-behaved timer (i.e. one that releases control with `sit-for'), this logic essentially translates to "we may choose to show an undo-boundary in at this point, or we may not". So I'd need an example, though, or some way of causing this sort of problem that you are worried about. A failing ert test in test/automated would be ideal, but anything is good! Phil ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-08-09 15:39 ` Phillip Lord @ 2015-08-09 16:30 ` Stefan Monnier 2015-08-09 16:50 ` Phillip Lord 0 siblings, 1 reply; 52+ messages in thread From: Stefan Monnier @ 2015-08-09 16:30 UTC (permalink / raw) To: Phillip Lord; +Cc: Emacs-Devel devel > Will buffer-undo-list not be truncated by GC anyway? Truncation is only done at undo-boundaries. Hence the problem. > I'm struggling with understanding this also. I've tried tracing when the > code my patch removes actually runs and it is pretty rarely. When you're editing buffer FOO while some process is inserting data in buffer BAR. Or when your commands modify two buffers (e.g. in your case). > Also, adding boundaries in all modified buffers strikes me as fairly > stochastic. Not sure what you mean. > Assuming a well-behaved timer (i.e. one that releases > control with `sit-for'), Hmm? timers usually shouldn't call sit-for. Stefan ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-08-09 16:30 ` Stefan Monnier @ 2015-08-09 16:50 ` Phillip Lord 2015-08-09 17:40 ` Stefan Monnier 0 siblings, 1 reply; 52+ messages in thread From: Phillip Lord @ 2015-08-09 16:50 UTC (permalink / raw) To: Stefan Monnier; +Cc: Emacs-Devel devel, Phillip Lord Stefan Monnier <monnier@IRO.UMontreal.CA> writes: >> Will buffer-undo-list not be truncated by GC anyway? > > Truncation is only done at undo-boundaries. Hence the problem. Ah, yes, okay. >> I'm struggling with understanding this also. I've tried tracing when the >> code my patch removes actually runs and it is pretty rarely. > > When you're editing buffer FOO while some process is inserting data in > buffer BAR. Okay. So, buffer BAR should get undo-boundaries when a command runs in FOO? And FOO should get an undo-boundary when the process adds something to BAR? > Or when your commands modify two buffers (e.g. in your case). Well, I think that this is my problem (as the author of the command, rather than as the user). I mean, I modify two buffers, I need to fix the undo, to decide what I want to do about this. For my use case, this would work much better because I could even do the "undo-boundary unless it's self-insert in which case wait for 20 of them" logic. In the case of a logging mode (i.e. which logs all events), I'd switch the undo off in that buffer anyway. >> Also, adding boundaries in all modified buffers strikes me as fairly >> stochastic. > > Not sure what you mean. I am editing a buffer, FOO. I type something in the usual way, with some pauses for me to think. Mean time, an idle-timer is running, doing something to BAR. If I think long, the undo will behave in one way, if I think quick, the undo will behave in another, depending on whether the idle-timer has modified BAR or not. > >> Assuming a well-behaved timer (i.e. one that releases >> control with `sit-for'), > > Hmm? timers usually shouldn't call sit-for. Oh, now I am sure that this used to be recommended (which is why I did it). I use this when I have a long running idle timer -- I sit-for a very short gap, then carry on if there is no input pending, then carry on. Well, that's more code to fix! Phil ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-08-09 16:50 ` Phillip Lord @ 2015-08-09 17:40 ` Stefan Monnier 2015-08-10 9:27 ` Phillip Lord 0 siblings, 1 reply; 52+ messages in thread From: Stefan Monnier @ 2015-08-09 17:40 UTC (permalink / raw) To: Phillip Lord; +Cc: Emacs-Devel devel, Phillip Lord >>> I'm struggling with understanding this also. I've tried tracing when the >>> code my patch removes actually runs and it is pretty rarely. >> When you're editing buffer FOO while some process is inserting data in >> buffer BAR. > Okay. So, buffer BAR should get undo-boundaries when a command runs in > FOO? And FOO should get an undo-boundary when the process adds something > to BAR? The general goal is: add undo-boundaries often enough so the undo-log doesn't grow too large, both in FOO and in BAR, and ideally in ways which are somewhat predictable for the user. If you ask my ideal: FOO would get an undo-boundary after each command, and BAR would get an undo boundary after each N bytes inserted, or after every N seconds. >>> Also, adding boundaries in all modified buffers strikes me as fairly >>> stochastic. >> Not sure what you mean. > I am editing a buffer, FOO. I type something in the usual way, with some > pauses for me to think. > Mean time, an idle-timer is running, doing something to BAR. If I think > long, the undo will behave in one way, if I think quick, the undo will > behave in another, depending on whether the idle-timer has modified BAR > or not. In the scenario of "add boundaries to every buffer modified since last time"? Why do you think so? The boundaries in Foo will not be influenced by the timer. The boundaries in Bar will, indeed, because they'll only be inserted as a side-effect of the commands in Foo and depending on how much you think, the timer could fire several times between commands. Hence my ideal wish of "get an undo boundary after each N bytes inserted, or after every N seconds" for things like process output or timers. >>> Assuming a well-behaved timer (i.e. one that releases >>> control with `sit-for'), >> Hmm? timers usually shouldn't call sit-for. > Oh, now I am sure that this used to be recommended (which is why I did > it). I use this when I have a long running idle timer -- I sit-for a > very short gap, then carry on if there is no input pending, then carry > on. Ah, you're thinking of a long-running idle-timer, basically a poor man's background task. Yes, then it needs to call sit-for, but I don't think it makes much difference in the end result in the scenarios discussed here. Stefan ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-08-09 17:40 ` Stefan Monnier @ 2015-08-10 9:27 ` Phillip Lord 2015-08-10 21:21 ` Phillip Lord 2015-08-12 21:15 ` Stefan Monnier 0 siblings, 2 replies; 52+ messages in thread From: Phillip Lord @ 2015-08-10 9:27 UTC (permalink / raw) To: Stefan Monnier; +Cc: Emacs-Devel devel Stefan Monnier <monnier@iro.umontreal.ca> writes: >>>> I'm struggling with understanding this also. I've tried tracing when the >>>> code my patch removes actually runs and it is pretty rarely. >>> When you're editing buffer FOO while some process is inserting data in >>> buffer BAR. >> Okay. So, buffer BAR should get undo-boundaries when a command runs in >> FOO? And FOO should get an undo-boundary when the process adds something >> to BAR? > > The general goal is: add undo-boundaries often enough so the undo-log > doesn't grow too large, both in FOO and in BAR, and ideally in ways > which are somewhat predictable for the user. > > If you ask my ideal: FOO would get an undo-boundary after each command, > and BAR would get an undo boundary after each N bytes inserted, or after > every N seconds. My own feeling is that undo-boundaries should be the task of the mode author, with sensible default behaviour (like the current one) for user-centric modes (i.e. non process buffers). My guess is that most buffers connected to non-interactive processes have undo switched off. As an alternative, why not handle this at GC? So, change the current logic to "iff buffer undo-log is too large, and you have no undo-boundaries, GC to 50% of length regardless". This addresses your concern (overly long undo-logs, i.e. memory leaks) within the memory management system, rather than in as a heuristic in a user system (i.e. undo). >>>> Also, adding boundaries in all modified buffers strikes me as fairly >>>> stochastic. >>> Not sure what you mean. >> I am editing a buffer, FOO. I type something in the usual way, with some >> pauses for me to think. >> Mean time, an idle-timer is running, doing something to BAR. If I think >> long, the undo will behave in one way, if I think quick, the undo will >> behave in another, depending on whether the idle-timer has modified BAR >> or not. > > In the scenario of "add boundaries to every buffer modified since last > time"? Why do you think so? The boundaries in Foo will not be > influenced by the timer. Sorry, my mistake. "command" != function call. So, the call to the idle-timer function will not trigger this. >>>> Assuming a well-behaved timer (i.e. one that releases >>>> control with `sit-for'), >>> Hmm? timers usually shouldn't call sit-for. >> Oh, now I am sure that this used to be recommended (which is why I did >> it). I use this when I have a long running idle timer -- I sit-for a >> very short gap, then carry on if there is no input pending, then carry >> on. > > Ah, you're thinking of a long-running idle-timer, basically a poor man's > background task. Yes, then it needs to call sit-for, but I don't think > it makes much difference in the end result in the scenarios > discussed here. Yeah, a "background" task. And you are correct. Phil ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-08-10 9:27 ` Phillip Lord @ 2015-08-10 21:21 ` Phillip Lord 2015-08-12 21:15 ` Stefan Monnier 1 sibling, 0 replies; 52+ messages in thread From: Phillip Lord @ 2015-08-10 21:21 UTC (permalink / raw) To: Stefan Monnier; +Cc: Emacs-Devel devel Phillip Lord <phillip.lord@russet.org.uk> writes: > Stefan Monnier <monnier@iro.umontreal.ca> writes: > >>>>> I'm struggling with understanding this also. I've tried tracing when the >>>>> code my patch removes actually runs and it is pretty rarely. >>>> When you're editing buffer FOO while some process is inserting data in >>>> buffer BAR. >>> Okay. So, buffer BAR should get undo-boundaries when a command runs in >>> FOO? And FOO should get an undo-boundary when the process adds something >>> to BAR? >> >> The general goal is: add undo-boundaries often enough so the undo-log >> doesn't grow too large, both in FOO and in BAR, and ideally in ways >> which are somewhat predictable for the user. >> >> If you ask my ideal: FOO would get an undo-boundary after each command, >> and BAR would get an undo boundary after each N bytes inserted, or after >> every N seconds. > > My own feeling is that undo-boundaries should be the task of the mode > author, with sensible default behaviour (like the current one) for > user-centric modes (i.e. non process buffers). My guess is that most > buffers connected to non-interactive processes have undo switched off. > > As an alternative, why not handle this at GC? So, change the current > logic to "iff buffer undo-log is too large, and you have no > undo-boundaries, GC to 50% of length regardless". This addresses your > concern (overly long undo-logs, i.e. memory leaks) within the memory > management system, rather than in as a heuristic in a user system (i.e. > undo). Okay, to answer my own question, this *is* already handled at GC, with the undo-outer-limit logic. Not handled ideally -- undo-outer-limit is two orders greater than normal and the compaction function is noisy. But it should stop Emacs from memory leaking to crash. Phil ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-08-10 9:27 ` Phillip Lord 2015-08-10 21:21 ` Phillip Lord @ 2015-08-12 21:15 ` Stefan Monnier 2015-08-12 22:34 ` Phillip Lord 1 sibling, 1 reply; 52+ messages in thread From: Stefan Monnier @ 2015-08-12 21:15 UTC (permalink / raw) To: Phillip Lord; +Cc: Emacs-Devel devel > My own feeling is that undo-boundaries should be the task of the mode > author, with sensible default behaviour (like the current one) for > user-centric modes (i.e. non process buffers). In 99.9% of the cases, authors don't want to know about undo boundaries, they should "just work", so the default is very important. Stefan ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-08-12 21:15 ` Stefan Monnier @ 2015-08-12 22:34 ` Phillip Lord 2015-08-13 2:23 ` Stefan Monnier 0 siblings, 1 reply; 52+ messages in thread From: Phillip Lord @ 2015-08-12 22:34 UTC (permalink / raw) To: Stefan Monnier; +Cc: Emacs-Devel devel Stefan Monnier <monnier@IRO.UMontreal.CA> writes: >> My own feeling is that undo-boundaries should be the task of the mode >> author, with sensible default behaviour (like the current one) for >> user-centric modes (i.e. non process buffers). > > In 99.9% of the cases, authors don't want to know about undo boundaries, > they should "just work", so the default is very important. I would agree, but I still need to something that breaks so I can check it is all working. The closest I have got so far is with cider interaction mode (i.e. the repl). I managed to get this to crash out with the "excessively large undo this is probably a bug" error message after my patch, running (doall (map #(println %)) (range 100000)) However, without my patch, emacs just runs to hang as it gets into a tight GC cycle, presumably as the buffer gets enormous, so in fact this really is a bug (i.e. the buffer is never truncated), and my patch improves things. Implementing "add an undo-boundary if there isn't one in any buffer with a big buffer-undo-list" I can certainly do. Any reason to not do this on a timer (i.e. why tie it to the command cycle)? In lisp? This is a ten minute job. In C, it will take longer. Phil ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-08-12 22:34 ` Phillip Lord @ 2015-08-13 2:23 ` Stefan Monnier 2015-08-21 9:40 ` Phillip Lord 0 siblings, 1 reply; 52+ messages in thread From: Stefan Monnier @ 2015-08-13 2:23 UTC (permalink / raw) To: Phillip Lord; +Cc: Emacs-Devel devel > a big buffer-undo-list" I can certainly do. Any reason to not do this on > a timer (i.e. why tie it to the command cycle)? As mentioned, for buffers modified by timers/processes I like the idea of adding undo-boundaries every N seconds or every N modifications. Stefan ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-08-13 2:23 ` Stefan Monnier @ 2015-08-21 9:40 ` Phillip Lord 0 siblings, 0 replies; 52+ messages in thread From: Phillip Lord @ 2015-08-21 9:40 UTC (permalink / raw) To: Stefan Monnier; +Cc: Emacs-Devel devel Stefan Monnier <monnier@iro.umontreal.ca> writes: >> a big buffer-undo-list" I can certainly do. Any reason to not do this on >> a timer (i.e. why tie it to the command cycle)? > > As mentioned, for buffers modified by timers/processes I like the idea > of adding undo-boundaries every N seconds or every N modifications. I've add an update for this to the same branch (fix/no-undo-boundary-on-secondary-buffer-change). Is this the sort of thing that you had in mind? Is it not complete yet -- I was not considering leaving it noisy (it messages at the moment). And I am not sure it is in the right place -- simple.el does not currently require timer. Finally, the timer needs to be manually started. Phil ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-05-21 15:44 ` Stefan Monnier 2015-05-21 17:03 ` Phillip Lord @ 2015-08-07 23:49 ` Davis Herring 2015-08-08 10:01 ` Phillip Lord 1 sibling, 1 reply; 52+ messages in thread From: Davis Herring @ 2015-08-07 23:49 UTC (permalink / raw) To: Stefan Monnier; +Cc: Phillip Lord, Emacs development discussions [I'm late to this thread, but after reading the more recent portion, this still seems a useful reply.] > For self-insert-command, it's more tricky, and you'd probably need to do > the extra manual work. E.g. add a post-self-insert-hook which checks if > this self-insert-command removed the previous undo-boundary and then > remove it as well in the sibling buffer. I can't see how undo.c could > do that for you magically, since it doesn't know that the insertions in > the sibling buffer are "clones" of the insertions in the main buffer, > nor that it's done by self-insert-command. Another approach would be > for you to arrange such that your a-f-c uses self-insert-command rather > than `insert' when cloning the insertion from a self-insert-command, but > that's probably just as hard if not harder. Shouldn't it be easy to write a function (callable from Lisp) that emulates self-insert-command (and its special behavior w.r.t. undo), except that it takes a character as an argument? Davis -- This product is sold by volume, not by mass. If it appears too dense or too sparse, it is because mass-energy conversion has occurred during shipping. ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: disabling undo boundaries 2015-08-07 23:49 ` Davis Herring @ 2015-08-08 10:01 ` Phillip Lord 0 siblings, 0 replies; 52+ messages in thread From: Phillip Lord @ 2015-08-08 10:01 UTC (permalink / raw) To: Davis Herring; +Cc: Stefan Monnier, Emacs development discussions Davis Herring <herring@lanl.gov> writes: > [I'm late to this thread, but after reading the more recent portion, > this still seems a useful reply.] > >> For self-insert-command, it's more tricky, and you'd probably need to do >> the extra manual work. E.g. add a post-self-insert-hook which checks if >> this self-insert-command removed the previous undo-boundary and then >> remove it as well in the sibling buffer. I can't see how undo.c could >> do that for you magically, since it doesn't know that the insertions in >> the sibling buffer are "clones" of the insertions in the main buffer, >> nor that it's done by self-insert-command. Another approach would be >> for you to arrange such that your a-f-c uses self-insert-command rather >> than `insert' when cloning the insertion from a self-insert-command, but >> that's probably just as hard if not harder. > > Shouldn't it be easy to write a function (callable from Lisp) that > emulates self-insert-command (and its special behavior w.r.t. undo), > except that it takes a character as an argument? That would help a little in my use case, although the self-insert-command behaviour is a tweak for me, not a main concern. I think that the main issue is the use of "nil" for an undo-boundary. This makes all undo-boundaries equivalent and impossible to tag. Something like '(:boundary) or (:boundary :reason) would be far easier, at the cost of two cons cells rather than one, at least for a naive implementation. Phil ^ permalink raw reply [flat|nested] 52+ messages in thread
end of thread, other threads:[~2015-08-21 9:40 UTC | newest] Thread overview: 52+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2015-05-10 21:43 disabling undo boundaries Phillip Lord 2015-05-11 1:42 ` Stefan Monnier 2015-05-11 11:46 ` Phillip Lord 2015-05-11 14:45 ` Stefan Monnier 2015-05-11 16:31 ` Phillip Lord 2015-05-11 19:30 ` Stefan Monnier 2015-05-11 20:42 ` Phillip Lord 2015-05-11 22:23 ` Stefan Monnier 2015-05-12 11:52 ` Phillip Lord 2015-05-12 20:15 ` Stefan Monnier 2015-05-12 20:59 ` Phillip Lord 2015-05-13 12:32 ` Stefan Monnier 2015-05-13 15:40 ` Phillip Lord 2015-05-14 15:28 ` Stefan Monnier 2015-05-15 12:27 ` Phillip Lord 2015-05-15 18:08 ` Stefan Monnier 2015-05-15 19:49 ` Phillip Lord 2015-05-15 23:45 ` Stefan Monnier 2015-05-16 13:31 ` Phillip Lord 2015-05-19 11:59 ` Phillip Lord 2015-05-19 19:42 ` Stefan Monnier 2015-05-19 21:48 ` Phillip Lord 2015-05-20 2:00 ` Stefan Monnier 2015-05-20 7:45 ` Phillip Lord 2015-05-20 12:53 ` Stefan Monnier 2015-05-21 11:15 ` Phillip Lord 2015-05-21 15:44 ` Stefan Monnier 2015-05-21 17:03 ` Phillip Lord 2015-05-27 11:46 ` Phillip Lord 2015-06-29 0:46 ` Stefan Monnier 2015-08-04 14:18 ` Phillip Lord 2015-08-06 21:02 ` Phillip Lord 2015-08-06 22:20 ` Stefan Monnier 2015-08-07 13:40 ` Phillip Lord 2015-08-07 13:59 ` David Kastrup 2015-08-07 21:10 ` Phillip Lord 2015-08-08 5:39 ` David Kastrup 2015-08-08 9:58 ` Phillip Lord 2015-08-07 17:10 ` Stefan Monnier 2015-08-08 21:28 ` Stefan Monnier 2015-08-09 15:39 ` Phillip Lord 2015-08-09 16:30 ` Stefan Monnier 2015-08-09 16:50 ` Phillip Lord 2015-08-09 17:40 ` Stefan Monnier 2015-08-10 9:27 ` Phillip Lord 2015-08-10 21:21 ` Phillip Lord 2015-08-12 21:15 ` Stefan Monnier 2015-08-12 22:34 ` Phillip Lord 2015-08-13 2:23 ` Stefan Monnier 2015-08-21 9:40 ` Phillip Lord 2015-08-07 23:49 ` Davis Herring 2015-08-08 10:01 ` Phillip Lord
Code repositories for project(s) associated with this external index https://git.savannah.gnu.org/cgit/emacs.git https://git.savannah.gnu.org/cgit/emacs/org-mode.git This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.