X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/0273a428450950cf846767982cdb77cc9937a1f3..d3155315c85212f224fc5df0239182dafdfd6284:/src/undo.c diff --git a/src/undo.c b/src/undo.c index 63edc8e9b8..750bc8afff 100644 --- a/src/undo.c +++ b/src/undo.c @@ -1,5 +1,5 @@ /* undo handling for GNU Emacs. - Copyright (C) 1990, 1993-1994, 2000-2013 Free Software Foundation, + Copyright (C) 1990, 1993-1994, 2000-2015 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -34,12 +34,6 @@ static struct buffer *last_undo_buffer; static struct buffer *last_boundary_buffer; static ptrdiff_t last_boundary_position; -Lisp_Object Qinhibit_read_only; - -/* Marker for function call undo list elements. */ - -Lisp_Object Qapply; - /* The first time a command records something for undo. it also allocates the undo-boundary object which will be added to the list at the end of the command. @@ -55,7 +49,7 @@ static Lisp_Object pending_boundary; static void record_point (ptrdiff_t pt) { - int at_boundary; + bool at_boundary; /* Don't record position of pt when undo_inhibit_record_point holds. */ if (undo_inhibit_record_point) @@ -75,27 +69,8 @@ record_point (ptrdiff_t pt) Fundo_boundary (); last_undo_buffer = current_buffer; - if (CONSP (BVAR (current_buffer, undo_list))) - { - /* Set AT_BOUNDARY to 1 only when we have nothing other than - marker adjustment before undo boundary. */ - - Lisp_Object tail = BVAR (current_buffer, undo_list), elt; - - while (1) - { - if (NILP (tail)) - elt = Qnil; - else - elt = XCAR (tail); - if (NILP (elt) || ! (CONSP (elt) && MARKERP (XCAR (elt)))) - break; - tail = XCDR (tail); - } - at_boundary = NILP (elt); - } - else - at_boundary = 1; + at_boundary = ! CONSP (BVAR (current_buffer, undo_list)) + || NILP (XCAR (BVAR (current_buffer, undo_list))); if (MODIFF <= SAVE_MODIFF) record_first_change (); @@ -147,11 +122,61 @@ record_insert (ptrdiff_t beg, ptrdiff_t length) Fcons (Fcons (lbeg, lend), BVAR (current_buffer, undo_list))); } -/* Record that a deletion is about to take place, - of the characters in STRING, at location BEG. */ +/* Record the fact that markers in the region of FROM, TO are about to + be adjusted. This is done only when a marker points within text + being deleted, because that's the only case where an automatic + marker adjustment won't be inverted automatically by undoing the + buffer modification. */ + +static void +record_marker_adjustments (ptrdiff_t from, ptrdiff_t to) +{ + Lisp_Object marker; + register struct Lisp_Marker *m; + register ptrdiff_t charpos, adjustment; + + /* Allocate a cons cell to be the undo boundary after this command. */ + if (NILP (pending_boundary)) + pending_boundary = Fcons (Qnil, Qnil); + + if (current_buffer != last_undo_buffer) + Fundo_boundary (); + last_undo_buffer = current_buffer; + + for (m = BUF_MARKERS (current_buffer); m; m = m->next) + { + charpos = m->charpos; + eassert (charpos <= Z); + + if (from <= charpos && charpos <= to) + { + /* insertion_type nil markers will end up at the beginning of + the re-inserted text after undoing a deletion, and must be + adjusted to move them to the correct place. + + insertion_type t markers will automatically move forward + upon re-inserting the deleted text, so we have to arrange + for them to move backward to the correct position. */ + adjustment = (m->insertion_type ? to : from) - charpos; + + if (adjustment) + { + XSETMISC (marker, m); + bset_undo_list + (current_buffer, + Fcons (Fcons (marker, make_number (adjustment)), + BVAR (current_buffer, undo_list))); + } + } + } +} + +/* Record that a deletion is about to take place, of the characters in + STRING, at location BEG. Optionally record adjustments for markers + in the region STRING occupies in the current buffer. */ void -record_delete (ptrdiff_t beg, Lisp_Object string) +record_delete (ptrdiff_t beg, Lisp_Object string, bool record_markers) { Lisp_Object sbeg; @@ -169,34 +194,15 @@ record_delete (ptrdiff_t beg, Lisp_Object string) record_point (beg); } - bset_undo_list - (current_buffer, - Fcons (Fcons (string, sbeg), BVAR (current_buffer, undo_list))); -} - -/* Record the fact that MARKER is about to be adjusted by ADJUSTMENT. - This is done only when a marker points within text being deleted, - because that's the only case where an automatic marker adjustment - won't be inverted automatically by undoing the buffer modification. */ - -void -record_marker_adjustment (Lisp_Object marker, ptrdiff_t adjustment) -{ - if (EQ (BVAR (current_buffer, undo_list), Qt)) - return; - - /* Allocate a cons cell to be the undo boundary after this command. */ - if (NILP (pending_boundary)) - pending_boundary = Fcons (Qnil, Qnil); - - if (current_buffer != last_undo_buffer) - Fundo_boundary (); - last_undo_buffer = current_buffer; + /* primitive-undo assumes marker adjustments are recorded + immediately before the deletion is recorded. See bug 16818 + discussion. */ + if (record_markers) + record_marker_adjustments (beg, beg + SCHARS (string)); bset_undo_list (current_buffer, - Fcons (Fcons (marker, make_number (adjustment)), - BVAR (current_buffer, undo_list))); + Fcons (Fcons (string, sbeg), BVAR (current_buffer, undo_list))); } /* Record that a replacement is about to take place, @@ -206,7 +212,7 @@ record_marker_adjustment (Lisp_Object marker, ptrdiff_t adjustment) void record_change (ptrdiff_t beg, ptrdiff_t length) { - record_delete (beg, make_buffer_string (beg, beg + length, 1)); + record_delete (beg, make_buffer_string (beg, beg + length, true), false); record_insert (beg, length); } @@ -229,10 +235,9 @@ record_first_change (void) if (base_buffer->base_buffer) base_buffer = base_buffer->base_buffer; - bset_undo_list - (current_buffer, - Fcons (Fcons (Qt, make_lisp_time (base_buffer->modtime)), - BVAR (current_buffer, undo_list))); + bset_undo_list (current_buffer, + Fcons (Fcons (Qt, Fvisited_file_modtime ()), + BVAR (current_buffer, undo_list))); } /* Record a change in property PROP (whose old value was VAL) @@ -245,7 +250,7 @@ record_property_change (ptrdiff_t beg, ptrdiff_t length, { Lisp_Object lbeg, lend, entry; struct buffer *obuf = current_buffer, *buf = XBUFFER (buffer); - int boundary = 0; + bool boundary = false; if (EQ (BVAR (buf, undo_list), Qt)) return; @@ -255,7 +260,7 @@ record_property_change (ptrdiff_t beg, ptrdiff_t length, pending_boundary = Fcons (Qnil, Qnil); if (buf != last_undo_buffer) - boundary = 1; + boundary = true; last_undo_buffer = buf; /* Switch temporarily to the buffer that was changed. */ @@ -445,17 +450,13 @@ truncate_undo_list (struct buffer *b) unbind_to (count, Qnil); } -static _Noreturn void -user_error (const char *msg) -{ - xsignal1 (Quser_error, build_string (msg)); -} - void syms_of_undo (void) { DEFSYM (Qinhibit_read_only, "inhibit-read-only"); + + /* Marker for function call undo list elements. */ DEFSYM (Qapply, "apply"); pending_boundary = Qnil; @@ -518,5 +519,5 @@ so it must make sure not to do a lot of consing. */); DEFVAR_BOOL ("undo-inhibit-record-point", undo_inhibit_record_point, doc: /* Non-nil means do not record `point' in `buffer-undo-list'. */); - undo_inhibit_record_point = 0; + undo_inhibit_record_point = false; }