* simple.el (transpose-subr-1): Preserve marker positions
authorChong Yidong <cyd@gnu.org>
Fri, 21 Dec 2012 05:42:59 +0000 (13:42 +0800)
committerChong Yidong <cyd@gnu.org>
Fri, 21 Dec 2012 05:42:59 +0000 (13:42 +0800)
by changing the insertion sequence.

Fixes: debbugs:13122

lisp/ChangeLog
lisp/simple.el

index e89602c..a26fc63 100644 (file)
@@ -1,3 +1,8 @@
+2012-12-21  Chong Yidong  <cyd@gnu.org>
+
+       * simple.el (transpose-subr-1): Preserve marker positions by
+       changing the insertion sequence (Bug#13122).
+
 2012-12-21  Kelly Dean  <kellydeanch@yahoo.com>  (tiny change)
 
        * simple.el (kill-region): Deactivate mark even for empty regions
index 8c7e88d..c0ba547 100644 (file)
@@ -5300,14 +5300,21 @@ current object."
       (setq pos1 pos2 pos2 swap)))
   (if (> (cdr pos1) (car pos2)) (error "Don't have two things to transpose"))
   (atomic-change-group
-   (let (word2)
-     ;; FIXME: We first delete the two pieces of text, so markers that
-     ;; used to point to after the text end up pointing to before it :-(
-     (setq word2 (delete-and-extract-region (car pos2) (cdr pos2)))
-     (goto-char (car pos2))
-     (insert (delete-and-extract-region (car pos1) (cdr pos1)))
-     (goto-char (car pos1))
-     (insert word2))))
+    ;; This sequence of insertions attempts to preserve marker
+    ;; positions at the start and end of the transposed objects.
+    (let* ((word (buffer-substring (car pos2) (cdr pos2)))
+          (len1 (- (cdr pos1) (car pos1)))
+          (len2 (length word))
+          (boundary (make-marker)))
+      (set-marker boundary (car pos2))
+      (goto-char (cdr pos1))
+      (insert-before-markers word)
+      (setq word (delete-and-extract-region (car pos1) (+ (car pos1) len1)))
+      (goto-char boundary)
+      (insert word)
+      (goto-char (+ boundary len1))
+      (delete-region (point) (+ (point) len2))
+      (set-marker boundary nil))))
 \f
 (defun backward-word (&optional arg)
   "Move backward until encountering the beginning of a word.