1 /* Buffer insertion/deletion and gap motion for GNU Emacs.
2 Copyright (C) 1985, 1986, 1993 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 1, or (at your option)
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
23 #include "intervals.h"
27 /* Move gap to position `pos'.
28 Note that this can quit! */
39 /* Move the gap to POS, which is less than the current GPT.
40 If NEWGAP is nonzero, then don't update beg_unchanged and end_unchanged. */
42 gap_left (pos
, newgap
)
46 register unsigned char *to
, *from
;
54 if (unchanged_modified
== MODIFF
)
57 end_unchanged
= Z
- pos
- 1;
61 if (Z
- GPT
< end_unchanged
)
62 end_unchanged
= Z
- GPT
;
63 if (pos
< beg_unchanged
)
73 /* Now copy the characters. To move the gap down,
74 copy characters up. */
78 /* I gets number of characters left to copy. */
82 /* If a quit is requested, stop copying now.
83 Change POS to be where we have actually moved the gap to. */
89 /* Move at most 32000 chars before checking again for a quit. */
94 /* bcopy is safe if the two areas of memory do not overlap
95 or on systems where bcopy is always safe for moving upward. */
99 /* If overlap is not safe, avoid it by not moving too many
100 characters at once. */
101 if (!BCOPY_UPWARD_SAFE
&& i
> to
- from
)
116 /* Adjust markers, and buffer data structure, to put the gap at POS.
117 POS is where the loop above stopped, which may be what was specified
118 or may be where a quit was detected. */
119 adjust_markers (pos
+ 1, GPT
, GAP_SIZE
);
127 register unsigned char *to
, *from
;
133 if (unchanged_modified
== MODIFF
)
136 end_unchanged
= Z
- pos
- 1;
140 if (Z
- pos
- 1 < end_unchanged
)
141 end_unchanged
= Z
- pos
- 1;
142 if (GPT
- BEG
< beg_unchanged
)
143 beg_unchanged
= GPT
- BEG
;
151 /* Now copy the characters. To move the gap up,
152 copy characters down. */
156 /* I gets number of characters left to copy. */
160 /* If a quit is requested, stop copying now.
161 Change POS to be where we have actually moved the gap to. */
167 /* Move at most 32000 chars before checking again for a quit. */
172 /* bcopy is safe if the two areas of memory do not overlap
173 or on systems where bcopy is always safe for moving downward. */
174 && (BCOPY_DOWNWARD_SAFE
175 || from
- to
>= 128))
177 /* If overlap is not safe, avoid it by not moving too many
178 characters at once. */
179 if (!BCOPY_DOWNWARD_SAFE
&& i
> from
- to
)
194 adjust_markers (GPT
+ GAP_SIZE
, pos
+ 1 + GAP_SIZE
, - GAP_SIZE
);
199 /* Add `amount' to the position of every marker in the current buffer
200 whose current position is between `from' (exclusive) and `to' (inclusive).
201 Also, any markers past the outside of that interval, in the direction
202 of adjustment, are first moved back to the near end of the interval
203 and then adjusted by `amount'. */
205 adjust_markers (from
, to
, amount
)
206 register int from
, to
, amount
;
209 register struct Lisp_Marker
*m
;
212 marker
= current_buffer
->markers
;
214 while (!NILP (marker
))
216 m
= XMARKER (marker
);
220 if (mpos
> to
&& mpos
< to
+ amount
)
225 if (mpos
> from
+ amount
&& mpos
<= from
)
226 mpos
= from
+ amount
;
228 if (mpos
> from
&& mpos
<= to
)
235 /* Make the gap INCREMENT characters longer. */
240 unsigned char *result
;
245 /* If we have to get more space, get enough to last a while. */
248 result
= BUFFER_REALLOC (BEG_ADDR
, (Z
- BEG
+ GAP_SIZE
+ increment
));
253 /* Prevent quitting in move_gap. */
258 old_gap_size
= GAP_SIZE
;
260 /* Call the newly allocated space a gap at the end of the whole space. */
262 GAP_SIZE
= increment
;
264 /* Move the new gap down to be consecutive with the end of the old one.
265 This adjusts the markers properly too. */
266 gap_left (real_gap_loc
+ old_gap_size
, 1);
268 /* Now combine the two into one large gap. */
269 GAP_SIZE
+= old_gap_size
;
275 /* Insert a string of specified length before point.
276 DO NOT use this for the contents of a Lisp string!
277 prepare_to_modify_buffer could relocate the string. */
279 insert (string
, length
)
280 register unsigned char *string
;
283 register Lisp_Object temp
;
288 /* Make sure point-max won't overflow after this insertion. */
289 XSET (temp
, Lisp_Int
, length
+ Z
);
290 if (length
+ Z
!= XINT (temp
))
291 error ("maximum buffer size exceeded");
293 prepare_to_modify_buffer (point
, point
);
297 if (GAP_SIZE
< length
)
298 make_gap (length
- GAP_SIZE
);
300 record_insert (point
, length
);
303 bcopy (string
, GPT_ADDR
, length
);
305 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
306 offset_intervals (current_buffer
, point
, length
);
312 SET_PT (point
+ length
);
314 signal_after_change (point
-length
, 0, length
);
317 /* Insert the part of the text of STRING, a Lisp object assumed to be
318 of type string, consisting of the LENGTH characters starting at
319 position POS. If the text of STRING has properties, they are absorbed
322 It does not work to use `insert' for this, because a GC could happen
323 before we bcopy the stuff into the buffer, and relocate the string
324 without insert noticing. */
326 insert_from_string (string
, pos
, length
)
328 register int pos
, length
;
330 register Lisp_Object temp
;
336 /* Make sure point-max won't overflow after this insertion. */
337 XSET (temp
, Lisp_Int
, length
+ Z
);
338 if (length
+ Z
!= XINT (temp
))
339 error ("maximum buffer size exceeded");
342 prepare_to_modify_buffer (point
, point
);
346 if (GAP_SIZE
< length
)
347 make_gap (length
- GAP_SIZE
);
349 record_insert (point
, length
);
353 bcopy (XSTRING (string
)->data
, GPT_ADDR
, length
);
355 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
356 offset_intervals (current_buffer
, point
, length
);
363 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
364 graft_intervals_into_buffer (XSTRING (string
)->intervals
, point
,
367 SET_PT (point
+ length
);
369 signal_after_change (point
-length
, 0, length
);
372 /* Insert the character C before point */
381 /* Insert the null-terminated string S before point */
387 insert (s
, strlen (s
));
390 /* Like `insert' except that all markers pointing at the place where
391 the insertion happens are adjusted to point after it.
392 Don't use this function to insert part of a Lisp string,
393 since gc could happen and relocate it. */
395 insert_before_markers (string
, length
)
396 unsigned char *string
;
399 register int opoint
= point
;
400 insert (string
, length
);
401 adjust_markers (opoint
- 1, opoint
, length
);
404 /* Insert part of a Lisp string, relocating markers after. */
406 insert_from_string_before_markers (string
, pos
, length
)
408 register int pos
, length
;
410 register int opoint
= point
;
411 insert_from_string (string
, pos
, length
);
412 adjust_markers (opoint
- 1, opoint
, length
);
415 /* Delete characters in current buffer
416 from FROM up to (but not including) TO. */
419 register int from
, to
;
423 /* Make args be valid */
429 if ((numdel
= to
- from
) <= 0)
432 /* Make sure the gap is somewhere in or next to what we are deleting. */
438 prepare_to_modify_buffer (from
, to
);
440 record_delete (from
, numdel
);
443 /* Relocate point as if it were a marker. */
449 SET_PT (point
- numdel
);
452 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
453 offset_intervals (current_buffer
, point
, - numdel
);
455 /* Relocate all markers pointing into the new, larger gap
456 to point at the end of the text before the gap. */
457 adjust_markers (to
+ GAP_SIZE
, to
+ GAP_SIZE
, - numdel
- GAP_SIZE
);
464 if (GPT
- BEG
< beg_unchanged
)
465 beg_unchanged
= GPT
- BEG
;
466 if (Z
- GPT
< end_unchanged
)
467 end_unchanged
= Z
- GPT
;
469 signal_after_change (from
, numdel
, 0);
472 modify_region (start
, end
)
475 prepare_to_modify_buffer (start
, end
);
477 if (start
- 1 < beg_unchanged
|| unchanged_modified
== MODIFF
)
478 beg_unchanged
= start
- 1;
479 if (Z
- end
< end_unchanged
480 || unchanged_modified
== MODIFF
)
481 end_unchanged
= Z
- end
;
485 /* Check that it is okay to modify the buffer between START and END.
486 Run the before-change-function, if any. If intervals are in use,
487 verify that the text to be modified is not read-only, and call
488 any modification properties the text may have. */
490 prepare_to_modify_buffer (start
, end
)
491 Lisp_Object start
, end
;
493 if (!NILP (current_buffer
->read_only
))
494 Fbarf_if_buffer_read_only ();
496 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
497 verify_interval_modification (current_buffer
, start
, end
);
499 #ifdef CLASH_DETECTION
500 if (!NILP (current_buffer
->filename
)
501 && current_buffer
->save_modified
>= MODIFF
)
502 lock_file (current_buffer
->filename
);
504 /* At least warn if this file has changed on disk since it was visited. */
505 if (!NILP (current_buffer
->filename
)
506 && current_buffer
->save_modified
>= MODIFF
507 && NILP (Fverify_visited_file_modtime (Fcurrent_buffer ()))
508 && !NILP (Ffile_exists_p (current_buffer
->filename
)))
509 call1 (intern ("ask-user-about-supersession-threat"),
510 current_buffer
->filename
);
511 #endif /* not CLASH_DETECTION */
513 signal_before_change (start
, end
);
515 Vdeactivate_mark
= Qt
;
519 before_change_function_restore (value
)
522 Vbefore_change_function
= value
;
526 after_change_function_restore (value
)
529 Vafter_change_function
= value
;
532 /* Signal a change to the buffer immediatly before it happens.
533 START and END are the bounds of the text to be changed,
536 signal_before_change (start
, end
)
537 Lisp_Object start
, end
;
539 /* If buffer is unmodified, run a special hook for that case. */
540 if (current_buffer
->save_modified
>= MODIFF
541 && !NILP (Vfirst_change_hook
)
542 && !NILP (Vrun_hooks
))
543 call1 (Vrun_hooks
, Qfirst_change_hook
);
545 /* Now in any case run the before-change-function if any. */
546 if (!NILP (Vbefore_change_function
))
548 int count
= specpdl_ptr
- specpdl
;
549 Lisp_Object function
;
551 function
= Vbefore_change_function
;
552 record_unwind_protect (after_change_function_restore
,
553 Vafter_change_function
);
554 record_unwind_protect (before_change_function_restore
,
555 Vbefore_change_function
);
556 Vafter_change_function
= Qnil
;
557 Vbefore_change_function
= Qnil
;
559 call2 (function
, start
, end
);
560 unbind_to (count
, Qnil
);
564 /* Signal a change immediatly after it happens.
565 POS is the address of the start of the changed text.
566 LENDEL is the number of characters of the text before the change.
567 (Not the whole buffer; just the part that was changed.)
568 LENINS is the number of characters in the changed text. */
570 signal_after_change (pos
, lendel
, lenins
)
571 int pos
, lendel
, lenins
;
573 if (!NILP (Vafter_change_function
))
575 int count
= specpdl_ptr
- specpdl
;
576 Lisp_Object function
;
577 function
= Vafter_change_function
;
579 record_unwind_protect (after_change_function_restore
,
580 Vafter_change_function
);
581 record_unwind_protect (before_change_function_restore
,
582 Vbefore_change_function
);
583 Vafter_change_function
= Qnil
;
584 Vbefore_change_function
= Qnil
;
586 call3 (function
, make_number (pos
), make_number (pos
+ lenins
),
587 make_number (lendel
));
588 unbind_to (count
, Qnil
);