/* 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, bool record_markers) { Lisp_Object sbeg; if (EQ (BVAR (current_buffer, undo_list), Qt)) return; if (point_before_last_command_or_undo != beg && buffer_before_last_command_or_undo == current_buffer) record_point (point_before_last_command_or_undo); if (PT == beg + SCHARS (string)) { XSETINT (sbeg, -beg); prepare_record (); } else { XSETFASTINT (sbeg, beg); prepare_record (); } /* 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 (string, sbeg), BVAR (current_buffer, undo_list))); }
void record_insert (ptrdiff_t beg, ptrdiff_t length) { Lisp_Object lbeg, lend; if (EQ (BVAR (current_buffer, undo_list), Qt)) return; prepare_record (); record_point (beg); /* If this is following another insertion and consecutive with it in the buffer, combine the two. */ if (CONSP (BVAR (current_buffer, undo_list))) { Lisp_Object elt; elt = XCAR (BVAR (current_buffer, undo_list)); if (CONSP (elt) && INTEGERP (XCAR (elt)) && INTEGERP (XCDR (elt)) && XINT (XCDR (elt)) == beg) { XSETCDR (elt, make_number (beg + length)); return; } } XSETFASTINT (lbeg, beg); XSETINT (lend, beg + length); bset_undo_list (current_buffer, Fcons (Fcons (lbeg, lend), BVAR (current_buffer, undo_list))); }
/* Record point as it was at beginning of this command. PT is the position of point that will naturally occur as a result of the undo record that will be added just after this command terminates. */ static void record_point (ptrdiff_t pt) { /* Don't record position of pt when undo_inhibit_record_point holds. */ if (undo_inhibit_record_point) return; bool at_boundary; at_boundary = ! CONSP (BVAR (current_buffer, undo_list)) || NILP (XCAR (BVAR (current_buffer, undo_list))); prepare_record (); /* If we are just after an undo boundary, and point wasn't at start of deleted range, record where it was. */ if (at_boundary) bset_undo_list (current_buffer, Fcons (make_number (pt), BVAR (current_buffer, undo_list))); }
void record_property_change (ptrdiff_t beg, ptrdiff_t length, Lisp_Object prop, Lisp_Object value, Lisp_Object buffer) { Lisp_Object lbeg, lend, entry; struct buffer *buf = XBUFFER (buffer); if (EQ (BVAR (buf, undo_list), Qt)) return; prepare_record(); if (MODIFF <= SAVE_MODIFF) record_first_change (); XSETINT (lbeg, beg); XSETINT (lend, beg + length); entry = Fcons (Qnil, Fcons (prop, Fcons (value, Fcons (lbeg, lend)))); bset_undo_list (current_buffer, Fcons (entry, BVAR (current_buffer, undo_list))); }
static void record_marker_adjustments (ptrdiff_t from, ptrdiff_t to) { Lisp_Object marker; register struct Lisp_Marker *m; register ptrdiff_t charpos, adjustment; prepare_record(); 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))); } } } }