/* 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 ();
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);
abort ();
if (XMARKER (tail)->bytepos > Z_BYTE)
abort ();
+ if (multibyte && ! CHAR_HEAD_P (FETCH_BYTE (XMARKER (tail)->bytepos)))
+ abort ();
tail = XMARKER (tail)->chain;
}
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;
{
if (m->insertion_type || before_markers)
{
- m->bytepos += nbytes + combined_after_bytes;
- m->charpos += nchars + !!combined_after_bytes;
+ m->bytepos = to_byte + combined_after_bytes;
+ m->charpos = to - combined_before_bytes;
/* Point the marker before the combined character,
so that undoing the insertion puts it back where it was. */
if (combined_after_bytes)
but don't leave it pointing in the middle of a character.
Point the marker after the combined character,
so that undoing the insertion puts it back where it was. */
-
- /* Here we depend on the fact that the gap is after
- all of the combining bytes that we are going to skip over. */
- DEC_BOTH (m->charpos, m->bytepos);
- INC_BOTH (m->charpos, m->bytepos);
+ m->bytepos += combined_before_bytes;
+ if (combined_before_bytes == nbytes)
+ /* All new bytes plus combined_after_bytes (if any)
+ are combined. */
+ m->bytepos += combined_after_bytes;
}
}
/* If a marker was pointing into the combining bytes
{
/* Put it after the combining bytes. */
m->bytepos = to_byte + combined_after_bytes;
- m->charpos = to + 1;
+ m->charpos = to - combined_before_bytes;
/* Now move it back before the combined character,
so that undoing the insertion will put it where it was. */
DEC_BOTH (m->charpos, m->bytepos);
else if (m->bytepos > from_byte)
{
m->bytepos += nbytes;
- m->charpos += nchars;
+ m->charpos += nchars - combined_after_bytes - combined_before_bytes;
}
marker = m->chain;
{
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)
{
{
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. */
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);
{
unsigned int c = *ptr++;
- if (c < 0240 && NILP (Vnonascii_translation_table))
+ if (c < 0200 || (c < 0240 && NILP (Vnonascii_translation_table)))
outgoing_nbytes++;
else
{
inherit, prepare, before_markers);
}
\f
+/* See if the byte sequence at STR1 of length LEN1 combine with the
+ byte sequence at STR2 of length LEN2 to form a single composite
+ character. If so, return the number of bytes at the start of STR2
+ which combine in this way. Otherwise, return 0. If STR3 is not
+ NULL, it is a byte sequence of length LEN3 to be appended to STR1
+ before checking the combining. */
+int
+count_combining_composition (str1, len1, str2, len2, str3, len3)
+ unsigned char *str1, *str2, *str3;
+ int len1, len2, len3;
+{
+ int len = len1 + len2 + len3;
+ unsigned char *buf = (unsigned char *) alloca (len + 1);
+ int bytes;
+
+ bcopy (str1, buf, len1);
+ if (str3)
+ {
+ bcopy (str3, buf + len1, len3);
+ len1 += len3;
+ }
+ bcopy (str2, buf + len1 , len2);
+ buf[len] = 0;
+ PARSE_MULTIBYTE_SEQ (buf, len, bytes);
+ return (bytes <= len1 ? 0 : bytes - len1);
+}
+
/* See if the bytes before POS/POS_BYTE combine with bytes
at the start of STRING to form a single character.
If so, return the number of bytes at the start of STRING
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 == BEGV)
+ 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))
+
+ /* A sequence of a composite character requires a special handling. */
+ if (*p == LEADING_CODE_COMPOSITION)
+ return count_combining_composition (p, len, string, length, NULL, 0);
+
+ 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;
+ /* A sequence of a composite character requires a special handling. */
+ if (p[i] == LEADING_CODE_COMPOSITION)
+ return count_combining_composition (p + i, pos_byte - 1 - i,
+ bufp, Z_BYTE - pos_byte,
+ string, length);
+ 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;
+ /* A sequence of a composite character requires a special handling. */
+ if (string[i] == LEADING_CODE_COMPOSITION)
+ return count_combining_composition (string + i, length - i,
+ bufp, Z_BYTE - pos_byte, NULL, 0);
- if (pos == ZV)
- return 0;
- c = FETCH_BYTE (pos_byte);
- if (CHAR_HEAD_P (c))
- return 0;
- while (pos_byte < ZV_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
This function does not adjust markers for byte combining. That
should be done in advance by the functions
- adjust_markers_for_insert, adjust_markers_for_delete, or
- adjust_markers_for_replace. */
+ adjust_markers_for_insert or adjust_markers_for_replace. */
static void
combine_bytes (pos, pos_byte, nbytes)
/* 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)) \
+ byte_combining_error (); \
+ } while (0)
+
\f
/* Insert a sequence of NCHARS chars which occupy NBYTES bytes
starting at STRING. INHERIT, PREPARE and BEFORE_MARKERS
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))
= count_combining_before (string, nbytes, PT, PT_BYTE);
combined_after_bytes
= count_combining_after (string, nbytes, PT, PT_BYTE);
+ CHECK_BYTE_COMBINING_FOR_INSERT (PT);
/* Record deletion of the surrounding text that combines with
the insertion. This, together with recording the insertion,
if (combined_before_bytes)
combine_bytes (pos, pos_byte, combined_before_bytes);
}
+
+ CHECK_MARKERS ();
}
\f
/* Insert the part of the text of STRING, a Lisp object assumed to be
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_before (GPT_ADDR, outgoing_nbytes, PT, PT_BYTE);
combined_after_bytes
= 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;
+ }
/* Record deletion of the surrounding text that combines with
the insertion. This, together with recording the insertion,
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));
combined_before_bytes
= count_combining_before (GPT_ADDR, outgoing_nbytes, PT, PT_BYTE);
combined_after_bytes
- = count_combining_after (GPT_ADDR, outgoing_nbytes,
- PT, PT_BYTE);
+ = 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;
+ }
/* Record deletion of the surrounding text that combines with
the insertion. This, together with recording the insertion,
= 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))
+ {
+ nchars_del = XSTRING (prev_text)->size;
+ nbytes_del = STRING_BYTES (XSTRING (prev_text));
+ }
+
+ 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. */
+ len = len_byte = 1;
+ combined_before_bytes = combined_after_bytes = 0;
+ *(GPT_ADDR) = ' ';
+ }
+
if (combined_after_bytes)
{
Lisp_Object deletion;
from_byte + combined_after_bytes);
if (! EQ (current_buffer->undo_list, Qt))
- record_delete (from + len, deletion);
+ record_delete (from + nchars_del, deletion);
}
- if (combined_before_bytes)
+ if (combined_before_bytes
+ || (len_byte == 0 && combined_after_bytes > 0))
{
Lisp_Object deletion;
deletion = Qnil;
GPT += len; GPT_BYTE += len_byte;
if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
+ /* The gap should be at character boundary. */
if (combined_after_bytes)
move_gap_both (GPT + combined_after_bytes,
GPT_BYTE + combined_after_bytes);
- if (STRINGP (prev_text))
- {
- nchars_del = XSTRING (prev_text)->size;
- nbytes_del = STRING_BYTES (XSTRING (prev_text));
- }
adjust_markers_for_replace (from, from_byte, nchars_del, nbytes_del,
len, len_byte,
combined_before_bytes, combined_after_bytes);
- if (STRINGP (prev_text))
- record_delete (from - !!combined_before_bytes, prev_text);
- record_insert (from - !!combined_before_bytes,
- len - combined_before_bytes + !!combined_before_bytes);
+ if (! EQ (current_buffer->undo_list, Qt))
+ {
+ if (nchars_del > 0)
+ record_delete (from - combine_before, prev_text);
+ if (combine_before)
+ record_insert (from - 1, len - combined_before_bytes + 1);
+ else
+ record_insert (from, len);
+ }
if (len > nchars_del)
adjust_overlays_for_insert (from, len - nchars_del);
#endif
{
- int pos = PT, pos_byte = PT_BYTE;
-
if (from < PT)
adjust_point (len - nchars_del, len_byte - nbytes_del);
if (combined_after_bytes)
{
- if (combined_before_bytes)
+ if (combined_before_bytes == len_byte)
+ /* This is the case that all new bytes are combined. */
combined_before_bytes += combined_after_bytes;
else
combine_bytes (from + len, from_byte + len_byte,
combined_after_bytes);
}
-
if (combined_before_bytes)
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;
+
CHECK_MARKERS ();
if (len == 0)
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);
combined_after_bytes
= count_combining_after (GPT_ADDR, outgoing_insbytes, from, from_byte);
+ 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,
will add up to the right stuff in the undo list.
if (! EQ (current_buffer->undo_list, Qt))
deletion = make_buffer_string_both (from, from_byte,
from + combined_after_bytes,
- from_byte + combined_after_bytes, 1);
+ from_byte + combined_after_bytes,
+ 1);
adjust_markers_for_record_delete (from, from_byte,
from + combined_after_bytes,
from_byte + combined_after_bytes);
if (! EQ (current_buffer->undo_list, Qt))
- record_delete (from + inschars, deletion);
+ record_delete (from + nchars_del, deletion);
}
if (combined_before_bytes)
if (combined_after_bytes)
{
- if (combined_before_bytes)
+ if (combined_before_bytes == outgoing_insbytes)
+ /* This is the case that all new bytes are combined. */
combined_before_bytes += combined_after_bytes;
else
combine_bytes (from + inschars, from_byte + outgoing_insbytes,
if (combined_before_bytes)
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 (outgoing_insbytes == 0)
evaporate_overlays (from);
to_byte = CHAR_TO_BYTE (to);
del_range_2 (from, from_byte, to, to_byte);
+ signal_after_change (from, to - from, 0);
}
/* Like del_range_1 but args are byte positions, not char positions. */
}
del_range_2 (from, from_byte, to, to_byte);
+ signal_after_change (from, to - from, 0);
}
/* Like del_range_1, but positions are specified both as charpos
}
del_range_2 (from, from_byte, to, to_byte);
+ signal_after_change (from, to - from, 0);
}
/* Delete a range of text, specified both as character positions
combined_after_bytes
= count_combining_before (BUF_BYTE_ADDRESS (current_buffer, to_byte),
- ZV_BYTE - to_byte, from, from_byte);
+ Z_BYTE - to_byte, from, from_byte);
if (combined_after_bytes)
{
+ if (from == BEGV || to == ZV)
+ byte_combining_error ();
from_byte_1 = from_byte;
DEC_POS (from_byte_1);
}
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)
{
+ /* Adjust markers for byte combining. As we have already
+ adjuted markers without concerning byte combining, here we
+ must concern only byte combining. */
+ adjust_markers_for_replace (from, from_byte, 0, 0, 0, 0,
+ 0, combined_after_bytes);
combine_bytes (from, from_byte, combined_after_bytes);
record_insert (GPT - 1, 1);
+
+ if (Z - GPT < END_UNCHANGED)
+ END_UNCHANGED = Z - GPT;
}
CHECK_MARKERS ();
evaporate_overlays (from);
- signal_after_change (from, nchars_del, 0);
}
\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 ();
+ /* Let redisplay consider other windows than selected_window
+ if modifying another buffer. */
+ if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
+ ++windows_or_buffers_changed;
+
/* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
if (BUF_INTERVALS (current_buffer) != 0)
{
"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;
Vcombine_after_change_calls);
signal_after_change (begpos, endpos - begpos - change, endpos - begpos);
- 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);
}