]> code.delx.au - gnu-emacs/blob - src/insdel.c
(x_window): With Motif, double extra_borders.
[gnu-emacs] / src / insdel.c
1 /* Buffer insertion/deletion and gap motion for GNU Emacs.
2 Copyright (C) 1985, 1986, 1993, 1994, 1995 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
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 2, or (at your option)
9 any later version.
10
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.
15
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, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21
22 #include <config.h>
23 #include "lisp.h"
24 #include "intervals.h"
25 #include "buffer.h"
26 #include "window.h"
27 #include "blockinput.h"
28
29 #define min(x, y) ((x) < (y) ? (x) : (y))
30
31 static void insert_from_string_1 ();
32 static void insert_from_buffer_1 ();
33 static void gap_left ();
34 static void gap_right ();
35 static void adjust_markers ();
36 static void adjust_point ();
37
38 /* Move gap to position `pos'.
39 Note that this can quit! */
40
41 void
42 move_gap (pos)
43 int pos;
44 {
45 if (pos < GPT)
46 gap_left (pos, 0);
47 else if (pos > GPT)
48 gap_right (pos);
49 }
50
51 /* Move the gap to POS, which is less than the current GPT.
52 If NEWGAP is nonzero, then don't update beg_unchanged and end_unchanged. */
53
54 static void
55 gap_left (pos, newgap)
56 register int pos;
57 int newgap;
58 {
59 register unsigned char *to, *from;
60 register int i;
61 int new_s1;
62
63 pos--;
64
65 if (!newgap)
66 {
67 if (unchanged_modified == MODIFF
68 && overlay_unchanged_modified == OVERLAY_MODIFF)
69 {
70 beg_unchanged = pos;
71 end_unchanged = Z - pos - 1;
72 }
73 else
74 {
75 if (Z - GPT < end_unchanged)
76 end_unchanged = Z - GPT;
77 if (pos < beg_unchanged)
78 beg_unchanged = pos;
79 }
80 }
81
82 i = GPT;
83 to = GAP_END_ADDR;
84 from = GPT_ADDR;
85 new_s1 = GPT - BEG;
86
87 /* Now copy the characters. To move the gap down,
88 copy characters up. */
89
90 while (1)
91 {
92 /* I gets number of characters left to copy. */
93 i = new_s1 - pos;
94 if (i == 0)
95 break;
96 /* If a quit is requested, stop copying now.
97 Change POS to be where we have actually moved the gap to. */
98 if (QUITP)
99 {
100 pos = new_s1;
101 break;
102 }
103 /* Move at most 32000 chars before checking again for a quit. */
104 if (i > 32000)
105 i = 32000;
106 #ifdef GAP_USE_BCOPY
107 if (i >= 128
108 /* bcopy is safe if the two areas of memory do not overlap
109 or on systems where bcopy is always safe for moving upward. */
110 && (BCOPY_UPWARD_SAFE
111 || to - from >= 128))
112 {
113 /* If overlap is not safe, avoid it by not moving too many
114 characters at once. */
115 if (!BCOPY_UPWARD_SAFE && i > to - from)
116 i = to - from;
117 new_s1 -= i;
118 from -= i, to -= i;
119 bcopy (from, to, i);
120 }
121 else
122 #endif
123 {
124 new_s1 -= i;
125 while (--i >= 0)
126 *--to = *--from;
127 }
128 }
129
130 /* Adjust markers, and buffer data structure, to put the gap at POS.
131 POS is where the loop above stopped, which may be what was specified
132 or may be where a quit was detected. */
133 adjust_markers (pos + 1, GPT, GAP_SIZE);
134 GPT = pos + 1;
135 QUIT;
136 }
137
138 static void
139 gap_right (pos)
140 register int pos;
141 {
142 register unsigned char *to, *from;
143 register int i;
144 int new_s1;
145
146 pos--;
147
148 if (unchanged_modified == MODIFF
149 && overlay_unchanged_modified == OVERLAY_MODIFF)
150
151 {
152 beg_unchanged = pos;
153 end_unchanged = Z - pos - 1;
154 }
155 else
156 {
157 if (Z - pos - 1 < end_unchanged)
158 end_unchanged = Z - pos - 1;
159 if (GPT - BEG < beg_unchanged)
160 beg_unchanged = GPT - BEG;
161 }
162
163 i = GPT;
164 from = GAP_END_ADDR;
165 to = GPT_ADDR;
166 new_s1 = GPT - 1;
167
168 /* Now copy the characters. To move the gap up,
169 copy characters down. */
170
171 while (1)
172 {
173 /* I gets number of characters left to copy. */
174 i = pos - new_s1;
175 if (i == 0)
176 break;
177 /* If a quit is requested, stop copying now.
178 Change POS to be where we have actually moved the gap to. */
179 if (QUITP)
180 {
181 pos = new_s1;
182 break;
183 }
184 /* Move at most 32000 chars before checking again for a quit. */
185 if (i > 32000)
186 i = 32000;
187 #ifdef GAP_USE_BCOPY
188 if (i >= 128
189 /* bcopy is safe if the two areas of memory do not overlap
190 or on systems where bcopy is always safe for moving downward. */
191 && (BCOPY_DOWNWARD_SAFE
192 || from - to >= 128))
193 {
194 /* If overlap is not safe, avoid it by not moving too many
195 characters at once. */
196 if (!BCOPY_DOWNWARD_SAFE && i > from - to)
197 i = from - to;
198 new_s1 += i;
199 bcopy (from, to, i);
200 from += i, to += i;
201 }
202 else
203 #endif
204 {
205 new_s1 += i;
206 while (--i >= 0)
207 *to++ = *from++;
208 }
209 }
210
211 adjust_markers (GPT + GAP_SIZE, pos + 1 + GAP_SIZE, - GAP_SIZE);
212 GPT = pos + 1;
213 QUIT;
214 }
215
216 /* Add AMOUNT to the position of every marker in the current buffer
217 whose current position is between FROM (exclusive) and TO (inclusive).
218
219 Also, any markers past the outside of that interval, in the direction
220 of adjustment, are first moved back to the near end of the interval
221 and then adjusted by AMOUNT.
222
223 When the latter adjustment is done, if AMOUNT is negative,
224 we record the adjustment for undo. (This case happens only for
225 deletion.) */
226
227 static void
228 adjust_markers (from, to, amount)
229 register int from, to, amount;
230 {
231 Lisp_Object marker;
232 register struct Lisp_Marker *m;
233 register int mpos;
234
235 marker = BUF_MARKERS (current_buffer);
236
237 while (!NILP (marker))
238 {
239 m = XMARKER (marker);
240 mpos = m->bufpos;
241 if (amount > 0)
242 {
243 if (mpos > to && mpos < to + amount)
244 mpos = to + amount;
245 }
246 else
247 {
248 /* Here's the case where a marker is inside text being deleted.
249 AMOUNT can be negative for gap motion, too,
250 but then this range contains no markers. */
251 if (mpos > from + amount && mpos <= from)
252 {
253 record_marker_adjustment (marker, from + amount - mpos);
254 mpos = from + amount;
255 }
256 }
257 if (mpos > from && mpos <= to)
258 mpos += amount;
259 m->bufpos = mpos;
260 marker = m->chain;
261 }
262 }
263
264 /* Adjust markers whose insertion-type is t
265 for an insertion of AMOUNT characters at POS. */
266
267 static void
268 adjust_markers_for_insert (pos, amount)
269 register int pos, amount;
270 {
271 Lisp_Object marker;
272
273 marker = BUF_MARKERS (current_buffer);
274
275 while (!NILP (marker))
276 {
277 register struct Lisp_Marker *m = XMARKER (marker);
278 if (m->insertion_type && m->bufpos == pos)
279 m->bufpos += amount;
280 marker = m->chain;
281 }
282 }
283
284 /* Add the specified amount to point. This is used only when the value
285 of point changes due to an insert or delete; it does not represent
286 a conceptual change in point as a marker. In particular, point is
287 not crossing any interval boundaries, so there's no need to use the
288 usual SET_PT macro. In fact it would be incorrect to do so, because
289 either the old or the new value of point is out of sync with the
290 current set of intervals. */
291 static void
292 adjust_point (amount)
293 int amount;
294 {
295 BUF_PT (current_buffer) += amount;
296 }
297 \f
298 /* Make the gap INCREMENT characters longer. */
299
300 void
301 make_gap (increment)
302 int increment;
303 {
304 unsigned char *result;
305 Lisp_Object tem;
306 int real_gap_loc;
307 int old_gap_size;
308
309 /* If we have to get more space, get enough to last a while. */
310 increment += 2000;
311
312 /* Don't allow a buffer size that won't fit in an int
313 even if it will fit in a Lisp integer.
314 That won't work because so many places use `int'. */
315
316 if (Z - BEG + GAP_SIZE + increment
317 >= ((unsigned) 1 << (min (BITS_PER_INT, VALBITS) - 1)))
318 error ("Buffer exceeds maximum size");
319
320 BLOCK_INPUT;
321 result = BUFFER_REALLOC (BEG_ADDR, (Z - BEG + GAP_SIZE + increment));
322
323 if (result == 0)
324 {
325 UNBLOCK_INPUT;
326 memory_full ();
327 }
328
329 /* We can't unblock until the new address is properly stored. */
330 BEG_ADDR = result;
331 UNBLOCK_INPUT;
332
333 /* Prevent quitting in move_gap. */
334 tem = Vinhibit_quit;
335 Vinhibit_quit = Qt;
336
337 real_gap_loc = GPT;
338 old_gap_size = GAP_SIZE;
339
340 /* Call the newly allocated space a gap at the end of the whole space. */
341 GPT = Z + GAP_SIZE;
342 GAP_SIZE = increment;
343
344 /* Move the new gap down to be consecutive with the end of the old one.
345 This adjusts the markers properly too. */
346 gap_left (real_gap_loc + old_gap_size, 1);
347
348 /* Now combine the two into one large gap. */
349 GAP_SIZE += old_gap_size;
350 GPT = real_gap_loc;
351
352 Vinhibit_quit = tem;
353 }
354 \f
355 /* Insert a string of specified length before point.
356 DO NOT use this for the contents of a Lisp string or a Lisp buffer!
357 prepare_to_modify_buffer could relocate the text. */
358
359 void
360 insert (string, length)
361 register unsigned char *string;
362 register length;
363 {
364 if (length > 0)
365 {
366 insert_1 (string, length, 0, 1);
367 signal_after_change (PT-length, 0, length);
368 }
369 }
370
371 void
372 insert_and_inherit (string, length)
373 register unsigned char *string;
374 register length;
375 {
376 if (length > 0)
377 {
378 insert_1 (string, length, 1, 1);
379 signal_after_change (PT-length, 0, length);
380 }
381 }
382
383 void
384 insert_1 (string, length, inherit, prepare)
385 register unsigned char *string;
386 register int length;
387 int inherit, prepare;
388 {
389 register Lisp_Object temp;
390
391 if (prepare)
392 prepare_to_modify_buffer (PT, PT);
393
394 if (PT != GPT)
395 move_gap (PT);
396 if (GAP_SIZE < length)
397 make_gap (length - GAP_SIZE);
398
399 record_insert (PT, length);
400 MODIFF++;
401
402 bcopy (string, GPT_ADDR, length);
403
404 #ifdef USE_TEXT_PROPERTIES
405 if (BUF_INTERVALS (current_buffer) != 0)
406 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES. */
407 offset_intervals (current_buffer, PT, length);
408 #endif
409
410 GAP_SIZE -= length;
411 GPT += length;
412 ZV += length;
413 Z += length;
414 adjust_overlays_for_insert (PT, length);
415 adjust_markers_for_insert (PT, length);
416 adjust_point (length);
417
418 #ifdef USE_TEXT_PROPERTIES
419 if (!inherit && BUF_INTERVALS (current_buffer) != 0)
420 Fset_text_properties (make_number (PT - length), make_number (PT),
421 Qnil, Qnil);
422 #endif
423 }
424
425 /* Insert the part of the text of STRING, a Lisp object assumed to be
426 of type string, consisting of the LENGTH characters starting at
427 position POS. If the text of STRING has properties, they are absorbed
428 into the buffer.
429
430 It does not work to use `insert' for this, because a GC could happen
431 before we bcopy the stuff into the buffer, and relocate the string
432 without insert noticing. */
433
434 void
435 insert_from_string (string, pos, length, inherit)
436 Lisp_Object string;
437 register int pos, length;
438 int inherit;
439 {
440 if (length > 0)
441 {
442 insert_from_string_1 (string, pos, length, inherit);
443 signal_after_change (PT-length, 0, length);
444 }
445 }
446
447 static void
448 insert_from_string_1 (string, pos, length, inherit)
449 Lisp_Object string;
450 register int pos, length;
451 int inherit;
452 {
453 register Lisp_Object temp;
454 struct gcpro gcpro1;
455
456 /* Make sure point-max won't overflow after this insertion. */
457 XSETINT (temp, length + Z);
458 if (length + Z != XINT (temp))
459 error ("maximum buffer size exceeded");
460
461 GCPRO1 (string);
462 prepare_to_modify_buffer (PT, PT);
463
464 if (PT != GPT)
465 move_gap (PT);
466 if (GAP_SIZE < length)
467 make_gap (length - GAP_SIZE);
468
469 record_insert (PT, length);
470 MODIFF++;
471 UNGCPRO;
472
473 bcopy (XSTRING (string)->data, GPT_ADDR, length);
474
475 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
476 offset_intervals (current_buffer, PT, length);
477
478 GAP_SIZE -= length;
479 GPT += length;
480 ZV += length;
481 Z += length;
482 adjust_overlays_for_insert (PT, length);
483 adjust_markers_for_insert (PT, length);
484
485 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
486 graft_intervals_into_buffer (XSTRING (string)->intervals, PT, length,
487 current_buffer, inherit);
488
489 adjust_point (length);
490 }
491
492 /* Insert text from BUF, starting at POS and having length LENGTH, into the
493 current buffer. If the text in BUF has properties, they are absorbed
494 into the current buffer.
495
496 It does not work to use `insert' for this, because a malloc could happen
497 and relocate BUF's text before the bcopy happens. */
498
499 void
500 insert_from_buffer (buf, pos, length, inherit)
501 struct buffer *buf;
502 int pos, length;
503 int inherit;
504 {
505 if (length > 0)
506 {
507 insert_from_buffer_1 (buf, pos, length, inherit);
508 signal_after_change (PT-length, 0, length);
509 }
510 }
511
512 static void
513 insert_from_buffer_1 (buf, pos, length, inherit)
514 struct buffer *buf;
515 int pos, length;
516 int inherit;
517 {
518 register Lisp_Object temp;
519 int chunk;
520
521 /* Make sure point-max won't overflow after this insertion. */
522 XSETINT (temp, length + Z);
523 if (length + Z != XINT (temp))
524 error ("maximum buffer size exceeded");
525
526 prepare_to_modify_buffer (PT, PT);
527
528 if (PT != GPT)
529 move_gap (PT);
530 if (GAP_SIZE < length)
531 make_gap (length - GAP_SIZE);
532
533 record_insert (PT, length);
534 MODIFF++;
535
536 if (pos < BUF_GPT (buf))
537 {
538 chunk = BUF_GPT (buf) - pos;
539 if (chunk > length)
540 chunk = length;
541 bcopy (BUF_CHAR_ADDRESS (buf, pos), GPT_ADDR, chunk);
542 }
543 else
544 chunk = 0;
545 if (chunk < length)
546 bcopy (BUF_CHAR_ADDRESS (buf, pos + chunk),
547 GPT_ADDR + chunk, length - chunk);
548
549 #ifdef USE_TEXT_PROPERTIES
550 if (BUF_INTERVALS (current_buffer) != 0)
551 offset_intervals (current_buffer, PT, length);
552 #endif
553
554 GAP_SIZE -= length;
555 GPT += length;
556 ZV += length;
557 Z += length;
558 adjust_overlays_for_insert (PT, length);
559 adjust_markers_for_insert (PT, length);
560 adjust_point (length);
561
562 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
563 graft_intervals_into_buffer (copy_intervals (BUF_INTERVALS (buf),
564 pos, length),
565 PT - length, length, current_buffer, inherit);
566 }
567
568 /* Insert the character C before point */
569
570 void
571 insert_char (c)
572 unsigned char c;
573 {
574 insert (&c, 1);
575 }
576
577 /* Insert the null-terminated string S before point */
578
579 void
580 insert_string (s)
581 char *s;
582 {
583 insert (s, strlen (s));
584 }
585
586 /* Like `insert' except that all markers pointing at the place where
587 the insertion happens are adjusted to point after it.
588 Don't use this function to insert part of a Lisp string,
589 since gc could happen and relocate it. */
590
591 void
592 insert_before_markers (string, length)
593 unsigned char *string;
594 register int length;
595 {
596 if (length > 0)
597 {
598 register int opoint = PT;
599 insert_1 (string, length, 0, 1);
600 adjust_markers (opoint - 1, opoint, length);
601 signal_after_change (PT-length, 0, length);
602 }
603 }
604
605 void
606 insert_before_markers_and_inherit (string, length)
607 unsigned char *string;
608 register int length;
609 {
610 if (length > 0)
611 {
612 register int opoint = PT;
613 insert_1 (string, length, 1, 1);
614 adjust_markers (opoint - 1, opoint, length);
615 signal_after_change (PT-length, 0, length);
616 }
617 }
618
619 /* Insert part of a Lisp string, relocating markers after. */
620
621 void
622 insert_from_string_before_markers (string, pos, length, inherit)
623 Lisp_Object string;
624 register int pos, length;
625 int inherit;
626 {
627 if (length > 0)
628 {
629 register int opoint = PT;
630 insert_from_string_1 (string, pos, length, inherit);
631 adjust_markers (opoint - 1, opoint, length);
632 signal_after_change (PT-length, 0, length);
633 }
634 }
635 \f
636 /* Delete characters in current buffer
637 from FROM up to (but not including) TO. */
638
639 void
640 del_range (from, to)
641 register int from, to;
642 {
643 del_range_1 (from, to, 1);
644 }
645
646 /* Like del_range; PREPARE says whether to call prepare_to_modify_buffer. */
647
648 void
649 del_range_1 (from, to, prepare)
650 register int from, to, prepare;
651 {
652 register int numdel;
653
654 /* Make args be valid */
655 if (from < BEGV)
656 from = BEGV;
657 if (to > ZV)
658 to = ZV;
659
660 if ((numdel = to - from) <= 0)
661 return;
662
663 /* Make sure the gap is somewhere in or next to what we are deleting. */
664 if (from > GPT)
665 gap_right (from);
666 if (to < GPT)
667 gap_left (to, 0);
668
669 if (prepare)
670 prepare_to_modify_buffer (from, to);
671
672 /* Relocate all markers pointing into the new, larger gap
673 to point at the end of the text before the gap.
674 This has to be done before recording the deletion,
675 so undo handles this after reinserting the text. */
676 adjust_markers (to + GAP_SIZE, to + GAP_SIZE, - numdel - GAP_SIZE);
677
678 record_delete (from, numdel);
679 MODIFF++;
680
681 /* Relocate point as if it were a marker. */
682 if (from < PT)
683 adjust_point (from - (PT < to ? PT : to));
684
685 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
686 offset_intervals (current_buffer, from, - numdel);
687
688 /* Adjust the overlay center as needed. This must be done after
689 adjusting the markers that bound the overlays. */
690 adjust_overlays_for_delete (from, numdel);
691
692 GAP_SIZE += numdel;
693 ZV -= numdel;
694 Z -= numdel;
695 GPT = from;
696
697 if (GPT - BEG < beg_unchanged)
698 beg_unchanged = GPT - BEG;
699 if (Z - GPT < end_unchanged)
700 end_unchanged = Z - GPT;
701
702 evaporate_overlays (from);
703 signal_after_change (from, numdel, 0);
704 }
705 \f
706 /* Call this if you're about to change the region of BUFFER from START
707 to END. This checks the read-only properties of the region, calls
708 the necessary modification hooks, and warns the next redisplay that
709 it should pay attention to that area. */
710 void
711 modify_region (buffer, start, end)
712 struct buffer *buffer;
713 int start, end;
714 {
715 struct buffer *old_buffer = current_buffer;
716
717 if (buffer != old_buffer)
718 set_buffer_internal (buffer);
719
720 prepare_to_modify_buffer (start, end);
721
722 if (start - 1 < beg_unchanged
723 || (unchanged_modified == MODIFF
724 && overlay_unchanged_modified == OVERLAY_MODIFF))
725 beg_unchanged = start - 1;
726 if (Z - end < end_unchanged
727 || (unchanged_modified == MODIFF
728 && overlay_unchanged_modified == OVERLAY_MODIFF))
729 end_unchanged = Z - end;
730
731 if (MODIFF <= SAVE_MODIFF)
732 record_first_change ();
733 MODIFF++;
734
735 buffer->point_before_scroll = Qnil;
736
737 if (buffer != old_buffer)
738 set_buffer_internal (old_buffer);
739 }
740
741 /* Check that it is okay to modify the buffer between START and END.
742 Run the before-change-function, if any. If intervals are in use,
743 verify that the text to be modified is not read-only, and call
744 any modification properties the text may have. */
745
746 void
747 prepare_to_modify_buffer (start, end)
748 int start, end;
749 {
750 if (!NILP (current_buffer->read_only))
751 Fbarf_if_buffer_read_only ();
752
753 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
754 if (BUF_INTERVALS (current_buffer) != 0)
755 verify_interval_modification (current_buffer, start, end);
756
757 #ifdef CLASH_DETECTION
758 if (!NILP (current_buffer->file_truename)
759 /* Make binding buffer-file-name to nil effective. */
760 && !NILP (current_buffer->filename)
761 && SAVE_MODIFF >= MODIFF)
762 lock_file (current_buffer->file_truename);
763 #else
764 /* At least warn if this file has changed on disk since it was visited. */
765 if (!NILP (current_buffer->filename)
766 && SAVE_MODIFF >= MODIFF
767 && NILP (Fverify_visited_file_modtime (Fcurrent_buffer ()))
768 && !NILP (Ffile_exists_p (current_buffer->filename)))
769 call1 (intern ("ask-user-about-supersession-threat"),
770 current_buffer->filename);
771 #endif /* not CLASH_DETECTION */
772
773 signal_before_change (start, end);
774
775 if (current_buffer->newline_cache)
776 invalidate_region_cache (current_buffer,
777 current_buffer->newline_cache,
778 start - BEG, Z - end);
779 if (current_buffer->width_run_cache)
780 invalidate_region_cache (current_buffer,
781 current_buffer->width_run_cache,
782 start - BEG, Z - end);
783
784 Vdeactivate_mark = Qt;
785 }
786 \f
787 /* Signal a change to the buffer immediately before it happens.
788 START_INT and END_INT are the bounds of the text to be changed. */
789
790 void
791 signal_before_change (start_int, end_int)
792 int start_int, end_int;
793 {
794 Lisp_Object start, end;
795
796 start = make_number (start_int);
797 end = make_number (end_int);
798
799 /* If buffer is unmodified, run a special hook for that case. */
800 if (SAVE_MODIFF >= MODIFF
801 && !NILP (Vfirst_change_hook)
802 && !NILP (Vrun_hooks))
803 call1 (Vrun_hooks, Qfirst_change_hook);
804
805 /* Run the before-change-function if any.
806 We don't bother "binding" this variable to nil
807 because it is obsolete anyway and new code should not use it. */
808 if (!NILP (Vbefore_change_function))
809 call2 (Vbefore_change_function, start, end);
810
811 /* Now run the before-change-functions if any. */
812 if (!NILP (Vbefore_change_functions))
813 {
814 Lisp_Object args[3];
815 Lisp_Object before_change_functions;
816 Lisp_Object after_change_functions;
817 struct gcpro gcpro1, gcpro2;
818
819 /* "Bind" before-change-functions and after-change-functions
820 to nil--but in a way that errors don't know about.
821 That way, if there's an error in them, they will stay nil. */
822 before_change_functions = Vbefore_change_functions;
823 after_change_functions = Vafter_change_functions;
824 Vbefore_change_functions = Qnil;
825 Vafter_change_functions = Qnil;
826 GCPRO2 (before_change_functions, after_change_functions);
827
828 /* Actually run the hook functions. */
829 args[0] = Qbefore_change_functions;
830 args[1] = start;
831 args[2] = end;
832 run_hook_list_with_args (before_change_functions, 3, args);
833
834 /* "Unbind" the variables we "bound" to nil. */
835 Vbefore_change_functions = before_change_functions;
836 Vafter_change_functions = after_change_functions;
837 UNGCPRO;
838 }
839
840 if (!NILP (current_buffer->overlays_before)
841 || !NILP (current_buffer->overlays_after))
842 report_overlay_modification (start, end, 0, start, end, Qnil);
843 }
844
845 /* Signal a change immediately after it happens.
846 POS is the address of the start of the changed text.
847 LENDEL is the number of characters of the text before the change.
848 (Not the whole buffer; just the part that was changed.)
849 LENINS is the number of characters in that part of the text
850 after the change. */
851
852 void
853 signal_after_change (pos, lendel, lenins)
854 int pos, lendel, lenins;
855 {
856 /* Run the after-change-function if any.
857 We don't bother "binding" this variable to nil
858 because it is obsolete anyway and new code should not use it. */
859 if (!NILP (Vafter_change_function))
860 call3 (Vafter_change_function,
861 make_number (pos), make_number (pos + lenins),
862 make_number (lendel));
863
864 if (!NILP (Vafter_change_functions))
865 {
866 Lisp_Object args[4];
867 Lisp_Object before_change_functions;
868 Lisp_Object after_change_functions;
869 struct gcpro gcpro1, gcpro2;
870
871 /* "Bind" before-change-functions and after-change-functions
872 to nil--but in a way that errors don't know about.
873 That way, if there's an error in them, they will stay nil. */
874 before_change_functions = Vbefore_change_functions;
875 after_change_functions = Vafter_change_functions;
876 Vbefore_change_functions = Qnil;
877 Vafter_change_functions = Qnil;
878 GCPRO2 (before_change_functions, after_change_functions);
879
880 /* Actually run the hook functions. */
881 args[0] = Qafter_change_functions;
882 XSETFASTINT (args[1], pos);
883 XSETFASTINT (args[2], pos + lenins);
884 XSETFASTINT (args[3], lendel);
885 run_hook_list_with_args (after_change_functions,
886 4, args);
887
888 /* "Unbind" the variables we "bound" to nil. */
889 Vbefore_change_functions = before_change_functions;
890 Vafter_change_functions = after_change_functions;
891 UNGCPRO;
892 }
893
894 if (!NILP (current_buffer->overlays_before)
895 || !NILP (current_buffer->overlays_after))
896 report_overlay_modification (make_number (pos),
897 make_number (pos + lenins),
898 1,
899 make_number (pos), make_number (pos + lenins),
900 make_number (lendel));
901
902 /* After an insertion, call the text properties
903 insert-behind-hooks or insert-in-front-hooks. */
904 if (lendel == 0)
905 report_interval_modification (pos, pos + lenins);
906 }