/* 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, 2000, 01, 2003
+ Free Software Foundation, Inc.
This file is part of GNU Emacs.
#include "charset.h"
#include "window.h"
#include "blockinput.h"
+#include "region-cache.h"
#ifndef NULL
#define NULL 0
#endif
-#define min(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_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, int, int));
-static void adjust_markers_for_delete P_ ((int, int, int, int));
+static void adjust_markers_for_insert P_ ((int, int, int, int, int));
+void adjust_markers_for_delete P_ ((int, int, int, int));
+static void adjust_markers_for_replace P_ ((int, int, int, int, int, int));
static void adjust_point P_ ((int, int));
Lisp_Object Fcombine_after_change_execute ();
/* Buffer which combine_after_change_list is about. */
Lisp_Object combine_after_change_buffer;
+
+Lisp_Object Qinhibit_modification_hooks;
+
+\f
+/* Check all markers in the current buffer, looking for something invalid. */
+
+static int check_markers_debug_flag;
+
+#define CHECK_MARKERS() \
+ if (check_markers_debug_flag) \
+ check_markers (); \
+ else
+
+void
+check_markers ()
+{
+ register struct Lisp_Marker *tail;
+ int multibyte = ! NILP (current_buffer->enable_multibyte_characters);
+
+ for (tail = BUF_MARKERS (current_buffer); tail; tail = tail->next)
+ {
+ if (tail->buffer->text != current_buffer->text)
+ abort ();
+ if (tail->charpos > Z)
+ abort ();
+ if (tail->bytepos > Z_BYTE)
+ abort ();
+ if (multibyte && ! CHAR_HEAD_P (FETCH_BYTE (tail->bytepos)))
+ abort ();
+ }
+}
\f
/* Move gap to position CHARPOS.
Note that this can quit! */
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;
{
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))
+ for (m = BUF_MARKERS (current_buffer); m; m = m->next)
{
- m = XMARKER (marker);
charpos = m->charpos;
if (charpos > Z)
m->charpos -= to - from;
m->bytepos -= to_byte - from_byte;
}
-
/* Here's the case where a marker is inside text being deleted. */
else if (charpos > from)
{
- record_marker_adjustment (marker, from - charpos);
+ if (! m->insertion_type)
+ { /* Normal markers will end up at the beginning of the
+ re-inserted text after undoing a deletion, and must be
+ adjusted to move them to the correct place. */
+ XSETMISC (marker, m);
+ record_marker_adjustment (marker, from - charpos);
+ }
+ else if (charpos < to)
+ { /* Before-insertion markers will automatically move forward
+ upon re-inserting the deleted text, so we have to arrange
+ for them to move backward to the correct position. */
+ XSETMISC (marker, m);
+ record_marker_adjustment (marker, charpos - to);
+ }
m->charpos = from;
m->bytepos = from_byte;
}
-
- marker = m->chain;
+ /* Here's the case where a before-insertion marker is immediately
+ before the deleted region. */
+ else if (charpos == from && m->insertion_type)
+ {
+ /* Undoing the change uses normal insertion, which will
+ incorrectly make MARKER move forward, so we arrange for it
+ to then move backward to the correct place at the beginning
+ of the deleted region. */
+ XSETMISC (marker, m);
+ record_marker_adjustment (marker, to - from);
+ }
}
}
+
\f
/* Adjust markers for an insertion that stretches from FROM / FROM_BYTE
to TO / TO_BYTE. We have to relocate the charpos of every marker
that points after the insertion (but not their bytepos).
- COMBINED_BEFORE_BYTES is the number of bytes at the start of the insertion
- that combine into one character with the text before the insertion.
- COMBINED_AFTER_BYTES is the number of bytes after the insertion
- that combine into one character with the last inserted bytes.
-
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,
- combined_before_bytes, combined_after_bytes,
- before_markers)
+adjust_markers_for_insert (from, from_byte, to, to_byte, before_markers)
register int from, from_byte, to, to_byte;
- int combined_before_bytes, combined_after_bytes, before_markers;
+ int before_markers;
{
- Lisp_Object marker;
+ struct Lisp_Marker *m;
int adjusted = 0;
int nchars = to - from;
int nbytes = to_byte - from_byte;
- marker = BUF_MARKERS (current_buffer);
-
- while (!NILP (marker))
+ for (m = BUF_MARKERS (current_buffer); m; m = m->next)
{
- register struct Lisp_Marker *m = XMARKER (marker);
-
- /* In a single-byte buffer, a marker's two positions must be equal.
- (If this insertion is going to combine characters, Z will
- become different from Z_BYTE, but they might be the same now.
- If so, the two OLD positions of the marker should be equal.) */
+ /* In a single-byte buffer, a marker's two positions must be
+ equal. */
if (Z == Z_BYTE)
{
if (m->charpos != m->bytepos)
{
if (m->insertion_type || before_markers)
{
- m->bytepos += nbytes + combined_after_bytes;
- m->charpos += nchars + !!combined_after_bytes;
- /* Point the marker before the combined character,
- so that undoing the insertion puts it back where it was. */
- if (combined_after_bytes)
- DEC_BOTH (m->charpos, m->bytepos);
+ m->bytepos = to_byte;
+ m->charpos = to;
if (m->insertion_type)
adjusted = 1;
}
- else if (combined_before_bytes)
- {
- /* This marker doesn't "need relocation",
- 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);
- }
- }
- /* If a marker was pointing into the combining bytes
- after the insertion, don't leave it there
- in the middle of a character. */
- else if (combined_after_bytes && m->bytepos >= from_byte
- && m->bytepos < from_byte + combined_after_bytes)
- {
- /* Put it after the combining bytes. */
- m->bytepos = to_byte + combined_after_bytes;
- m->charpos = to + 1;
- /* 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;
}
-
- marker = m->chain;
}
/* Adjusting only markers whose insertion-type is t may result in
- disordered overlays in the slot `overlays_before'. */
+ - disordered start and end in overlays, and
+ - disordered overlays in the slot `overlays_before' of current_buffer. */
if (adjusted)
- fix_overlays_before (current_buffer, from, to);
+ {
+ fix_start_end_in_overlays(from, to);
+ fix_overlays_before (current_buffer, from, to);
+ }
}
/* Adjust point for an insertion of NBYTES bytes, which are NCHARS characters.
&& PT != PT_BYTE)
abort ();
}
+\f
+/* Adjust markers for a replacement of a text at FROM (FROM_BYTE) of
+ length OLD_CHARS (OLD_BYTES) to a new text of length NEW_CHARS
+ (NEW_BYTES). It is assumed that OLD_CHARS > 0, i.e., this is not
+ an insertion. */
+
+static void
+adjust_markers_for_replace (from, from_byte, old_chars, old_bytes,
+ new_chars, new_bytes)
+ int from, from_byte, old_chars, old_bytes, new_chars, new_bytes;
+{
+ register struct Lisp_Marker *m;
+ int prev_to_byte = from_byte + old_bytes;
+ int diff_chars = new_chars - old_chars;
+ int diff_bytes = new_bytes - old_bytes;
+
+ for (m = BUF_MARKERS (current_buffer); m; m = m->next)
+ {
+ if (m->bytepos >= prev_to_byte)
+ {
+ m->charpos += diff_chars;
+ m->bytepos += diff_bytes;
+ }
+ else if (m->bytepos > from_byte)
+ {
+ m->charpos = from;
+ m->bytepos = from_byte;
+ }
+ }
+
+ CHECK_MARKERS ();
+}
+
\f
/* Make the gap NBYTES_ADDED bytes longer. */
void
-make_gap (nbytes_added)
+make_gap_larger (nbytes_added)
int nbytes_added;
{
- unsigned char *result;
Lisp_Object tem;
int real_gap_loc;
int real_gap_loc_byte;
/* 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_BYTE - BEG_BYTE + GAP_SIZE + nbytes_added
- >= ((unsigned) 1 << (min (BITS_PER_INT, VALBITS) - 1)))
- error ("Buffer exceeds maximum size");
+ That won't work because so many places use `int'.
- BLOCK_INPUT;
- /* We allocate extra 1-byte `\0' at the tail for anchoring a search. */
- result = BUFFER_REALLOC (BEG_ADDR, (Z_BYTE - BEG_BYTE
- + GAP_SIZE + nbytes_added + 1));
+ Make sure we don't introduce overflows in the calculation. */
- if (result == 0)
- {
- UNBLOCK_INPUT;
- memory_full ();
- }
+ if (Z_BYTE - BEG_BYTE + GAP_SIZE
+ >= (((EMACS_INT) 1 << (min (VALBITS, BITS_PER_INT) - 1)) - 1
+ - nbytes_added))
+ error ("Buffer exceeds maximum size");
- /* We can't unblock until the new address is properly stored. */
- BEG_ADDR = result;
- UNBLOCK_INPUT;
+ enlarge_buffer_text (current_buffer, nbytes_added);
/* Prevent quitting in move_gap. */
tem = Vinhibit_quit;
Vinhibit_quit = tem;
}
+
+
+/* Make the gap NBYTES_REMOVED bytes shorter. */
+
+void
+make_gap_smaller (nbytes_removed)
+ int nbytes_removed;
+{
+ Lisp_Object tem;
+ int real_gap_loc;
+ int real_gap_loc_byte;
+ int real_Z;
+ int real_Z_byte;
+ int real_beg_unchanged;
+ int new_gap_size;
+
+ /* Make sure the gap is at least 20 bytes. */
+ if (GAP_SIZE - nbytes_removed < 20)
+ nbytes_removed = GAP_SIZE - 20;
+
+ /* Prevent quitting in move_gap. */
+ tem = Vinhibit_quit;
+ Vinhibit_quit = Qt;
+
+ real_gap_loc = GPT;
+ real_gap_loc_byte = GPT_BYTE;
+ new_gap_size = GAP_SIZE - nbytes_removed;
+ real_Z = Z;
+ real_Z_byte = Z_BYTE;
+ real_beg_unchanged = BEG_UNCHANGED;
+
+ /* Pretend that the last unwanted part of the gap is the entire gap,
+ and that the first desired part of the gap is part of the buffer
+ text. */
+ bzero (GPT_ADDR, new_gap_size);
+ GPT += new_gap_size;
+ GPT_BYTE += new_gap_size;
+ Z += new_gap_size;
+ Z_BYTE += new_gap_size;
+ GAP_SIZE = nbytes_removed;
+
+ /* Move the unwanted pretend gap to the end of the buffer. This
+ adjusts the markers properly too. */
+ gap_right (Z, Z_BYTE);
+
+ enlarge_buffer_text (current_buffer, -nbytes_removed);
+
+ /* Now restore the desired gap. */
+ GAP_SIZE = new_gap_size;
+ GPT = real_gap_loc;
+ GPT_BYTE = real_gap_loc_byte;
+ Z = real_Z;
+ Z_BYTE = real_Z_byte;
+ BEG_UNCHANGED = real_beg_unchanged;
+
+ /* Put an anchor. */
+ *(Z_ADDR) = 0;
+
+ Vinhibit_quit = tem;
+}
+
+void
+make_gap (nbytes_added)
+ int nbytes_added;
+{
+ if (nbytes_added >= 0)
+ make_gap_larger (nbytes_added);
+#if defined USE_MMAP_FOR_BUFFERS || defined REL_ALLOC || defined DOUG_LEA_MALLOC
+ else
+ make_gap_smaller (-nbytes_added);
+#endif
+}
\f
/* Copy NBYTES bytes of text from FROM_ADDR to TO_ADDR.
FROM_MULTIBYTE says whether the incoming text is multibyte.
int
copy_text (from_addr, to_addr, nbytes,
from_multibyte, to_multibyte)
- unsigned char *from_addr;
+ const unsigned char *from_addr;
unsigned char *to_addr;
int nbytes;
int from_multibyte, to_multibyte;
{
int nchars = 0;
int bytes_left = nbytes;
+ Lisp_Object tbl = Qnil;
+
+ /* We set the variable tbl to the reverse table of
+ Vnonascii_translation_table in advance. */
+ if (CHAR_TABLE_P (Vnonascii_translation_table))
+ {
+ tbl = Fchar_table_extra_slot (Vnonascii_translation_table,
+ make_number (0));
+ if (!CHAR_TABLE_P (tbl))
+ tbl = Qnil;
+ }
/* Convert multibyte to single byte. */
while (bytes_left > 0)
{
int thislen, c;
c = STRING_CHAR_AND_LENGTH (from_addr, bytes_left, thislen);
- *to_addr++ = SINGLE_BYTE_CHAR_P (c) ? c : (c & 0177) + 0200;
+ if (!SINGLE_BYTE_CHAR_P (c))
+ c = multibyte_char_to_unibyte (c, tbl);
+ *to_addr++ = c;
from_addr += thislen;
- bytes_left--;
+ bytes_left -= thislen;
nchars++;
}
return nchars;
while (nbytes > 0)
{
int c = *from_addr++;
- unsigned char workbuf[4], *str;
- int len;
- if (c >= 0240 && c < 0400)
+ if (c >= 0200)
{
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
int
count_size_as_multibyte (ptr, nbytes)
- unsigned char *ptr;
+ const unsigned char *ptr;
int nbytes;
{
int i;
{
unsigned int c = *ptr++;
- if (c < 0240)
+ if (c < 0200)
outgoing_nbytes++;
else
{
c = unibyte_char_to_multibyte (c);
- outgoing_nbytes += XINT (Fchar_bytes (make_number (c)));
+ outgoing_nbytes += CHAR_BYTES (c);
}
}
void
insert (string, nbytes)
- register unsigned char *string;
- register nbytes;
+ register const unsigned char *string;
+ register int nbytes;
{
if (nbytes > 0)
{
int opoint = PT;
insert_1 (string, nbytes, 0, 1, 0);
signal_after_change (opoint, 0, PT - opoint);
+ update_compositions (opoint, PT, CHECK_BORDER);
}
}
void
insert_and_inherit (string, nbytes)
- register unsigned char *string;
- register nbytes;
+ register const unsigned char *string;
+ register int nbytes;
{
if (nbytes > 0)
{
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);
void
insert_string (s)
- char *s;
+ const char *s;
{
insert (s, strlen (s));
}
void
insert_before_markers (string, nbytes)
- unsigned char *string;
+ const unsigned char *string;
register int nbytes;
{
if (nbytes > 0)
insert_1 (string, nbytes, 0, 1, 1);
signal_after_change (opoint, 0, PT - opoint);
+ update_compositions (opoint, PT, CHECK_BORDER);
}
}
void
insert_before_markers_and_inherit (string, nbytes)
- unsigned char *string;
+ const unsigned char *string;
register int nbytes;
{
if (nbytes > 0)
insert_1 (string, nbytes, 1, 1, 1);
signal_after_change (opoint, 0, PT - opoint);
+ update_compositions (opoint, PT, CHECK_BORDER);
}
}
void
insert_1 (string, nbytes, inherit, prepare, before_markers)
- register unsigned char *string;
+ register const unsigned char *string;
register int nbytes;
int inherit, prepare, before_markers;
{
insert_1_both (string, chars_in_text (string, nbytes), nbytes,
inherit, prepare, before_markers);
}
+
\f
+#ifdef BYTE_COMBINING_DEBUG
+
/* 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
count_combining_before (string, length, pos, pos_byte)
- unsigned char *string;
+ const unsigned char *string;
int length;
int pos, pos_byte;
{
- int opos = pos, opos_byte = pos_byte;
- int c;
- unsigned char *p = string;
+ int len, combining_bytes;
+ const 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))
+
+ 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
count_combining_after (string, length, pos, pos_byte)
- unsigned char *string;
+ const unsigned char *string;
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]))
+ while (i >= 0 && ! CHAR_HEAD_P (string[i]))
{
i--;
}
- if (! BASE_LEADING_CODE_P (string[i]))
- return 0;
-
- if (pos == ZV)
- return 0;
- c = FETCH_BYTE (pos_byte);
- if (CHAR_HEAD_P (c))
- return 0;
- while (pos_byte < ZV_BYTE)
+ if (i < 0)
{
- c = FETCH_BYTE (pos_byte);
- if (CHAR_HEAD_P (c))
- break;
- pos_byte++;
+ /* 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 (p[i]))
+ 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));
}
+ if (!BASE_LEADING_CODE_P (string[i]))
+ return 0;
- return pos_byte - opos_byte;
-}
-
-/* Adjust the position TARGET/TARGET_BYTE for the combining of NBYTES
- following the position POS/POS_BYTE to the character preceding POS.
- If TARGET is after POS+NBYTES, we only have to adjust the character
- position TARGET, else, if TARGET is after POS, we have to adjust
- both the character position TARGET and the byte position
- TARGET_BYTE, else we don't have to do any adjustment. */
-
-#define ADJUST_CHAR_POS(target, target_byte) \
- do { \
- if (target > pos + nbytes) \
- target -= nbytes; \
- else if (target >= pos) \
- { \
- target = pos; \
- target_byte = pos_byte + nbytes; \
- } \
- } while (0)
-
-/* Combine NBYTES stray trailing-codes, which were formerly separate
- characters, with the preceding character. These bytes
- are located after position POS / POS_BYTE, and the preceding character
- is located just before that position. */
-
-static void
-combine_bytes (pos, pos_byte, nbytes)
- int pos, pos_byte, nbytes;
-{
- /* Adjust all markers. */
- adjust_markers_for_delete (pos, pos_byte, pos + nbytes, pos_byte);
+ bytes = BYTES_BY_CHAR_HEAD (string[i]) - (length - i);
+ bufp++, pos_byte++;
+ while (!CHAR_HEAD_P (*bufp)) bufp++, pos_byte++;
- adjust_overlays_for_delete (pos, nbytes);
+ return (bytes <= pos_byte - opos_byte ? bytes : pos_byte - opos_byte);
+}
- ADJUST_CHAR_POS (BUF_PT (current_buffer), BUF_PT_BYTE (current_buffer));
- ADJUST_CHAR_POS (GPT, GPT_BYTE);
- ADJUST_CHAR_POS (Z, Z_BYTE);
- ADJUST_CHAR_POS (ZV, ZV_BYTE);
+#endif
- if (BUF_INTERVALS (current_buffer) != 0)
- /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES. */
- offset_intervals (current_buffer, pos, - nbytes);
-}
\f
/* Insert a sequence of NCHARS chars which occupy NBYTES bytes
starting at STRING. INHERIT, PREPARE and BEFORE_MARKERS
void
insert_1_both (string, nchars, nbytes, inherit, prepare, before_markers)
- register unsigned char *string;
+ register const unsigned char *string;
register int nchars, nbytes;
int inherit, prepare, before_markers;
{
- register Lisp_Object temp;
- int combined_before_bytes, combined_after_bytes;
+ if (nchars == 0)
+ return;
if (NILP (current_buffer->enable_multibyte_characters))
nchars = nbytes;
+ if (prepare)
+ /* Do this before moving and increasing the gap,
+ because the before-change hooks might move the gap
+ or make it smaller. */
+ prepare_to_modify_buffer (PT, PT, NULL);
+
if (PT != GPT)
move_gap_both (PT, PT_BYTE);
if (GAP_SIZE < nbytes)
make_gap (nbytes - GAP_SIZE);
- if (prepare)
- prepare_to_modify_buffer (PT, PT, NULL);
-
- combined_before_bytes
- = count_combining_before (string, nbytes, PT, PT_BYTE);
- combined_after_bytes
- = count_combining_after (string, nbytes, PT, PT_BYTE);
+#ifdef BYTE_COMBINING_DEBUG
+ if (count_combining_before (string, nbytes, PT, PT_BYTE)
+ || count_combining_after (string, nbytes, PT, PT_BYTE))
+ abort ();
+#endif
/* 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.
-
- But there is no need to actually delete the combining bytes
- from the buffer and reinsert them. */
-
- if (combined_after_bytes)
- record_delete (PT, combined_after_bytes);
-
- if (combined_before_bytes)
- record_delete (PT - 1, 1);
-
- record_insert (PT - !!combined_before_bytes,
- nchars - combined_before_bytes + !!combined_before_bytes);
+ will add up to the right stuff in the undo list. */
+ record_insert (PT, nchars);
MODIFF++;
bcopy (string, GPT_ADDR, nbytes);
GAP_SIZE -= nbytes;
- /* When we have combining at the end of the insertion,
- this is the character position before the combined character. */
GPT += nchars;
ZV += nchars;
Z += nchars;
Z_BYTE += nbytes;
if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
- if (combined_after_bytes)
- move_gap_both (GPT + combined_after_bytes,
- GPT_BYTE + combined_after_bytes);
-
if (GPT_BYTE < GPT)
abort ();
+ /* The insert may have been in the unchanged region, so check again. */
+ if (Z - GPT < END_UNCHANGED)
+ END_UNCHANGED = Z - GPT;
+
adjust_overlays_for_insert (PT, nchars);
adjust_markers_for_insert (PT, PT_BYTE,
PT + nchars, PT_BYTE + nbytes,
- 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
-
- {
- int pos = PT, pos_byte = PT_BYTE;
+ set_text_properties (make_number (PT), make_number (PT + nchars),
+ Qnil, Qnil, Qnil);
- adjust_point (nchars + combined_after_bytes,
- nbytes + combined_after_bytes);
+ adjust_point (nchars, nbytes);
- if (combined_after_bytes)
- combine_bytes (pos + nchars, pos_byte + nbytes, combined_after_bytes);
-
- 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, length, length_byte;
int inherit;
{
- if (length > 0)
- {
- int opoint = PT;
- insert_from_string_1 (string, pos, pos_byte, length, length_byte,
- inherit, 0);
- signal_after_change (opoint, 0, PT - opoint);
- }
+ int opoint = PT;
+
+ if (SCHARS (string) == 0)
+ return;
+
+ 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
register int pos, pos_byte, length, length_byte;
int inherit;
{
- if (length > 0)
- {
- int opoint = PT;
- insert_from_string_1 (string, pos, pos_byte, length, length_byte,
- inherit, 1);
- signal_after_change (opoint, 0, PT - opoint);
- }
+ int opoint = PT;
+
+ if (SCHARS (string) == 0)
+ return;
+
+ 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 (NILP (current_buffer->enable_multibyte_characters))
outgoing_nbytes = nchars;
- else if (nchars == nbytes)
+ else if (! STRING_MULTIBYTE (string))
outgoing_nbytes
- = count_size_as_multibyte (&XSTRING (string)->data[pos_byte],
+ = count_size_as_multibyte (SDATA (string) + pos_byte,
nbytes);
- /* Make sure point-max won't overflow after this insertion. */
- XSETINT (temp, outgoing_nbytes + Z);
- if (outgoing_nbytes + Z != XINT (temp))
- error ("Maximum buffer size exceeded");
-
GCPRO1 (string);
+ /* Do this before moving and increasing the gap,
+ because the before-change hooks might move the gap
+ or make it smaller. */
prepare_to_modify_buffer (PT, PT, NULL);
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;
/* Copy the string text into the buffer, perhaps converting
between single-byte and multibyte. */
- copy_text (XSTRING (string)->data + pos_byte, GPT_ADDR, nbytes,
- /* If these are equal, it is a single-byte string.
- Its chars are either ASCII, in which case copy_text
- won't change it, or single-byte non-ASCII chars,
- that need to be changed. */
- nchars != nbytes,
+ copy_text (SDATA (string) + pos_byte, GPT_ADDR, nbytes,
+ STRING_MULTIBYTE (string),
! NILP (current_buffer->enable_multibyte_characters));
+#ifdef BYTE_COMBINING_DEBUG
/* We have copied text into the gap, but we have not altered
PT or PT_BYTE yet. So we can pass PT and PT_BYTE
to these functions and get the same results as we would
have got earlier on. Meanwhile, PT_ADDR does point to
the text that has been stored by copy_text. */
+ if (count_combining_before (GPT_ADDR, outgoing_nbytes, PT, PT_BYTE)
+ || count_combining_after (GPT_ADDR, outgoing_nbytes, PT, PT_BYTE))
+ abort ();
+#endif
- 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);
-
- /* 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.
-
- But there is no need to actually delete the combining bytes
- from the buffer and reinsert them. */
-
- if (combined_after_bytes)
- record_delete (PT, combined_after_bytes);
-
- if (combined_before_bytes)
- record_delete (PT - 1, 1);
-
- record_insert (PT - !!combined_before_bytes,
- nchars - combined_before_bytes + !!combined_before_bytes);
+ record_insert (PT, nchars);
MODIFF++;
GAP_SIZE -= outgoing_nbytes;
Z_BYTE += outgoing_nbytes;
if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
- if (combined_after_bytes)
- move_gap_both (GPT + combined_after_bytes,
- GPT_BYTE + combined_after_bytes);
-
if (GPT_BYTE < GPT)
abort ();
+ /* The insert may have been in the unchanged region, so check again. */
+ if (Z - GPT < END_UNCHANGED)
+ END_UNCHANGED = Z - GPT;
+
adjust_overlays_for_insert (PT, nchars);
adjust_markers_for_insert (PT, PT_BYTE, PT + nchars,
PT_BYTE + outgoing_nbytes,
- 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;
- /* Get the intervals for the part of the string we are inserting--
- not including the combined-before bytes. */
- if (nbytes < XSTRING (string)->size_byte)
+ intervals = STRING_INTERVALS (string);
+ /* Get the intervals for the part of the string we are inserting. */
+ if (nbytes < SBYTES (string))
intervals = copy_intervals (intervals, pos, nchars);
-
+
/* Insert those intervals. */
graft_intervals_into_buffer (intervals, PT, nchars,
current_buffer, inherit);
- {
- int pos = PT, pos_byte = PT_BYTE;
-
- adjust_point (nchars + combined_after_bytes,
- outgoing_nbytes + combined_after_bytes);
-
- if (combined_after_bytes)
- combine_bytes (pos + nchars, pos_byte + outgoing_nbytes,
- combined_after_bytes);
-
- if (combined_before_bytes)
- combine_bytes (pos, pos_byte, combined_before_bytes);
- }
+ adjust_point (nchars, outgoing_nbytes);
}
\f
/* Insert text from BUF, NCHARS characters starting at CHARPOS, into the
int charpos, nchars;
int inherit;
{
- if (nchars > 0)
- {
- int opoint = PT;
+ int opoint = PT;
- insert_from_buffer_1 (buf, charpos, nchars, inherit);
- signal_after_change (opoint, 0, PT - opoint);
- }
+ 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))
error ("Maximum buffer size exceeded");
+ /* Do this before moving and increasing the gap,
+ because the before-change hooks might move the gap
+ or make it smaller. */
prepare_to_modify_buffer (PT, PT, NULL);
if (PT != GPT)
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));
+#ifdef BYTE_COMBINING_DEBUG
/* We have copied text into the gap, but we have not altered
PT or PT_BYTE yet. So we can pass PT and PT_BYTE
to these functions and get the same results as we would
have got earlier on. Meanwhile, GPT_ADDR does point to
the text that has been stored by copy_text. */
- 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);
-
- /* 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.
-
- But there is no need to actually delete the combining bytes
- from the buffer and reinsert them. */
-
- if (combined_after_bytes)
- record_delete (PT, combined_after_bytes);
-
- if (combined_before_bytes)
- record_delete (PT - 1, 1);
+ if (count_combining_before (GPT_ADDR, outgoing_nbytes, PT, PT_BYTE)
+ || count_combining_after (GPT_ADDR, outgoing_nbytes, PT, PT_BYTE))
+ abort ();
+#endif
- record_insert (PT - !!combined_before_bytes,
- nchars - combined_before_bytes + !!combined_before_bytes);
+ record_insert (PT, nchars);
MODIFF++;
GAP_SIZE -= outgoing_nbytes;
Z_BYTE += outgoing_nbytes;
if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
- if (combined_after_bytes)
- move_gap_both (GPT + combined_after_bytes,
- GPT_BYTE + combined_after_bytes);
-
if (GPT_BYTE < GPT)
abort ();
+ /* The insert may have been in the unchanged region, so check again. */
+ if (Z - GPT < END_UNCHANGED)
+ END_UNCHANGED = Z - GPT;
+
adjust_overlays_for_insert (PT, nchars);
adjust_markers_for_insert (PT, PT_BYTE, PT + nchars,
PT_BYTE + outgoing_nbytes,
- combined_before_bytes, combined_after_bytes, 0);
+ 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. */
+ /* Get the intervals for the part of the string we are inserting. */
intervals = BUF_INTERVALS (buf);
if (outgoing_nbytes < BUF_Z_BYTE (buf) - BUF_BEG_BYTE (buf))
- intervals = copy_intervals (intervals, from, nchars);
-
+ {
+ if (buf == current_buffer && PT <= from)
+ from += nchars;
+ intervals = copy_intervals (intervals, from, nchars);
+ }
+
/* Insert those intervals. */
graft_intervals_into_buffer (intervals, PT, nchars, current_buffer, inherit);
- {
- int pos = PT, pos_byte = PT_BYTE;
-
- adjust_point (nchars + combined_after_bytes,
- outgoing_nbytes + combined_after_bytes);
-
- if (combined_after_bytes)
- combine_bytes (pos + nchars, pos_byte + outgoing_nbytes,
- combined_after_bytes);
-
- if (combined_before_bytes)
- combine_bytes (pos, pos_byte, combined_before_bytes);
- }
+ adjust_point (nchars, outgoing_nbytes);
}
\f
-/* This function should be called after moving gap to FROM and before
- altering text between FROM and TO. This adjusts various position
- keepers and markers as if the text is deleted. Don't forget to
- call adjust_after_replace after you actually alter the text. */
+/* Record undo information and adjust markers and position keepers for
+ a replacement of a text PREV_TEXT at FROM to a new text of LEN
+ chars (LEN_BYTE bytes) which resides in the gap just after
+ GPT_ADDR.
-void
-adjust_before_replace (from, from_byte, to, to_byte)
- int from, from_byte, to, to_byte;
-{
- adjust_markers_for_delete (from, from_byte, to, to_byte);
- record_delete (from, to - from);
- adjust_overlays_for_delete (from, to - from);
-}
-
-/* This function should be called after altering the text between FROM
- and TO to a new text of LEN chars (LEN_BYTE bytes), but before
- making the text a buffer contents. It exists just after GPT_ADDR. */
+ PREV_TEXT nil means the new text was just inserted. */
void
-adjust_after_replace (from, from_byte, to, to_byte, len, len_byte, replace)
- int from, from_byte, to, to_byte, len, len_byte, replace;
+adjust_after_replace (from, from_byte, prev_text, len, len_byte)
+ int from, from_byte, len, len_byte;
+ Lisp_Object prev_text;
{
- int 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);
+ int nchars_del = 0, nbytes_del = 0;
- if (combined_after_bytes)
- record_delete (from, combined_after_bytes);
+#ifdef BYTE_COMBINING_DEBUG
+ if (count_combining_before (GPT_ADDR, len_byte, from, from_byte)
+ || count_combining_after (GPT_ADDR, len_byte, from, from_byte))
+ abort ();
+#endif
- if (combined_before_bytes)
- record_delete (from - 1, 1);
+ if (STRINGP (prev_text))
+ {
+ nchars_del = SCHARS (prev_text);
+ nbytes_del = SBYTES (prev_text);
+ }
/* Update various buffer positions for the new text. */
GAP_SIZE -= len_byte;
GPT += len; GPT_BYTE += len_byte;
if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
- if (combined_after_bytes)
- move_gap_both (GPT + combined_after_bytes,
- GPT_BYTE + combined_after_bytes);
-
- record_insert (from - !!combined_before_bytes,
- len - combined_before_bytes + !!combined_before_bytes);
- adjust_overlays_for_insert (from, len);
- adjust_markers_for_insert (from, from_byte,
- from + len, from_byte + len_byte,
- combined_before_bytes, combined_after_bytes, 0);
-#ifdef USE_TEXT_PROPERTIES
+ if (nchars_del > 0)
+ adjust_markers_for_replace (from, from_byte, nchars_del, nbytes_del,
+ len, len_byte);
+ else
+ adjust_markers_for_insert (from, from_byte,
+ from + len, from_byte + len_byte, 0);
+
+ if (! EQ (current_buffer->undo_list, Qt))
+ {
+ if (nchars_del > 0)
+ record_delete (from, prev_text);
+ record_insert (from, len);
+ }
+
+ if (len > nchars_del)
+ adjust_overlays_for_insert (from, len - nchars_del);
+ else if (len < nchars_del)
+ adjust_overlays_for_delete (from, nchars_del - len);
if (BUF_INTERVALS (current_buffer) != 0)
- /* REPLACE zero means that we have not yet adjusted the interval
- tree for the text between FROM and TO, thus, we must treat the
- new text as a newly inserted text, not as a replacement of
- something. */
- offset_intervals (current_buffer, from, len - (replace ? to - from : 0));
+ {
+ offset_intervals (current_buffer, from, len - nchars_del);
+ }
+
+ 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;
+
+ CHECK_MARKERS ();
+
+ if (len == 0)
+ evaporate_overlays (from);
+ MODIFF++;
+}
+
+/* Like adjust_after_replace, but doesn't require PREV_TEXT.
+ This is for use when undo is not enabled in the current buffer. */
+
+void
+adjust_after_replace_noundo (from, from_byte, nchars_del, nbytes_del, len, len_byte)
+ int from, from_byte, nchars_del, nbytes_del, len, len_byte;
+{
+#ifdef BYTE_COMBINING_DEBUG
+ if (count_combining_before (GPT_ADDR, len_byte, from, from_byte)
+ || count_combining_after (GPT_ADDR, len_byte, from, from_byte))
+ abort ();
#endif
- {
- int pos = PT, pos_byte = PT_BYTE;
+ /* Update various buffer positions for the new text. */
+ GAP_SIZE -= len_byte;
+ ZV += len; Z+= len;
+ ZV_BYTE += len_byte; Z_BYTE += len_byte;
+ GPT += len; GPT_BYTE += len_byte;
+ if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
+
+ if (nchars_del > 0)
+ adjust_markers_for_replace (from, from_byte, nchars_del, nbytes_del,
+ len, len_byte);
+ else
+ adjust_markers_for_insert (from, from_byte,
+ from + len, from_byte + len_byte, 0);
- if (from < PT)
- adjust_point (len - (to - from) + combined_after_bytes,
- len_byte - (to_byte - from_byte) + combined_after_bytes);
- else if (from == PT && combined_before_bytes)
- adjust_point (0, combined_before_bytes);
+ if (len > nchars_del)
+ adjust_overlays_for_insert (from, len - nchars_del);
+ else if (len < nchars_del)
+ adjust_overlays_for_delete (from, nchars_del - len);
+ if (BUF_INTERVALS (current_buffer) != 0)
+ {
+ offset_intervals (current_buffer, from, len - nchars_del);
+ }
- if (combined_after_bytes)
- combine_bytes (from + len, from_byte + len_byte, combined_after_bytes);
+ 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 (combined_before_bytes)
- combine_bytes (from, from_byte, combined_before_bytes);
- }
+ CHECK_MARKERS ();
if (len == 0)
evaporate_overlays (from);
MODIFF++;
}
+/* Record undo information, adjust markers and position keepers for an
+ insertion of a text from FROM (FROM_BYTE) to TO (TO_BYTE). The
+ text already exists in the current buffer but character length (TO
+ - FROM) may be incorrect, the correct length is NEWLEN. */
+
+void
+adjust_after_insert (from, from_byte, to, to_byte, newlen)
+ int from, from_byte, to, to_byte, newlen;
+{
+ int len = to - from, len_byte = to_byte - from_byte;
+
+ if (GPT != to)
+ move_gap_both (to, to_byte);
+ GAP_SIZE += len_byte;
+ GPT -= len; GPT_BYTE -= len_byte;
+ ZV -= len; ZV_BYTE -= len_byte;
+ Z -= len; Z_BYTE -= len_byte;
+ adjust_after_replace (from, from_byte, Qnil, newlen, len_byte);
+}
+\f
/* Replace the text from character positions FROM to TO with NEW,
If PREPARE is nonzero, call prepare_to_modify_buffer.
If INHERIT, the newly inserted text should inherit text properties
/* Note that this does not yet handle markers quite right.
Also it needs to record a single undo-entry that does a replacement
rather than a separate delete and insert.
- That way, undo will also handle markers properly. */
+ That way, undo will also handle markers properly.
+
+ But if MARKERS is 0, don't relocate markers. */
void
-replace_range (from, to, new, prepare, inherit)
+replace_range (from, to, new, prepare, inherit, markers)
Lisp_Object new;
- int from, to, prepare, inherit;
+ int from, to, prepare, inherit, markers;
{
- int inschars = XSTRING (new)->size;
- int insbytes = XSTRING (new)->size_byte;
+ int inschars = SCHARS (new);
+ int insbytes = SBYTES (new);
int from_byte, to_byte;
int nbytes_del, nchars_del;
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;
+
+ CHECK_MARKERS ();
GCPRO1 (new);
+ deletion = Qnil;
if (prepare)
{
if (NILP (current_buffer->enable_multibyte_characters))
outgoing_insbytes = inschars;
- else if (inschars == insbytes)
+ else if (! STRING_MULTIBYTE (new))
outgoing_insbytes
- = count_size_as_multibyte (XSTRING (new)->data, insbytes);
+ = count_size_as_multibyte (SDATA (new), insbytes);
/* Make sure point-max won't overflow after this insertion. */
XSETINT (temp, Z_BYTE - nbytes_del + insbytes);
if (to < GPT)
gap_left (to, to_byte, 0);
- /* Relocate all markers pointing into the new, larger gap
- to point at the end of the text before the gap.
- Do this before recording the deletion,
- so that undo handles this after reinserting the text. */
- adjust_markers_for_delete (from, from_byte, to, to_byte);
-
- record_delete (from, nchars_del);
+ /* 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. */
+ if (! EQ (current_buffer->undo_list, Qt))
+ deletion = make_buffer_string_both (from, from_byte, to, to_byte, 1);
GAP_SIZE += nbytes_del;
ZV -= nchars_del;
Z_BYTE -= nbytes_del;
GPT = from;
GPT_BYTE = from_byte;
- *(GPT_ADDR) = 0; /* Put an anchor. */
+ if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
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);
/* Copy the string text into the buffer, perhaps converting
between single-byte and multibyte. */
- copy_text (XSTRING (new)->data, GPT_ADDR, insbytes,
- /* If these are equal, it is a single-byte string.
- Its chars are either ASCII, in which case copy_text
- won't change it, or single-byte non-ASCII chars,
- that need to be changed. */
- inschars != insbytes,
+ copy_text (SDATA (new), GPT_ADDR, insbytes,
+ STRING_MULTIBYTE (new),
! NILP (current_buffer->enable_multibyte_characters));
- /* We have copied text into the gap, but we have not altered
- PT or PT_BYTE yet. So we can pass PT and PT_BYTE
- to these functions and get the same results as we would
- have got earlier on. Meanwhile, GPT_ADDR does point to
+#ifdef BYTE_COMBINING_DEBUG
+ /* We have copied text into the gap, but we have not marked
+ it as part of the buffer. So we can use the old FROM and FROM_BYTE
+ here, for both the previous text and the following text.
+ Meanwhile, GPT_ADDR does point to
the text that has been stored by copy_text. */
+ if (count_combining_before (GPT_ADDR, outgoing_insbytes, from, from_byte)
+ || count_combining_after (GPT_ADDR, outgoing_insbytes, from, from_byte))
+ abort ();
+#endif
- combined_before_bytes
- = count_combining_before (GPT_ADDR, outgoing_insbytes, PT, PT_BYTE);
- combined_after_bytes
- = count_combining_after (GPT_ADDR, outgoing_insbytes, PT, PT_BYTE);
-
- /* 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.
-
- But there is no need to actually delete the combining bytes
- from the buffer and reinsert them. */
-
- if (combined_after_bytes)
- record_delete (PT, combined_after_bytes);
-
- if (combined_before_bytes)
- record_delete (PT - 1, 1);
-
- record_insert (PT - !!combined_before_bytes,
- inschars - combined_before_bytes + !!combined_before_bytes);
+ if (! EQ (current_buffer->undo_list, Qt))
+ {
+ record_delete (from, deletion);
+ record_insert (from, inschars);
+ }
GAP_SIZE -= outgoing_insbytes;
GPT += inschars;
Z_BYTE += outgoing_insbytes;
if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
- if (combined_after_bytes)
- move_gap_both (GPT + combined_after_bytes,
- GPT_BYTE + combined_after_bytes);
-
if (GPT_BYTE < GPT)
abort ();
adjusting the markers that bound the overlays. */
adjust_overlays_for_delete (from, nchars_del);
adjust_overlays_for_insert (from, inschars);
- adjust_markers_for_insert (from, from_byte,
- from + inschars, from_byte + outgoing_insbytes,
- combined_before_bytes, combined_after_bytes, 0);
-#ifdef USE_TEXT_PROPERTIES
- offset_intervals (current_buffer, PT, inschars - nchars_del);
+ /* Adjust markers for the deletion and the insertion. */
+ if (markers)
+ adjust_markers_for_replace (from, from_byte, nchars_del, nbytes_del,
+ inschars, outgoing_insbytes);
+
+ offset_intervals (current_buffer, from, inschars - nchars_del);
/* Get the intervals for the part of the string we are inserting--
not including the combined-before bytes. */
- intervals = XSTRING (new)->intervals;
+ intervals = STRING_INTERVALS (new);
/* 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)
- adjust_point ((from + inschars - (PT < to ? PT : to)
- + combined_after_bytes),
+ adjust_point ((from + inschars - (PT < to ? PT : to)),
(from_byte + outgoing_insbytes
- - (PT_BYTE < to_byte ? PT_BYTE : to_byte)
- + combined_after_bytes));
-
- if (combined_after_bytes)
- combine_bytes (from + inschars, from_byte + outgoing_insbytes,
- combined_after_bytes);
-
- if (combined_before_bytes)
- combine_bytes (from, from_byte, combined_before_bytes);
+ - (PT_BYTE < to_byte ? PT_BYTE : to_byte)));
if (outgoing_insbytes == 0)
evaporate_overlays (from);
+ CHECK_MARKERS ();
+
MODIFF++;
UNGCPRO;
- signal_after_change (from, nchars_del, PT - from);
+ signal_after_change (from, nchars_del, GPT - from);
+ update_compositions (from, GPT, CHECK_BORDER);
+}
+\f
+/* Replace the text from character positions FROM to TO with
+ the text in INS of length INSCHARS.
+ Keep the text properties that applied to the old characters
+ (extending them to all the new chars if there are more new chars).
+
+ Note that this does not yet handle markers quite right.
+
+ If MARKERS is nonzero, relocate markers.
+
+ Unlike most functions at this level, never call
+ prepare_to_modify_buffer and never call signal_after_change. */
+
+void
+replace_range_2 (from, from_byte, to, to_byte, ins, inschars, insbytes, markers)
+ int from, from_byte, to, to_byte;
+ char *ins;
+ int inschars, insbytes, markers;
+{
+ int nbytes_del, nchars_del;
+ Lisp_Object temp;
+
+ CHECK_MARKERS ();
+
+ nchars_del = to - from;
+ nbytes_del = to_byte - from_byte;
+
+ if (nbytes_del <= 0 && insbytes == 0)
+ return;
+
+ /* Make sure point-max won't overflow after this insertion. */
+ XSETINT (temp, Z_BYTE - nbytes_del + insbytes);
+ if (Z_BYTE - nbytes_del + insbytes != XINT (temp))
+ error ("Maximum buffer size exceeded");
+
+ /* Make sure the gap is somewhere in or next to what we are deleting. */
+ if (from > GPT)
+ gap_right (from, from_byte);
+ if (to < GPT)
+ gap_left (to, to_byte, 0);
+
+ GAP_SIZE += nbytes_del;
+ ZV -= nchars_del;
+ Z -= nchars_del;
+ ZV_BYTE -= nbytes_del;
+ Z_BYTE -= nbytes_del;
+ GPT = from;
+ GPT_BYTE = from_byte;
+ if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
+
+ if (GPT_BYTE < GPT)
+ abort ();
+
+ 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);
+
+ /* Copy the replacement text into the buffer. */
+ bcopy (ins, GPT_ADDR, insbytes);
+
+#ifdef BYTE_COMBINING_DEBUG
+ /* We have copied text into the gap, but we have not marked
+ it as part of the buffer. So we can use the old FROM and FROM_BYTE
+ here, for both the previous text and the following text.
+ Meanwhile, GPT_ADDR does point to
+ the text that has been stored by copy_text. */
+ if (count_combining_before (GPT_ADDR, insbytes, from, from_byte)
+ || count_combining_after (GPT_ADDR, insbytes, from, from_byte))
+ abort ();
+#endif
+
+ GAP_SIZE -= insbytes;
+ GPT += inschars;
+ ZV += inschars;
+ Z += inschars;
+ GPT_BYTE += insbytes;
+ ZV_BYTE += insbytes;
+ Z_BYTE += insbytes;
+ if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
+
+ if (GPT_BYTE < GPT)
+ abort ();
+
+ /* Adjust the overlay center as needed. This must be done after
+ adjusting the markers that bound the overlays. */
+ if (nchars_del != inschars)
+ {
+ adjust_overlays_for_insert (from, inschars);
+ adjust_overlays_for_delete (from + inschars, nchars_del);
+ }
+
+ /* Adjust markers for the deletion and the insertion. */
+ if (markers
+ && ! (nchars_del == 1 && inschars == 1))
+ adjust_markers_for_replace (from, from_byte, nchars_del, nbytes_del,
+ inschars, insbytes);
+
+ offset_intervals (current_buffer, from, inschars - nchars_del);
+
+ /* Relocate point as if it were a marker. */
+ if (from < PT && nchars_del != inschars)
+ adjust_point ((from + inschars - (PT < to ? PT : to)),
+ (from_byte + insbytes
+ - (PT_BYTE < to_byte ? PT_BYTE : to_byte)));
+
+ if (insbytes == 0)
+ evaporate_overlays (from);
+
+ CHECK_MARKERS ();
+
+ MODIFF++;
}
\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)
{
int range_length = to - from;
prepare_to_modify_buffer (from, to, &from);
- to = from + range_length;
+ to = min (ZV, from + range_length);
}
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. */
if (old_from != from)
from_byte = CHAR_TO_BYTE (from);
- if (old_to == Z - to)
+ if (to > ZV)
+ {
+ to = ZV;
+ to_byte = ZV_BYTE;
+ }
+ else if (old_to == Z - to)
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
if (old_from != from)
from_byte = CHAR_TO_BYTE (from);
- if (old_to == Z - to)
+ if (to > ZV)
+ {
+ to = ZV;
+ to_byte = ZV_BYTE;
+ }
+ else if (old_to == Z - to)
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;
+ Lisp_Object deletion;
+
+ CHECK_MARKERS ();
nchars_del = to - from;
nbytes_del = to_byte - from_byte;
if (to < GPT)
gap_left (to, to_byte, 0);
- combined_after_bytes
- = count_combining_before (BUF_BYTE_ADDRESS (current_buffer, to_byte),
- ZV_BYTE - to_byte, from, from_byte);
+#ifdef BYTE_COMBINING_DEBUG
+ if (count_combining_before (BUF_BYTE_ADDRESS (current_buffer, to_byte),
+ Z_BYTE - to_byte, from, from_byte))
+ abort ();
+#endif
+
+ if (ret_string || ! EQ (current_buffer->undo_list, Qt))
+ deletion = make_buffer_string_both (from, from_byte, to, to_byte, 1);
+ else
+ deletion = Qnil;
/* Relocate all markers pointing into the new, larger gap
to point at the end of the text before the gap.
so that undo handles this after reinserting the text. */
adjust_markers_for_delete (from, from_byte, to, to_byte);
- record_delete (from - !!combined_after_bytes,
- nchars_del + combined_after_bytes + !!combined_after_bytes);
- if (combined_after_bytes)
- /* COMBINED_AFTER_BYTES nonzero means that the above record_delete
- moved the gap by calling Fbuffer_substring. We must move the
- gap again to a proper place. */
- move_gap_both (from, from_byte);
+ if (! EQ (current_buffer->undo_list, Qt))
+ record_delete (from, deletion);
MODIFF++;
/* Relocate point as if it were a marker. */
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
Z -= nchars_del;
GPT = from;
GPT_BYTE = from_byte;
-
- if (combined_after_bytes)
- move_gap_both (GPT + combined_after_bytes,
- GPT_BYTE + combined_after_bytes);
-
- *(GPT_ADDR) = 0; /* Put an anchor. */
+ if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
if (GPT_BYTE < GPT)
abort ();
- if (GPT - BEG < beg_unchanged)
- beg_unchanged = GPT - BEG;
- if (Z - GPT < end_unchanged)
- end_unchanged = Z - GPT;
-
- if (combined_after_bytes)
- combine_bytes (from, from_byte, combined_after_bytes);
+ 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);
+ 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)
GCPRO1 (preserve_marker);
verify_interval_modification (current_buffer, start, end);
*preserve_ptr = marker_position (preserve_marker);
- unchain_marker (preserve_marker);
+ unchain_marker (XMARKER (preserve_marker));
UNGCPRO;
}
else
if (! NILP (preserve_marker)) \
{ \
*preserve_ptr = marker_position (preserve_marker); \
- unchain_marker (preserve_marker); \
+ unchain_marker (XMARKER (preserve_marker)); \
}
#define PRESERVE_START_END \
Lisp_Object preserve_marker;
struct gcpro gcpro1, gcpro2, gcpro3;
+ if (inhibit_modification_hooks)
+ return;
+
start = make_number (start_int);
end = make_number (end_int);
preserve_marker = Qnil;
call1 (Vrun_hooks, Qfirst_change_hook);
}
- /* Run the before-change-function if any.
- We don't bother "binding" this variable to nil
- because it is obsolete anyway and new code should not use it. */
- if (!NILP (Vbefore_change_function))
- {
- PRESERVE_VALUE;
- PRESERVE_START_END;
- call2 (Vbefore_change_function, FETCH_START, FETCH_END);
- }
-
/* Now run the before-change-functions if any. */
if (!NILP (Vbefore_change_functions))
{
Lisp_Object before_change_functions;
Lisp_Object after_change_functions;
struct gcpro gcpro1, gcpro2;
+ struct buffer *old = current_buffer;
+ struct buffer *new;
PRESERVE_VALUE;
PRESERVE_START_END;
args[2] = FETCH_END;
run_hook_list_with_args (before_change_functions, 3, args);
- /* "Unbind" the variables we "bound" to nil. */
- Vbefore_change_functions = before_change_functions;
- Vafter_change_functions = after_change_functions;
+ /* "Unbind" the variables we "bound" to nil. Beware a
+ buffer-local hook which changes the buffer when run (e.g. W3). */
+ if (old != current_buffer)
+ {
+ new = current_buffer;
+ set_buffer_internal (old);
+ Vbefore_change_functions = before_change_functions;
+ Vafter_change_functions = after_change_functions;
+ set_buffer_internal (new);
+ }
+ else
+ {
+ Vbefore_change_functions = before_change_functions;
+ Vafter_change_functions = after_change_functions;
+ }
UNGCPRO;
}
- if (!NILP (current_buffer->overlays_before)
- || !NILP (current_buffer->overlays_after))
+ if (current_buffer->overlays_before || current_buffer->overlays_after)
{
PRESERVE_VALUE;
report_overlay_modification (FETCH_START, FETCH_END, 0,
signal_after_change (charpos, lendel, lenins)
int charpos, lendel, lenins;
{
+ if (inhibit_modification_hooks)
+ return;
+
/* If we are deferring calls to the after-change functions
and there are no before-change functions,
just record the args that we were going to use. */
if (! NILP (Vcombine_after_change_calls)
- && NILP (Vbefore_change_function) && NILP (Vbefore_change_functions)
- && NILP (current_buffer->overlays_before)
- && NILP (current_buffer->overlays_after))
+ && NILP (Vbefore_change_functions)
+ && !current_buffer->overlays_before
+ && !current_buffer->overlays_after)
{
Lisp_Object elt;
return;
}
- if (!NILP (combine_after_change_list))
+ if (!NILP (combine_after_change_list))
Fcombine_after_change_execute ();
- /* Run the after-change-function if any.
- We don't bother "binding" this variable to nil
- because it is obsolete anyway and new code should not use it. */
- if (!NILP (Vafter_change_function))
- call3 (Vafter_change_function,
- make_number (charpos), make_number (charpos + lenins),
- make_number (lendel));
-
if (!NILP (Vafter_change_functions))
{
Lisp_Object args[4];
Lisp_Object before_change_functions;
Lisp_Object after_change_functions;
+ struct buffer *old = current_buffer;
+ struct buffer *new;
struct gcpro gcpro1, gcpro2;
/* "Bind" before-change-functions and after-change-functions
run_hook_list_with_args (after_change_functions,
4, args);
- /* "Unbind" the variables we "bound" to nil. */
- Vbefore_change_functions = before_change_functions;
- Vafter_change_functions = after_change_functions;
+ /* "Unbind" the variables we "bound" to nil. Beware a
+ buffer-local hook which changes the buffer when run (e.g. W3). */
+ if (old != current_buffer)
+ {
+ new = current_buffer;
+ set_buffer_internal (old);
+ Vbefore_change_functions = before_change_functions;
+ Vafter_change_functions = after_change_functions;
+ set_buffer_internal (new);
+ }
+ else
+ {
+ Vbefore_change_functions = before_change_functions;
+ Vafter_change_functions = after_change_functions;
+ }
UNGCPRO;
}
- if (!NILP (current_buffer->overlays_before)
- || !NILP (current_buffer->overlays_after))
+ if (current_buffer->overlays_before || current_buffer->overlays_after)
report_overlay_modification (make_number (charpos),
make_number (charpos + lenins),
1,
/* After an insertion, call the text properties
insert-behind-hooks or insert-in-front-hooks. */
if (lendel == 0)
- report_interval_modification (charpos, charpos + lenins);
+ report_interval_modification (make_number (charpos),
+ make_number (charpos + lenins));
}
Lisp_Object
}
DEFUN ("combine-after-change-execute", Fcombine_after_change_execute,
- Scombine_after_change_execute, 0, 0, 0,
- "This function is for use internally in `combine-after-change-calls'.")
- ()
+ Scombine_after_change_execute, 0, 0, 0,
+ doc: /* This function is for use internally in `combine-after-change-calls'. */)
+ ()
{
- register Lisp_Object val;
- int count = specpdl_ptr - specpdl;
+ int count = SPECPDL_INDEX ();
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;
that was changed. */
begpos = BEG + beg;
endpos = Z - end;
-
+
/* We are about to handle these, so discard them. */
combine_after_change_list = Qnil;
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
syms_of_insdel ()
{
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,
+ doc: /* Non-nil means enable debugging checks for invalid marker positions. */);
+ check_markers_debug_flag = 0;
DEFVAR_LISP ("combine-after-change-calls", &Vcombine_after_change_calls,
- "Used internally by the `combine-after-change-calls' macro.");
+ doc: /* Used internally by the `combine-after-change-calls' macro. */);
Vcombine_after_change_calls = Qnil;
+ DEFVAR_BOOL ("inhibit-modification-hooks", &inhibit_modification_hooks,
+ doc: /* Non-nil means don't run any of the hooks that respond to buffer changes.
+This affects `before-change-functions' and `after-change-functions',
+as well as hooks attached to text properties and overlays. */);
+ inhibit_modification_hooks = 0;
+ Qinhibit_modification_hooks = intern ("inhibit-modification-hooks");
+ staticpro (&Qinhibit_modification_hooks);
+
defsubr (&Scombine_after_change_execute);
}
+
+/* arch-tag: 9b34b886-47d7-465e-a234-299af411b23d
+ (do not change this comment) */