Commit 3be11131 authored by Richard M. Stallman's avatar Richard M. Stallman
Browse files

(move_gap): Use move_gap_both.

(move_gap_both): New function.
(gap_left, gap_right): Take both charpos and bytepos args.
(adjust_markers_gap_motion): Renamed from adjust_markers and simplified.
(adjust_markers_for_delete): New function.
(adjust_markers_for_insert): Take args in chars and bytes.
Also new arg BEFORE_MARKERS.  One call does all marker updating
needed for any insert.
(adjust_point): Take 2 args and update PT and PT_BYTE.
(make_gap): Handle bytes vs chars.
(insert, insert_and_inherit): Handle bytes vs chars.
Pass new BEFORE_MARKERS arg to insert_1.
(insert_before_markers, insert_before_markers_and_inherit): Likewise.
(insert_from_string, insert_from_string_before_markers): Likewise.
(insert_from_buffer): Likewise.
(insert_1): Handle bytes vs chars.  New arg BEFORE_MARKERS.
(insert_from_string_1, insert_from_buffer_1): Likewise.
(replace_range): Likewise.
(del_range_2): New subroutine, taken from del_range_1.
(del_range_1): Use del_range_2.
(del_range_byte, del_range_both): New functions.
parent 604ee0f3
/* Buffer insertion/deletion and gap motion for GNU Emacs.
Copyright (C) 1985, 1986, 1993, 1994, 1995 Free Software Foundation, Inc.
Copyright (C) 1985, 86, 93, 94, 95, 1997 Free Software Foundation, Inc.
This file is part of GNU Emacs.
......@@ -33,12 +33,14 @@ Boston, MA 02111-1307, USA. */
#define min(x, y) ((x) < (y) ? (x) : (y))
static void insert_from_string_1 ();
static void insert_from_string_1 P_ ((Lisp_Object, int, int, int, int, int));
static void insert_from_buffer_1 ();
static void gap_left ();
static void gap_right ();
static void adjust_markers ();
static void adjust_point ();
static void gap_left P_ ((int, int, int));
static void gap_right P_ ((int, int));
static void adjust_markers_gap_motion P_ ((int, int, int));
static void adjust_markers_for_insert P_ ((int, int, int, int, int));
static void adjust_markers_for_delete P_ ((int, int, int, int));
static void adjust_point P_ ((int, int));
Lisp_Object Fcombine_after_change_execute ();
......@@ -61,54 +63,64 @@ Lisp_Object combine_after_change_list;
/* Buffer which combine_after_change_list is about. */
Lisp_Object combine_after_change_buffer;
/* Move gap to position `pos'.
/* Move gap to position CHARPOS.
Note that this can quit! */
void
move_gap (pos)
int pos;
move_gap (charpos)
int charpos;
{
if (pos < GPT)
gap_left (pos, 0);
else if (pos > GPT)
gap_right (pos);
move_gap_both (charpos, charpos_to_bytepos (charpos));
}
/* Move the gap to POS, which is less than the current GPT.
/* Move gap to byte position BYTEPOS, which is also char position CHARPOS.
Note that this can quit! */
void
move_gap_both (charpos, bytepos)
int charpos, bytepos;
{
if (bytepos < GPT_BYTE)
gap_left (charpos, bytepos, 0);
else if (bytepos > GPT_BYTE)
gap_right (charpos, bytepos);
}
/* Move the gap to a position less than the current GPT.
BYTEPOS describes the new position as a byte position,
and CHARPOS is the corresponding char position.
If NEWGAP is nonzero, then don't update beg_unchanged and end_unchanged. */
static void
gap_left (pos, newgap)
register int pos;
gap_left (charpos, bytepos, newgap)
register int charpos, bytepos;
int newgap;
{
register unsigned char *to, *from;
register int i;
int new_s1;
pos--;
if (!newgap)
{
if (unchanged_modified == MODIFF
&& overlay_unchanged_modified == OVERLAY_MODIFF)
{
beg_unchanged = pos;
end_unchanged = Z - pos - 1;
beg_unchanged = charpos - BEG;
end_unchanged = Z - charpos;
}
else
{
if (Z - GPT < end_unchanged)
end_unchanged = Z - GPT;
if (pos < beg_unchanged)
beg_unchanged = pos;
if (charpos < beg_unchanged)
beg_unchanged = charpos - BEG;
}
}
i = GPT;
i = GPT_BYTE;
to = GAP_END_ADDR;
from = GPT_ADDR;
new_s1 = GPT - BEG;
new_s1 = GPT_BYTE;
/* Now copy the characters. To move the gap down,
copy characters up. */
......@@ -116,14 +128,15 @@ gap_left (pos, newgap)
while (1)
{
/* I gets number of characters left to copy. */
i = new_s1 - pos;
i = new_s1 - bytepos;
if (i == 0)
break;
/* If a quit is requested, stop copying now.
Change POS to be where we have actually moved the gap to. */
Change BYTEPOS to be where we have actually moved the gap to. */
if (QUITP)
{
pos = new_s1;
bytepos = new_s1;
charpos = BYTE_TO_CHAR (bytepos);
break;
}
/* Move at most 32000 chars before checking again for a quit. */
......@@ -153,44 +166,48 @@ gap_left (pos, newgap)
}
}
/* Adjust markers, and buffer data structure, to put the gap at POS.
POS is where the loop above stopped, which may be what was specified
/* Adjust markers, and buffer data structure, to put the gap at BYTEPOS.
BYTEPOS is where the loop above stopped, which may be what was specified
or may be where a quit was detected. */
adjust_markers (pos + 1, GPT, GAP_SIZE);
GPT = pos + 1;
adjust_markers_gap_motion (bytepos, GPT_BYTE, GAP_SIZE);
GPT_BYTE = bytepos;
GPT = charpos;
if (bytepos < charpos)
abort ();
if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
QUIT;
}
/* Move the gap to a position greater than than the current GPT.
BYTEPOS describes the new position as a byte position,
and CHARPOS is the corresponding char position. */
static void
gap_right (pos)
register int pos;
gap_right (charpos, bytepos)
register int charpos, bytepos;
{
register unsigned char *to, *from;
register int i;
int new_s1;
pos--;
if (unchanged_modified == MODIFF
&& overlay_unchanged_modified == OVERLAY_MODIFF)
{
beg_unchanged = pos;
end_unchanged = Z - pos - 1;
beg_unchanged = charpos - BEG;
end_unchanged = Z - charpos;
}
else
{
if (Z - pos - 1 < end_unchanged)
end_unchanged = Z - pos - 1;
if (Z - charpos - 1 < end_unchanged)
end_unchanged = Z - charpos;
if (GPT - BEG < beg_unchanged)
beg_unchanged = GPT - BEG;
}
i = GPT;
i = GPT_BYTE;
from = GAP_END_ADDR;
to = GPT_ADDR;
new_s1 = GPT - 1;
new_s1 = GPT_BYTE;
/* Now copy the characters. To move the gap up,
copy characters down. */
......@@ -198,14 +215,15 @@ gap_right (pos)
while (1)
{
/* I gets number of characters left to copy. */
i = pos - new_s1;
i = bytepos - new_s1;
if (i == 0)
break;
/* If a quit is requested, stop copying now.
Change POS to be where we have actually moved the gap to. */
Change BYTEPOS to be where we have actually moved the gap to. */
if (QUITP)
{
pos = new_s1;
bytepos = new_s1;
charpos = BYTE_TO_CHAR (bytepos);
break;
}
/* Move at most 32000 chars before checking again for a quit. */
......@@ -235,14 +253,18 @@ gap_right (pos)
}
}
adjust_markers (GPT + GAP_SIZE, pos + 1 + GAP_SIZE, - GAP_SIZE);
GPT = pos + 1;
adjust_markers_gap_motion (GPT_BYTE + GAP_SIZE, bytepos + GAP_SIZE,
- GAP_SIZE);
GPT = charpos;
GPT_BYTE = bytepos;
if (bytepos < charpos)
abort ();
if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
QUIT;
}
/* Add AMOUNT to the position of every marker in the current buffer
whose current position is between FROM (exclusive) and TO (inclusive).
/* Add AMOUNT to the byte position of every marker in the current buffer
whose current byte position is between FROM (exclusive) and TO (inclusive).
Also, any markers past the outside of that interval, in the direction
of adjustment, are first moved back to the near end of the interval
......@@ -250,10 +272,15 @@ gap_right (pos)
When the latter adjustment is done, if AMOUNT is negative,
we record the adjustment for undo. (This case happens only for
deletion.) */
deletion.)
The markers' character positions are not altered,
because gap motion does not affect character positions. */
int adjust_markers_test;
static void
adjust_markers (from, to, amount)
adjust_markers_gap_motion (from, to, amount)
register int from, to, amount;
{
Lisp_Object marker;
......@@ -269,7 +296,11 @@ adjust_markers (from, to, amount)
if (amount > 0)
{
if (mpos > to && mpos < to + amount)
mpos = to + amount;
{
if (adjust_markers_test)
abort ();
mpos = to + amount;
}
}
else
{
......@@ -278,24 +309,9 @@ adjust_markers (from, to, amount)
but then this range contains no markers. */
if (mpos > from + amount && mpos <= from)
{
int before = mpos;
int after = from + amount;
mpos = after;
/* Compute the before and after positions
as buffer positions. */
if (before > GPT + GAP_SIZE)
before -= GAP_SIZE;
else if (before > GPT)
before = GPT;
if (after > GPT + GAP_SIZE)
after -= GAP_SIZE;
else if (after > GPT)
after = GPT;
record_marker_adjustment (marker, after - before);
if (adjust_markers_test)
abort ();
mpos = from + amount;
}
}
if (mpos > from && mpos <= to)
......@@ -305,73 +321,177 @@ adjust_markers (from, to, amount)
}
}
/* Adjust markers whose insertion-type is t
for an insertion of AMOUNT characters at POS. */
/* Adjust all markers for a deletion
whose range in bytes is FROM_BYTE to TO_BYTE.
The range in charpos is FROM to TO.
This function assumes that the gap is adjacent to
or inside of the range being deleted. */
static void
adjust_markers_for_insert (pos, amount)
register int pos, amount;
adjust_markers_for_delete (from, from_byte, to, to_byte)
register int from, from_byte, to, to_byte;
{
Lisp_Object marker;
register struct Lisp_Marker *m;
register int charpos;
/* This is what GAP_SIZE will be when this deletion is finished. */
int coming_gap_size = GAP_SIZE + to_byte - from_byte;
marker = BUF_MARKERS (current_buffer);
while (!NILP (marker))
{
m = XMARKER (marker);
charpos = m->charpos;
if (charpos > Z)
abort ();
/* If the marker is after the deletion,
its bufpos needs no change because the deleted text
becomes gap; but its charpos needs to be decreased. */
if (charpos > to)
m->charpos -= to - from;
/* Here's the case where a marker is inside text being deleted.
We take advantage of the fact that the deletion is at the gap. */
else if (charpos > from)
{
record_marker_adjustment (marker, from - charpos);
m->charpos = from;
/* The gap must be at or after FROM_BYTE when we do a deletion. */
m->bufpos = from_byte;
}
/* In a single-byte buffer, a marker's two positions must be equal. */
if (Z == Z_BYTE)
{
register int i = m->bufpos;
/* We use FROM_BYTE here instead of GPT_BYTE
because FROM_BYTE is where the gap will be after the deletion. */
if (i > from_byte + coming_gap_size)
i -= coming_gap_size;
else if (i > from_byte)
i = from_byte;
if (m->charpos != i)
abort ();
}
marker = m->chain;
}
}
/* Adjust markers for an insertion at CHARPOS / BYTEPOS
consisting of NCHARS chars, which are NBYTES bytes.
We have to relocate the charpos of every marker that points
after the insertion (but not their bufpos).
When a marker points at the insertion point,
we advance it if either its insertion-type is t
or BEFORE_MARKERS is true. */
static void
adjust_markers_for_insert (from, from_byte, to, to_byte, before_markers)
register int from, from_byte, to, to_byte, before_markers;
{
Lisp_Object marker;
int adjusted = 0;
int nchars = to - from;
int nbytes = to_byte - from_byte;
marker = BUF_MARKERS (current_buffer);
while (!NILP (marker))
{
register struct Lisp_Marker *m = XMARKER (marker);
if (m->insertion_type && m->bufpos == pos)
if (m->bufpos == from_byte
&& (m->insertion_type || before_markers))
{
m->bufpos += amount;
adjusted = 1;
m->bufpos += nbytes;
m->charpos += nchars;
if (m->insertion_type)
adjusted = 1;
}
else if (m->bufpos > from_byte)
m->charpos += nchars;
/* In a single-byte buffer, a marker's two positions must be equal. */
if (Z == Z_BYTE)
{
register int i = m->bufpos;
if (i > GPT_BYTE + GAP_SIZE)
i -= GAP_SIZE;
else if (i > GPT_BYTE)
i = GPT_BYTE;
if (m->charpos != i)
abort ();
}
marker = m->chain;
}
/* Adjusting only markers whose insertion-type is t may result in
disordered overlays in the slot `overlays_before'. */
if (adjusted)
/* Adjusting only markers whose insertion-type is t may result in
disordered overlays in the slot `overlays_before'. */
fix_overlays_before (current_buffer, pos, pos + amount);
fix_overlays_before (current_buffer, from, to);
}
/* Add the specified amount to point. This is used only when the value
of point changes due to an insert or delete; it does not represent
a conceptual change in point as a marker. In particular, point is
not crossing any interval boundaries, so there's no need to use the
usual SET_PT macro. In fact it would be incorrect to do so, because
either the old or the new value of point is out of sync with the
current set of intervals. */
/* Adjust point for an insertion of NBYTES bytes, which are NCHARS characters.
This is used only when the value of point changes due to an insert
or delete; it does not represent a conceptual change in point as a
marker. In particular, point is not crossing any interval
boundaries, so there's no need to use the usual SET_PT macro. In
fact it would be incorrect to do so, because either the old or the
new value of point is out of sync with the current set of
intervals. */
static void
adjust_point (amount)
int amount;
adjust_point (nchars, nbytes)
int nchars, nbytes;
{
BUF_PT (current_buffer) += amount;
BUF_PT (current_buffer) += nchars;
BUF_PT_BYTE (current_buffer) += nbytes;
/* In a single-byte buffer, the two positions must be equal. */
if (ZV == ZV_BYTE
&& PT != PT_BYTE)
abort ();
}
/* Make the gap INCREMENT characters longer. */
/* Make the gap NBYTES_ADDED bytes longer. */
void
make_gap (increment)
int increment;
make_gap (nbytes_added)
int nbytes_added;
{
unsigned char *result;
Lisp_Object tem;
int real_gap_loc;
int real_gap_loc_byte;
int old_gap_size;
/* If we have to get more space, get enough to last a while. */
increment += 2000;
nbytes_added += 2000;
/* Don't allow a buffer size that won't fit in an int
even if it will fit in a Lisp integer.
That won't work because so many places use `int'. */
if (Z - BEG + GAP_SIZE + increment
if (Z_BYTE - BEG_BYTE + GAP_SIZE + nbytes_added
>= ((unsigned) 1 << (min (BITS_PER_INT, VALBITS) - 1)))
error ("Buffer exceeds maximum size");
BLOCK_INPUT;
/* We allocate extra 1-byte `\0' at the tail for anchoring a search. */
result = BUFFER_REALLOC (BEG_ADDR, (Z - BEG + GAP_SIZE + increment + 1));
result = BUFFER_REALLOC (BEG_ADDR, (Z_BYTE - BEG_BYTE
+ GAP_SIZE + nbytes_added + 1));
if (result == 0)
{
......@@ -388,19 +508,21 @@ make_gap (increment)
Vinhibit_quit = Qt;
real_gap_loc = GPT;
real_gap_loc_byte = GPT_BYTE;
old_gap_size = GAP_SIZE;
/* Call the newly allocated space a gap at the end of the whole space. */
GPT = Z + GAP_SIZE;
GAP_SIZE = increment;
GAP_SIZE = nbytes_added;
/* Move the new gap down to be consecutive with the end of the old one.
This adjusts the markers properly too. */
gap_left (real_gap_loc + old_gap_size, 1);
gap_left (real_gap_loc + old_gap_size, real_gap_loc_byte + old_gap_size, 1);
/* Now combine the two into one large gap. */
GAP_SIZE += old_gap_size;
GPT = real_gap_loc;
GPT_BYTE = real_gap_loc_byte;
/* Put an anchor. */
*(Z_ADDR) = 0;
......@@ -413,72 +535,138 @@ make_gap (increment)
prepare_to_modify_buffer could relocate the text. */
void
insert (string, length)
insert (string, nbytes)
register unsigned char *string;
register length;
register nbytes;
{
if (length > 0)
if (nbytes > 0)
{
insert_1 (string, length, 0, 1);
signal_after_change (PT-length, 0, length);
int opoint = PT;
insert_1 (string, nbytes, 0, 1, 0);
signal_after_change (opoint, 0, PT - opoint);
}
}
void
insert_and_inherit (string, length)
insert_and_inherit (string, nbytes)
register unsigned char *string;
register length;
register nbytes;
{
if (length > 0)
if (nbytes > 0)
{
insert_1 (string, length, 1, 1);
signal_after_change (PT-length, 0, length);
int opoint = PT;
insert_1 (string, nbytes, 1, 1, 0);
signal_after_change (opoint, 0, PT - opoint);
}
}
/* Insert the character C before point */
void
insert_1 (string, length, inherit, prepare)
insert_char (c)
int c;
{
unsigned char workbuf[4], *str;
int len = CHAR_STRING (c, workbuf, str);
insert (str, len);
}
/* Insert the null-terminated string S before point */
void
insert_string (s)
char *s;
{
insert (s, strlen (s));
}
/* Like `insert' except that all markers pointing at the place where
the insertion happens are adjusted to point after it.
Don't use this function to insert part of a Lisp string,
since gc could happen and relocate it. */
void
insert_before_markers (string, nbytes)
unsigned char *string;
register int nbytes;
{
if (nbytes > 0)
{
int opoint = PT;
insert_1 (string, nbytes, 0, 1, 1);
signal_after_change (opoint, 0, PT - opoint);
}
}
void
insert_before_markers_and_inherit (string, nbytes)
unsigned char *string;
register int nbytes;
{
if (nbytes > 0)
{
int opoint = PT;
insert_1 (string, nbytes, 1, 1, 1);
signal_after_change (opoint, 0, PT - opoint);
}
}
/* Subroutine used by the insert functions above. */
void
insert_1 (string, nbytes, inherit, prepare, before_markers)
register unsigned char *string;
register int length;
int inherit, prepare;
register int nbytes;
int inherit, prepare, before_markers;
{
register Lisp_Object temp;
int nchars = chars_in_text (string, nbytes);
if (prepare)
prepare_to_modify_buffer (PT, PT, NULL);
if (PT != GPT)
move_gap (PT);
if (GAP_SIZE < length)
make_gap (length - GAP_SIZE);
move_gap_both (PT, PT_BYTE);
if (GAP_SIZE < nbytes)
make_gap (nbytes - GAP_SIZE);
record_insert (PT, length);
record_insert (PT, nchars);
MODIFF++;
bcopy (string, GPT_ADDR, length);
bcopy (string, GPT_ADDR, nbytes);
#ifdef USE_TEXT_PROPERTIES