X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/04d360e7bb114321e9b9e35f6e8edb8ec0766f18..2bfa3d3e1fb347ba76bddf77f3e288049635821d:/src/insdel.c diff --git a/src/insdel.c b/src/insdel.c index ed68426424..c6d89da6d5 100644 --- a/src/insdel.c +++ b/src/insdel.c @@ -1,6 +1,6 @@ /* Buffer insertion/deletion and gap motion for GNU Emacs. - Copyright (C) 1985-1986, 1993-1995, 1997-2013 Free Software - Foundation, Inc. + +Copyright (C) 1985-1986, 1993-1995, 1997-2014 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -214,9 +214,8 @@ void adjust_markers_for_delete (ptrdiff_t from, ptrdiff_t from_byte, ptrdiff_t to, ptrdiff_t to_byte) { - Lisp_Object marker; - register struct Lisp_Marker *m; - register ptrdiff_t charpos; + struct Lisp_Marker *m; + ptrdiff_t charpos; for (m = BUF_MARKERS (current_buffer); m; m = m->next) { @@ -233,34 +232,9 @@ adjust_markers_for_delete (ptrdiff_t from, ptrdiff_t from_byte, /* Here's the case where a marker is inside text being deleted. */ else if (charpos > from) { - if (! m->insertion_type) - { /* Normal 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. */ - XSETMISC (marker, m); - record_marker_adjustment (marker, from - charpos); - } - else if (charpos < to) - { /* Before-insertion 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. */ - XSETMISC (marker, m); - record_marker_adjustment (marker, to - charpos); - } m->charpos = from; m->bytepos = from_byte; } - /* Here's the case where a before-insertion marker is immediately - before the deleted region. */ - else if (charpos == from && m->insertion_type) - { - /* Undoing the change uses normal insertion, which will - incorrectly make MARKER move forward, so we arrange for it - to then move backward to the correct place at the beginning - of the deleted region. */ - XSETMISC (marker, m); - record_marker_adjustment (marker, to - from); - } } } @@ -727,7 +701,7 @@ count_combining_after (const unsigned char *string, (2) POS is the last of the current buffer. (3) A character at POS can't be a following byte of multibyte character. */ - if (length > 0 && ASCII_BYTE_P (string[length - 1])) /* case (1) */ + if (length > 0 && ASCII_CHAR_P (string[length - 1])) /* case (1) */ return 0; if (pos_byte == Z_BYTE) /* case (2) */ return 0; @@ -827,7 +801,7 @@ insert_1_both (const char *string, eassert (GPT <= GPT_BYTE); - /* The insert may have been in the unchanged region, so check again. */ + /* The insert may have been in the unchanged region, so check again. */ if (Z - GPT < END_UNCHANGED) END_UNCHANGED = Z - GPT; @@ -956,7 +930,7 @@ insert_from_string_1 (Lisp_Object string, ptrdiff_t pos, ptrdiff_t pos_byte, eassert (GPT <= GPT_BYTE); - /* The insert may have been in the unchanged region, so check again. */ + /* The insert may have been in the unchanged region, so check again. */ if (Z - GPT < END_UNCHANGED) END_UNCHANGED = Z - GPT; @@ -988,12 +962,16 @@ insert_from_string_1 (Lisp_Object string, ptrdiff_t pos, ptrdiff_t pos_byte, void insert_from_gap (ptrdiff_t nchars, ptrdiff_t nbytes, bool text_at_gap_tail) { - int ins_charpos = GPT; - int ins_bytepos = GPT_BYTE; + ptrdiff_t ins_charpos = GPT, ins_bytepos = GPT_BYTE; if (NILP (BVAR (current_buffer, enable_multibyte_characters))) nchars = nbytes; + /* No need to call prepare_to_modify_buffer, since this is called + from places that replace some region with a different text, so + prepare_to_modify_buffer was already called by the deletion part + of this dance. */ + invalidate_buffer_caches (current_buffer, GPT, GPT); record_insert (GPT, nchars); MODIFF++; @@ -1057,6 +1035,9 @@ insert_from_buffer_1 (struct buffer *buf, ptrdiff_t outgoing_nbytes = incoming_nbytes; INTERVAL intervals; + if (nchars == 0) + return; + /* Make OUTGOING_NBYTES describe the text as it will be inserted in this buffer. */ @@ -1146,7 +1127,7 @@ insert_from_buffer_1 (struct buffer *buf, eassert (GPT <= GPT_BYTE); - /* The insert may have been in the unchanged region, so check again. */ + /* The insert may have been in the unchanged region, so check again. */ if (Z - GPT < END_UNCHANGED) END_UNCHANGED = Z - GPT; @@ -1211,12 +1192,9 @@ adjust_after_replace (ptrdiff_t from, ptrdiff_t from_byte, adjust_markers_for_insert (from, from_byte, from + len, from_byte + len_byte, 0); - if (! EQ (BVAR (current_buffer, undo_list), Qt)) - { - if (nchars_del > 0) - record_delete (from, prev_text); - record_insert (from, len); - } + if (nchars_del > 0) + record_delete (from, prev_text, false); + record_insert (from, len); if (len > nchars_del) adjust_overlays_for_insert (from, len - nchars_del); @@ -1373,14 +1351,14 @@ replace_range (ptrdiff_t from, ptrdiff_t to, Lisp_Object new, emacs_abort (); #endif - if (! EQ (BVAR (current_buffer, undo_list), Qt)) + /* Record the insertion first, so that when we undo, + the deletion will be undone first. Thus, undo + will insert before deleting, and thus will keep + the markers before and after this text separate. */ + if (!NILP (deletion)) { - /* Record the insertion first, so that when we undo, - the deletion will be undone first. Thus, undo - will insert before deleting, and thus will keep - the markers before and after this text separate. */ record_insert (from + SCHARS (deletion), inschars); - record_delete (from, deletion); + record_delete (from, deletion, false); } GAP_SIZE -= outgoing_insbytes; @@ -1712,14 +1690,14 @@ del_range_2 (ptrdiff_t from, ptrdiff_t from_byte, else deletion = Qnil; - /* Relocate all markers pointing into the new, larger gap - to point at the end of the text before the gap. - Do this before recording the deletion, - so that undo handles this after reinserting the text. */ + /* Record marker adjustments, and text deletion into undo + history. */ + record_delete (from, deletion, true); + + /* Relocate all markers pointing into the new, larger gap to point + at the end of the text before the gap. */ adjust_markers_for_delete (from, from_byte, to, to_byte); - if (! EQ (BVAR (current_buffer, undo_list), Qt)) - record_delete (from, deletion); MODIFF++; CHARS_MODIFF = MODIFF; @@ -1760,31 +1738,28 @@ del_range_2 (ptrdiff_t from, ptrdiff_t from_byte, return deletion; } -/* Call this if you're about to change the region of current buffer +/* Call this if you're about to change the text of current buffer from character positions START to END. This checks the read-only properties of the region, calls the necessary modification hooks, and warns the next redisplay that it should pay attention to that - area. - - If PRESERVE_CHARS_MODIFF, do not update CHARS_MODIFF. - Otherwise set CHARS_MODIFF to the new value of MODIFF. */ + area. */ void -modify_region_1 (ptrdiff_t start, ptrdiff_t end, bool preserve_chars_modiff) +modify_text (ptrdiff_t start, ptrdiff_t end) { prepare_to_modify_buffer (start, end, NULL); BUF_COMPUTE_UNCHANGED (current_buffer, start - 1, end); - if (MODIFF <= SAVE_MODIFF) record_first_change (); MODIFF++; - if (! preserve_chars_modiff) - CHARS_MODIFF = MODIFF; + CHARS_MODIFF = MODIFF; bset_point_before_scroll (current_buffer, Qnil); } +Lisp_Object Qregion_extract_function; + /* Check that it is okay to modify the buffer between START and END, which are char positions. @@ -1796,19 +1771,15 @@ modify_region_1 (ptrdiff_t start, ptrdiff_t end, bool preserve_chars_modiff) by holding its value temporarily in a marker. */ void -prepare_to_modify_buffer (ptrdiff_t start, ptrdiff_t end, - ptrdiff_t *preserve_ptr) +prepare_to_modify_buffer_1 (ptrdiff_t start, ptrdiff_t end, + ptrdiff_t *preserve_ptr) { struct buffer *base_buffer; if (!NILP (BVAR (current_buffer, read_only))) Fbarf_if_buffer_read_only (); - /* If we're modifying the buffer other than shown in a selected window, - let redisplay consider other windows if this buffer is visible. */ - if (XBUFFER (XWINDOW (selected_window)->contents) != current_buffer - && buffer_window_count (current_buffer)) - ++windows_or_buffers_changed; + bset_redisplay (current_buffer); if (buffer_intervals (current_buffer)) { @@ -1833,54 +1804,93 @@ prepare_to_modify_buffer (ptrdiff_t start, ptrdiff_t end, else base_buffer = current_buffer; -#ifdef CLASH_DETECTION + if (inhibit_modification_hooks) + return; + if (!NILP (BVAR (base_buffer, file_truename)) /* Make binding buffer-file-name to nil effective. */ && !NILP (BVAR (base_buffer, filename)) && SAVE_MODIFF >= MODIFF) lock_file (BVAR (base_buffer, file_truename)); -#else - /* At least warn if this file has changed on disk since it was visited. */ - if (!NILP (BVAR (base_buffer, filename)) - && SAVE_MODIFF >= MODIFF - && NILP (Fverify_visited_file_modtime (Fcurrent_buffer ())) - && !NILP (Ffile_exists_p (BVAR (base_buffer, filename)))) - call1 (intern ("ask-user-about-supersession-threat"), - BVAR (base_buffer,filename)); -#endif /* not CLASH_DETECTION */ /* If `select-active-regions' is non-nil, save the region text. */ + /* FIXME: Move this to Elisp (via before-change-functions). */ if (!NILP (BVAR (current_buffer, mark_active)) - && !inhibit_modification_hooks && XMARKER (BVAR (current_buffer, mark))->buffer && NILP (Vsaved_region_selection) && (EQ (Vselect_active_regions, Qonly) ? EQ (CAR_SAFE (Vtransient_mark_mode), Qonly) : (!NILP (Vselect_active_regions) && !NILP (Vtransient_mark_mode)))) - { - ptrdiff_t b = marker_position (BVAR (current_buffer, mark)); - ptrdiff_t e = PT; - if (b < e) - Vsaved_region_selection = make_buffer_string (b, e, 0); - else if (b > e) - Vsaved_region_selection = make_buffer_string (e, b, 0); - } + Vsaved_region_selection + = call1 (Fsymbol_value (Qregion_extract_function), Qnil); signal_before_change (start, end, preserve_ptr); + Vdeactivate_mark = Qt; +} - if (current_buffer->newline_cache) - invalidate_region_cache (current_buffer, - current_buffer->newline_cache, - start - BEG, Z - end); - if (current_buffer->width_run_cache) - invalidate_region_cache (current_buffer, - current_buffer->width_run_cache, - start - BEG, Z - end); +/* Like above, but called when we know that the buffer text + will be modified and region caches should be invalidated. */ - Vdeactivate_mark = Qt; +void +prepare_to_modify_buffer (ptrdiff_t start, ptrdiff_t end, + ptrdiff_t *preserve_ptr) +{ + prepare_to_modify_buffer_1 (start, end, preserve_ptr); + invalidate_buffer_caches (current_buffer, start, end); } - + +/* Invalidate the caches maintained by the buffer BUF, if any, for the + region between buffer positions START and END. */ +void +invalidate_buffer_caches (struct buffer *buf, ptrdiff_t start, ptrdiff_t end) +{ + /* Indirect buffers usually have their caches set to NULL, but we + need to consider the caches of their base buffer. */ + if (buf->base_buffer) + buf = buf->base_buffer; + /* The bidi_paragraph_cache must be invalidated first, because doing + so might need to use the newline_cache (via find_newline_no_quit, + see below). */ + if (buf->bidi_paragraph_cache) + { + if (start != end + && start > BUF_BEG (buf)) + { + /* If we are deleting or replacing characters, we could + create a paragraph start, because all of the characters + from START to the beginning of START's line are + whitespace. Therefore, we must extend the region to be + invalidated up to the newline before START. */ + ptrdiff_t line_beg = start; + ptrdiff_t start_byte = buf_charpos_to_bytepos (buf, start); + + if (BUF_FETCH_BYTE (buf, start_byte - 1) != '\n') + { + struct buffer *old = current_buffer; + + set_buffer_internal (buf); + + line_beg = find_newline_no_quit (start, start_byte, -1, + &start_byte); + set_buffer_internal (old); + } + start = line_beg - (line_beg > BUF_BEG (buf)); + } + invalidate_region_cache (buf, + buf->bidi_paragraph_cache, + start - BUF_BEG (buf), BUF_Z (buf) - end); + } + if (buf->newline_cache) + invalidate_region_cache (buf, + buf->newline_cache, + start - BUF_BEG (buf), BUF_Z (buf) - end); + if (buf->width_run_cache) + invalidate_region_cache (buf, + buf->width_run_cache, + start - BUF_BEG (buf), BUF_Z (buf) - end); +} + /* These macros work with an argument named `preserve_ptr' and a local variable named `preserve_marker'. */ @@ -1913,12 +1923,18 @@ prepare_to_modify_buffer (ptrdiff_t start, ptrdiff_t end, VARIABLE is the variable to maybe set to nil. NO-ERROR-FLAG is nil if there was an error, anything else meaning no error (so this function does nothing). */ -static Lisp_Object -reset_var_on_error (Lisp_Object val) +struct rvoe_arg { - if (NILP (XCDR (val))) - Fset (XCAR (val), Qnil); - return Qnil; + Lisp_Object *location; + bool errorp; +}; + +static void +reset_var_on_error (void *ptr) +{ + struct rvoe_arg *p = ptr; + if (p->errorp) + *p->location = Qnil; } /* Signal a change to the buffer immediately before it happens. @@ -1935,10 +1951,8 @@ signal_before_change (ptrdiff_t start_int, ptrdiff_t end_int, Lisp_Object start_marker, end_marker; Lisp_Object preserve_marker; struct gcpro gcpro1, gcpro2, gcpro3; - ptrdiff_t count = SPECPDL_INDEX (); - - if (inhibit_modification_hooks) - return; + dynwind_begin (); + struct rvoe_arg rvoe_arg; start = make_number (start_int); end = make_number (end_int); @@ -1950,7 +1964,7 @@ signal_before_change (ptrdiff_t start_int, ptrdiff_t end_int, specbind (Qinhibit_modification_hooks, Qt); /* If buffer is unmodified, run a special hook for that case. The - check for Vfirst_change_hook is just a minor optimization. */ + check for Vfirst_change_hook is just a minor optimization. */ if (SAVE_MODIFF >= MODIFF && !NILP (Vfirst_change_hook)) { @@ -1963,13 +1977,14 @@ signal_before_change (ptrdiff_t start_int, ptrdiff_t end_int, if (!NILP (Vbefore_change_functions)) { Lisp_Object args[3]; - Lisp_Object rvoe_arg = Fcons (Qbefore_change_functions, Qnil); + rvoe_arg.location = &Vbefore_change_functions; + rvoe_arg.errorp = 1; PRESERVE_VALUE; PRESERVE_START_END; /* Mark before-change-functions to be reset to nil in case of error. */ - record_unwind_protect (reset_var_on_error, rvoe_arg); + record_unwind_protect_ptr (reset_var_on_error, &rvoe_arg); /* Actually run the hook functions. */ args[0] = Qbefore_change_functions; @@ -1978,7 +1993,7 @@ signal_before_change (ptrdiff_t start_int, ptrdiff_t end_int, Frun_hook_with_args (3, args); /* There was no error: unarm the reset_on_error. */ - XSETCDR (rvoe_arg, Qt); + rvoe_arg.errorp = 0; } if (buffer_has_overlays ()) @@ -1988,14 +2003,10 @@ signal_before_change (ptrdiff_t start_int, ptrdiff_t end_int, FETCH_START, FETCH_END, Qnil); } - if (! NILP (start_marker)) - free_marker (start_marker); - if (! NILP (end_marker)) - free_marker (end_marker); RESTORE_VALUE; UNGCPRO; - unbind_to (count, Qnil); + dynwind_end (); } /* Signal a change immediately after it happens. @@ -2008,9 +2019,13 @@ signal_before_change (ptrdiff_t start_int, ptrdiff_t end_int, void signal_after_change (ptrdiff_t charpos, ptrdiff_t lendel, ptrdiff_t lenins) { - ptrdiff_t count = SPECPDL_INDEX (); - if (inhibit_modification_hooks) + dynwind_begin (); + struct rvoe_arg rvoe_arg; + + if (inhibit_modification_hooks) { + dynwind_end (); return; + } /* If we are deferring calls to the after-change functions and there are no before-change functions, @@ -2031,6 +2046,7 @@ signal_after_change (ptrdiff_t charpos, ptrdiff_t lendel, ptrdiff_t lenins) = Fcons (elt, combine_after_change_list); combine_after_change_buffer = Fcurrent_buffer (); + dynwind_end (); return; } @@ -2042,10 +2058,11 @@ signal_after_change (ptrdiff_t charpos, ptrdiff_t lendel, ptrdiff_t lenins) if (!NILP (Vafter_change_functions)) { Lisp_Object args[4]; - Lisp_Object rvoe_arg = Fcons (Qafter_change_functions, Qnil); + rvoe_arg.location = &Vafter_change_functions; + rvoe_arg.errorp = 1; /* Mark after-change-functions to be reset to nil in case of error. */ - record_unwind_protect (reset_var_on_error, rvoe_arg); + record_unwind_protect_ptr (reset_var_on_error, &rvoe_arg); /* Actually run the hook functions. */ args[0] = Qafter_change_functions; @@ -2055,7 +2072,7 @@ signal_after_change (ptrdiff_t charpos, ptrdiff_t lendel, ptrdiff_t lenins) Frun_hook_with_args (4, args); /* There was no error: unarm the reset_on_error. */ - XSETCDR (rvoe_arg, Qt); + rvoe_arg.errorp = 0; } if (buffer_has_overlays ()) @@ -2072,14 +2089,13 @@ signal_after_change (ptrdiff_t charpos, ptrdiff_t lendel, ptrdiff_t lenins) report_interval_modification (make_number (charpos), make_number (charpos + lenins)); - unbind_to (count, Qnil); + dynwind_end (); } -static Lisp_Object +static void Fcombine_after_change_execute_1 (Lisp_Object val) { Vcombine_after_change_calls = val; - return val; } DEFUN ("combine-after-change-execute", Fcombine_after_change_execute, @@ -2087,13 +2103,15 @@ DEFUN ("combine-after-change-execute", Fcombine_after_change_execute, doc: /* This function is for use internally in the function `combine-after-change-calls'. */) (void) { - ptrdiff_t count = SPECPDL_INDEX (); + dynwind_begin (); ptrdiff_t beg, end, change; ptrdiff_t begpos, endpos; Lisp_Object tail; - if (NILP (combine_after_change_list)) + if (NILP (combine_after_change_list)) { + dynwind_end (); return Qnil; + } /* It is rare for combine_after_change_buffer to be invalid, but possible. It can happen when combine-after-change-calls is @@ -2103,6 +2121,7 @@ DEFUN ("combine-after-change-execute", Fcombine_after_change_execute, || !BUFFER_LIVE_P (XBUFFER (combine_after_change_buffer))) { combine_after_change_list = Qnil; + dynwind_end (); return Qnil; } @@ -2164,12 +2183,15 @@ DEFUN ("combine-after-change-execute", Fcombine_after_change_execute, signal_after_change (begpos, endpos - begpos - change, endpos - begpos); update_compositions (begpos, endpos, CHECK_ALL); - return unbind_to (count, Qnil); + dynwind_end (); + return Qnil; } void syms_of_insdel (void) { +#include "insdel.x" + staticpro (&combine_after_change_list); staticpro (&combine_after_change_buffer); combine_after_change_list = Qnil; @@ -2186,5 +2208,5 @@ as well as hooks attached to text properties and overlays. */); inhibit_modification_hooks = 0; DEFSYM (Qinhibit_modification_hooks, "inhibit-modification-hooks"); - defsubr (&Scombine_after_change_execute); + DEFSYM (Qregion_extract_function, "region-extract-function"); }