#include "window.h"
#include "blockinput.h"
+#ifndef NULL
+#define NULL 0
+#endif
+
#define min(x, y) ((x) < (y) ? (x) : (y))
static void insert_from_string_1 ();
but then this range contains no markers. */
if (mpos > from + amount && mpos <= from)
{
- record_marker_adjustment (marker, from + amount - mpos);
- mpos = from + amount;
+ int before = mpos;
+ int after = from + amount;
+
+ mpos = after;
+
+ /* Compute the before and after positions
+ as buffer positions. */
+ if (before > GPT + GAP_SIZE)
+ before -= GAP_SIZE;
+ else if (before > GPT)
+ before = GPT;
+
+ if (after > GPT + GAP_SIZE)
+ after -= GAP_SIZE;
+ else if (after > GPT)
+ after = GPT;
+
+ record_marker_adjustment (marker, after - before);
}
}
if (mpos > from && mpos <= to)
register Lisp_Object temp;
if (prepare)
- prepare_to_modify_buffer (PT, PT);
+ prepare_to_modify_buffer (PT, PT, NULL);
if (PT != GPT)
move_gap (PT);
error ("maximum buffer size exceeded");
GCPRO1 (string);
- prepare_to_modify_buffer (PT, PT);
+ prepare_to_modify_buffer (PT, PT, NULL);
if (PT != GPT)
move_gap (PT);
if (length + Z != XINT (temp))
error ("maximum buffer size exceeded");
- prepare_to_modify_buffer (PT, PT);
+ prepare_to_modify_buffer (PT, PT, NULL);
if (PT != GPT)
move_gap (PT);
}
}
\f
+/* Replace the text from FROM to TO with NEW,
+ If PREPARE is nonzero, call prepare_to_modify_buffer.
+ If INHERIT, the newly inserted text should inherit text properties
+ from the surrounding non-deleted text. */
+
+/* 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. */
+
+void
+replace_range (from, to, new, prepare, inherit)
+ Lisp_Object new;
+ int from, to, prepare, inherit;
+{
+ int numdel;
+ int inslen = XSTRING (new)->size;
+ register Lisp_Object temp;
+ struct gcpro gcpro1;
+
+ GCPRO1 (new);
+
+ if (prepare)
+ {
+ int range_length = to - from;
+ prepare_to_modify_buffer (from, to, &from);
+ to = from + range_length;
+ }
+
+ /* Make args be valid */
+ if (from < BEGV)
+ from = BEGV;
+ if (to > ZV)
+ to = ZV;
+
+ UNGCPRO;
+
+ numdel = to - from;
+
+ /* Make sure point-max won't overflow after this insertion. */
+ XSETINT (temp, Z - numdel + inslen);
+ if (Z - numdel + inslen != XINT (temp))
+ error ("maximum buffer size exceeded");
+
+ if (numdel <= 0 && inslen == 0)
+ return;
+
+ GCPRO1 (new);
+
+ /* Make sure the gap is somewhere in or next to what we are deleting. */
+ if (from > GPT)
+ gap_right (from);
+ if (to < GPT)
+ gap_left (to, 0);
+
+ /* Relocate all markers pointing into the new, larger gap
+ to point at the end of the text before the gap.
+ This has to be done before recording the deletion,
+ so undo handles this after reinserting the text. */
+ adjust_markers (to + GAP_SIZE, to + GAP_SIZE, - numdel - GAP_SIZE);
+
+ record_delete (from, numdel);
+
+ GAP_SIZE += numdel;
+ ZV -= numdel;
+ Z -= numdel;
+ GPT = from;
+ *(GPT_ADDR) = 0; /* Put an anchor. */
+
+ if (GPT - BEG < beg_unchanged)
+ beg_unchanged = GPT - BEG;
+ if (Z - GPT < end_unchanged)
+ end_unchanged = Z - GPT;
+
+ if (GAP_SIZE < inslen)
+ make_gap (inslen - GAP_SIZE);
+
+ record_insert (from, inslen);
+
+ bcopy (XSTRING (new)->data, GPT_ADDR, inslen);
+
+ /* Relocate point as if it were a marker. */
+ if (from < PT)
+ adjust_point (from + inslen - (PT < to ? PT : to));
+
+#ifdef USE_TEXT_PROPERTIES
+ offset_intervals (current_buffer, PT, inslen - numdel);
+#endif
+
+ GAP_SIZE -= inslen;
+ GPT += inslen;
+ ZV += inslen;
+ Z += inslen;
+ if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */
+
+ /* Adjust the overlay center as needed. This must be done after
+ adjusting the markers that bound the overlays. */
+ adjust_overlays_for_delete (from, numdel);
+ adjust_overlays_for_insert (from, inslen);
+ adjust_markers_for_insert (from, inslen);
+
+#ifdef USE_TEXT_PROPERTIES
+ /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
+ graft_intervals_into_buffer (XSTRING (new)->intervals, from, inslen,
+ current_buffer, inherit);
+#endif
+
+ if (inslen == 0)
+ evaporate_overlays (from);
+
+ MODIFF++;
+ UNGCPRO;
+
+ signal_after_change (from, numdel, inslen);
+}
+\f
/* Delete characters in current buffer
from FROM up to (but not including) TO. */
void
del_range_1 (from, to, prepare)
- register int from, to, prepare;
+ int from, to, prepare;
{
register int numdel;
+ if (prepare)
+ {
+ int range_length = to - from;
+ prepare_to_modify_buffer (from, to, &from);
+ to = from + range_length;
+ }
+
/* Make args be valid */
if (from < BEGV)
from = BEGV;
if (to < GPT)
gap_left (to, 0);
- if (prepare)
- prepare_to_modify_buffer (from, to);
-
/* Relocate all markers pointing into the new, larger gap
to point at the end of the text before the gap.
This has to be done before recording the deletion,
if (buffer != old_buffer)
set_buffer_internal (buffer);
- prepare_to_modify_buffer (start, end);
+ prepare_to_modify_buffer (start, end, NULL);
if (start - 1 < beg_unchanged
|| (unchanged_modified == MODIFF
if (buffer != old_buffer)
set_buffer_internal (old_buffer);
}
-
+\f
/* Check that it is okay to modify the buffer between START and END.
Run the before-change-function, if any. If intervals are in use,
verify that the text to be modified is not read-only, and call
- any modification properties the text may have. */
+ any modification properties the text may have.
+
+ If PRESERVE_PTR is nonzero, we relocate *PRESERVE_PTR
+ by holding its value temporarily in a marker. */
void
-prepare_to_modify_buffer (start, end)
+prepare_to_modify_buffer (start, end, preserve_ptr)
int start, end;
+ int *preserve_ptr;
{
if (!NILP (current_buffer->read_only))
Fbarf_if_buffer_read_only ();
/* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
if (BUF_INTERVALS (current_buffer) != 0)
- verify_interval_modification (current_buffer, start, end);
+ {
+ if (preserve_ptr)
+ {
+ Lisp_Object preserve_marker;
+ struct gcpro gcpro1;
+ preserve_marker = Fcopy_marker (make_number (*preserve_ptr), Qnil);
+ GCPRO1 (preserve_marker);
+ verify_interval_modification (current_buffer, start, end);
+ *preserve_ptr = marker_position (preserve_marker);
+ unchain_marker (preserve_marker);
+ UNGCPRO;
+ }
+ else
+ verify_interval_modification (current_buffer, start, end);
+ }
#ifdef CLASH_DETECTION
if (!NILP (current_buffer->file_truename)
current_buffer->filename);
#endif /* not CLASH_DETECTION */
- signal_before_change (start, end);
+ signal_before_change (start, end, preserve_ptr);
if (current_buffer->newline_cache)
invalidate_region_cache (current_buffer,
Vdeactivate_mark = Qt;
}
\f
+/* These macros work with an argument named `preserve_ptr'
+ and a local variable named `preserve_marker'. */
+
+#define PRESERVE_VALUE \
+ if (preserve_ptr && NILP (preserve_marker)) \
+ preserve_marker = Fcopy_marker (make_number (*preserve_ptr), Qnil)
+
+#define RESTORE_VALUE \
+ if (! NILP (preserve_marker)) \
+ { \
+ *preserve_ptr = marker_position (preserve_marker); \
+ unchain_marker (preserve_marker); \
+ }
+
+#define PRESERVE_START_END \
+ if (NILP (start_marker)) \
+ start_marker = Fcopy_marker (start, Qnil); \
+ if (NILP (end_marker)) \
+ end_marker = Fcopy_marker (end, Qnil);
+
+#define FETCH_START \
+ (! NILP (start_marker) ? Fmarker_position (start_marker) : start)
+
+#define FETCH_END \
+ (! NILP (end_marker) ? Fmarker_position (end_marker) : end)
+
/* Signal a change to the buffer immediately before it happens.
- START_INT and END_INT are the bounds of the text to be changed. */
+ START_INT and END_INT are the bounds of the text to be changed.
+
+ If PRESERVE_PTR is nonzero, we relocate *PRESERVE_PTR
+ by holding its value temporarily in a marker. */
void
-signal_before_change (start_int, end_int)
+signal_before_change (start_int, end_int, preserve_ptr)
int start_int, end_int;
+ int *preserve_ptr;
{
Lisp_Object start, end;
+ Lisp_Object start_marker, end_marker;
+ Lisp_Object preserve_marker;
+ struct gcpro gcpro1, gcpro2, gcpro3;
start = make_number (start_int);
end = make_number (end_int);
+ preserve_marker = Qnil;
+ start_marker = Qnil;
+ end_marker = Qnil;
+ GCPRO3 (preserve_marker, start_marker, end_marker);
/* If buffer is unmodified, run a special hook for that case. */
if (SAVE_MODIFF >= MODIFF
&& !NILP (Vfirst_change_hook)
&& !NILP (Vrun_hooks))
- call1 (Vrun_hooks, Qfirst_change_hook);
+ {
+ PRESERVE_VALUE;
+ PRESERVE_START_END;
+ 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))
- call2 (Vbefore_change_function, start, end);
+ {
+ 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 after_change_functions;
struct gcpro gcpro1, gcpro2;
+ PRESERVE_VALUE;
+ PRESERVE_START_END;
+
/* "Bind" before-change-functions and after-change-functions
to nil--but in a way that errors don't know about.
That way, if there's an error in them, they will stay nil. */
/* Actually run the hook functions. */
args[0] = Qbefore_change_functions;
- args[1] = start;
- args[2] = end;
+ args[1] = FETCH_START;
+ args[2] = FETCH_END;
run_hook_list_with_args (before_change_functions, 3, args);
/* "Unbind" the variables we "bound" to nil. */
if (!NILP (current_buffer->overlays_before)
|| !NILP (current_buffer->overlays_after))
- report_overlay_modification (start, end, 0, start, end, Qnil);
+ {
+ PRESERVE_VALUE;
+ report_overlay_modification (FETCH_START, FETCH_END, 0,
+ FETCH_START, FETCH_END, Qnil);
+ }
+
+ if (! NILP (start_marker))
+ free_marker (start_marker);
+ if (! NILP (end_marker))
+ free_marker (end_marker);
+ RESTORE_VALUE;
+ UNGCPRO;
}
/* Signal a change immediately after it happens.
for (tail = combine_after_change_list; CONSP (tail);
tail = XCONS (tail)->cdr)
{
- Lisp_Object elt, thisbeg, thisend, thischange;
+ Lisp_Object elt;
+ int thisbeg, thisend, thischange;
/* Extract the info from the next element. */
elt = XCONS (tail)->car;