aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorBarry O'Reilly2014-03-24 22:47:39 -0400
committerBarry O'Reilly2014-03-24 22:47:39 -0400
commit37ea8275f7faad1192ddaba9f4a0789580675e17 (patch)
treecb6242b0298180f32d8c253c1b3aa8af3c6572fa /lisp
parent3e2377ce2f4eeb141ffbd000723c55813f78b08f (diff)
downloademacs-37ea8275f7faad1192ddaba9f4a0789580675e17.tar.gz
emacs-37ea8275f7faad1192ddaba9f4a0789580675e17.zip
Undo in region after markers in undo history relocated
* simple.el (primitive-undo): Only process marker adjustments validated against their corresponding (TEXT . POS). Issue warning for lone marker adjustments in undo history. (Bug#16818) (undo-make-selective-list): Add marker adjustments to selective undo list based on whether their corresponding (TEXT . POS) is in the region. Remove variable adjusted-markers, which was unused and only non nil during undo-make-selective-list. (undo-elt-in-region): Return nil when passed a marker adjustment and explain in function doc. Have (MARKER . ADJUSTMENT) undo records always be immediately after their corresponding (TEXT . POS) record in undo list. (Bug#16818) * lisp.h (record-delete): New arg record_markers. (record_marker_adjustment): No longer needed outside undo.c. * insdel.c (adjust_markers_for_delete): Move calculation of marker adjustments to undo.c's record_marker_adjustments. Note that fileio.c's decide_coding_unwind is another caller to adjust_markers_for_delete. Because it has undo list bound to t, it does not rely on adjust_markers_for_delete to record marker adjustments. (del_range_2): Swap call to record_delete and adjust_markers_for_delete so as undo marker adjustments are recorded before current deletion's adjustments, as before. (adjust_after_replace): (replace_range): Pass value for new record_markers arg to delete_record. * undo.c (record_marker_adjustment): Renamed to record_marker_adjustments and made static. (record_delete): Check record_markers arg and call record_marker_adjustments. (record_change): Pass value for new record_markers arg to delete_record. (record_point): at_boundary calculation no longer needs to account for marker adjustments. * undo-tests.el (undo-test-marker-adjustment-nominal): (undo-test-region-t-marker): New tests of marker adjustments. (undo-test-marker-adjustment-moved): (undo-test-region-mark-adjustment): New tests to demonstrate bug#16818, which fail without the fix. * markers.texi (Moving Marker Positions): The 2014-03-02 doc change mentioning undo's inability to handle relocated markers no longer applies. See bug#16818. * text.texi (Undo): Expand documentation of (TEXT . POS) and (MARKER . ADJUSTMENT) undo elements.
Diffstat (limited to 'lisp')
-rw-r--r--lisp/ChangeLog12
-rw-r--r--lisp/simple.el93
2 files changed, 71 insertions, 34 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 667b85729d7..b34a0b8bd7e 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,15 @@
12014-03-24 Barry O'Reilly <gundaetiapo@gmail.com>
2
3 * simple.el (primitive-undo): Only process marker adjustments
4 validated against their corresponding (TEXT . POS). Issue warning
5 for lone marker adjustments in undo history. (Bug#16818)
6 (undo-make-selective-list): Add marker adjustments to selective
7 undo list based on whether their corresponding (TEXT . POS) is in
8 the region. Remove variable adjusted-markers, which was unused
9 and only non nil during undo-make-selective-list.
10 (undo-elt-in-region): Return nil when passed a marker adjustment
11 and explain in function doc.
12
12014-03-24 Dmitry Gutov <dgutov@yandex.ru> 132014-03-24 Dmitry Gutov <dgutov@yandex.ru>
2 14
3 * emacs-lisp/package.el (package--add-to-archive-contents): 15 * emacs-lisp/package.el (package--add-to-archive-contents):
diff --git a/lisp/simple.el b/lisp/simple.el
index c8350005acc..7be1f1f6399 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -2289,24 +2289,41 @@ Return what remains of the list."
2289 (when (let ((apos (abs pos))) 2289 (when (let ((apos (abs pos)))
2290 (or (< apos (point-min)) (> apos (point-max)))) 2290 (or (< apos (point-min)) (> apos (point-max))))
2291 (error "Changes to be undone are outside visible portion of buffer")) 2291 (error "Changes to be undone are outside visible portion of buffer"))
2292 (if (< pos 0) 2292 (let (valid-marker-adjustments)
2293 (progn 2293 ;; Check that marker adjustments which were recorded
2294 (goto-char (- pos)) 2294 ;; with the (STRING . POS) record are still valid, ie
2295 (insert string)) 2295 ;; the markers haven't moved. We check their validity
2296 (goto-char pos) 2296 ;; before reinserting the string so as we don't need to
2297 ;; Now that we record marker adjustments 2297 ;; mind marker insertion-type.
2298 ;; (caused by deletion) for undo, 2298 (while (and (markerp (car-safe (car list)))
2299 ;; we should always insert after markers, 2299 (integerp (cdr-safe (car list))))
2300 ;; so that undoing the marker adjustments 2300 (let* ((marker-adj (pop list))
2301 ;; put the markers back in the right place. 2301 (m (car marker-adj)))
2302 (insert string) 2302 (and (eq (marker-buffer m) (current-buffer))
2303 (goto-char pos))) 2303 (= pos m)
2304 (push marker-adj valid-marker-adjustments))))
2305 ;; Insert string and adjust point
2306 (if (< pos 0)
2307 (progn
2308 (goto-char (- pos))
2309 (insert string))
2310 (goto-char pos)
2311 (insert string)
2312 (goto-char pos))
2313 ;; Adjust the valid marker adjustments
2314 (dolist (adj valid-marker-adjustments)
2315 (set-marker (car adj)
2316 (- (car adj) (cdr adj))))))
2304 ;; (MARKER . OFFSET) means a marker MARKER was adjusted by OFFSET. 2317 ;; (MARKER . OFFSET) means a marker MARKER was adjusted by OFFSET.
2305 (`(,(and marker (pred markerp)) . ,(and offset (pred integerp))) 2318 (`(,(and marker (pred markerp)) . ,(and offset (pred integerp)))
2306 (when (marker-buffer marker) 2319 (warn "Encountered %S entry in undo list with no matching (TEXT . POS) entry"
2307 (set-marker marker 2320 next)
2308 (- marker offset) 2321 ;; Even though these elements are not expected in the undo
2309 (marker-buffer marker)))) 2322 ;; list, adjust them to be conservative for the 24.4
2323 ;; release. (Bug#16818)
2324 (set-marker marker
2325 (- marker offset)
2326 (marker-buffer marker)))
2310 (_ (error "Unrecognized entry in undo list %S" next)))) 2327 (_ (error "Unrecognized entry in undo list %S" next))))
2311 (setq arg (1- arg))) 2328 (setq arg (1- arg)))
2312 ;; Make sure an apply entry produces at least one undo entry, 2329 ;; Make sure an apply entry produces at least one undo entry,
@@ -2341,8 +2358,6 @@ are ignored. If BEG and END are nil, all undo elements are used."
2341 (undo-make-selective-list (min beg end) (max beg end)) 2358 (undo-make-selective-list (min beg end) (max beg end))
2342 buffer-undo-list))) 2359 buffer-undo-list)))
2343 2360
2344(defvar undo-adjusted-markers)
2345
2346(defun undo-make-selective-list (start end) 2361(defun undo-make-selective-list (start end)
2347 "Return a list of undo elements for the region START to END. 2362 "Return a list of undo elements for the region START to END.
2348The elements come from `buffer-undo-list', but we keep only 2363The elements come from `buffer-undo-list', but we keep only
@@ -2351,7 +2366,6 @@ If we find an element that crosses an edge of this region,
2351we stop and ignore all further elements." 2366we stop and ignore all further elements."
2352 (let ((undo-list-copy (undo-copy-list buffer-undo-list)) 2367 (let ((undo-list-copy (undo-copy-list buffer-undo-list))
2353 (undo-list (list nil)) 2368 (undo-list (list nil))
2354 undo-adjusted-markers
2355 some-rejected 2369 some-rejected
2356 undo-elt temp-undo-list delta) 2370 undo-elt temp-undo-list delta)
2357 (while undo-list-copy 2371 (while undo-list-copy
@@ -2361,15 +2375,30 @@ we stop and ignore all further elements."
2361 ;; This is a "was unmodified" element. 2375 ;; This is a "was unmodified" element.
2362 ;; Keep it if we have kept everything thus far. 2376 ;; Keep it if we have kept everything thus far.
2363 (not some-rejected)) 2377 (not some-rejected))
2378 ;; Skip over marker adjustments, instead relying on
2379 ;; finding them after (TEXT . POS) elements
2380 ((markerp (car-safe undo-elt))
2381 nil)
2364 (t 2382 (t
2365 (undo-elt-in-region undo-elt start end))))) 2383 (undo-elt-in-region undo-elt start end)))))
2366 (if keep-this 2384 (if keep-this
2367 (progn 2385 (progn
2368 (setq end (+ end (cdr (undo-delta undo-elt)))) 2386 (setq end (+ end (cdr (undo-delta undo-elt))))
2369 ;; Don't put two nils together in the list 2387 ;; Don't put two nils together in the list
2370 (if (not (and (eq (car undo-list) nil) 2388 (when (not (and (eq (car undo-list) nil)
2371 (eq undo-elt nil))) 2389 (eq undo-elt nil)))
2372 (setq undo-list (cons undo-elt undo-list)))) 2390 (setq undo-list (cons undo-elt undo-list))
2391 ;; If (TEXT . POS), "keep" its subsequent (MARKER
2392 ;; . ADJUSTMENT) whose markers haven't moved.
2393 (when (and (stringp (car-safe undo-elt))
2394 (integerp (cdr-safe undo-elt)))
2395 (let ((list-i (cdr undo-list-copy)))
2396 (while (markerp (car-safe (car list-i)))
2397 (let* ((adj-elt (pop list-i))
2398 (m (car adj-elt)))
2399 (and (eq (marker-buffer m) (current-buffer))
2400 (= (cdr undo-elt) m)
2401 (push adj-elt undo-list))))))))
2373 (if (undo-elt-crosses-region undo-elt start end) 2402 (if (undo-elt-crosses-region undo-elt start end)
2374 (setq undo-list-copy nil) 2403 (setq undo-list-copy nil)
2375 (setq some-rejected t) 2404 (setq some-rejected t)
@@ -2417,7 +2446,12 @@ we stop and ignore all further elements."
2417 2446
2418(defun undo-elt-in-region (undo-elt start end) 2447(defun undo-elt-in-region (undo-elt start end)
2419 "Determine whether UNDO-ELT falls inside the region START ... END. 2448 "Determine whether UNDO-ELT falls inside the region START ... END.
2420If it crosses the edge, we return nil." 2449If it crosses the edge, we return nil.
2450
2451Generally this function is not useful for determining
2452whether (MARKER . ADJUSTMENT) undo elements are in the region,
2453because markers can be arbitrarily relocated. Instead, pass the
2454marker adjustment's corresponding (TEXT . POS) element."
2421 (cond ((integerp undo-elt) 2455 (cond ((integerp undo-elt)
2422 (and (>= undo-elt start) 2456 (and (>= undo-elt start)
2423 (<= undo-elt end))) 2457 (<= undo-elt end)))
@@ -2430,17 +2464,8 @@ If it crosses the edge, we return nil."
2430 (and (>= (abs (cdr undo-elt)) start) 2464 (and (>= (abs (cdr undo-elt)) start)
2431 (<= (abs (cdr undo-elt)) end))) 2465 (<= (abs (cdr undo-elt)) end)))
2432 ((and (consp undo-elt) (markerp (car undo-elt))) 2466 ((and (consp undo-elt) (markerp (car undo-elt)))
2433 ;; This is a marker-adjustment element (MARKER . ADJUSTMENT). 2467 ;; (MARKER . ADJUSTMENT)
2434 ;; See if MARKER is inside the region. 2468 (<= start (car undo-elt) end))
2435 (let ((alist-elt (assq (car undo-elt) undo-adjusted-markers)))
2436 (unless alist-elt
2437 (setq alist-elt (cons (car undo-elt)
2438 (marker-position (car undo-elt))))
2439 (setq undo-adjusted-markers
2440 (cons alist-elt undo-adjusted-markers)))
2441 (and (cdr alist-elt)
2442 (>= (cdr alist-elt) start)
2443 (<= (cdr alist-elt) end))))
2444 ((null (car undo-elt)) 2469 ((null (car undo-elt))
2445 ;; (nil PROPERTY VALUE BEG . END) 2470 ;; (nil PROPERTY VALUE BEG . END)
2446 (let ((tail (nthcdr 3 undo-elt))) 2471 (let ((tail (nthcdr 3 undo-elt)))