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. /* 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. This file is part of GNU Emacs.
...@@ -33,12 +33,14 @@ Boston, MA 02111-1307, USA. */ ...@@ -33,12 +33,14 @@ Boston, MA 02111-1307, USA. */
#define min(x, y) ((x) < (y) ? (x) : (y)) #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 insert_from_buffer_1 ();
static void gap_left (); static void gap_left P_ ((int, int, int));
static void gap_right (); static void gap_right P_ ((int, int));
static void adjust_markers (); static void adjust_markers_gap_motion P_ ((int, int, int));
static void adjust_point (); 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 (); Lisp_Object Fcombine_after_change_execute ();
...@@ -61,54 +63,64 @@ Lisp_Object combine_after_change_list; ...@@ -61,54 +63,64 @@ Lisp_Object combine_after_change_list;
/* Buffer which combine_after_change_list is about. */ /* Buffer which combine_after_change_list is about. */
Lisp_Object combine_after_change_buffer; Lisp_Object combine_after_change_buffer;
/* Move gap to position `pos'. /* Move gap to position CHARPOS.
Note that this can quit! */ Note that this can quit! */
void void
move_gap (pos) move_gap (charpos)
int pos; int charpos;
{ {
if (pos < GPT) move_gap_both (charpos, charpos_to_bytepos (charpos));
gap_left (pos, 0);
else if (pos > GPT)
gap_right (pos);
} }
/* 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. */ If NEWGAP is nonzero, then don't update beg_unchanged and end_unchanged. */
static void static void
gap_left (pos, newgap) gap_left (charpos, bytepos, newgap)
register int pos; register int charpos, bytepos;
int newgap; int newgap;
{ {
register unsigned char *to, *from; register unsigned char *to, *from;
register int i; register int i;
int new_s1; int new_s1;
pos--;
if (!newgap) if (!newgap)
{ {
if (unchanged_modified == MODIFF if (unchanged_modified == MODIFF
&& overlay_unchanged_modified == OVERLAY_MODIFF) && overlay_unchanged_modified == OVERLAY_MODIFF)
{ {
beg_unchanged = pos; beg_unchanged = charpos - BEG;
end_unchanged = Z - pos - 1; end_unchanged = Z - charpos;
} }
else else
{ {
if (Z - GPT < end_unchanged) if (Z - GPT < end_unchanged)
end_unchanged = Z - GPT; end_unchanged = Z - GPT;
if (pos < beg_unchanged) if (charpos < beg_unchanged)
beg_unchanged = pos; beg_unchanged = charpos - BEG;
} }
} }
i = GPT; i = GPT_BYTE;
to = GAP_END_ADDR; to = GAP_END_ADDR;
from = GPT_ADDR; from = GPT_ADDR;
new_s1 = GPT - BEG; new_s1 = GPT_BYTE;
/* Now copy the characters. To move the gap down, /* Now copy the characters. To move the gap down,
copy characters up. */ copy characters up. */
...@@ -116,14 +128,15 @@ gap_left (pos, newgap) ...@@ -116,14 +128,15 @@ gap_left (pos, newgap)
while (1) while (1)
{ {
/* I gets number of characters left to copy. */ /* I gets number of characters left to copy. */
i = new_s1 - pos; i = new_s1 - bytepos;
if (i == 0) if (i == 0)
break; break;
/* If a quit is requested, stop copying now. /* 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) if (QUITP)
{ {
pos = new_s1; bytepos = new_s1;
charpos = BYTE_TO_CHAR (bytepos);
break; break;
} }
/* Move at most 32000 chars before checking again for a quit. */ /* Move at most 32000 chars before checking again for a quit. */
...@@ -153,44 +166,48 @@ gap_left (pos, newgap) ...@@ -153,44 +166,48 @@ gap_left (pos, newgap)
} }
} }
/* Adjust markers, and buffer data structure, to put the gap at POS. /* Adjust markers, and buffer data structure, to put the gap at BYTEPOS.
POS is where the loop above stopped, which may be what was specified BYTEPOS is where the loop above stopped, which may be what was specified
or may be where a quit was detected. */ or may be where a quit was detected. */
adjust_markers (pos + 1, GPT, GAP_SIZE); adjust_markers_gap_motion (bytepos, GPT_BYTE, GAP_SIZE);
GPT = pos + 1; GPT_BYTE = bytepos;
GPT = charpos;
if (bytepos < charpos)
abort ();
if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */ if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
QUIT; 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 static void
gap_right (pos) gap_right (charpos, bytepos)
register int pos; register int charpos, bytepos;
{ {
register unsigned char *to, *from; register unsigned char *to, *from;
register int i; register int i;
int new_s1; int new_s1;
pos--;
if (unchanged_modified == MODIFF if (unchanged_modified == MODIFF
&& overlay_unchanged_modified == OVERLAY_MODIFF) && overlay_unchanged_modified == OVERLAY_MODIFF)
{ {
beg_unchanged = pos; beg_unchanged = charpos - BEG;
end_unchanged = Z - pos - 1; end_unchanged = Z - charpos;
} }
else else
{ {
if (Z - pos - 1 < end_unchanged) if (Z - charpos - 1 < end_unchanged)
end_unchanged = Z - pos - 1; end_unchanged = Z - charpos;
if (GPT - BEG < beg_unchanged) if (GPT - BEG < beg_unchanged)
beg_unchanged = GPT - BEG; beg_unchanged = GPT - BEG;
} }
i = GPT; i = GPT_BYTE;
from = GAP_END_ADDR; from = GAP_END_ADDR;
to = GPT_ADDR; to = GPT_ADDR;
new_s1 = GPT - 1; new_s1 = GPT_BYTE;
/* Now copy the characters. To move the gap up, /* Now copy the characters. To move the gap up,
copy characters down. */ copy characters down. */
...@@ -198,14 +215,15 @@ gap_right (pos) ...@@ -198,14 +215,15 @@ gap_right (pos)
while (1) while (1)
{ {
/* I gets number of characters left to copy. */ /* I gets number of characters left to copy. */
i = pos - new_s1; i = bytepos - new_s1;
if (i == 0) if (i == 0)
break; break;
/* If a quit is requested, stop copying now. /* 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) if (QUITP)
{ {
pos = new_s1; bytepos = new_s1;
charpos = BYTE_TO_CHAR (bytepos);
break; break;
} }
/* Move at most 32000 chars before checking again for a quit. */ /* Move at most 32000 chars before checking again for a quit. */
...@@ -235,14 +253,18 @@ gap_right (pos) ...@@ -235,14 +253,18 @@ gap_right (pos)
} }
} }
adjust_markers (GPT + GAP_SIZE, pos + 1 + GAP_SIZE, - GAP_SIZE); adjust_markers_gap_motion (GPT_BYTE + GAP_SIZE, bytepos + GAP_SIZE,
GPT = pos + 1; - GAP_SIZE);
GPT = charpos;
GPT_BYTE = bytepos;
if (bytepos < charpos)
abort ();
if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */ if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
QUIT; QUIT;
} }
/* Add AMOUNT to the position of every marker in the current buffer /* Add AMOUNT to the byte position of every marker in the current buffer
whose current position is between FROM (exclusive) and TO (inclusive). whose current byte position is between FROM (exclusive) and TO (inclusive).
Also, any markers past the outside of that interval, in the direction 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 of adjustment, are first moved back to the near end of the interval
...@@ -250,10 +272,15 @@ gap_right (pos) ...@@ -250,10 +272,15 @@ gap_right (pos)
When the latter adjustment is done, if AMOUNT is negative, When the latter adjustment is done, if AMOUNT is negative,
we record the adjustment for undo. (This case happens only for 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 static void
adjust_markers (from, to, amount) adjust_markers_gap_motion (from, to, amount)
register int from, to, amount; register int from, to, amount;
{ {
Lisp_Object marker; Lisp_Object marker;
...@@ -269,7 +296,11 @@ adjust_markers (from, to, amount) ...@@ -269,7 +296,11 @@ adjust_markers (from, to, amount)
if (amount > 0) if (amount > 0)
{ {
if (mpos > to && mpos < to + amount) if (mpos > to && mpos < to + amount)
mpos = to + amount; {
if (adjust_markers_test)
abort ();
mpos = to + amount;
}
} }
else else
{ {
...@@ -278,24 +309,9 @@ adjust_markers (from, to, amount) ...@@ -278,24 +309,9 @@ adjust_markers (from, to, amount)
but then this range contains no markers. */ but then this range contains no markers. */
if (mpos > from + amount && mpos <= from) if (mpos > from + amount && mpos <= from)
{ {
int before = mpos; if (adjust_markers_test)
int after = from + amount; abort ();
mpos = 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 (mpos > from && mpos <= to) if (mpos > from && mpos <= to)
...@@ -305,73 +321,177 @@ adjust_markers (from, to, amount) ...@@ -305,73 +321,177 @@ adjust_markers (from, to, amount)
} }
} }
/* Adjust markers whose insertion-type is t /* Adjust all markers for a deletion
for an insertion of AMOUNT characters at POS. */ 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 static void
adjust_markers_for_insert (pos, amount) adjust_markers_for_delete (from, from_byte, to, to_byte)
register int pos, amount; 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; Lisp_Object marker;
int adjusted = 0; int adjusted = 0;
int nchars = to - from;
int nbytes = to_byte - from_byte;
marker = BUF_MARKERS (current_buffer); marker = BUF_MARKERS (current_buffer);
while (!NILP (marker)) while (!NILP (marker))
{ {
register struct Lisp_Marker *m = XMARKER (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; m->bufpos += nbytes;
adjusted = 1; 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; marker = m->chain;
} }
/* Adjusting only markers whose insertion-type is t may result in
disordered overlays in the slot `overlays_before'. */
if (adjusted) if (adjusted)
/* Adjusting only markers whose insertion-type is t may result in fix_overlays_before (current_buffer, from, to);
disordered overlays in the slot `overlays_before'. */
fix_overlays_before (current_buffer, pos, pos + amount);
} }
/* Add the specified amount to point. This is used only when the value /* Adjust point for an insertion of NBYTES bytes, which are NCHARS characters.
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 This is used only when the value of point changes due to an insert
not crossing any interval boundaries, so there's no need to use the or delete; it does not represent a conceptual change in point as a
usual SET_PT macro. In fact it would be incorrect to do so, because marker. In particular, point is not crossing any interval
either the old or the new value of point is out of sync with the boundaries, so there's no need to use the usual SET_PT macro. In
current set of intervals. */ 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 static void
adjust_point (amount) adjust_point (nchars, nbytes)
int amount; 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 void
make_gap (increment) make_gap (nbytes_added)
int increment; int nbytes_added;
{ {
unsigned char *result; unsigned char *result;
Lisp_Object tem; Lisp_Object tem;
int real_gap_loc; int real_gap_loc;
int real_gap_loc_byte;
int old_gap_size; int old_gap_size;
/* If we have to get more space, get enough to last a while. */ /* 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 /* Don't allow a buffer size that won't fit in an int
even if it will fit in a Lisp integer. even if it will fit in a Lisp integer.
That won't work because so many places use `int'. */ 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))) >= ((unsigned) 1 << (min (BITS_PER_INT, VALBITS) - 1)))
error ("Buffer exceeds maximum size"); error ("Buffer exceeds maximum size");
BLOCK_INPUT; BLOCK_INPUT;
/* We allocate extra 1-byte `\0' at the tail for anchoring a search. */ /* 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) if (result == 0)
{ {
...@@ -388,19 +508,21 @@ make_gap (increment) ...@@ -388,19 +508,21 @@ make_gap (increment)
Vinhibit_quit = Qt; Vinhibit_quit = Qt;
real_gap_loc = GPT; real_gap_loc = GPT;
real_gap_loc_byte = GPT_BYTE;
old_gap_size = GAP_SIZE; old_gap_size = GAP_SIZE;
/* Call the newly allocated space a gap at the end of the whole space. */ /* Call the newly allocated space a gap at the end of the whole space. */
GPT = Z + GAP_SIZE; 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. /* Move the new gap down to be consecutive with the end of the old one.
This adjusts the markers properly too. */ 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. */