summaryrefslogtreecommitdiff
path: root/src/insdel.c
diff options
context:
space:
mode:
authorStefan Monnier <monnier@iro.umontreal.ca>2022-09-25 16:15:16 -0400
committerStefan Monnier <monnier@iro.umontreal.ca>2022-09-25 16:15:16 -0400
commit650c20f1ca4e07591a727e1cfcc74b3363d15985 (patch)
tree85d11f6437cde22f410c25e0e5f71a3131ebd07d /src/insdel.c
parent8869332684c2302b5ba1ead4568bbc7ba1c0183e (diff)
parent4b85ae6a24380fb67a3315eaec9233f17a872473 (diff)
downloademacs-650c20f1ca4e07591a727e1cfcc74b3363d15985.tar.gz
Merge 'master' into noverlay
Diffstat (limited to 'src/insdel.c')
-rw-r--r--src/insdel.c184
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);
}