]> git.eshelyaron.com Git - emacs.git/commitdiff
(Ftranspose_regions): Fix bug#76124
authorStefan Monnier <monnier@iro.umontreal.ca>
Sun, 6 Jul 2025 23:15:51 +0000 (19:15 -0400)
committerEshel Yaron <me@eshelyaron.com>
Thu, 24 Jul 2025 07:45:46 +0000 (09:45 +0200)
* src/editfns.c (Ftranspose_regions): Be careful that ELisp code could
move the gap from under our feet.

* test/src/editfns-tests.el (editfns-tests--bug76124): New test.

(cherry picked from commit b93d49a3787085407a9dd57d678d0fc552878fcc)

src/editfns.c
test/src/editfns-tests.el

index 714ed422b38a4b7374a19c428691a09ba3b40316..af53923f92c1a8d2853dd1e4417f75b8135e09b3 100644 (file)
@@ -4588,6 +4588,9 @@ ring.  */)
                             BUF_TS_LINECOL_POINT (current_buffer));
 #endif
 
+  /* Run the before-change-functions *before* we move the gap.  */
+  modify_text (start1, end2);
+
   /* Make sure the gap won't interfere, by moving it out of the text
      we will operate on.  */
   if (start1 < gap && gap < end2)
@@ -4632,7 +4635,6 @@ ring.  */)
      enough to use as the temporary storage?  That would avoid an
      allocation... interesting.  Later, don't fool with it now.  */
 
-  modify_text (start1, end2);
   tmp_interval1 = copy_intervals (cur_intv, start1, len1);
   tmp_interval2 = copy_intervals (cur_intv, start2, len2);
   USE_SAFE_ALLOCA;
index 9a27c420f1ed114eaa0f6b4c497f3c1d9a7c9880..2fce2315edb9b4a13f46378bc092ab236bc35619 100644 (file)
      (should (string= (format "%S" (format "%S %S" [1] (symbol-function '+)))
                       str))))
 
+(ert-deftest editfns-tests--bug76124 ()
+  (with-temp-buffer
+    (insert "Emacs forever!foo\n")
+    (insert "toto\n")
+    (goto-char (point-min))
+    ;; Remove the trailing "foo", so as to move the gap between the
+    ;; two lines.
+    (delete-region (- (pos-eol) 3) (pos-eol))
+    (add-hook 'before-change-functions
+              (lambda (beg end)
+                ;; Eglot uses `encode-coding-region' which can also move
+                ;; the gap, but let's do it more forcefully here.
+                (save-excursion
+                  (goto-char beg)
+                  (end-of-line)
+                  (unless (> (point) end)
+                    (with-silent-modifications
+                      (insert "foo")
+                      (delete-char -3)))))
+              nil t)
+    (goto-char (point-min))
+    (transpose-regions (pos-bol) (pos-eol)
+                       (pos-bol 2) (pos-eol 2))
+    (should (equal (buffer-string) "toto\nEmacs forever!\n"))))
+
 ;;; editfns-tests.el ends here