all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Stefan Monnier <monnier@iro.umontreal.ca>
To: Markus Triska <triska@metalevel.at>
Cc: Phillip Lord <phillip.lord@russet.org.uk>, 23906@debbugs.gnu.org
Subject: bug#23906: 25.0.95; Undo boundary after process output is not consistent
Date: Mon, 18 Jul 2016 00:18:36 -0400	[thread overview]
Message-ID: <jwv60s34m4x.fsf-monnier+emacsbugs@gnu.org> (raw)
In-Reply-To: <87shvccl2h.fsf@metalevel.at> (Markus Triska's message of "Thu, 14 Jul 2016 17:10:14 +0200")

> Please let us use this opportunity to fix the more general case
> too. Stefan agreed that the following primitives would work:

>     -) undo-begin-transaction
>        Starts a new transaction.
>     -) undo-end-transaction
>        Ends the most recently started undo transaction.

> The effects of all commands between would be undone as a single unit.

How 'bout the patch below (see the viper part to get an idea about how
to use it in ediprolog)?


        Stefan


diff --git a/lisp/simple.el b/lisp/simple.el
index f114235..e54d4f2 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -3054,6 +3054,41 @@ undo-auto--undoable-change
   (undo-auto--boundary-ensure-timer))
 ;; End auto-boundary section
 
