diff options
author | Po Lu <luangruo@yahoo.com> | 2024-04-30 18:26:39 +0800 |
---|---|---|
committer | Po Lu <luangruo@yahoo.com> | 2024-04-30 18:28:05 +0800 |
commit | b36fd07560fd12c5e819e808a6f0eb9579f77c25 (patch) | |
tree | 81de96a5c2b3c0f5e0465a028c8c6b98e4e65ce0 /src | |
parent | aad80e1934f09b643b93aeb3bf9c1d583af6e2ec (diff) |
Fix deletion of text holding `inhibit-read-only' properties
* src/intervals.h (INTERVAL_VISIBLE_P): Split into ...
(INTERVAL_GENERALLY_WRITABLE_P, INTERVAL_EXPRESSLY_WRITABLE_P):
... two new macros.
* src/textprop.c (verify_interval_modification): If the buffer
is read only, verify not that there is only a single exempting
interval spanning the area of a multiple-character operation,
but that every intervening interval in such an operation exempts
it from write restrictions, either by providing a read-only
property that appears in Vinhibit_read_only, or by providing an
inhibit-read-only property.
* test/src/textprop-tests.el (textprop-interval-immutability):
New test.
Diffstat (limited to 'src')
-rw-r--r-- | src/intervals.h | 23 | ||||
-rw-r--r-- | src/textprop.c | 33 |
2 files changed, 41 insertions, 15 deletions
diff --git a/src/intervals.h b/src/intervals.h index 610c803cc77..5c6ef33a3a9 100644 --- a/src/intervals.h +++ b/src/intervals.h @@ -204,14 +204,21 @@ set_interval_plist (INTERVAL i, Lisp_Object plist) #define INTERVAL_VISIBLE_P(i) \ (i && NILP (textget ((i)->plist, Qinvisible))) -/* Is this interval writable? Replace later with cache access. */ -#define INTERVAL_WRITABLE_P(i) \ - (NILP (textget ((i)->plist, Qread_only)) \ - || !NILP (textget ((i)->plist, Qinhibit_read_only)) \ - || ((CONSP (Vinhibit_read_only) \ - ? !NILP (Fmemq (textget ((i)->plist, Qread_only), \ - Vinhibit_read_only)) \ - : !NILP (Vinhibit_read_only)))) +/* Is this interval writable by virtue of not being marked read-only, or + a general value of Vinhibit_read_only? Replace later with cache + access. */ +#define INTERVAL_GENERALLY_WRITABLE_P(i, ro) \ + (NILP (ro) || (!NILP (Vinhibit_read_only) \ + && !CONSP (Vinhibit_read_only))) + +/* Is this interval writable by virtue of an explicit inhibit-read-only + property, or the specific presence of its Qread_only property in + Vinhibit_read_only? */ +#define INTERVAL_EXPRESSLY_WRITABLE_P(i, ro) \ + (!NILP (textget ((i)->plist, Qinhibit_read_only)) \ + || (!NILP (ro) \ + && CONSP (Vinhibit_read_only) \ + && !NILP (Fmemq ((ro), Vinhibit_read_only)))) /* Macros to tell whether insertions before or after this interval should stick to it. Now we have Vtext_property_default_nonsticky, diff --git a/src/textprop.c b/src/textprop.c index 7d9aae0d2c5..84d6b5f1545 100644 --- a/src/textprop.c +++ b/src/textprop.c @@ -2186,6 +2186,7 @@ verify_interval_modification (struct buffer *buf, { INTERVAL intervals = buffer_intervals (buf); INTERVAL i; + ptrdiff_t p; Lisp_Object hooks; Lisp_Object prev_mod_hooks; Lisp_Object mod_hooks; @@ -2314,14 +2315,30 @@ verify_interval_modification (struct buffer *buf, } else { + bool buffer_read_only; + /* Loop over intervals on or next to START...END, collecting their hooks. */ + /* Extent of last writable interval. */ i = find_interval (intervals, start); + p = 0; + buffer_read_only = (!NILP (BVAR (current_buffer, read_only)) + && NILP (Vinhibit_read_only)); do { - if (! INTERVAL_WRITABLE_P (i)) - text_read_only (textget (i->plist, Qread_only)); + bool implied, express; + Lisp_Object read_only; + + read_only = textget ((i)->plist, Qread_only); + implied = INTERVAL_GENERALLY_WRITABLE_P (i, read_only); + express = INTERVAL_EXPRESSLY_WRITABLE_P (i, read_only); + if (!implied && !express) + text_read_only (read_only); + /* If this interval is only implicitly read only and the + buffer is read only as a whole, signal an error. */ + else if (!express && buffer_read_only) + xsignal1 (Qbuffer_read_only, Fcurrent_buffer ()); if (!inhibit_modification_hooks) { @@ -2333,16 +2350,18 @@ verify_interval_modification (struct buffer *buf, } } - if (i->position + LENGTH (i) < end - && (!NILP (BVAR (current_buffer, read_only)) - && NILP (Vinhibit_read_only))) - xsignal1 (Qbuffer_read_only, Fcurrent_buffer ()); - + p = i->position + LENGTH (i); i = next_interval (i); } /* Keep going thru the interval containing the char before END. */ while (i && i->position < end); + /* Should the buffer be read only while the last interval with an + `inhibit-read-only' property does not enclose the entire change + under consideration, signal error. */ + if (p < end && buffer_read_only) + xsignal1 (Qbuffer_read_only, Fcurrent_buffer ()); + if (!inhibit_modification_hooks) { hooks = Fnreverse (hooks); |