Commit 294efdbe authored by Richard M. Stallman's avatar Richard M. Stallman
Browse files

(verify_interval_modification): Handle insertions

specially.  For non-insertions, check only the chars being changed.
`modification-hooks' property is now a list of functions.
(set_point): Ignore chars outside current restriction.
parent 83ec8b67
/* Code for doing intervals. /* Code for doing intervals.
Copyright (C) 1991, 1992 Free Software Foundation, Inc. Copyright (C) 1993 Free Software Foundation, Inc.
This file is part of GNU Emacs. This file is part of GNU Emacs.
...@@ -1071,7 +1071,7 @@ make_new_interval (intervals, start, length) ...@@ -1071,7 +1071,7 @@ make_new_interval (intervals, start, length)
split_interval_right (slot, length + 1); split_interval_right (slot, length + 1);
return slot; return slot;
} }
/* Insert the intervals of SOURCE into BUFFER at POSITION. /* Insert the intervals of SOURCE into BUFFER at POSITION.
This is used in insdel.c when inserting Lisp_Strings into This is used in insdel.c when inserting Lisp_Strings into
...@@ -1225,7 +1225,7 @@ textget (plist, prop) ...@@ -1225,7 +1225,7 @@ textget (plist, prop)
} }
return Qnil; return Qnil;
} }
/* Set point in BUFFER to POSITION. If the target position is in /* Set point in BUFFER to POSITION. If the target position is in
after an invisible character which is not displayed with a special glyph, after an invisible character which is not displayed with a special glyph,
move back to an ok place to display. */ move back to an ok place to display. */
...@@ -1256,22 +1256,24 @@ set_point (position, buffer) ...@@ -1256,22 +1256,24 @@ set_point (position, buffer)
abort (); abort ();
/* Position Z is really one past the last char in the buffer. */ /* Position Z is really one past the last char in the buffer. */
if (position == BUF_Z (buffer)) if (position == BUF_ZV (buffer))
iposition = position - 1; iposition = position - 1;
/* Set TO to the interval containing the char after POSITION, /* Set TO to the interval containing the char after POSITION,
and TOPREV to the interval containing the char before POSITION. and TOPREV to the interval containing the char before POSITION.
Either one may be null. They may be equal. */ Either one may be null. They may be equal. */
to = find_interval (buffer->intervals, iposition); to = find_interval (buffer->intervals, iposition);
if (to->position == position) if (position == BUF_BEGV (buffer))
toprev = 0;
else if (to->position == position)
toprev = previous_interval (to); toprev = previous_interval (to);
else if (iposition != position) else if (iposition != position)
toprev = to, to = 0; toprev = to, to = 0;
else else
toprev = to; toprev = to;
buffer_point = (BUF_PT (buffer) == BUF_Z (buffer) buffer_point = (BUF_PT (buffer) == BUF_ZV (buffer)
? BUF_Z (buffer) - 1 ? BUF_ZV (buffer) - 1
: BUF_PT (buffer)); : BUF_PT (buffer));
/* Set FROM to the interval containing the char after PT, /* Set FROM to the interval containing the char after PT,
...@@ -1279,7 +1281,9 @@ set_point (position, buffer) ...@@ -1279,7 +1281,9 @@ set_point (position, buffer)
Either one may be null. They may be equal. */ Either one may be null. They may be equal. */
/* We could cache this and save time. */ /* We could cache this and save time. */
from = find_interval (buffer->intervals, buffer_point); from = find_interval (buffer->intervals, buffer_point);
if (from->position == BUF_PT (buffer)) if (from->position == BUF_BEGV (buffer))
fromprev = 0;
else if (from->position == BUF_PT (buffer))
fromprev = previous_interval (from); fromprev = previous_interval (from);
else if (buffer_point != BUF_PT (buffer)) else if (buffer_point != BUF_PT (buffer))
fromprev = from, from = 0; fromprev = from, from = 0;
...@@ -1353,6 +1357,22 @@ temp_set_point (position, buffer) ...@@ -1353,6 +1357,22 @@ temp_set_point (position, buffer)
{ {
buffer->text.pt = position; buffer->text.pt = position;
} }
/* Call the modification hook functions in LIST, each with START and END. */
static void
call_mod_hooks (list, start, end)
Lisp_Object list, start, end;
{
struct gcpro gcpro1;
GCPRO1 (list);
while (!NILP (list))
{
call2 (Fcar (list), start, end);
list = Fcdr (list);
}
UNGCPRO;
}
/* Check for read-only intervals and signal an error if we find one. /* Check for read-only intervals and signal an error if we find one.
Then check for any modification hooks in the range START up to Then check for any modification hooks in the range START up to
...@@ -1367,12 +1387,16 @@ verify_interval_modification (buf, start, end) ...@@ -1367,12 +1387,16 @@ verify_interval_modification (buf, start, end)
int start, end; int start, end;
{ {
register INTERVAL intervals = buf->intervals; register INTERVAL intervals = buf->intervals;
register INTERVAL i; register INTERVAL i, prev;
Lisp_Object hooks = Qnil; Lisp_Object hooks;
register prev_mod_hook = Qnil; register Lisp_Object prev_mod_hooks;
register Lisp_Object mod_hook; Lisp_Object mod_hooks;
struct gcpro gcpro1; struct gcpro gcpro1;
hooks = Qnil;
prev_mod_hooks = Qnil;
mod_hooks = Qnil;
if (NULL_INTERVAL_P (intervals)) if (NULL_INTERVAL_P (intervals))
return; return;
...@@ -1383,43 +1407,93 @@ verify_interval_modification (buf, start, end) ...@@ -1383,43 +1407,93 @@ verify_interval_modification (buf, start, end)
end = temp; end = temp;
} }
if (start == BUF_Z (buf)) /* For an insert operation, check the two chars around the position. */
if (start == end)
{ {
/* This should not be getting called on empty buffers. */ INTERVAL prev;
if (BUF_Z (buf) == 1) Lisp_Object before, after;
abort ();
i = find_interval (intervals, start - 1); /* Set I to the interval containing the char after START,
if (! END_STICKY_P (i)) and PREV to the interval containing the char before START.
return; Either one may be null. They may be equal. */
i = find_interval (intervals,
(start == BUF_ZV (buf) ? start - 1 : start));
if (start == BUF_BEGV (buf))
prev = 0;
if (i->position == start)
prev = previous_interval (i);
else if (i->position < start)
prev = i;
if (start == BUF_ZV (buf))
i = 0;
if (NULL_INTERVAL_P (prev))
{
after = textget (i, Qread_only);
if (! NILP (after))
error ("Attempt to insert within read-only text");
}
else if (NULL_INTERVAL_P (i))
{
before = textget (prev, Qread_only);
if (! NILP (before))
error ("Attempt to insert within read-only text");
}
else
{
before = textget (prev, Qread_only);
after = textget (i, Qread_only);
if (! NILP (before) && EQ (before, after))
error ("Attempt to insert within read-only text");
}
/* Run both mod hooks (just once if they're the same). */
if (!NULL_INTERVAL_P (prev))
prev_mod_hooks = textget (prev->plist, Qmodification_hooks);
if (!NULL_INTERVAL_P (i))
mod_hooks = textget (i->plist, Qmodification_hooks);
GCPRO1 (mod_hooks);
if (! NILP (prev_mod_hooks))
call_mod_hooks (prev_mod_hooks, make_number (start),
make_number (end));
UNGCPRO;
if (! NILP (mod_hooks) && ! EQ (mod_hooks, prev_mod_hooks))
call_mod_hooks (mod_hooks, make_number (start), make_number (end));
} }
else else
i = find_interval (intervals, start);
do
{ {
if (! INTERVAL_WRITABLE_P (i)) /* Loop over intervals on or next to START...END,
error ("Attempt to modify read-only text"); collecting their hooks. */
mod_hook = Fget (Qmodification, i->plist); i = find_interval (intervals, start);
if (! NILP (mod_hook) && ! EQ (mod_hook, prev_mod_hook)) do
{ {
hooks = Fcons (mod_hook, hooks); if (! INTERVAL_WRITABLE_P (i))
prev_mod_hook = mod_hook; error ("Attempt to modify read-only text");
}
i = next_interval (i); mod_hooks = textget (i->plist, Qmodification_hooks);
} if (! NILP (mod_hooks) && ! EQ (mod_hooks, prev_mod_hooks))
while (! NULL_INTERVAL_P (i) && i->position <= end); {
hooks = Fcons (mod_hooks, hooks);
prev_mod_hooks = mod_hooks;
}
GCPRO1 (hooks); i = next_interval (i);
hooks = Fnreverse (hooks); }
while (! EQ (hooks, Qnil)) /* Keep going thru the interval containing the char before END. */
{ while (! NULL_INTERVAL_P (i) && i->position < end);
call2 (Fcar (hooks), start, end - 1);
hooks = Fcdr (hooks); GCPRO1 (hooks);
hooks = Fnreverse (hooks);
while (! EQ (hooks, Qnil))
{
call_mod_hooks (Fcar (hooks), make_number (start),
make_number (end));
hooks = Fcdr (hooks);
}
UNGCPRO;
} }
UNGCPRO;
} }
/* Balance an interval node if the amount of text in its left and right /* Balance an interval node if the amount of text in its left and right
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment