/* Buffer insertion/deletion and gap motion for GNU Emacs.
- Copyright (C) 1985, 86, 93, 94, 95, 97, 1998 Free Software Foundation, Inc.
+ Copyright (C) 1985, 86,93,94,95,97,98, 1999 Free Software Foundation, Inc.
This file is part of GNU Emacs.
#endif
#define min(x, y) ((x) < (y) ? (x) : (y))
+#define max(x, y) ((x) > (y) ? (x) : (y))
static void insert_from_string_1 P_ ((Lisp_Object, int, int, int, int, int, int));
static void insert_from_buffer_1 ();
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, int, int));
-static void adjust_markers_for_delete P_ ((int, int, int, int));
+void adjust_markers_for_delete P_ ((int, int, int, int));
static void adjust_markers_for_record_delete P_ ((int, int, int, int));
static void adjust_point P_ ((int, int));
void
check_markers ()
{
- register Lisp_Object tail, prev, next;
+ register Lisp_Object tail;
int multibyte = ! NILP (current_buffer->enable_multibyte_characters);
tail = BUF_MARKERS (current_buffer);
int new_s1;
if (!newgap)
- {
- if (unchanged_modified == MODIFF
- && overlay_unchanged_modified == OVERLAY_MODIFF)
- {
- beg_unchanged = charpos - BEG;
- end_unchanged = Z - charpos;
- }
- else
- {
- if (Z - GPT < end_unchanged)
- end_unchanged = Z - GPT;
- if (charpos < beg_unchanged)
- beg_unchanged = charpos - BEG;
- }
- }
+ BUF_COMPUTE_UNCHANGED (current_buffer, charpos, GPT);
i = GPT_BYTE;
to = GAP_END_ADDR;
register int i;
int new_s1;
- if (unchanged_modified == MODIFF
- && overlay_unchanged_modified == OVERLAY_MODIFF)
- {
- beg_unchanged = charpos - BEG;
- end_unchanged = Z - charpos;
- }
- else
- {
- if (Z - charpos - 1 < end_unchanged)
- end_unchanged = Z - charpos;
- if (GPT - BEG < beg_unchanged)
- beg_unchanged = GPT - BEG;
- }
+ BUF_COMPUTE_UNCHANGED (current_buffer, charpos, GPT);
i = GPT_BYTE;
from = GAP_END_ADDR;
This function assumes that the gap is adjacent to
or inside of the range being deleted. */
-static void
+void
adjust_markers_for_delete (from, from_byte, to, to_byte)
register int from, from_byte, to, to_byte;
{
{
register struct Lisp_Marker *m = XMARKER (marker);
- if (m->bytepos >= prev_to_byte)
+ if (m->bytepos >= prev_to_byte
+ && (old_bytes != 0
+ /* If this is an insertion (replacing 0 chars),
+ reject the case of a marker that is at the
+ insertion point and should stay before the insertion. */
+ || m->bytepos > from_byte || m->insertion_type))
{
if (m->bytepos < prev_to_byte + combined_after_bytes)
{
}
else
{
- m->charpos += diff_chars;
- m->bytepos += diff_bytes;
+ m->charpos = min (from + new_chars, m->charpos + diff_chars);
+ m->bytepos = min (from_byte + new_bytes,
+ m->bytepos + diff_bytes);
}
}
else if (m->bytepos >= from_byte)
{
int nchars = 0;
int bytes_left = nbytes;
- Lisp_Object tbl = Qnil, temp;
+ Lisp_Object tbl = Qnil;
/* We set the variable tbl to the reverse table of
Vnonascii_translation_table in advance. */
while (nbytes > 0)
{
int c = *from_addr++;
- unsigned char workbuf[4], *str;
- int len;
- if ((c >= 0240 || !NILP (Vnonascii_translation_table)) && c < 0400)
+ if (c < 0400
+ && (c >= 0240
+ || (c >= 0200 && !NILP (Vnonascii_translation_table))))
{
c = unibyte_char_to_multibyte (c);
- len = CHAR_STRING (c, workbuf, str);
- bcopy (str, to_addr, len);
- to_addr += len;
+ to_addr += CHAR_STRING (c, to_addr);
nbytes--;
}
else
{
unsigned int c = *ptr++;
- if (c < 0240 && NILP (Vnonascii_translation_table))
+ if (c < 0200 || (c < 0240 && NILP (Vnonascii_translation_table)))
outgoing_nbytes++;
else
{
int opoint = PT;
insert_1 (string, nbytes, 0, 1, 0);
signal_after_change (opoint, 0, PT - opoint);
+ update_compositions (opoint, PT, CHECK_BORDER);
}
}
int opoint = PT;
insert_1 (string, nbytes, 1, 1, 0);
signal_after_change (opoint, 0, PT - opoint);
+ update_compositions (opoint, PT, CHECK_BORDER);
}
}
insert_char (c)
int c;
{
- unsigned char workbuf[4], *str;
+ unsigned char str[MAX_MULTIBYTE_LENGTH];
int len;
if (! NILP (current_buffer->enable_multibyte_characters))
- len = CHAR_STRING (c, workbuf, str);
+ len = CHAR_STRING (c, str);
else
{
len = 1;
- workbuf[0] = c;
- str = workbuf;
+ str[0] = c;
}
insert (str, len);
insert_1 (string, nbytes, 0, 1, 1);
signal_after_change (opoint, 0, PT - opoint);
+ update_compositions (opoint, PT, CHECK_BORDER);
}
}
insert_1 (string, nbytes, 1, 1, 1);
signal_after_change (opoint, 0, PT - opoint);
+ update_compositions (opoint, PT, CHECK_BORDER);
}
}
int length;
int pos, pos_byte;
{
- int opos = pos, opos_byte = pos_byte;
- int c;
- unsigned char *p = string;
+ int len, combining_bytes;
+ unsigned char *p;
if (NILP (current_buffer->enable_multibyte_characters))
return 0;
- if (length == 0 || CHAR_HEAD_P (*string))
+
+ /* At first, we can exclude the following cases:
+ (1) STRING[0] can't be a following byte of multibyte sequence.
+ (2) POS is the start of the current buffer.
+ (3) A character before POS is not a multibyte character. */
+ if (length == 0 || CHAR_HEAD_P (*string)) /* case (1) */
return 0;
- if (pos == BEG)
+ if (pos_byte == BEG_BYTE) /* case (2) */
return 0;
- c = FETCH_BYTE (pos_byte - 1);
- if (ASCII_BYTE_P (c))
+ len = 1;
+ p = BYTE_POS_ADDR (pos_byte - 1);
+ while (! CHAR_HEAD_P (*p)) p--, len++;
+ if (! BASE_LEADING_CODE_P (*p)) /* case (3) */
return 0;
- DEC_BOTH (pos, pos_byte);
- c = FETCH_BYTE (pos_byte);
- if (! BASE_LEADING_CODE_P (c))
+
+ combining_bytes = BYTES_BY_CHAR_HEAD (*p) - len;
+ if (combining_bytes <= 0)
+ /* The character preceding POS is, complete and no room for
+ combining bytes (combining_bytes == 0), or an independent 8-bit
+ character (combining_bytes < 0). */
return 0;
- /* We have a combination situation.
- Count the bytes at STRING that will combine. */
+ /* We have a combination situation. Count the bytes at STRING that
+ may combine. */
+ p = string + 1;
while (!CHAR_HEAD_P (*p) && p < string + length)
p++;
- return p - string;
+ return (combining_bytes < p - string ? combining_bytes : p - string);
}
/* See if the bytes after POS/POS_BYTE combine with bytes
int length;
int pos, pos_byte;
{
- int opos = pos, opos_byte = pos_byte;
+ int opos_byte = pos_byte;
int i;
- int c;
+ int bytes;
+ unsigned char *bufp;
if (NILP (current_buffer->enable_multibyte_characters))
return 0;
- if (length > 0 && ASCII_BYTE_P (string[length - 1]))
+
+ /* At first, we can exclude the following cases:
+ (1) The last byte of STRING is an ASCII.
+ (2) POS is the last of the current buffer.
+ (3) A character at POS can't be a following byte of multibyte
+ character. */
+ if (length > 0 && ASCII_BYTE_P (string[length - 1])) /* case (1) */
+ return 0;
+ if (pos_byte == Z_BYTE) /* case (2) */
return 0;
+ bufp = BYTE_POS_ADDR (pos_byte);
+ if (CHAR_HEAD_P (*bufp)) /* case (3) */
+ return 0;
+
i = length - 1;
while (i >= 0 && ! CHAR_HEAD_P (string[i]))
{
}
if (i < 0)
{
- /* All characters in `string' are not character head.
- We must check also preceding bytes at POS.
- We are sure that the gap is at POS. */
- string = BEG_ADDR;
+ /* All characters in STRING are not character head. We must
+ check also preceding bytes at POS. We are sure that the gap
+ is at POS. */
+ unsigned char *p = BEG_ADDR;
i = pos_byte - 2;
- while (i >= 0 && ! CHAR_HEAD_P (string[i]))
+ while (i >= 0 && ! CHAR_HEAD_P (p[i]))
i--;
- if (i < 0 || !BASE_LEADING_CODE_P (string[i]))
+ if (i < 0 || !BASE_LEADING_CODE_P (p[i]))
return 0;
+
+ bytes = BYTES_BY_CHAR_HEAD (p[i]);
+ return (bytes <= pos_byte - 1 - i + length
+ ? 0
+ : bytes - (pos_byte - 1 - i + length));
}
- else if (!BASE_LEADING_CODE_P (string[i]))
+ if (!BASE_LEADING_CODE_P (string[i]))
return 0;
- if (pos == Z)
- return 0;
- c = FETCH_BYTE (pos_byte);
- if (CHAR_HEAD_P (c))
- return 0;
- while (pos_byte < Z_BYTE)
- {
- c = FETCH_BYTE (pos_byte);
- if (CHAR_HEAD_P (c))
- break;
- pos_byte++;
- }
+ bytes = BYTES_BY_CHAR_HEAD (string[i]) - (length - i);
+ bufp++, pos_byte++;
+ while (!CHAR_HEAD_P (*bufp)) bufp++, pos_byte++;
- return pos_byte - opos_byte;
+ return (bytes <= pos_byte - opos_byte ? bytes : pos_byte - opos_byte);
}
/* Adjust the position TARGET/TARGET_BYTE for the combining of NBYTES
ADJUST_CHAR_POS (ZV, ZV_BYTE);
if (BUF_INTERVALS (current_buffer) != 0)
- /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES. */
offset_intervals (current_buffer, pos, - nbytes);
}
+void
+byte_combining_error ()
+{
+ error ("Byte combining across boundary of accessible buffer text inhibitted");
+}
+
/* If we are going to combine bytes at POS which is at a narrowed
region boundary, signal an error. */
#define CHECK_BYTE_COMBINING_FOR_INSERT(pos) \
do { \
- if (combined_before_bytes && pos == BEGV \
- || combined_after_bytes && pos == ZV) \
- error ("Byte combining across region boundary inhibitted"); \
+ if ((combined_before_bytes && pos == BEGV) \
+ || (combined_after_bytes && pos == ZV)) \
+ byte_combining_error (); \
} while (0)
\f
register int nchars, nbytes;
int inherit, prepare, before_markers;
{
- register Lisp_Object temp;
int combined_before_bytes, combined_after_bytes;
if (NILP (current_buffer->enable_multibyte_characters))
combined_before_bytes, combined_after_bytes,
before_markers);
-#ifdef USE_TEXT_PROPERTIES
if (BUF_INTERVALS (current_buffer) != 0)
- /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES. */
offset_intervals (current_buffer, PT, nchars);
if (!inherit && BUF_INTERVALS (current_buffer) != 0)
- Fset_text_properties (make_number (PT), make_number (PT + nchars),
- Qnil, Qnil);
-#endif
+ set_text_properties (make_number (PT), make_number (PT + nchars),
+ Qnil, Qnil, Qnil);
{
int pos = PT, pos_byte = PT_BYTE;
insert_from_string_1 (string, pos, pos_byte, length, length_byte,
inherit, 0);
signal_after_change (opoint, 0, PT - opoint);
+ update_compositions (opoint, PT, CHECK_BORDER);
}
/* Like `insert_from_string' except that all markers pointing
insert_from_string_1 (string, pos, pos_byte, length, length_byte,
inherit, 1);
signal_after_change (opoint, 0, PT - opoint);
+ update_compositions (opoint, PT, CHECK_BORDER);
}
/* Subroutine of the insertion functions above. */
register int pos, pos_byte, nchars, nbytes;
int inherit, before_markers;
{
- register Lisp_Object temp;
struct gcpro gcpro1;
int outgoing_nbytes = nbytes;
int combined_before_bytes, combined_after_bytes;
- int adjusted_nchars;
INTERVAL intervals;
/* Make OUTGOING_NBYTES describe the text
if (PT != GPT)
move_gap_both (PT, PT_BYTE);
- if (GAP_SIZE < nbytes)
+ if (GAP_SIZE < outgoing_nbytes)
make_gap (outgoing_nbytes - GAP_SIZE);
UNGCPRO;
= count_combining_after (GPT_ADDR, outgoing_nbytes, PT, PT_BYTE);
{
unsigned char save = *(GPT_ADDR);
+ *(GPT_ADDR) = 0;
CHECK_BYTE_COMBINING_FOR_INSERT (PT);
*(GPT_ADDR) = save;
}
combined_before_bytes, combined_after_bytes,
before_markers);
- /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
offset_intervals (current_buffer, PT, nchars);
intervals = XSTRING (string)->intervals;
insert_from_buffer_1 (buf, charpos, nchars, inherit);
signal_after_change (opoint, 0, PT - opoint);
+ update_compositions (opoint, PT, CHECK_BORDER);
}
static void
int inherit;
{
register Lisp_Object temp;
- int chunk;
+ int chunk, chunk_expanded;
int from_byte = buf_charpos_to_bytepos (buf, from);
int to_byte = buf_charpos_to_bytepos (buf, from + nchars);
int incoming_nbytes = to_byte - from_byte;
int outgoing_nbytes = incoming_nbytes;
int combined_before_bytes, combined_after_bytes;
- int adjusted_nchars;
INTERVAL intervals;
/* Make OUTGOING_NBYTES describe the text
if (NILP (current_buffer->enable_multibyte_characters))
outgoing_nbytes = nchars;
else if (NILP (buf->enable_multibyte_characters))
- outgoing_nbytes
- = count_size_as_multibyte (BUF_BYTE_ADDRESS (buf, from_byte),
- incoming_nbytes);
+ {
+ int outgoing_before_gap = 0;
+ int outgoing_after_gap = 0;
+ if (from < BUF_GPT (buf))
+ {
+ chunk = BUF_GPT_BYTE (buf) - from_byte;
+ if (chunk > incoming_nbytes)
+ chunk = incoming_nbytes;
+ outgoing_before_gap
+ = count_size_as_multibyte (BUF_BYTE_ADDRESS (buf, from_byte),
+ chunk);
+ }
+ else
+ chunk = 0;
+
+ if (chunk < incoming_nbytes)
+ outgoing_after_gap
+ = count_size_as_multibyte (BUF_BYTE_ADDRESS (buf,
+ from_byte + chunk),
+ incoming_nbytes - chunk);
+
+ outgoing_nbytes = outgoing_before_gap + outgoing_after_gap;
+ }
+
/* Make sure point-max won't overflow after this insertion. */
XSETINT (temp, outgoing_nbytes + Z);
if (outgoing_nbytes + Z != XINT (temp))
chunk = BUF_GPT_BYTE (buf) - from_byte;
if (chunk > incoming_nbytes)
chunk = incoming_nbytes;
- copy_text (BUF_BYTE_ADDRESS (buf, from_byte),
- GPT_ADDR, chunk,
- ! NILP (buf->enable_multibyte_characters),
- ! NILP (current_buffer->enable_multibyte_characters));
+ /* Record number of output bytes, so we know where
+ to put the output from the second copy_text. */
+ chunk_expanded
+ = copy_text (BUF_BYTE_ADDRESS (buf, from_byte),
+ GPT_ADDR, chunk,
+ ! NILP (buf->enable_multibyte_characters),
+ ! NILP (current_buffer->enable_multibyte_characters));
}
else
- chunk = 0;
+ chunk_expanded = chunk = 0;
+
if (chunk < incoming_nbytes)
copy_text (BUF_BYTE_ADDRESS (buf, from_byte + chunk),
- GPT_ADDR + chunk, incoming_nbytes - chunk,
+ GPT_ADDR + chunk_expanded, incoming_nbytes - chunk,
! NILP (buf->enable_multibyte_characters),
! NILP (current_buffer->enable_multibyte_characters));
= count_combining_after (GPT_ADDR, outgoing_nbytes, PT, PT_BYTE);
{
unsigned char save = *(GPT_ADDR);
+ *(GPT_ADDR) = 0;
CHECK_BYTE_COMBINING_FOR_INSERT (PT);
*(GPT_ADDR) = save;
}
PT_BYTE + outgoing_nbytes,
combined_before_bytes, combined_after_bytes, 0);
-#ifdef USE_TEXT_PROPERTIES
if (BUF_INTERVALS (current_buffer) != 0)
offset_intervals (current_buffer, PT, nchars);
-#endif
/* Get the intervals for the part of the string we are inserting--
not including the combined-before bytes. */
= count_combining_before (GPT_ADDR, len_byte, from, from_byte);
int combined_after_bytes
= count_combining_after (GPT_ADDR, len_byte, from, from_byte);
+ /* This flag tells if we combine some bytes with a character before
+ FROM. This happens even if combined_before_bytes is zero. */
+ int combine_before = (combined_before_bytes
+ || (len == 0 && combined_after_bytes));
+
int nchars_del = 0, nbytes_del = 0;
if (STRINGP (prev_text))
nbytes_del = STRING_BYTES (XSTRING (prev_text));
}
- if (combined_before_bytes && from == BEGV
- || combined_after_bytes && from == ZV)
+ if ((combine_before && from == BEGV)
+ || (combined_after_bytes && from == ZV))
{
/* We can't combine bytes nor signal an error here. So, let's
pretend that the new text is just a single space. */
}
if (combined_before_bytes
- || len_byte == 0 && combined_after_bytes > 0)
+ || (len_byte == 0 && combined_after_bytes > 0))
{
Lisp_Object deletion;
deletion = Qnil;
combined_before_bytes, combined_after_bytes);
if (! EQ (current_buffer->undo_list, Qt))
{
- /* This flag tells if we combine some bytes with a character
- before FROM. This happens even if combined_before_bytes is
- zero. */
- int combine_before = (combined_before_bytes
- || (len == 0 && combined_after_bytes));
-
if (nchars_del > 0)
record_delete (from - combine_before, prev_text);
if (combine_before)
adjust_overlays_for_insert (from, len - nchars_del);
else if (len < nchars_del)
adjust_overlays_for_delete (from, nchars_del - len);
-#ifdef USE_TEXT_PROPERTIES
if (BUF_INTERVALS (current_buffer) != 0)
{
offset_intervals (current_buffer, from, len - nchars_del);
}
-#endif
{
- int pos = PT, pos_byte = PT_BYTE;
-
if (from < PT)
adjust_point (len - nchars_del, len_byte - nbytes_del);
}
/* As byte combining will decrease Z, we must check this again. */
- if (Z - GPT < end_unchanged)
- end_unchanged = Z - GPT;
+ if (Z - GPT < END_UNCHANGED)
+ END_UNCHANGED = Z - GPT;
CHECK_MARKERS ();
register Lisp_Object temp;
struct gcpro gcpro1;
int combined_before_bytes, combined_after_bytes;
- int adjusted_inschars;
INTERVAL intervals;
int outgoing_insbytes = insbytes;
Lisp_Object deletion;
if (to < GPT)
gap_left (to, to_byte, 0);
- deletion = Qnil;
-
- if (! EQ (current_buffer->undo_list, Qt))
- deletion = make_buffer_string_both (from, from_byte, to, to_byte, 1);
+ /* Even if we don't record for undo, we must keep the original text
+ because we may have to recover it because of inappropriate byte
+ combining. */
+ deletion = make_buffer_string_both (from, from_byte, to, to_byte, 1);
if (markers)
/* Relocate all markers pointing into the new, larger gap
if (GPT_BYTE < GPT)
abort ();
- if (GPT - BEG < beg_unchanged)
- beg_unchanged = GPT - BEG;
- if (Z - GPT < end_unchanged)
- end_unchanged = Z - GPT;
+ if (GPT - BEG < BEG_UNCHANGED)
+ BEG_UNCHANGED = GPT - BEG;
+ if (Z - GPT < END_UNCHANGED)
+ END_UNCHANGED = Z - GPT;
if (GAP_SIZE < insbytes)
make_gap (insbytes - GAP_SIZE);
= count_combining_before (GPT_ADDR, outgoing_insbytes, from, from_byte);
combined_after_bytes
= count_combining_after (GPT_ADDR, outgoing_insbytes, from, from_byte);
- {
- unsigned char save = *(GPT_ADDR);
- CHECK_BYTE_COMBINING_FOR_INSERT (from);
- *(GPT_ADDR) = save;
- }
+
+ if ((combined_before_bytes && from == BEGV)
+ || (combined_after_bytes && from == ZV))
+ {
+ /* Bytes are being combined across the region boundary. We
+ should avoid it. We recover the original contents before
+ signaling an error. */
+ bcopy (XSTRING (deletion)->data, GPT_ADDR, nbytes_del);
+ GAP_SIZE -= nbytes_del;
+ ZV += nchars_del;
+ Z += nchars_del;
+ ZV_BYTE += nbytes_del;
+ Z_BYTE += nbytes_del;
+ GPT = from + nchars_del;
+ GPT_BYTE = from_byte + nbytes_del;
+ *(GPT_ADDR) = 0; /* Put an anchor. */
+ if (markers)
+ adjust_markers_for_insert (from, from_byte, to, to_byte, 0, 0, 0);
+ UNGCPRO;
+ byte_combining_error ();
+ GCPRO1 (new);
+ }
/* Record deletion of the surrounding text that combines with
the insertion. This, together with recording the insertion,
from + inschars, from_byte + outgoing_insbytes,
combined_before_bytes, combined_after_bytes, 0);
-#ifdef USE_TEXT_PROPERTIES
offset_intervals (current_buffer, from, inschars - nchars_del);
/* Get the intervals for the part of the string we are inserting--
/* Insert those intervals. */
graft_intervals_into_buffer (intervals, from, inschars,
current_buffer, inherit);
-#endif
/* Relocate point as if it were a marker. */
if (from < PT)
combine_bytes (from, from_byte, combined_before_bytes);
/* As byte combining will decrease Z, we must check this again. */
- if (Z - GPT < end_unchanged)
- end_unchanged = Z - GPT;
+ if (Z - GPT < END_UNCHANGED)
+ END_UNCHANGED = Z - GPT;
if (outgoing_insbytes == 0)
evaporate_overlays (from);
UNGCPRO;
signal_after_change (from, nchars_del, GPT - from);
+ update_compositions (from, GPT, CHECK_BORDER);
}
\f
/* Delete characters in current buffer
del_range (from, to)
register int from, to;
{
- del_range_1 (from, to, 1);
+ del_range_1 (from, to, 1, 0);
}
-/* Like del_range; PREPARE says whether to call prepare_to_modify_buffer. */
+/* Like del_range; PREPARE says whether to call prepare_to_modify_buffer.
+ RET_STRING says to return the deleted text. */
-void
-del_range_1 (from, to, prepare)
- int from, to, prepare;
+Lisp_Object
+del_range_1 (from, to, prepare, ret_string)
+ int from, to, prepare, ret_string;
{
int from_byte, to_byte;
+ Lisp_Object deletion;
+ struct gcpro gcpro1;
/* Make args be valid */
if (from < BEGV)
to = ZV;
if (to <= from)
- return;
+ return Qnil;
if (prepare)
{
from_byte = CHAR_TO_BYTE (from);
to_byte = CHAR_TO_BYTE (to);
- del_range_2 (from, from_byte, to, to_byte);
+ deletion = del_range_2 (from, from_byte, to, to_byte, ret_string);
+ GCPRO1(deletion);
+ signal_after_change (from, to - from, 0);
+ update_compositions (from, from, CHECK_HEAD);
+ UNGCPRO;
+ return deletion;
}
/* Like del_range_1 but args are byte positions, not char positions. */
to_byte = CHAR_TO_BYTE (to);
}
- del_range_2 (from, from_byte, to, to_byte);
+ del_range_2 (from, from_byte, to, to_byte, 0);
+ signal_after_change (from, to - from, 0);
+ update_compositions (from, from, CHECK_HEAD);
}
/* Like del_range_1, but positions are specified both as charpos
to_byte = CHAR_TO_BYTE (to);
}
- del_range_2 (from, from_byte, to, to_byte);
+ del_range_2 (from, from_byte, to, to_byte, 0);
+ signal_after_change (from, to - from, 0);
+ update_compositions (from, from, CHECK_HEAD);
}
/* Delete a range of text, specified both as character positions
and byte positions. FROM and TO are character positions,
- while FROM_BYTE and TO_BYTE are byte positions. */
+ while FROM_BYTE and TO_BYTE are byte positions.
+ If RET_STRING is true, the deleted area is returned as a string. */
-void
-del_range_2 (from, from_byte, to, to_byte)
- int from, from_byte, to, to_byte;
+Lisp_Object
+del_range_2 (from, from_byte, to, to_byte, ret_string)
+ int from, from_byte, to, to_byte, ret_string;
{
register int nbytes_del, nchars_del;
int combined_after_bytes;
Z_BYTE - to_byte, from, from_byte);
if (combined_after_bytes)
{
- if (to == ZV_BYTE)
- error ("Byte combining across region boundary inhibitted");
+ if (from == BEGV || to == ZV)
+ byte_combining_error ();
from_byte_1 = from_byte;
DEC_POS (from_byte_1);
}
else
from_byte_1 = from_byte;
- if (! EQ (current_buffer->undo_list, Qt))
+ if (ret_string || ! EQ (current_buffer->undo_list, Qt))
deletion
= make_buffer_string_both (from - !!combined_after_bytes,
from_byte_1,
to + combined_after_bytes,
to_byte + combined_after_bytes, 1);
+ else
+ deletion = Qnil;
+
if (combined_after_bytes)
/* COMBINED_AFTER_BYTES nonzero means that the above code moved
the gap. We must move the gap again to a proper place. */
adjust_point (from - (PT < to ? PT : to),
from_byte - (PT_BYTE < to_byte ? PT_BYTE : to_byte));
- /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
offset_intervals (current_buffer, from, - nchars_del);
/* Adjust the overlay center as needed. This must be done after
if (GPT_BYTE < GPT)
abort ();
- if (GPT - BEG < beg_unchanged)
- beg_unchanged = GPT - BEG;
- if (Z - GPT < end_unchanged)
- end_unchanged = Z - GPT;
+ if (GPT - BEG < BEG_UNCHANGED)
+ BEG_UNCHANGED = GPT - BEG;
+ if (Z - GPT < END_UNCHANGED)
+ END_UNCHANGED = Z - GPT;
if (combined_after_bytes)
{
record_insert (GPT - 1, 1);
- if (Z - GPT < end_unchanged)
- end_unchanged = Z - GPT;
+ if (Z - GPT < END_UNCHANGED)
+ END_UNCHANGED = Z - GPT;
}
CHECK_MARKERS ();
evaporate_overlays (from);
- signal_after_change (from, nchars_del, 0);
+
+ return deletion;
}
\f
/* Call this if you're about to change the region of BUFFER from
prepare_to_modify_buffer (start, end, NULL);
- if (start - 1 < beg_unchanged
- || (unchanged_modified == MODIFF
- && overlay_unchanged_modified == OVERLAY_MODIFF))
- beg_unchanged = start - 1;
- if (Z - end < end_unchanged
- || (unchanged_modified == MODIFF
- && overlay_unchanged_modified == OVERLAY_MODIFF))
- end_unchanged = Z - end;
+ BUF_COMPUTE_UNCHANGED (buffer, start - 1, end);
if (MODIFF <= SAVE_MODIFF)
record_first_change ();
if (!NILP (current_buffer->read_only))
Fbarf_if_buffer_read_only ();
- /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
+ /* Let redisplay consider other windows than selected_window
+ if modifying another buffer. */
+ if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
+ ++windows_or_buffers_changed;
+
if (BUF_INTERVALS (current_buffer) != 0)
{
if (preserve_ptr)
"This function is for use internally in `combine-after-change-calls'.")
()
{
- register Lisp_Object val;
int count = specpdl_ptr - specpdl;
int beg, end, change;
int begpos, endpos;
Lisp_Object tail;
+ if (NILP (combine_after_change_list))
+ return Qnil;
+
record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
Fset_buffer (combine_after_change_buffer);
/* Scan the various individual changes,
accumulating the range info in BEG, END and CHANGE. */
for (tail = combine_after_change_list; CONSP (tail);
- tail = XCONS (tail)->cdr)
+ tail = XCDR (tail))
{
Lisp_Object elt;
int thisbeg, thisend, thischange;
/* Extract the info from the next element. */
- elt = XCONS (tail)->car;
+ elt = XCAR (tail);
if (! CONSP (elt))
continue;
- thisbeg = XINT (XCONS (elt)->car);
+ thisbeg = XINT (XCAR (elt));
- elt = XCONS (elt)->cdr;
+ elt = XCDR (elt);
if (! CONSP (elt))
continue;
- thisend = XINT (XCONS (elt)->car);
+ thisend = XINT (XCAR (elt));
- elt = XCONS (elt)->cdr;
+ elt = XCDR (elt);
if (! CONSP (elt))
continue;
- thischange = XINT (XCONS (elt)->car);
+ thischange = XINT (XCAR (elt));
/* Merge this range into the accumulated range. */
change += thischange;
record_unwind_protect (Fcombine_after_change_execute_1,
Vcombine_after_change_calls);
signal_after_change (begpos, endpos - begpos - change, endpos - begpos);
+ update_compositions (begpos, endpos, CHECK_ALL);
- return unbind_to (count, val);
+ return unbind_to (count, Qnil);
}
\f
void
{
staticpro (&combine_after_change_list);
combine_after_change_list = Qnil;
+ combine_after_change_buffer = Qnil;
DEFVAR_BOOL ("check-markers-debug-flag", &check_markers_debug_flag,
"Non-nil means enable debugging checks for invalid marker positions.");
"Used internally by the `combine-after-change-calls' macro.");
Vcombine_after_change_calls = Qnil;
+ DEFVAR_BOOL ("inhibit-modification-hooks", &inhibit_modification_hooks,
+ "Non-nil means don't run any of the hooks that respond to buffer changes.\n\
+This affects `before-change-functions' and `after-change-functions',\n\
+as well as hooks attached to text properties and overlays.");
+ inhibit_modification_hooks = 0;
+
defsubr (&Scombine_after_change_execute);
}