From 71bc4e8352c6662458d5d18f328bd955054a91cc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mattias=20Engdeg=C3=A5rd?= <mattiase@acm.org>
Date: Wed, 30 Oct 2019 19:13:47 +0100
Subject: [PATCH 2/2] Adapt undo message when undoing unconfined actions in
 region

* lisp/simple.el (undo): Don't say "Undo in region" when the action
undone explicitly ignores region confinement (bug#37700).
(undo--first-record-unconfined): New.
(undo-make-selective-list): Use undo--first-record-unconfined.
---
 lisp/simple.el | 37 ++++++++++++++++++++++++-------------
 1 file changed, 24 insertions(+), 13 deletions(-)

diff --git a/lisp/simple.el b/lisp/simple.el
index 83be410074..e08c9b6a89 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -2508,6 +2508,8 @@ undo
 	 (base-buffer (or (buffer-base-buffer) (current-buffer)))
 	 (recent-save (with-current-buffer base-buffer
 			(recent-auto-save-p)))
+         (unconfined nil)
+         (count (if (numberp arg) (prefix-numeric-value arg) 1))
 	 message)
     ;; If we get an error in undo-start,
     ;; the next command should not be a "consecutive undo".
@@ -2527,7 +2529,9 @@ undo
       (setq undo-in-region
 	    (or (region-active-p) (and arg (not (numberp arg)))))
       (if undo-in-region
-	  (undo-start (region-beginning) (region-end))
+          (progn
+            (setq unconfined (undo--first-record-unconfined buffer-undo-list))
+            (undo-start (region-beginning) (region-end)))
 	(undo-start))
       ;; get rid of initial undo boundary
       (undo-more 1))
@@ -2537,20 +2541,20 @@ undo
     ;; so, ask the user whether she wants to skip the redo/undo pair.
     (let ((equiv (gethash pending-undo-list undo-equiv-table)))
       (or (eq (selected-window) (minibuffer-window))
-	  (setq message (format "%s%s"
-                                (if (or undo-no-redo (not equiv))
-                                    "Undo" "Redo")
-                                (if undo-in-region " in region" ""))))
+	  (setq message (concat
+                         (if (or undo-no-redo (not equiv))
+                             "Undo" "Redo")
+                         (cond ((and unconfined (> count 1))
+                                " in region (except first action)")
+                               ((and undo-in-region (not unconfined))
+                                " in region")))))
       (when (and (consp equiv) undo-no-redo)
 	;; The equiv entry might point to another redo record if we have done
 	;; undo-redo-undo-redo-... so skip to the very last equiv.
 	(while (let ((next (gethash equiv undo-equiv-table)))
 		 (if next (setq equiv next))))
 	(setq pending-undo-list equiv)))
-    (undo-more
-     (if (numberp arg)
-	 (prefix-numeric-value arg)
-       1))
+    (undo-more count)
     ;; Record the fact that the just-generated undo records come from an
     ;; undo operation--that is, they are redo records.
     ;; In the ordinary case (not within a region), map the redo
@@ -2847,6 +2851,13 @@ undo-start
 ;; "ccaabad", as though the first "d" became detached from the
 ;; original "ddd" insertion.  This quirk is a FIXME.
 
+(defun undo--first-record-unconfined (undo-list)
+  "If the first record of UNDO-LIST is marked unconfined, return the argument
+without the leading `unconfined' directive; otherwise nil."
+  (pcase undo-list
+    (`(nil unconfined . ,rest)
+     rest)))
+
 (defun undo-make-selective-list (start end)
   "Return a list of undo elements for the region START to END.
 The elements come from `buffer-undo-list', but we keep only the
@@ -2861,10 +2872,10 @@ undo-make-selective-list
         undo-deltas
         undo-elt)
     ;; The `unconfined' directive only applies to the very first record.
-    (pcase ulist
-      (`(nil unconfined . ,rest)
-       (setq unconfined t)
-       (setq ulist rest)))
+    (let ((ul (undo--first-record-unconfined ulist)))
+      (when ul
+        (setq ulist ul)
+        (setq unconfined t)))
     (while ulist
       (when undo-no-redo
         (while (gethash ulist undo-equiv-table)
-- 
2.21.0 (Apple Git-122)

