diff options
| author | Barry O'Reilly | 2014-03-24 22:47:39 -0400 |
|---|---|---|
| committer | Barry O'Reilly | 2014-03-24 22:47:39 -0400 |
| commit | 37ea8275f7faad1192ddaba9f4a0789580675e17 (patch) | |
| tree | cb6242b0298180f32d8c253c1b3aa8af3c6572fa /lisp | |
| parent | 3e2377ce2f4eeb141ffbd000723c55813f78b08f (diff) | |
| download | emacs-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/ChangeLog | 12 | ||||
| -rw-r--r-- | lisp/simple.el | 93 |
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 @@ | |||
| 1 | 2014-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 | |||
| 1 | 2014-03-24 Dmitry Gutov <dgutov@yandex.ru> | 13 | 2014-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. |
| 2348 | The elements come from `buffer-undo-list', but we keep only | 2363 | The 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, | |||
| 2351 | we stop and ignore all further elements." | 2366 | we 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. |
| 2420 | If it crosses the edge, we return nil." | 2449 | If it crosses the edge, we return nil. |
| 2450 | |||
| 2451 | Generally this function is not useful for determining | ||
| 2452 | whether (MARKER . ADJUSTMENT) undo elements are in the region, | ||
| 2453 | because markers can be arbitrarily relocated. Instead, pass the | ||
| 2454 | marker 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))) |