diff options
author | Stefan Monnier <monnier@iro.umontreal.ca> | 2022-09-25 16:15:16 -0400 |
---|---|---|
committer | Stefan Monnier <monnier@iro.umontreal.ca> | 2022-09-25 16:15:16 -0400 |
commit | 650c20f1ca4e07591a727e1cfcc74b3363d15985 (patch) | |
tree | 85d11f6437cde22f410c25e0e5f71a3131ebd07d /src/insdel.c | |
parent | 8869332684c2302b5ba1ead4568bbc7ba1c0183e (diff) | |
parent | 4b85ae6a24380fb67a3315eaec9233f17a872473 (diff) | |
download | emacs-650c20f1ca4e07591a727e1cfcc74b3363d15985.tar.gz emacs-650c20f1ca4e07591a727e1cfcc74b3363d15985.tar.bz2 emacs-650c20f1ca4e07591a727e1cfcc74b3363d15985.zip |
Merge 'master' into noverlay
Diffstat (limited to 'src/insdel.c')
-rw-r--r-- | src/insdel.c | 184 |
1 files changed, 123 insertions, 61 deletions
diff --git a/src/insdel.c b/src/insdel.c index 3e9f0c90e34..6d56a76c77a 100644 --- a/src/insdel.c +++ b/src/insdel.c @@ -1,5 +1,5 @@ /* Buffer insertion/deletion and gap motion for GNU Emacs. -*- coding: utf-8 -*- - Copyright (C) 1985-1986, 1993-1995, 1997-2017 Free Software + Copyright (C) 1985-1986, 1993-1995, 1997-2022 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -29,6 +29,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include "buffer.h" #include "window.h" #include "region-cache.h" +#include "pdumper.h" static void insert_from_string_1 (Lisp_Object, ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t, bool, bool); @@ -114,7 +115,7 @@ gap_left (ptrdiff_t charpos, ptrdiff_t bytepos, bool newgap) i = GPT_BYTE; to = GAP_END_ADDR; from = GPT_ADDR; - new_s1 = GPT_BYTE; + new_s1 = GPT_BYTE; /* May point in the middle of multibyte sequences. */ /* Now copy the characters. To move the gap down, copy characters up. */ @@ -132,11 +133,17 @@ gap_left (ptrdiff_t charpos, ptrdiff_t bytepos, bool newgap) make_gap_smaller set inhibit-quit. */ if (QUITP) { + /* FIXME: This can point in the middle of a multibyte character. */ bytepos = new_s1; charpos = BYTE_TO_CHAR (bytepos); break; } /* Move at most 32000 chars before checking again for a quit. */ + /* FIXME: This 32KB chunk size dates back to before 1991. + Maybe we should bump it to reflect the >1000x increase + in memory size and bandwidth since that time. + Is it even worthwhile checking `quit` within this loop? + Especially since make_gap_smaller/larger binds inhibit-quit anyway! */ if (i > 32000) i = 32000; new_s1 -= i; @@ -163,7 +170,7 @@ gap_right (ptrdiff_t charpos, ptrdiff_t bytepos) { register unsigned char *to, *from; register ptrdiff_t i; - ptrdiff_t new_s1; + ptrdiff_t new_s1; /* May point in the middle of multibyte sequences. */ BUF_COMPUTE_UNCHANGED (current_buffer, charpos, GPT); @@ -188,6 +195,7 @@ gap_right (ptrdiff_t charpos, ptrdiff_t bytepos) make_gap_smaller set inhibit-quit. */ if (QUITP) { + /* FIXME: This can point in the middle of a multibyte character. */ bytepos = new_s1; charpos = BYTE_TO_CHAR (bytepos); break; @@ -362,10 +370,10 @@ count_bytes (ptrdiff_t pos, ptrdiff_t bytepos, ptrdiff_t endpos) if (pos <= endpos) for ( ; pos < endpos; pos++) - INC_POS (bytepos); + bytepos += next_char_len (bytepos); else for ( ; pos > endpos; pos--) - DEC_POS (bytepos); + bytepos -= prev_char_len (bytepos); return bytepos; } @@ -606,8 +614,7 @@ copy_text (const unsigned char *from_addr, unsigned char *to_addr, while (bytes_left > 0) { - int thislen, c; - c = STRING_CHAR_AND_LENGTH (from_addr, thislen); + int thislen, c = string_char_and_length (from_addr, &thislen); if (! ASCII_CHAR_P (c)) c &= 0xFF; *to_addr++ = c; @@ -890,7 +897,7 @@ insert_1_both (const char *string, the insertion. This, together with recording the insertion, will add up to the right stuff in the undo list. */ record_insert (PT, nchars); - MODIFF++; + modiff_incr (&MODIFF, nchars); CHARS_MODIFF = MODIFF; memcpy (GPT_ADDR, string, nbytes); @@ -918,7 +925,7 @@ insert_1_both (const char *string, offset_intervals (current_buffer, PT, nchars); if (!inherit && buffer_intervals (current_buffer)) - set_text_properties (make_number (PT), make_number (PT + nchars), + set_text_properties (make_fixnum (PT), make_fixnum (PT + nchars), Qnil, Qnil, Qnil); adjust_point (nchars, nbytes); @@ -1018,7 +1025,7 @@ insert_from_string_1 (Lisp_Object string, ptrdiff_t pos, ptrdiff_t pos_byte, #endif record_insert (PT, nchars); - MODIFF++; + modiff_incr (&MODIFF, nchars); CHARS_MODIFF = MODIFF; GAP_SIZE -= outgoing_nbytes; @@ -1059,6 +1066,34 @@ insert_from_string_1 (Lisp_Object string, ptrdiff_t pos, ptrdiff_t pos_byte, /* Insert a sequence of NCHARS chars which occupy NBYTES bytes starting at GAP_END_ADDR - NBYTES (if text_at_gap_tail) and at + GPT_ADDR (if not text_at_gap_tail). + Contrary to insert_from_gap, this does not invalidate any cache, + nor update any markers, nor record any buffer modification information + of any sort. */ +void +insert_from_gap_1 (ptrdiff_t nchars, ptrdiff_t nbytes, bool text_at_gap_tail) +{ + eassert (NILP (BVAR (current_buffer, enable_multibyte_characters)) + ? nchars == nbytes : nchars <= nbytes); + + GAP_SIZE -= nbytes; + if (! text_at_gap_tail) + { + GPT += nchars; + GPT_BYTE += nbytes; + } + ZV += nchars; + Z += nchars; + ZV_BYTE += nbytes; + Z_BYTE += nbytes; + + /* Put an anchor to ensure multi-byte form ends at gap. */ + if (GAP_SIZE > 0) *(GPT_ADDR) = 0; + eassert (GPT <= GPT_BYTE); +} + +/* Insert a sequence of NCHARS chars which occupy NBYTES bytes + starting at GAP_END_ADDR - NBYTES (if text_at_gap_tail) and at GPT_ADDR (if not text_at_gap_tail). */ void @@ -1075,21 +1110,10 @@ insert_from_gap (ptrdiff_t nchars, ptrdiff_t nbytes, bool text_at_gap_tail) of this dance. */ invalidate_buffer_caches (current_buffer, GPT, GPT); record_insert (GPT, nchars); - MODIFF++; - - GAP_SIZE -= nbytes; - if (! text_at_gap_tail) - { - GPT += nchars; - GPT_BYTE += nbytes; - } - ZV += nchars; - Z += nchars; - ZV_BYTE += nbytes; - Z_BYTE += nbytes; - if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */ + modiff_incr (&MODIFF, nchars); + CHARS_MODIFF = MODIFF; - eassert (GPT <= GPT_BYTE); + insert_from_gap_1 (nchars, nbytes, text_at_gap_tail); adjust_overlays_for_insert (ins_charpos, nchars); adjust_markers_for_insert (ins_charpos, ins_bytepos, @@ -1215,7 +1239,7 @@ insert_from_buffer_1 (struct buffer *buf, #endif record_insert (PT, nchars); - MODIFF++; + modiff_incr (&MODIFF, nchars); CHARS_MODIFF = MODIFF; GAP_SIZE -= outgoing_nbytes; @@ -1316,7 +1340,7 @@ adjust_after_replace (ptrdiff_t from, ptrdiff_t from_byte, if (len == 0) evaporate_overlays (from); - MODIFF++; + modiff_incr (&MODIFF, nchars_del + len); CHARS_MODIFF = MODIFF; } @@ -1357,7 +1381,7 @@ adjust_after_insert (ptrdiff_t from, ptrdiff_t from_byte, void replace_range (ptrdiff_t from, ptrdiff_t to, Lisp_Object new, bool prepare, bool inherit, bool markers, - bool adjust_match_data) + bool adjust_match_data, bool inhibit_mod_hooks) { ptrdiff_t inschars = SCHARS (new); ptrdiff_t insbytes = SBYTES (new); @@ -1511,14 +1535,17 @@ replace_range (ptrdiff_t from, ptrdiff_t to, Lisp_Object new, check_markers (); - MODIFF++; + modiff_incr (&MODIFF, nchars_del + inschars); CHARS_MODIFF = MODIFF; if (adjust_match_data) update_search_regs (from, to, from + SCHARS (new)); - signal_after_change (from, nchars_del, GPT - from); - update_compositions (from, GPT, CHECK_BORDER); + if (!inhibit_mod_hooks) + { + signal_after_change (from, nchars_del, GPT - from); + update_compositions (from, GPT, CHECK_BORDER); + } } /* Replace the text from character positions FROM to TO with @@ -1642,7 +1669,7 @@ replace_range_2 (ptrdiff_t from, ptrdiff_t from_byte, check_markers (); - MODIFF++; + modiff_incr (&MODIFF, nchars_del + inschars); CHARS_MODIFF = MODIFF; } @@ -1817,7 +1844,7 @@ del_range_2 (ptrdiff_t from, ptrdiff_t from_byte, at the end of the text before the gap. */ adjust_markers_for_delete (from, from_byte, to, to_byte); - MODIFF++; + modiff_incr (&MODIFF, nchars_del); CHARS_MODIFF = MODIFF; /* Relocate point as if it were a marker. */ @@ -1871,7 +1898,7 @@ modify_text (ptrdiff_t start, ptrdiff_t end) BUF_COMPUTE_UNCHANGED (current_buffer, start - 1, end); if (MODIFF <= SAVE_MODIFF) record_first_change (); - MODIFF++; + modiff_incr (&MODIFF, end - start); CHARS_MODIFF = MODIFF; bset_point_before_scroll (current_buffer, Qnil); @@ -1915,6 +1942,14 @@ prepare_to_modify_buffer_1 (ptrdiff_t start, ptrdiff_t end, if (!NILP (BVAR (current_buffer, read_only))) Fbarf_if_buffer_read_only (temp); + /* If we're about to modify a buffer the contents of which come from + a dump file, copy the contents to private storage first so we + don't take a COW fault on the buffer text and keep it around + forever. */ + if (pdumper_object_p (BEG_ADDR)) + enlarge_buffer_text (current_buffer, 0); + eassert (!pdumper_object_p (BEG_ADDR)); + run_undoable_change(); bset_redisplay (current_buffer); @@ -1924,7 +1959,7 @@ prepare_to_modify_buffer_1 (ptrdiff_t start, ptrdiff_t end, if (preserve_ptr) { Lisp_Object preserve_marker; - preserve_marker = Fcopy_marker (make_number (*preserve_ptr), Qnil); + preserve_marker = Fcopy_marker (make_fixnum (*preserve_ptr), Qnil); verify_interval_modification (current_buffer, start, end); *preserve_ptr = marker_position (preserve_marker); unchain_marker (XMARKER (preserve_marker)); @@ -1946,7 +1981,7 @@ prepare_to_modify_buffer_1 (ptrdiff_t start, ptrdiff_t end, /* Make binding buffer-file-name to nil effective. */ && !NILP (BVAR (base_buffer, filename)) && SAVE_MODIFF >= MODIFF) - lock_file (BVAR (base_buffer, file_truename)); + Flock_file (BVAR (base_buffer, file_truename)); /* If `select-active-regions' is non-nil, save the region text. */ /* FIXME: Move this to Elisp (via before-change-functions). */ @@ -1958,7 +1993,7 @@ prepare_to_modify_buffer_1 (ptrdiff_t start, ptrdiff_t end, : (!NILP (Vselect_active_regions) && !NILP (Vtransient_mark_mode)))) Vsaved_region_selection - = call1 (Fsymbol_value (Qregion_extract_function), Qnil); + = call1 (Vregion_extract_function, Qnil); signal_before_change (start, end, preserve_ptr); Fset (Qdeactivate_mark, Qt); @@ -2034,7 +2069,7 @@ invalidate_buffer_caches (struct buffer *buf, ptrdiff_t start, ptrdiff_t end) #define PRESERVE_VALUE \ if (preserve_ptr && NILP (preserve_marker)) \ - preserve_marker = Fcopy_marker (make_number (*preserve_ptr), Qnil) + preserve_marker = Fcopy_marker (make_fixnum (*preserve_ptr), Qnil) #define RESTORE_VALUE \ if (! NILP (preserve_marker)) \ @@ -2088,11 +2123,11 @@ signal_before_change (ptrdiff_t start_int, ptrdiff_t end_int, Lisp_Object start, end; Lisp_Object start_marker, end_marker; Lisp_Object preserve_marker; - ptrdiff_t count = SPECPDL_INDEX (); + specpdl_ref count = SPECPDL_INDEX (); struct rvoe_arg rvoe_arg; - start = make_number (start_int); - end = make_number (end_int); + start = make_fixnum (start_int); + end = make_fixnum (end_int); preserve_marker = Qnil; start_marker = Qnil; end_marker = Qnil; @@ -2137,9 +2172,9 @@ signal_before_change (ptrdiff_t start_int, ptrdiff_t end_int, } if (! NILP (start_marker)) - free_marker (start_marker); + detach_marker (start_marker); if (! NILP (end_marker)) - free_marker (end_marker); + detach_marker (end_marker); RESTORE_VALUE; unbind_to (count, Qnil); @@ -2155,8 +2190,9 @@ 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 (); + specpdl_ref count = SPECPDL_INDEX (); struct rvoe_arg rvoe_arg; + Lisp_Object tmp, save_insert_behind_hooks, save_insert_in_from_hooks; if (inhibit_modification_hooks) return; @@ -2165,7 +2201,16 @@ signal_after_change (ptrdiff_t charpos, ptrdiff_t lendel, ptrdiff_t lenins) and there are no before-change functions, just record the args that we were going to use. */ if (! NILP (Vcombine_after_change_calls) - && NILP (Vbefore_change_functions) + /* It's OK to defer after-changes even if syntax-ppss-flush-cache + * is on before-change-functions, which is common enough to be worth + * adding a special case for it. */ + && (NILP (Vbefore_change_functions) + || (CONSP (Vbefore_change_functions) + && EQ (Qt, XCAR (Vbefore_change_functions)) + && NILP (Fdefault_value (Qbefore_change_functions)) + && CONSP (tmp = XCDR (Vbefore_change_functions)) + && NILP (XCDR (tmp)) + && EQ (XCAR (tmp), Qsyntax_ppss_flush_cache))) && !buffer_has_overlays ()) { Lisp_Object elt; @@ -2183,6 +2228,12 @@ signal_after_change (ptrdiff_t charpos, ptrdiff_t lendel, ptrdiff_t lenins) return; } + /* Save and restore the insert-*-hooks, because other hooks like + after-change-functions, called below, could clobber them if they + manipulate text properties. */ + save_insert_behind_hooks = interval_insert_behind_hooks; + save_insert_in_from_hooks = interval_insert_in_front_hooks; + if (!NILP (combine_after_change_list)) Fcombine_after_change_execute (); @@ -2198,26 +2249,29 @@ signal_after_change (ptrdiff_t charpos, ptrdiff_t lendel, ptrdiff_t lenins) /* Actually run the hook functions. */ CALLN (Frun_hook_with_args, Qafter_change_functions, - make_number (charpos), make_number (charpos + lenins), - make_number (lendel)); + make_fixnum (charpos), make_fixnum (charpos + lenins), + make_fixnum (lendel)); /* There was no error: unarm the reset_on_error. */ rvoe_arg.errorp = 0; } + interval_insert_behind_hooks = save_insert_behind_hooks; + interval_insert_in_front_hooks = save_insert_in_from_hooks; + if (buffer_has_overlays ()) - report_overlay_modification (make_number (charpos), - make_number (charpos + lenins), + report_overlay_modification (make_fixnum (charpos), + make_fixnum (charpos + lenins), 1, - make_number (charpos), - make_number (charpos + lenins), - make_number (lendel)); + make_fixnum (charpos), + make_fixnum (charpos + lenins), + make_fixnum (lendel)); /* After an insertion, call the text properties insert-behind-hooks or insert-in-front-hooks. */ if (lendel == 0) - report_interval_modification (make_number (charpos), - make_number (charpos + lenins)); + report_interval_modification (make_fixnum (charpos), + make_fixnum (charpos + lenins)); unbind_to (count, Qnil); } @@ -2233,7 +2287,7 @@ 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 (); + specpdl_ref count = SPECPDL_INDEX (); ptrdiff_t beg, end, change; ptrdiff_t begpos, endpos; Lisp_Object tail; @@ -2243,7 +2297,7 @@ DEFUN ("combine-after-change-execute", Fcombine_after_change_execute, /* It is rare for combine_after_change_buffer to be invalid, but possible. It can happen when combine-after-change-calls is - non-nil, and insertion calls a file handler (e.g. through + non-nil, and insertion calls a file name handler (e.g. through lock_file) which scribbles into a temp file -- cyd */ if (!BUFFERP (combine_after_change_buffer) || !BUFFER_LIVE_P (XBUFFER (combine_after_change_buffer))) @@ -2275,17 +2329,17 @@ DEFUN ("combine-after-change-execute", Fcombine_after_change_execute, elt = XCAR (tail); if (! CONSP (elt)) continue; - thisbeg = XINT (XCAR (elt)); + thisbeg = XFIXNUM (XCAR (elt)); elt = XCDR (elt); if (! CONSP (elt)) continue; - thisend = XINT (XCAR (elt)); + thisend = XFIXNUM (XCAR (elt)); elt = XCDR (elt); if (! CONSP (elt)) continue; - thischange = XINT (XCAR (elt)); + thischange = XFIXNUM (XCAR (elt)); /* Merge this range into the accumulated range. */ change += thischange; @@ -2322,6 +2376,7 @@ syms_of_insdel (void) combine_after_change_buffer = Qnil; DEFSYM (Qundo_auto__undoable_change, "undo-auto--undoable-change"); + DEFSYM (Qsyntax_ppss_flush_cache, "syntax-ppss-flush-cache"); DEFVAR_LISP ("combine-after-change-calls", Vcombine_after_change_calls, doc: /* Used internally by the function `combine-after-change-calls' macro. */); @@ -2330,11 +2385,18 @@ syms_of_insdel (void) DEFVAR_BOOL ("inhibit-modification-hooks", inhibit_modification_hooks, doc: /* Non-nil means don't run any of the hooks that respond to buffer changes. This affects `before-change-functions' and `after-change-functions', -as well as hooks attached to text properties and overlays. */); +as well as hooks attached to text properties and overlays. +Setting this variable non-nil also inhibits file locks and checks +whether files are locked by another Emacs session, as well as +handling of the active region per `select-active-regions'. + +To delay change hooks during a series of changes, use +`combine-change-calls' or `combine-after-change-calls' instead of +binding this variable. + +See also the info node `(elisp) Change Hooks'. */); inhibit_modification_hooks = 0; DEFSYM (Qinhibit_modification_hooks, "inhibit-modification-hooks"); - DEFSYM (Qregion_extract_function, "region-extract-function"); - defsubr (&Scombine_after_change_execute); } |