+(defun undo-amalgamate-change-group (handle)
+  "Amalgamate changes in change-group since HANDLE.
+Remove all undo boundaries between the state of HANDLE and now.
+HANDLE is as returned by `prepare-change-group'."
+  (dolist (elt handle)
+    (with-current-buffer (car elt)
+      (setq elt (cdr elt))
+      (when (consp buffer-undo-list)
+        (let ((old-car (car-safe elt))
+              (old-cdr (cdr-safe elt)))
+          (unwind-protect
+              (progn
+                ;; Temporarily truncate the undo log at ELT.
+                (when (consp elt)
+                  (setcar elt t) (setcdr elt nil))
+                (when
+                    (or (null elt)        ;The undo-log was empty.
+                        ;; `elt' is still in the log: normal case.
+                        (eq elt (last buffer-undo-list))
+                        ;; `elt' is not in the log any more, but that's because
+                        ;; the log is "all new", so we should remove all
+                        ;; boundaries from it.
+                        (not (eq (last buffer-undo-list) (last old-cdr))))
+                  (cl-callf (lambda (x) (delq nil x))
+                      (if (car buffer-undo-list)
+                          buffer-undo-list
+                        ;; Preserve the undo-boundaries at either ends of the
+                        ;; change-groups.
+                        (cdr buffer-undo-list)))))
+            ;; Reset the modified cons cell ELT to its original content.
+            (when (consp elt)
+              (setcar elt old-car)
+              (setcdr elt old-cdr))))))))
+
+
 (defcustom undo-ask-before-discard nil
   "If non-nil ask about discarding undo info for the current command.
 Normally, Emacs discards the undo info for the current command if
diff --git a/lisp/emulation/viper-cmd.el b/lisp/emulation/viper-cmd.el
index 3d9d1cc..3ce1b4d 100644
--- a/lisp/emulation/viper-cmd.el
+++ b/lisp/emulation/viper-cmd.el
@@ -1709,40 +1709,20 @@ viper-undo-more
 ;; The following two functions are used to set up undo properly.
 ;; In VI, unlike Emacs, if you open a line, say, and add a bunch of lines,
 ;; they are undone all at once.
-(defun viper-adjust-undo ()
-  (if viper-undo-needs-adjustment
-      (let ((inhibit-quit t)
-	    tmp tmp2)
-	(setq viper-undo-needs-adjustment nil)
-	(when (listp buffer-undo-list)
-          (let ((had-boundary (null (car buffer-undo-list))))
-            (if (setq tmp (memq viper-buffer-undo-list-mark buffer-undo-list))
-		(progn
-		  (setq tmp2 (cdr tmp)) ; the part after mark
-
-		  ;; cut tail from buffer-undo-list temporarily by direct
-		  ;; manipulation with pointers in buffer-undo-list
-		  (setcdr tmp nil)
-
-		  (setq buffer-undo-list (delq nil buffer-undo-list))
-		  (setq buffer-undo-list
-			(delq viper-buffer-undo-list-mark buffer-undo-list))
-		  ;; restore tail of buffer-undo-list
-		  (setq buffer-undo-list (nconc buffer-undo-list tmp2)))
-	      (setq buffer-undo-list (delq nil buffer-undo-list)))
-            ;; The top-level loop only adds boundaries if there has been
-            ;; modifications in the buffer, so make sure we don't accidentally
-            ;; drop the "final" boundary (bug#22295).
-	    (if had-boundary (undo-boundary)))))))
+(viper-deflocalvar viper--undo-change-group-handle nil)
+(put 'viper--undo-change-group-handle 'permanent-local t)
 
+(defun viper-adjust-undo ()
+  (when viper--undo-change-group-handle
+    (undo-amalgamate-change-group
+     (prog1 viper--undo-change-group-handle
+       (setq viper--undo-change-group-handle nil)))))
 
 (defun viper-set-complex-command-for-undo ()
-  (if (listp buffer-undo-list)
-      (if (not viper-undo-needs-adjustment)
-	  (let ((inhibit-quit t))
-	    (setq buffer-undo-list
-		  (cons viper-buffer-undo-list-mark buffer-undo-list))
-	    (setq viper-undo-needs-adjustment t)))))
+  (and (listp buffer-undo-list)
+       (not viper--undo-change-group-handle)
+       (setq viper--undo-change-group-handle
+             (prepare-change-group))))
 
 
 ;;; Viper's destructive Command ring utilities
diff --git a/lisp/emulation/viper-init.el b/lisp/emulation/viper-init.el
index 086daf2..838d846 100644
--- a/lisp/emulation/viper-init.el
+++ b/lisp/emulation/viper-init.el
@@ -369,15 +369,6 @@ viper-set-input-method
 
 ;; VI-style Undo
 
-;; Used to 'undo' complex commands, such as replace and insert commands.
-(viper-deflocalvar viper-undo-needs-adjustment nil)
-(put 'viper-undo-needs-adjustment 'permanent-local t)
-
-;; A mark that Viper puts on buffer-undo-list.  Marks the beginning of a
-;; complex command that must be undone atomically.  If inserted, it is
-;; erased by viper-change-state-to-vi and viper-repeat.
-(defconst viper-buffer-undo-list-mark 'viper)
-
 (defcustom viper-keep-point-on-undo nil
   "Non-nil means not to move point while undoing commands.
 This style is different from Emacs and Vi.  Try it to see if





  parent reply	other threads:[~2016-07-18  4:18 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-07-06 17:56 bug#23906: 25.0.95; Undo boundary after process output is not consistent Markus Triska
2016-07-06 18:38 ` Eli Zaretskii
2016-07-11 11:45   ` Phillip Lord
2016-07-11 13:54     ` Markus Triska
2016-07-12 16:29       ` Phillip Lord
2016-07-12 17:03         ` Stefan Monnier
2016-07-12 18:56         ` Markus Triska
2016-07-12 20:22           ` Stefan Monnier
2016-07-12 21:02             ` Markus Triska
2016-07-12 21:20               ` Stefan Monnier
2016-07-12 22:35                 ` Markus Triska
2016-07-12 22:51                   ` Stefan Monnier
2016-07-12 22:45                 ` Markus Triska
2016-07-13 22:12               ` Phillip Lord
2016-07-14  8:34                 ` Markus Triska
2016-07-14 13:33                   ` Phillip Lord
2016-07-14 15:10                     ` Markus Triska
2016-07-14 20:25                       ` Phillip Lord
2016-07-14 22:12                         ` Stefan Monnier
2016-07-18  4:18                       ` Stefan Monnier [this message]
2016-07-18 19:03                         ` Markus Triska
2016-07-19  0:41                           ` Stefan Monnier
2016-07-19  1:05                         ` Stefan Monnier
2016-07-24 15:45                         ` Phillip Lord
2016-07-24 21:36                           ` Stefan Monnier
2020-09-04 13:55                         ` Lars Ingebrigtsen
2016-07-13  8:09           ` Phillip Lord
2016-07-13 14:29             ` Markus Triska
2016-07-13 22:23               ` Phillip Lord

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=jwv60s34m4x.fsf-monnier+emacsbugs@gnu.org \
    --to=monnier@iro.umontreal.ca \
    --cc=23906@debbugs.gnu.org \
    --cc=phillip.lord@russet.org.uk \
    --cc=triska@metalevel.at \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.