X-Git-Url: https://git.hcoop.net/bpt/emacs.git/blobdiff_plain/21733e4f154f8830fa568a347a0d6dbd59793c2b..HEAD:/src/undo.c diff --git a/src/undo.c b/src/undo.c index 63edc8e9b8..66b038e6ef 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-2014 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -55,7 +55,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 +75,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 +128,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 +200,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 +218,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, 1), false); record_insert (beg, length); } @@ -229,10 +241,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 +256,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 = 0; if (EQ (BVAR (buf, undo_list), Qt)) return; @@ -317,10 +328,8 @@ truncate_undo_list (struct buffer *b) Lisp_Object list; Lisp_Object prev, next, last_boundary; EMACS_INT size_so_far = 0; - - /* Make sure that calling undo-outer-limit-function - won't cause another GC. */ - ptrdiff_t count = inhibit_garbage_collection (); + dynwind_begin (); + static const size_t sizeof_cons = sizeof (scm_t_cell); /* Make the buffer current to get its local values of variables such as undo_limit. Also so that Vundo_outer_limit_function can @@ -338,7 +347,7 @@ truncate_undo_list (struct buffer *b) if (CONSP (next) && NILP (XCAR (next))) { /* Add in the space occupied by this element and its chain link. */ - size_so_far += sizeof (struct Lisp_Cons); + size_so_far += sizeof_cons; /* Advance to next element. */ prev = next; @@ -357,10 +366,10 @@ truncate_undo_list (struct buffer *b) elt = XCAR (next); /* Add in the space occupied by this element and its chain link. */ - size_so_far += sizeof (struct Lisp_Cons); + size_so_far += sizeof_cons; if (CONSP (elt)) { - size_so_far += sizeof (struct Lisp_Cons); + size_so_far += sizeof_cons; if (STRINGP (XCAR (elt))) size_so_far += (sizeof (struct Lisp_String) - 1 + SCHARS (XCAR (elt))); @@ -386,7 +395,7 @@ truncate_undo_list (struct buffer *b) { /* The function is responsible for making any desired changes in buffer-undo-list. */ - unbind_to (count, Qnil); + dynwind_end (); return; } /* That function probably used the minibuffer, and if so, that @@ -418,10 +427,10 @@ truncate_undo_list (struct buffer *b) } /* Add in the space occupied by this element and its chain link. */ - size_so_far += sizeof (struct Lisp_Cons); + size_so_far += sizeof_cons; if (CONSP (elt)) { - size_so_far += sizeof (struct Lisp_Cons); + size_so_far += sizeof_cons; if (STRINGP (XCAR (elt))) size_so_far += (sizeof (struct Lisp_String) - 1 + SCHARS (XCAR (elt))); @@ -442,19 +451,15 @@ truncate_undo_list (struct buffer *b) else bset_undo_list (b, Qnil); - unbind_to (count, Qnil); -} - -static _Noreturn void -user_error (const char *msg) -{ - xsignal1 (Quser_error, build_string (msg)); + dynwind_end (); } void syms_of_undo (void) { +#include "undo.x" + DEFSYM (Qinhibit_read_only, "inhibit-read-only"); DEFSYM (Qapply, "apply"); @@ -464,8 +469,6 @@ syms_of_undo (void) last_undo_buffer = NULL; last_boundary_buffer = NULL; - defsubr (&Sundo_boundary); - DEFVAR_INT ("undo-limit", undo_limit, doc: /* Keep no more undo information once it exceeds this size. This limit is applied when garbage collection happens.