Commit | Line | Data |
---|---|---|
b45433b3 | 1 | /* Buffer insertion/deletion and gap motion for GNU Emacs. |
4a2f9c6a | 2 | Copyright (C) 1985, 86, 93, 94, 95, 97, 1998 Free Software Foundation, Inc. |
b45433b3 JB |
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 | |
7c938215 | 8 | the Free Software Foundation; either version 2, or (at your option) |
b45433b3 JB |
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 | |
3b7ad313 EN |
18 | the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
19 | Boston, MA 02111-1307, USA. */ | |
b45433b3 JB |
20 | |
21 | ||
18160b98 | 22 | #include <config.h> |
c4a10daf DL |
23 | #ifdef HAVE_STDLIB_H |
24 | #include <stdlib.h> | |
25 | #endif | |
b45433b3 | 26 | #include "lisp.h" |
679194a6 | 27 | #include "intervals.h" |
b45433b3 | 28 | #include "buffer.h" |
469ff680 | 29 | #include "charset.h" |
b45433b3 | 30 | #include "window.h" |
d014bf88 | 31 | #include "blockinput.h" |
dfcf069d | 32 | #include "region-cache.h" |
b45433b3 | 33 | |
d206af14 RS |
34 | #ifndef NULL |
35 | #define NULL 0 | |
36 | #endif | |
37 | ||
14f6194b | 38 | #define min(x, y) ((x) < (y) ? (x) : (y)) |
2e9f55fd | 39 | #define max(x, y) ((x) > (y) ? (x) : (y)) |
14f6194b | 40 | |
2b083808 | 41 | static void insert_from_string_1 P_ ((Lisp_Object, int, int, int, int, int, int)); |
ef29f213 | 42 | static void insert_from_buffer_1 (); |
3be11131 RS |
43 | static void gap_left P_ ((int, int, int)); |
44 | static void gap_right P_ ((int, int)); | |
45 | static void adjust_markers_gap_motion P_ ((int, int, int)); | |
432f78d2 | 46 | static void adjust_markers_for_insert P_ ((int, int, int, int, int, int, int)); |
3be11131 | 47 | static void adjust_markers_for_delete P_ ((int, int, int, int)); |
7cc3983f | 48 | static void adjust_markers_for_record_delete P_ ((int, int, int, int)); |
3be11131 | 49 | static void adjust_point P_ ((int, int)); |
395ec62e | 50 | |
fb2e7d14 RS |
51 | Lisp_Object Fcombine_after_change_execute (); |
52 | ||
53 | /* Non-nil means don't call the after-change-functions right away, | |
54 | just record an element in Vcombine_after_change_calls_list. */ | |
55 | Lisp_Object Vcombine_after_change_calls; | |
56 | ||
57 | /* List of elements of the form (BEG-UNCHANGED END-UNCHANGED CHANGE-AMOUNT) | |
58 | describing changes which happened while combine_after_change_calls | |
59 | was nonzero. We use this to decide how to call them | |
60 | once the deferral ends. | |
61 | ||
62 | In each element. | |
63 | BEG-UNCHANGED is the number of chars before the changed range. | |
64 | END-UNCHANGED is the number of chars after the changed range, | |
65 | and CHANGE-AMOUNT is the number of characters inserted by the change | |
66 | (negative for a deletion). */ | |
67 | Lisp_Object combine_after_change_list; | |
68 | ||
69 | /* Buffer which combine_after_change_list is about. */ | |
70 | Lisp_Object combine_after_change_buffer; | |
2b083808 | 71 | \f |
60ea6052 RS |
72 | /* Check all markers in the current buffer, looking for something invalid. */ |
73 | ||
74 | static int check_markers_debug_flag; | |
75 | ||
76 | #define CHECK_MARKERS() \ | |
77 | if (check_markers_debug_flag) \ | |
78 | check_markers (); \ | |
79 | else | |
80 | ||
81 | void | |
82 | check_markers () | |
83 | { | |
84 | register Lisp_Object tail, prev, next; | |
9f3ede3c | 85 | int multibyte = ! NILP (current_buffer->enable_multibyte_characters); |
60ea6052 RS |
86 | |
87 | tail = BUF_MARKERS (current_buffer); | |
88 | ||
89 | while (XSYMBOL (tail) != XSYMBOL (Qnil)) | |
90 | { | |
91 | if (XMARKER (tail)->buffer->text != current_buffer->text) | |
92 | abort (); | |
93 | if (XMARKER (tail)->charpos > Z) | |
94 | abort (); | |
95 | if (XMARKER (tail)->bytepos > Z_BYTE) | |
96 | abort (); | |
9f3ede3c KH |
97 | if (multibyte && ! CHAR_HEAD_P (FETCH_BYTE (XMARKER (tail)->bytepos))) |
98 | abort (); | |
60ea6052 RS |
99 | |
100 | tail = XMARKER (tail)->chain; | |
101 | } | |
102 | } | |
103 | \f | |
3be11131 | 104 | /* Move gap to position CHARPOS. |
b45433b3 JB |
105 | Note that this can quit! */ |
106 | ||
c660b094 | 107 | void |
3be11131 RS |
108 | move_gap (charpos) |
109 | int charpos; | |
b45433b3 | 110 | { |
3be11131 | 111 | move_gap_both (charpos, charpos_to_bytepos (charpos)); |
b45433b3 JB |
112 | } |
113 | ||
3be11131 RS |
114 | /* Move gap to byte position BYTEPOS, which is also char position CHARPOS. |
115 | Note that this can quit! */ | |
116 | ||
117 | void | |
118 | move_gap_both (charpos, bytepos) | |
119 | int charpos, bytepos; | |
120 | { | |
121 | if (bytepos < GPT_BYTE) | |
122 | gap_left (charpos, bytepos, 0); | |
123 | else if (bytepos > GPT_BYTE) | |
124 | gap_right (charpos, bytepos); | |
125 | } | |
126 | ||
127 | /* Move the gap to a position less than the current GPT. | |
128 | BYTEPOS describes the new position as a byte position, | |
129 | and CHARPOS is the corresponding char position. | |
b45433b3 JB |
130 | If NEWGAP is nonzero, then don't update beg_unchanged and end_unchanged. */ |
131 | ||
2bcaed71 | 132 | static void |
3be11131 RS |
133 | gap_left (charpos, bytepos, newgap) |
134 | register int charpos, bytepos; | |
b45433b3 JB |
135 | int newgap; |
136 | { | |
137 | register unsigned char *to, *from; | |
138 | register int i; | |
139 | int new_s1; | |
140 | ||
b45433b3 | 141 | if (!newgap) |
a50df55b | 142 | BUF_COMPUTE_UNCHANGED (current_buffer, charpos, GPT); |
b45433b3 | 143 | |
3be11131 | 144 | i = GPT_BYTE; |
b45433b3 JB |
145 | to = GAP_END_ADDR; |
146 | from = GPT_ADDR; | |
3be11131 | 147 | new_s1 = GPT_BYTE; |
b45433b3 JB |
148 | |
149 | /* Now copy the characters. To move the gap down, | |
150 | copy characters up. */ | |
151 | ||
152 | while (1) | |
153 | { | |
154 | /* I gets number of characters left to copy. */ | |
3be11131 | 155 | i = new_s1 - bytepos; |
b45433b3 JB |
156 | if (i == 0) |
157 | break; | |
158 | /* If a quit is requested, stop copying now. | |
3be11131 | 159 | Change BYTEPOS to be where we have actually moved the gap to. */ |
b45433b3 JB |
160 | if (QUITP) |
161 | { | |
3be11131 RS |
162 | bytepos = new_s1; |
163 | charpos = BYTE_TO_CHAR (bytepos); | |
b45433b3 JB |
164 | break; |
165 | } | |
166 | /* Move at most 32000 chars before checking again for a quit. */ | |
167 | if (i > 32000) | |
168 | i = 32000; | |
169 | #ifdef GAP_USE_BCOPY | |
170 | if (i >= 128 | |
171 | /* bcopy is safe if the two areas of memory do not overlap | |
172 | or on systems where bcopy is always safe for moving upward. */ | |
173 | && (BCOPY_UPWARD_SAFE | |
174 | || to - from >= 128)) | |
175 | { | |
176 | /* If overlap is not safe, avoid it by not moving too many | |
177 | characters at once. */ | |
178 | if (!BCOPY_UPWARD_SAFE && i > to - from) | |
179 | i = to - from; | |
180 | new_s1 -= i; | |
181 | from -= i, to -= i; | |
182 | bcopy (from, to, i); | |
183 | } | |
184 | else | |
185 | #endif | |
186 | { | |
187 | new_s1 -= i; | |
188 | while (--i >= 0) | |
189 | *--to = *--from; | |
190 | } | |
191 | } | |
192 | ||
3be11131 RS |
193 | /* Adjust markers, and buffer data structure, to put the gap at BYTEPOS. |
194 | BYTEPOS is where the loop above stopped, which may be what was specified | |
b45433b3 | 195 | or may be where a quit was detected. */ |
3be11131 RS |
196 | adjust_markers_gap_motion (bytepos, GPT_BYTE, GAP_SIZE); |
197 | GPT_BYTE = bytepos; | |
198 | GPT = charpos; | |
199 | if (bytepos < charpos) | |
200 | abort (); | |
469ff680 | 201 | if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */ |
b45433b3 JB |
202 | QUIT; |
203 | } | |
204 | ||
3be11131 RS |
205 | /* Move the gap to a position greater than than the current GPT. |
206 | BYTEPOS describes the new position as a byte position, | |
207 | and CHARPOS is the corresponding char position. */ | |
208 | ||
2bcaed71 | 209 | static void |
3be11131 RS |
210 | gap_right (charpos, bytepos) |
211 | register int charpos, bytepos; | |
b45433b3 JB |
212 | { |
213 | register unsigned char *to, *from; | |
214 | register int i; | |
215 | int new_s1; | |
216 | ||
a50df55b | 217 | BUF_COMPUTE_UNCHANGED (current_buffer, charpos, GPT); |
b45433b3 | 218 | |
3be11131 | 219 | i = GPT_BYTE; |
b45433b3 JB |
220 | from = GAP_END_ADDR; |
221 | to = GPT_ADDR; | |
3be11131 | 222 | new_s1 = GPT_BYTE; |
b45433b3 JB |
223 | |
224 | /* Now copy the characters. To move the gap up, | |
225 | copy characters down. */ | |
226 | ||
227 | while (1) | |
228 | { | |
229 | /* I gets number of characters left to copy. */ | |
3be11131 | 230 | i = bytepos - new_s1; |
b45433b3 JB |
231 | if (i == 0) |
232 | break; | |
233 | /* If a quit is requested, stop copying now. | |
3be11131 | 234 | Change BYTEPOS to be where we have actually moved the gap to. */ |
b45433b3 JB |
235 | if (QUITP) |
236 | { | |
3be11131 RS |
237 | bytepos = new_s1; |
238 | charpos = BYTE_TO_CHAR (bytepos); | |
b45433b3 JB |
239 | break; |
240 | } | |
241 | /* Move at most 32000 chars before checking again for a quit. */ | |
242 | if (i > 32000) | |
243 | i = 32000; | |
244 | #ifdef GAP_USE_BCOPY | |
245 | if (i >= 128 | |
246 | /* bcopy is safe if the two areas of memory do not overlap | |
247 | or on systems where bcopy is always safe for moving downward. */ | |
248 | && (BCOPY_DOWNWARD_SAFE | |
249 | || from - to >= 128)) | |
250 | { | |
251 | /* If overlap is not safe, avoid it by not moving too many | |
252 | characters at once. */ | |
253 | if (!BCOPY_DOWNWARD_SAFE && i > from - to) | |
254 | i = from - to; | |
255 | new_s1 += i; | |
256 | bcopy (from, to, i); | |
257 | from += i, to += i; | |
258 | } | |
259 | else | |
260 | #endif | |
261 | { | |
262 | new_s1 += i; | |
263 | while (--i >= 0) | |
264 | *to++ = *from++; | |
265 | } | |
266 | } | |
267 | ||
3be11131 RS |
268 | adjust_markers_gap_motion (GPT_BYTE + GAP_SIZE, bytepos + GAP_SIZE, |
269 | - GAP_SIZE); | |
270 | GPT = charpos; | |
271 | GPT_BYTE = bytepos; | |
272 | if (bytepos < charpos) | |
273 | abort (); | |
469ff680 | 274 | if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */ |
b45433b3 JB |
275 | QUIT; |
276 | } | |
2b083808 | 277 | \f |
3be11131 RS |
278 | /* Add AMOUNT to the byte position of every marker in the current buffer |
279 | whose current byte position is between FROM (exclusive) and TO (inclusive). | |
8948d317 | 280 | |
b45433b3 JB |
281 | Also, any markers past the outside of that interval, in the direction |
282 | of adjustment, are first moved back to the near end of the interval | |
8948d317 RS |
283 | and then adjusted by AMOUNT. |
284 | ||
285 | When the latter adjustment is done, if AMOUNT is negative, | |
286 | we record the adjustment for undo. (This case happens only for | |
3be11131 RS |
287 | deletion.) |
288 | ||
289 | The markers' character positions are not altered, | |
290 | because gap motion does not affect character positions. */ | |
291 | ||
292 | int adjust_markers_test; | |
b45433b3 | 293 | |
2bcaed71 | 294 | static void |
3be11131 | 295 | adjust_markers_gap_motion (from, to, amount) |
b45433b3 JB |
296 | register int from, to, amount; |
297 | { | |
80f6e77c RS |
298 | /* Now that a marker has a bytepos, not counting the gap, |
299 | nothing needs to be done here. */ | |
300 | #if 0 | |
b45433b3 JB |
301 | Lisp_Object marker; |
302 | register struct Lisp_Marker *m; | |
303 | register int mpos; | |
304 | ||
9fbf87cd | 305 | marker = BUF_MARKERS (current_buffer); |
b45433b3 | 306 | |
d427b66a | 307 | while (!NILP (marker)) |
b45433b3 JB |
308 | { |
309 | m = XMARKER (marker); | |
80f6e77c | 310 | mpos = m->bytepos; |
b45433b3 JB |
311 | if (amount > 0) |
312 | { | |
313 | if (mpos > to && mpos < to + amount) | |
3be11131 RS |
314 | { |
315 | if (adjust_markers_test) | |
316 | abort (); | |
317 | mpos = to + amount; | |
318 | } | |
b45433b3 JB |
319 | } |
320 | else | |
321 | { | |
8948d317 RS |
322 | /* Here's the case where a marker is inside text being deleted. |
323 | AMOUNT can be negative for gap motion, too, | |
324 | but then this range contains no markers. */ | |
b45433b3 | 325 | if (mpos > from + amount && mpos <= from) |
8948d317 | 326 | { |
3be11131 RS |
327 | if (adjust_markers_test) |
328 | abort (); | |
329 | mpos = from + amount; | |
8948d317 | 330 | } |
b45433b3 JB |
331 | } |
332 | if (mpos > from && mpos <= to) | |
333 | mpos += amount; | |
334 | m->bufpos = mpos; | |
335 | marker = m->chain; | |
336 | } | |
80f6e77c | 337 | #endif |
b45433b3 | 338 | } |
2b083808 | 339 | \f |
3be11131 RS |
340 | /* Adjust all markers for a deletion |
341 | whose range in bytes is FROM_BYTE to TO_BYTE. | |
342 | The range in charpos is FROM to TO. | |
343 | ||
344 | This function assumes that the gap is adjacent to | |
345 | or inside of the range being deleted. */ | |
beecb55b RS |
346 | |
347 | static void | |
3be11131 RS |
348 | adjust_markers_for_delete (from, from_byte, to, to_byte) |
349 | register int from, from_byte, to, to_byte; | |
350 | { | |
351 | Lisp_Object marker; | |
352 | register struct Lisp_Marker *m; | |
353 | register int charpos; | |
3be11131 RS |
354 | |
355 | marker = BUF_MARKERS (current_buffer); | |
356 | ||
357 | while (!NILP (marker)) | |
358 | { | |
359 | m = XMARKER (marker); | |
360 | charpos = m->charpos; | |
361 | ||
362 | if (charpos > Z) | |
363 | abort (); | |
364 | ||
365 | /* If the marker is after the deletion, | |
80f6e77c | 366 | relocate by number of chars / bytes deleted. */ |
3be11131 | 367 | if (charpos > to) |
80f6e77c RS |
368 | { |
369 | m->charpos -= to - from; | |
370 | m->bytepos -= to_byte - from_byte; | |
371 | } | |
3be11131 | 372 | |
80f6e77c | 373 | /* Here's the case where a marker is inside text being deleted. */ |
3be11131 RS |
374 | else if (charpos > from) |
375 | { | |
376 | record_marker_adjustment (marker, from - charpos); | |
377 | m->charpos = from; | |
80f6e77c | 378 | m->bytepos = from_byte; |
3be11131 RS |
379 | } |
380 | ||
3be11131 RS |
381 | marker = m->chain; |
382 | } | |
383 | } | |
23b20a70 | 384 | |
2b083808 | 385 | \f |
7cc3983f RS |
386 | /* Adjust all markers for calling record_delete for combining bytes. |
387 | whose range in bytes is FROM_BYTE to TO_BYTE. | |
388 | The range in charpos is FROM to TO. */ | |
389 | ||
390 | static void | |
391 | adjust_markers_for_record_delete (from, from_byte, to, to_byte) | |
392 | register int from, from_byte, to, to_byte; | |
393 | { | |
394 | Lisp_Object marker; | |
395 | register struct Lisp_Marker *m; | |
396 | register int charpos; | |
397 | ||
398 | marker = BUF_MARKERS (current_buffer); | |
399 | ||
400 | while (!NILP (marker)) | |
401 | { | |
402 | m = XMARKER (marker); | |
403 | charpos = m->charpos; | |
404 | ||
405 | /* If the marker is after the deletion, | |
406 | relocate by number of chars / bytes deleted. */ | |
407 | if (charpos > to) | |
408 | ; | |
409 | /* Here's the case where a marker is inside text being deleted. */ | |
410 | else if (charpos > from) | |
411 | record_marker_adjustment (marker, from - charpos); | |
412 | ||
413 | marker = m->chain; | |
414 | } | |
415 | } | |
416 | \f | |
432f78d2 RS |
417 | /* Adjust markers for an insertion that stretches from FROM / FROM_BYTE |
418 | to TO / TO_BYTE. We have to relocate the charpos of every marker | |
419 | that points after the insertion (but not their bytepos). | |
3be11131 | 420 | |
ce97a2d7 RS |
421 | COMBINED_BEFORE_BYTES is the number of bytes at the start of the insertion |
422 | that combine into one character with the text before the insertion. | |
432f78d2 | 423 | COMBINED_AFTER_BYTES is the number of bytes after the insertion |
ce97a2d7 | 424 | that combine into one character with the last inserted bytes. |
3be11131 RS |
425 | |
426 | When a marker points at the insertion point, | |
427 | we advance it if either its insertion-type is t | |
428 | or BEFORE_MARKERS is true. */ | |
429 | ||
430 | static void | |
432f78d2 RS |
431 | adjust_markers_for_insert (from, from_byte, to, to_byte, |
432 | combined_before_bytes, combined_after_bytes, | |
433 | before_markers) | |
434 | register int from, from_byte, to, to_byte; | |
435 | int combined_before_bytes, combined_after_bytes, before_markers; | |
beecb55b RS |
436 | { |
437 | Lisp_Object marker; | |
469ff680 | 438 | int adjusted = 0; |
3be11131 RS |
439 | int nchars = to - from; |
440 | int nbytes = to_byte - from_byte; | |
beecb55b RS |
441 | |
442 | marker = BUF_MARKERS (current_buffer); | |
443 | ||
444 | while (!NILP (marker)) | |
445 | { | |
446 | register struct Lisp_Marker *m = XMARKER (marker); | |
1f90a790 RS |
447 | |
448 | /* In a single-byte buffer, a marker's two positions must be equal. | |
449 | (If this insertion is going to combine characters, Z will | |
450 | become different from Z_BYTE, but they might be the same now. | |
451 | If so, the two OLD positions of the marker should be equal.) */ | |
452 | if (Z == Z_BYTE) | |
453 | { | |
454 | if (m->charpos != m->bytepos) | |
455 | abort (); | |
456 | } | |
457 | ||
432f78d2 | 458 | if (m->bytepos == from_byte) |
469ff680 | 459 | { |
432f78d2 RS |
460 | if (m->insertion_type || before_markers) |
461 | { | |
828f1ed3 KH |
462 | m->bytepos = to_byte + combined_after_bytes; |
463 | m->charpos = to - combined_before_bytes; | |
432f78d2 RS |
464 | /* Point the marker before the combined character, |
465 | so that undoing the insertion puts it back where it was. */ | |
466 | if (combined_after_bytes) | |
467 | DEC_BOTH (m->charpos, m->bytepos); | |
468 | if (m->insertion_type) | |
469 | adjusted = 1; | |
470 | } | |
471 | else if (combined_before_bytes) | |
472 | { | |
473 | /* This marker doesn't "need relocation", | |
474 | but don't leave it pointing in the middle of a character. | |
475 | Point the marker after the combined character, | |
476 | so that undoing the insertion puts it back where it was. */ | |
828f1ed3 | 477 | m->bytepos += combined_before_bytes; |
9f3ede3c KH |
478 | if (combined_before_bytes == nbytes) |
479 | /* All new bytes plus combined_after_bytes (if any) | |
480 | are combined. */ | |
481 | m->bytepos += combined_after_bytes; | |
432f78d2 | 482 | } |
469ff680 | 483 | } |
ce97a2d7 RS |
484 | /* If a marker was pointing into the combining bytes |
485 | after the insertion, don't leave it there | |
486 | in the middle of a character. */ | |
487 | else if (combined_after_bytes && m->bytepos >= from_byte | |
488 | && m->bytepos < from_byte + combined_after_bytes) | |
489 | { | |
490 | /* Put it after the combining bytes. */ | |
491 | m->bytepos = to_byte + combined_after_bytes; | |
828f1ed3 | 492 | m->charpos = to - combined_before_bytes; |
ce97a2d7 RS |
493 | /* Now move it back before the combined character, |
494 | so that undoing the insertion will put it where it was. */ | |
495 | DEC_BOTH (m->charpos, m->bytepos); | |
496 | } | |
80f6e77c RS |
497 | else if (m->bytepos > from_byte) |
498 | { | |
499 | m->bytepos += nbytes; | |
828f1ed3 | 500 | m->charpos += nchars - combined_after_bytes - combined_before_bytes; |
80f6e77c | 501 | } |
3be11131 | 502 | |
beecb55b RS |
503 | marker = m->chain; |
504 | } | |
3be11131 RS |
505 | |
506 | /* Adjusting only markers whose insertion-type is t may result in | |
507 | disordered overlays in the slot `overlays_before'. */ | |
469ff680 | 508 | if (adjusted) |
3be11131 | 509 | fix_overlays_before (current_buffer, from, to); |
beecb55b RS |
510 | } |
511 | ||
3be11131 RS |
512 | /* Adjust point for an insertion of NBYTES bytes, which are NCHARS characters. |
513 | ||
514 | This is used only when the value of point changes due to an insert | |
515 | or delete; it does not represent a conceptual change in point as a | |
516 | marker. In particular, point is not crossing any interval | |
517 | boundaries, so there's no need to use the usual SET_PT macro. In | |
518 | fact it would be incorrect to do so, because either the old or the | |
519 | new value of point is out of sync with the current set of | |
520 | intervals. */ | |
521 | ||
a27a38d8 | 522 | static void |
3be11131 RS |
523 | adjust_point (nchars, nbytes) |
524 | int nchars, nbytes; | |
a27a38d8 | 525 | { |
3be11131 RS |
526 | BUF_PT (current_buffer) += nchars; |
527 | BUF_PT_BYTE (current_buffer) += nbytes; | |
528 | ||
529 | /* In a single-byte buffer, the two positions must be equal. */ | |
530 | if (ZV == ZV_BYTE | |
531 | && PT != PT_BYTE) | |
532 | abort (); | |
a27a38d8 | 533 | } |
b45433b3 | 534 | \f |
652838b5 KH |
535 | /* Adjust markers for a replacement of a text at FROM (FROM_BYTE) of |
536 | length OLD_CHARS (OLD_BYTES) to a new text of length NEW_CHARS | |
537 | (NEW_BYTES). | |
538 | ||
539 | See the comment of adjust_markers_for_insert for the args | |
540 | COMBINED_BEFORE_BYTES and COMBINED_AFTER_BYTES. */ | |
541 | ||
542 | static void | |
543 | adjust_markers_for_replace (from, from_byte, old_chars, old_bytes, | |
544 | new_chars, new_bytes, | |
545 | combined_before_bytes, combined_after_bytes) | |
546 | int from, from_byte, old_chars, old_bytes, new_chars, new_bytes; | |
547 | int combined_before_bytes, combined_after_bytes; | |
548 | { | |
549 | Lisp_Object marker = BUF_MARKERS (current_buffer); | |
550 | int prev_to_byte = from_byte + old_bytes; | |
3019692c KH |
551 | int diff_chars |
552 | = (new_chars - combined_before_bytes) - (old_chars + combined_after_bytes); | |
652838b5 KH |
553 | int diff_bytes = new_bytes - old_bytes; |
554 | ||
555 | while (!NILP (marker)) | |
556 | { | |
557 | register struct Lisp_Marker *m = XMARKER (marker); | |
558 | ||
c8a3c7eb RS |
559 | if (m->bytepos >= prev_to_byte |
560 | && (old_bytes != 0 | |
561 | /* If this is an insertion (replacing 0 chars), | |
562 | reject the case of a marker that is at the | |
563 | insertion point and should stay before the insertion. */ | |
564 | || m->bytepos > from_byte || m->insertion_type)) | |
652838b5 KH |
565 | { |
566 | if (m->bytepos < prev_to_byte + combined_after_bytes) | |
567 | { | |
568 | /* Put it after the combining bytes. */ | |
3019692c KH |
569 | m->bytepos = from_byte + new_bytes + combined_after_bytes; |
570 | m->charpos = from + new_chars - combined_before_bytes; | |
652838b5 KH |
571 | } |
572 | else | |
573 | { | |
574 | m->charpos += diff_chars; | |
575 | m->bytepos += diff_bytes; | |
576 | } | |
652838b5 | 577 | } |
3019692c | 578 | else if (m->bytepos >= from_byte) |
652838b5 | 579 | { |
652838b5 | 580 | m->charpos = from; |
3019692c KH |
581 | m->bytepos = from_byte + combined_before_bytes; |
582 | /* If all new bytes are combined in addition to that there | |
583 | are after combining bytes, we must set byte position of | |
584 | the marker after the after combining bytes. */ | |
585 | if (combined_before_bytes == new_bytes) | |
586 | m->bytepos += combined_after_bytes; | |
652838b5 | 587 | } |
652838b5 KH |
588 | |
589 | marker = m->chain; | |
590 | } | |
3019692c KH |
591 | |
592 | CHECK_MARKERS (); | |
652838b5 KH |
593 | } |
594 | ||
595 | \f | |
3be11131 | 596 | /* Make the gap NBYTES_ADDED bytes longer. */ |
b45433b3 | 597 | |
c660b094 | 598 | void |
3be11131 RS |
599 | make_gap (nbytes_added) |
600 | int nbytes_added; | |
b45433b3 JB |
601 | { |
602 | unsigned char *result; | |
603 | Lisp_Object tem; | |
604 | int real_gap_loc; | |
3be11131 | 605 | int real_gap_loc_byte; |
b45433b3 JB |
606 | int old_gap_size; |
607 | ||
608 | /* If we have to get more space, get enough to last a while. */ | |
3be11131 | 609 | nbytes_added += 2000; |
b45433b3 | 610 | |
94056516 RS |
611 | /* Don't allow a buffer size that won't fit in an int |
612 | even if it will fit in a Lisp integer. | |
613 | That won't work because so many places use `int'. */ | |
614 | ||
3be11131 | 615 | if (Z_BYTE - BEG_BYTE + GAP_SIZE + nbytes_added |
68be917d | 616 | >= ((unsigned) 1 << (min (BITS_PER_INT, VALBITS) - 1))) |
14f6194b | 617 | error ("Buffer exceeds maximum size"); |
94056516 | 618 | |
9ac0d9e0 | 619 | BLOCK_INPUT; |
469ff680 | 620 | /* We allocate extra 1-byte `\0' at the tail for anchoring a search. */ |
3be11131 RS |
621 | result = BUFFER_REALLOC (BEG_ADDR, (Z_BYTE - BEG_BYTE |
622 | + GAP_SIZE + nbytes_added + 1)); | |
9ac0d9e0 | 623 | |
b45433b3 | 624 | if (result == 0) |
270c2138 RS |
625 | { |
626 | UNBLOCK_INPUT; | |
627 | memory_full (); | |
628 | } | |
629 | ||
630 | /* We can't unblock until the new address is properly stored. */ | |
b45433b3 | 631 | BEG_ADDR = result; |
270c2138 | 632 | UNBLOCK_INPUT; |
b45433b3 JB |
633 | |
634 | /* Prevent quitting in move_gap. */ | |
635 | tem = Vinhibit_quit; | |
636 | Vinhibit_quit = Qt; | |
637 | ||
638 | real_gap_loc = GPT; | |
3be11131 | 639 | real_gap_loc_byte = GPT_BYTE; |
b45433b3 JB |
640 | old_gap_size = GAP_SIZE; |
641 | ||
642 | /* Call the newly allocated space a gap at the end of the whole space. */ | |
643 | GPT = Z + GAP_SIZE; | |
7d92db58 | 644 | GPT_BYTE = Z_BYTE + GAP_SIZE; |
3be11131 | 645 | GAP_SIZE = nbytes_added; |
b45433b3 JB |
646 | |
647 | /* Move the new gap down to be consecutive with the end of the old one. | |
648 | This adjusts the markers properly too. */ | |
3be11131 | 649 | gap_left (real_gap_loc + old_gap_size, real_gap_loc_byte + old_gap_size, 1); |
b45433b3 JB |
650 | |
651 | /* Now combine the two into one large gap. */ | |
652 | GAP_SIZE += old_gap_size; | |
653 | GPT = real_gap_loc; | |
3be11131 | 654 | GPT_BYTE = real_gap_loc_byte; |
b45433b3 | 655 | |
469ff680 KH |
656 | /* Put an anchor. */ |
657 | *(Z_ADDR) = 0; | |
658 | ||
b45433b3 JB |
659 | Vinhibit_quit = tem; |
660 | } | |
661 | \f | |
2b083808 RS |
662 | /* Copy NBYTES bytes of text from FROM_ADDR to TO_ADDR. |
663 | FROM_MULTIBYTE says whether the incoming text is multibyte. | |
664 | TO_MULTIBYTE says whether to store the text as multibyte. | |
665 | If FROM_MULTIBYTE != TO_MULTIBYTE, we convert. | |
666 | ||
667 | Return the number of bytes stored at TO_ADDR. */ | |
668 | ||
669 | int | |
670 | copy_text (from_addr, to_addr, nbytes, | |
671 | from_multibyte, to_multibyte) | |
672 | unsigned char *from_addr; | |
673 | unsigned char *to_addr; | |
674 | int nbytes; | |
675 | int from_multibyte, to_multibyte; | |
676 | { | |
677 | if (from_multibyte == to_multibyte) | |
678 | { | |
679 | bcopy (from_addr, to_addr, nbytes); | |
680 | return nbytes; | |
681 | } | |
682 | else if (from_multibyte) | |
683 | { | |
684 | int nchars = 0; | |
685 | int bytes_left = nbytes; | |
f44cbcd8 KH |
686 | Lisp_Object tbl = Qnil, temp; |
687 | ||
688 | /* We set the variable tbl to the reverse table of | |
689 | Vnonascii_translation_table in advance. */ | |
690 | if (CHAR_TABLE_P (Vnonascii_translation_table)) | |
691 | { | |
692 | tbl = Fchar_table_extra_slot (Vnonascii_translation_table, | |
693 | make_number (0)); | |
694 | if (!CHAR_TABLE_P (tbl)) | |
695 | tbl = Qnil; | |
696 | } | |
2b083808 RS |
697 | |
698 | /* Convert multibyte to single byte. */ | |
699 | while (bytes_left > 0) | |
700 | { | |
f44cbcd8 KH |
701 | int thislen, c, c_save; |
702 | c = c_save = STRING_CHAR_AND_LENGTH (from_addr, bytes_left, thislen); | |
703 | if (!SINGLE_BYTE_CHAR_P (c)) | |
4ec36780 | 704 | c = multibyte_char_to_unibyte (c, tbl); |
f44cbcd8 | 705 | *to_addr++ = c; |
2b083808 | 706 | from_addr += thislen; |
7e79b8e0 | 707 | bytes_left -= thislen; |
2b083808 RS |
708 | nchars++; |
709 | } | |
710 | return nchars; | |
711 | } | |
712 | else | |
713 | { | |
714 | unsigned char *initial_to_addr = to_addr; | |
715 | ||
716 | /* Convert single-byte to multibyte. */ | |
717 | while (nbytes > 0) | |
718 | { | |
719 | int c = *from_addr++; | |
720 | unsigned char workbuf[4], *str; | |
721 | int len; | |
722 | ||
8cbf107d EZ |
723 | if (c < 0400 |
724 | && (c >= 0240 | |
725 | || (c >= 0200 && !NILP (Vnonascii_translation_table)))) | |
2b083808 | 726 | { |
59a52d50 | 727 | c = unibyte_char_to_multibyte (c); |
2b083808 RS |
728 | len = CHAR_STRING (c, workbuf, str); |
729 | bcopy (str, to_addr, len); | |
730 | to_addr += len; | |
731 | nbytes--; | |
732 | } | |
733 | else | |
734 | /* Special case for speed. */ | |
735 | *to_addr++ = c, nbytes--; | |
736 | } | |
737 | return to_addr - initial_to_addr; | |
738 | } | |
739 | } | |
740 | ||
741 | /* Return the number of bytes it would take | |
742 | to convert some single-byte text to multibyte. | |
743 | The single-byte text consists of NBYTES bytes at PTR. */ | |
744 | ||
745 | int | |
746 | count_size_as_multibyte (ptr, nbytes) | |
747 | unsigned char *ptr; | |
748 | int nbytes; | |
749 | { | |
750 | int i; | |
751 | int outgoing_nbytes = 0; | |
752 | ||
753 | for (i = 0; i < nbytes; i++) | |
754 | { | |
755 | unsigned int c = *ptr++; | |
59a52d50 | 756 | |
8cbf107d | 757 | if (c < 0200 || (c < 0240 && NILP (Vnonascii_translation_table))) |
59a52d50 KH |
758 | outgoing_nbytes++; |
759 | else | |
2b083808 | 760 | { |
59a52d50 | 761 | c = unibyte_char_to_multibyte (c); |
643044eb | 762 | outgoing_nbytes += CHAR_BYTES (c); |
2b083808 | 763 | } |
2b083808 RS |
764 | } |
765 | ||
766 | return outgoing_nbytes; | |
767 | } | |
768 | \f | |
b45433b3 | 769 | /* Insert a string of specified length before point. |
2b083808 RS |
770 | This function judges multibyteness based on |
771 | enable_multibyte_characters in the current buffer; | |
772 | it never converts between single-byte and multibyte. | |
773 | ||
ef29f213 KH |
774 | DO NOT use this for the contents of a Lisp string or a Lisp buffer! |
775 | prepare_to_modify_buffer could relocate the text. */ | |
b45433b3 | 776 | |
c660b094 | 777 | void |
3be11131 | 778 | insert (string, nbytes) |
b45433b3 | 779 | register unsigned char *string; |
dfcf069d | 780 | register int nbytes; |
b45433b3 | 781 | { |
3be11131 | 782 | if (nbytes > 0) |
395ec62e | 783 | { |
3be11131 RS |
784 | int opoint = PT; |
785 | insert_1 (string, nbytes, 0, 1, 0); | |
786 | signal_after_change (opoint, 0, PT - opoint); | |
cd11ef31 RS |
787 | } |
788 | } | |
789 | ||
2b083808 RS |
790 | /* Likewise, but inherit text properties from neighboring characters. */ |
791 | ||
c660b094 | 792 | void |
3be11131 | 793 | insert_and_inherit (string, nbytes) |
cd11ef31 | 794 | register unsigned char *string; |
dfcf069d | 795 | register int nbytes; |
cd11ef31 | 796 | { |
3be11131 | 797 | if (nbytes > 0) |
cd11ef31 | 798 | { |
3be11131 RS |
799 | int opoint = PT; |
800 | insert_1 (string, nbytes, 1, 1, 0); | |
801 | signal_after_change (opoint, 0, PT - opoint); | |
395ec62e KH |
802 | } |
803 | } | |
b45433b3 | 804 | |
2b083808 | 805 | /* Insert the character C before point. Do not inherit text properties. */ |
3be11131 | 806 | |
c660b094 | 807 | void |
3be11131 RS |
808 | insert_char (c) |
809 | int c; | |
810 | { | |
811 | unsigned char workbuf[4], *str; | |
2b083808 RS |
812 | int len; |
813 | ||
814 | if (! NILP (current_buffer->enable_multibyte_characters)) | |
815 | len = CHAR_STRING (c, workbuf, str); | |
816 | else | |
817 | { | |
818 | len = 1; | |
819 | workbuf[0] = c; | |
820 | str = workbuf; | |
821 | } | |
3be11131 RS |
822 | |
823 | insert (str, len); | |
824 | } | |
825 | ||
2b083808 | 826 | /* Insert the null-terminated string S before point. */ |
3be11131 RS |
827 | |
828 | void | |
829 | insert_string (s) | |
830 | char *s; | |
831 | { | |
832 | insert (s, strlen (s)); | |
833 | } | |
834 | ||
835 | /* Like `insert' except that all markers pointing at the place where | |
836 | the insertion happens are adjusted to point after it. | |
837 | Don't use this function to insert part of a Lisp string, | |
838 | since gc could happen and relocate it. */ | |
839 | ||
840 | void | |
841 | insert_before_markers (string, nbytes) | |
842 | unsigned char *string; | |
843 | register int nbytes; | |
844 | { | |
845 | if (nbytes > 0) | |
846 | { | |
847 | int opoint = PT; | |
848 | ||
849 | insert_1 (string, nbytes, 0, 1, 1); | |
850 | signal_after_change (opoint, 0, PT - opoint); | |
851 | } | |
852 | } | |
853 | ||
2b083808 RS |
854 | /* Likewise, but inherit text properties from neighboring characters. */ |
855 | ||
3be11131 RS |
856 | void |
857 | insert_before_markers_and_inherit (string, nbytes) | |
858 | unsigned char *string; | |
859 | register int nbytes; | |
860 | { | |
861 | if (nbytes > 0) | |
862 | { | |
863 | int opoint = PT; | |
864 | ||
865 | insert_1 (string, nbytes, 1, 1, 1); | |
866 | signal_after_change (opoint, 0, PT - opoint); | |
867 | } | |
868 | } | |
1f90a790 | 869 | |
3be11131 RS |
870 | /* Subroutine used by the insert functions above. */ |
871 | ||
872 | void | |
873 | insert_1 (string, nbytes, inherit, prepare, before_markers) | |
395ec62e | 874 | register unsigned char *string; |
3be11131 RS |
875 | register int nbytes; |
876 | int inherit, prepare, before_markers; | |
395ec62e | 877 | { |
432f78d2 RS |
878 | insert_1_both (string, chars_in_text (string, nbytes), nbytes, |
879 | inherit, prepare, before_markers); | |
880 | } | |
1f90a790 | 881 | \f |
cae184f2 KH |
882 | /* See if the byte sequence at STR1 of length LEN1 combine with the |
883 | byte sequence at STR2 of length LEN2 to form a single composite | |
884 | character. If so, return the number of bytes at the start of STR2 | |
885 | which combine in this way. Otherwise, return 0. If STR3 is not | |
886 | NULL, it is a byte sequence of length LEN3 to be appended to STR1 | |
887 | before checking the combining. */ | |
888 | int | |
889 | count_combining_composition (str1, len1, str2, len2, str3, len3) | |
890 | unsigned char *str1, *str2, *str3; | |
891 | int len1, len2, len3; | |
892 | { | |
893 | int len = len1 + len2 + len3; | |
894 | unsigned char *buf = (unsigned char *) alloca (len + 1); | |
895 | int bytes; | |
896 | ||
897 | bcopy (str1, buf, len1); | |
898 | if (str3) | |
899 | { | |
900 | bcopy (str3, buf + len1, len3); | |
901 | len1 += len3; | |
902 | } | |
903 | bcopy (str2, buf + len1 , len2); | |
904 | buf[len] = 0; | |
905 | PARSE_MULTIBYTE_SEQ (buf, len, bytes); | |
906 | return (bytes <= len1 ? 0 : bytes - len1); | |
907 | } | |
908 | ||
432f78d2 RS |
909 | /* See if the bytes before POS/POS_BYTE combine with bytes |
910 | at the start of STRING to form a single character. | |
ce97a2d7 | 911 | If so, return the number of bytes at the start of STRING |
432f78d2 | 912 | which combine in this way. Otherwise, return 0. */ |
b45433b3 | 913 | |
432f78d2 RS |
914 | int |
915 | count_combining_before (string, length, pos, pos_byte) | |
916 | unsigned char *string; | |
917 | int length; | |
918 | int pos, pos_byte; | |
919 | { | |
cae184f2 KH |
920 | int len, combining_bytes; |
921 | unsigned char *p; | |
b45433b3 | 922 | |
432f78d2 RS |
923 | if (NILP (current_buffer->enable_multibyte_characters)) |
924 | return 0; | |
cae184f2 KH |
925 | |
926 | /* At first, we can exclude the following cases: | |
927 | (1) STRING[0] can't be a following byte of multibyte sequence. | |
928 | (2) POS is the start of the current buffer. | |
929 | (3) A character before POS is not a multibyte character. */ | |
930 | if (length == 0 || CHAR_HEAD_P (*string)) /* case (1) */ | |
432f78d2 | 931 | return 0; |
cae184f2 | 932 | if (pos_byte == BEG_BYTE) /* case (2) */ |
432f78d2 | 933 | return 0; |
cae184f2 KH |
934 | len = 1; |
935 | p = BYTE_POS_ADDR (pos_byte - 1); | |
936 | while (! CHAR_HEAD_P (*p)) p--, len++; | |
937 | if (! BASE_LEADING_CODE_P (*p)) /* case (3) */ | |
432f78d2 | 938 | return 0; |
cae184f2 KH |
939 | |
940 | /* A sequence of a composite character requires a special handling. */ | |
941 | if (*p == LEADING_CODE_COMPOSITION) | |
942 | return count_combining_composition (p, len, string, length, NULL, 0); | |
943 | ||
944 | combining_bytes = BYTES_BY_CHAR_HEAD (*p) - len; | |
945 | if (combining_bytes <= 0) | |
946 | /* The character preceding POS is, complete and no room for | |
947 | combining bytes (combining_bytes == 0), or an independent 8-bit | |
948 | character (combining_bytes < 0). */ | |
432f78d2 | 949 | return 0; |
ce97a2d7 | 950 | |
cae184f2 KH |
951 | /* We have a combination situation. Count the bytes at STRING that |
952 | may combine. */ | |
953 | p = string + 1; | |
ce97a2d7 RS |
954 | while (!CHAR_HEAD_P (*p) && p < string + length) |
955 | p++; | |
956 | ||
cae184f2 | 957 | return (combining_bytes < p - string ? combining_bytes : p - string); |
432f78d2 | 958 | } |
b45433b3 | 959 | |
432f78d2 RS |
960 | /* See if the bytes after POS/POS_BYTE combine with bytes |
961 | at the end of STRING to form a single character. | |
962 | If so, return the number of bytes after POS/POS_BYTE | |
963 | which combine in this way. Otherwise, return 0. */ | |
679194a6 | 964 | |
432f78d2 RS |
965 | int |
966 | count_combining_after (string, length, pos, pos_byte) | |
967 | unsigned char *string; | |
968 | int length; | |
969 | int pos, pos_byte; | |
970 | { | |
971 | int opos = pos, opos_byte = pos_byte; | |
972 | int i; | |
cae184f2 KH |
973 | int c, bytes; |
974 | unsigned char *bufp; | |
3be11131 | 975 | |
432f78d2 RS |
976 | if (NILP (current_buffer->enable_multibyte_characters)) |
977 | return 0; | |
cae184f2 KH |
978 | |
979 | /* At first, we can exclude the following cases: | |
980 | (1) The last byte of STRING is an ASCII. | |
981 | (2) POS is the last of the current buffer. | |
982 | (3) A character at POS can't be a following byte of multibyte | |
983 | character. */ | |
984 | if (length > 0 && ASCII_BYTE_P (string[length - 1])) /* case (1) */ | |
985 | return 0; | |
986 | if (pos_byte == Z_BYTE) /* case (2) */ | |
432f78d2 | 987 | return 0; |
cae184f2 KH |
988 | bufp = BYTE_POS_ADDR (pos_byte); |
989 | if (CHAR_HEAD_P (*bufp)) /* case (3) */ | |
990 | return 0; | |
991 | ||
432f78d2 | 992 | i = length - 1; |
b57a7b0b | 993 | while (i >= 0 && ! CHAR_HEAD_P (string[i])) |
432f78d2 RS |
994 | { |
995 | i--; | |
996 | } | |
b57a7b0b KH |
997 | if (i < 0) |
998 | { | |
cae184f2 KH |
999 | /* All characters in STRING are not character head. We must |
1000 | check also preceding bytes at POS. We are sure that the gap | |
1001 | is at POS. */ | |
1002 | unsigned char *p = BEG_ADDR; | |
b57a7b0b | 1003 | i = pos_byte - 2; |
cae184f2 | 1004 | while (i >= 0 && ! CHAR_HEAD_P (p[i])) |
b57a7b0b | 1005 | i--; |
cae184f2 | 1006 | if (i < 0 || !BASE_LEADING_CODE_P (p[i])) |
b57a7b0b | 1007 | return 0; |
cae184f2 KH |
1008 | /* A sequence of a composite character requires a special handling. */ |
1009 | if (p[i] == LEADING_CODE_COMPOSITION) | |
1010 | return count_combining_composition (p + i, pos_byte - 1 - i, | |
1011 | bufp, Z_BYTE - pos_byte, | |
1012 | string, length); | |
1013 | bytes = BYTES_BY_CHAR_HEAD (p[i]); | |
1014 | return (bytes <= pos_byte - 1 - i + length | |
1015 | ? 0 | |
1016 | : bytes - (pos_byte - 1 - i + length)); | |
b57a7b0b | 1017 | } |
cae184f2 | 1018 | if (!BASE_LEADING_CODE_P (string[i])) |
432f78d2 | 1019 | return 0; |
cae184f2 KH |
1020 | /* A sequence of a composite character requires a special handling. */ |
1021 | if (string[i] == LEADING_CODE_COMPOSITION) | |
1022 | return count_combining_composition (string + i, length - i, | |
1023 | bufp, Z_BYTE - pos_byte, NULL, 0); | |
432f78d2 | 1024 | |
cae184f2 KH |
1025 | bytes = BYTES_BY_CHAR_HEAD (string[i]) - (length - i); |
1026 | bufp++, pos_byte++; | |
1027 | while (!CHAR_HEAD_P (*bufp)) bufp++, pos_byte++; | |
cd11ef31 | 1028 | |
cae184f2 | 1029 | return (bytes <= pos_byte - opos_byte ? bytes : pos_byte - opos_byte); |
b45433b3 | 1030 | } |
2b083808 | 1031 | |
e3a87305 KH |
1032 | /* Adjust the position TARGET/TARGET_BYTE for the combining of NBYTES |
1033 | following the position POS/POS_BYTE to the character preceding POS. | |
1034 | If TARGET is after POS+NBYTES, we only have to adjust the character | |
1035 | position TARGET, else, if TARGET is after POS, we have to adjust | |
1036 | both the character position TARGET and the byte position | |
1037 | TARGET_BYTE, else we don't have to do any adjustment. */ | |
1038 | ||
1039 | #define ADJUST_CHAR_POS(target, target_byte) \ | |
1040 | do { \ | |
1041 | if (target > pos + nbytes) \ | |
1042 | target -= nbytes; \ | |
1043 | else if (target >= pos) \ | |
1044 | { \ | |
1045 | target = pos; \ | |
1046 | target_byte = pos_byte + nbytes; \ | |
1047 | } \ | |
1048 | } while (0) | |
1049 | ||
1f90a790 RS |
1050 | /* Combine NBYTES stray trailing-codes, which were formerly separate |
1051 | characters, with the preceding character. These bytes | |
1052 | are located after position POS / POS_BYTE, and the preceding character | |
3019692c KH |
1053 | is located just before that position. |
1054 | ||
1055 | This function does not adjust markers for byte combining. That | |
1056 | should be done in advance by the functions | |
f6ecdae5 | 1057 | adjust_markers_for_insert or adjust_markers_for_replace. */ |
1f90a790 RS |
1058 | |
1059 | static void | |
1060 | combine_bytes (pos, pos_byte, nbytes) | |
1061 | int pos, pos_byte, nbytes; | |
1062 | { | |
1f90a790 RS |
1063 | adjust_overlays_for_delete (pos, nbytes); |
1064 | ||
e3a87305 KH |
1065 | ADJUST_CHAR_POS (BUF_PT (current_buffer), BUF_PT_BYTE (current_buffer)); |
1066 | ADJUST_CHAR_POS (GPT, GPT_BYTE); | |
1067 | ADJUST_CHAR_POS (Z, Z_BYTE); | |
1068 | ADJUST_CHAR_POS (ZV, ZV_BYTE); | |
1f90a790 RS |
1069 | |
1070 | if (BUF_INTERVALS (current_buffer) != 0) | |
1071 | /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES. */ | |
1072 | offset_intervals (current_buffer, pos, - nbytes); | |
1073 | } | |
9f3ede3c | 1074 | |
039af53a KH |
1075 | void |
1076 | byte_combining_error () | |
1077 | { | |
ea12aa2b | 1078 | error ("Byte combining across boundary of accessible buffer text inhibitted"); |
039af53a KH |
1079 | } |
1080 | ||
9f3ede3c KH |
1081 | /* If we are going to combine bytes at POS which is at a narrowed |
1082 | region boundary, signal an error. */ | |
1083 | #define CHECK_BYTE_COMBINING_FOR_INSERT(pos) \ | |
1084 | do { \ | |
1085 | if (combined_before_bytes && pos == BEGV \ | |
1086 | || combined_after_bytes && pos == ZV) \ | |
039af53a | 1087 | byte_combining_error (); \ |
9f3ede3c KH |
1088 | } while (0) |
1089 | ||
1f90a790 | 1090 | \f |
2b083808 RS |
1091 | /* Insert a sequence of NCHARS chars which occupy NBYTES bytes |
1092 | starting at STRING. INHERIT, PREPARE and BEFORE_MARKERS | |
1093 | are the same as in insert_1. */ | |
1094 | ||
1095 | void | |
1096 | insert_1_both (string, nchars, nbytes, inherit, prepare, before_markers) | |
1097 | register unsigned char *string; | |
1098 | register int nchars, nbytes; | |
1099 | int inherit, prepare, before_markers; | |
1100 | { | |
0aa8c4b2 | 1101 | register Lisp_Object temp; |
432f78d2 | 1102 | int combined_before_bytes, combined_after_bytes; |
2b083808 | 1103 | |
57404188 KH |
1104 | if (NILP (current_buffer->enable_multibyte_characters)) |
1105 | nchars = nbytes; | |
1106 | ||
35d63725 RS |
1107 | if (prepare) |
1108 | /* Do this before moving and increasing the gap, | |
1109 | because the before-change hooks might move the gap | |
1110 | or make it smaller. */ | |
1111 | prepare_to_modify_buffer (PT, PT, NULL); | |
1112 | ||
2b083808 RS |
1113 | if (PT != GPT) |
1114 | move_gap_both (PT, PT_BYTE); | |
1115 | if (GAP_SIZE < nbytes) | |
1116 | make_gap (nbytes - GAP_SIZE); | |
1117 | ||
1f90a790 RS |
1118 | combined_before_bytes |
1119 | = count_combining_before (string, nbytes, PT, PT_BYTE); | |
1120 | combined_after_bytes | |
1121 | = count_combining_after (string, nbytes, PT, PT_BYTE); | |
9f3ede3c | 1122 | CHECK_BYTE_COMBINING_FOR_INSERT (PT); |
432f78d2 RS |
1123 | |
1124 | /* Record deletion of the surrounding text that combines with | |
1125 | the insertion. This, together with recording the insertion, | |
1126 | will add up to the right stuff in the undo list. | |
1127 | ||
1128 | But there is no need to actually delete the combining bytes | |
1129 | from the buffer and reinsert them. */ | |
1130 | ||
1131 | if (combined_after_bytes) | |
7cc3983f | 1132 | { |
0aa8c4b2 RS |
1133 | Lisp_Object deletion; |
1134 | deletion = Qnil; | |
1135 | ||
1136 | if (! EQ (current_buffer->undo_list, Qt)) | |
1137 | deletion = make_buffer_string_both (PT, PT_BYTE, | |
1138 | PT + combined_after_bytes, | |
1139 | PT_BYTE + combined_after_bytes, 1); | |
628cea90 | 1140 | |
7cc3983f RS |
1141 | adjust_markers_for_record_delete (PT, PT_BYTE, |
1142 | PT + combined_after_bytes, | |
1143 | PT_BYTE + combined_after_bytes); | |
0aa8c4b2 RS |
1144 | if (! EQ (current_buffer->undo_list, Qt)) |
1145 | record_delete (PT, deletion); | |
7cc3983f | 1146 | } |
432f78d2 RS |
1147 | |
1148 | if (combined_before_bytes) | |
7cc3983f | 1149 | { |
0aa8c4b2 RS |
1150 | Lisp_Object deletion; |
1151 | deletion = Qnil; | |
1152 | ||
1153 | if (! EQ (current_buffer->undo_list, Qt)) | |
1154 | deletion = make_buffer_string_both (PT - 1, CHAR_TO_BYTE (PT - 1), | |
1155 | PT, PT_BYTE, 1); | |
7cc3983f RS |
1156 | adjust_markers_for_record_delete (PT - 1, CHAR_TO_BYTE (PT - 1), |
1157 | PT, PT_BYTE); | |
0aa8c4b2 RS |
1158 | if (! EQ (current_buffer->undo_list, Qt)) |
1159 | record_delete (PT - 1, deletion); | |
7cc3983f | 1160 | } |
432f78d2 | 1161 | |
e0c0ed58 RS |
1162 | record_insert (PT - !!combined_before_bytes, |
1163 | nchars - combined_before_bytes + !!combined_before_bytes); | |
2b083808 RS |
1164 | MODIFF++; |
1165 | ||
1166 | bcopy (string, GPT_ADDR, nbytes); | |
1167 | ||
2b083808 | 1168 | GAP_SIZE -= nbytes; |
ce97a2d7 RS |
1169 | /* When we have combining at the end of the insertion, |
1170 | this is the character position before the combined character. */ | |
1f90a790 RS |
1171 | GPT += nchars; |
1172 | ZV += nchars; | |
1173 | Z += nchars; | |
2b083808 RS |
1174 | GPT_BYTE += nbytes; |
1175 | ZV_BYTE += nbytes; | |
1176 | Z_BYTE += nbytes; | |
1177 | if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */ | |
1f90a790 RS |
1178 | |
1179 | if (combined_after_bytes) | |
1180 | move_gap_both (GPT + combined_after_bytes, | |
1181 | GPT_BYTE + combined_after_bytes); | |
1182 | ||
1183 | if (GPT_BYTE < GPT) | |
1184 | abort (); | |
1185 | ||
1186 | adjust_overlays_for_insert (PT, nchars); | |
432f78d2 | 1187 | adjust_markers_for_insert (PT, PT_BYTE, |
1f90a790 | 1188 | PT + nchars, PT_BYTE + nbytes, |
432f78d2 | 1189 | combined_before_bytes, combined_after_bytes, |
2b083808 | 1190 | before_markers); |
ce97a2d7 | 1191 | |
ce97a2d7 | 1192 | #ifdef USE_TEXT_PROPERTIES |
1f90a790 RS |
1193 | if (BUF_INTERVALS (current_buffer) != 0) |
1194 | /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES. */ | |
1195 | offset_intervals (current_buffer, PT, nchars); | |
1196 | ||
ce97a2d7 | 1197 | if (!inherit && BUF_INTERVALS (current_buffer) != 0) |
1f90a790 | 1198 | Fset_text_properties (make_number (PT), make_number (PT + nchars), |
ce97a2d7 RS |
1199 | Qnil, Qnil); |
1200 | #endif | |
1201 | ||
1f90a790 RS |
1202 | { |
1203 | int pos = PT, pos_byte = PT_BYTE; | |
432f78d2 | 1204 | |
1f90a790 RS |
1205 | adjust_point (nchars + combined_after_bytes, |
1206 | nbytes + combined_after_bytes); | |
2b083808 | 1207 | |
1f90a790 RS |
1208 | if (combined_after_bytes) |
1209 | combine_bytes (pos + nchars, pos_byte + nbytes, combined_after_bytes); | |
1210 | ||
1211 | if (combined_before_bytes) | |
1212 | combine_bytes (pos, pos_byte, combined_before_bytes); | |
1213 | } | |
828f1ed3 KH |
1214 | |
1215 | CHECK_MARKERS (); | |
2b083808 | 1216 | } |
3be11131 | 1217 | \f |
679194a6 | 1218 | /* Insert the part of the text of STRING, a Lisp object assumed to be |
2b083808 RS |
1219 | of type string, consisting of the LENGTH characters (LENGTH_BYTE bytes) |
1220 | starting at position POS / POS_BYTE. If the text of STRING has properties, | |
1221 | copy them into the buffer. | |
679194a6 JA |
1222 | |
1223 | It does not work to use `insert' for this, because a GC could happen | |
7e1ea612 JB |
1224 | before we bcopy the stuff into the buffer, and relocate the string |
1225 | without insert noticing. */ | |
679194a6 | 1226 | |
c660b094 | 1227 | void |
2b083808 | 1228 | insert_from_string (string, pos, pos_byte, length, length_byte, inherit) |
b45433b3 | 1229 | Lisp_Object string; |
2b083808 | 1230 | register int pos, pos_byte, length, length_byte; |
9391e591 | 1231 | int inherit; |
395ec62e | 1232 | { |
62b82678 RS |
1233 | int opoint = PT; |
1234 | insert_from_string_1 (string, pos, pos_byte, length, length_byte, | |
1235 | inherit, 0); | |
1236 | signal_after_change (opoint, 0, PT - opoint); | |
395ec62e KH |
1237 | } |
1238 | ||
2b083808 RS |
1239 | /* Like `insert_from_string' except that all markers pointing |
1240 | at the place where the insertion happens are adjusted to point after it. */ | |
3be11131 RS |
1241 | |
1242 | void | |
2b083808 RS |
1243 | insert_from_string_before_markers (string, pos, pos_byte, |
1244 | length, length_byte, inherit) | |
395ec62e | 1245 | Lisp_Object string; |
2b083808 | 1246 | register int pos, pos_byte, length, length_byte; |
395ec62e | 1247 | int inherit; |
3be11131 | 1248 | { |
62b82678 RS |
1249 | int opoint = PT; |
1250 | insert_from_string_1 (string, pos, pos_byte, length, length_byte, | |
1251 | inherit, 1); | |
1252 | signal_after_change (opoint, 0, PT - opoint); | |
3be11131 RS |
1253 | } |
1254 | ||
1255 | /* Subroutine of the insertion functions above. */ | |
1256 | ||
1257 | static void | |
2b083808 RS |
1258 | insert_from_string_1 (string, pos, pos_byte, nchars, nbytes, |
1259 | inherit, before_markers) | |
3be11131 | 1260 | Lisp_Object string; |
2b083808 | 1261 | register int pos, pos_byte, nchars, nbytes; |
3be11131 | 1262 | int inherit, before_markers; |
b45433b3 JB |
1263 | { |
1264 | register Lisp_Object temp; | |
1265 | struct gcpro gcpro1; | |
2b083808 | 1266 | int outgoing_nbytes = nbytes; |
432f78d2 RS |
1267 | int combined_before_bytes, combined_after_bytes; |
1268 | int adjusted_nchars; | |
ce97a2d7 | 1269 | INTERVAL intervals; |
2b083808 RS |
1270 | |
1271 | /* Make OUTGOING_NBYTES describe the text | |
1272 | as it will be inserted in this buffer. */ | |
1273 | ||
1274 | if (NILP (current_buffer->enable_multibyte_characters)) | |
1275 | outgoing_nbytes = nchars; | |
2a1d8be0 | 1276 | else if (! STRING_MULTIBYTE (string)) |
2b083808 RS |
1277 | outgoing_nbytes |
1278 | = count_size_as_multibyte (&XSTRING (string)->data[pos_byte], | |
1279 | nbytes); | |
b45433b3 | 1280 | |
b45433b3 | 1281 | GCPRO1 (string); |
35d63725 RS |
1282 | /* Do this before moving and increasing the gap, |
1283 | because the before-change hooks might move the gap | |
1284 | or make it smaller. */ | |
d206af14 | 1285 | prepare_to_modify_buffer (PT, PT, NULL); |
b45433b3 | 1286 | |
2bcaed71 | 1287 | if (PT != GPT) |
3be11131 | 1288 | move_gap_both (PT, PT_BYTE); |
534b9840 | 1289 | if (GAP_SIZE < outgoing_nbytes) |
2b083808 | 1290 | make_gap (outgoing_nbytes - GAP_SIZE); |
b45433b3 JB |
1291 | UNGCPRO; |
1292 | ||
2b083808 RS |
1293 | /* Copy the string text into the buffer, perhaps converting |
1294 | between single-byte and multibyte. */ | |
1295 | copy_text (XSTRING (string)->data + pos_byte, GPT_ADDR, nbytes, | |
2a1d8be0 | 1296 | STRING_MULTIBYTE (string), |
2b083808 | 1297 | ! NILP (current_buffer->enable_multibyte_characters)); |
b45433b3 | 1298 | |
432f78d2 RS |
1299 | /* We have copied text into the gap, but we have not altered |
1300 | PT or PT_BYTE yet. So we can pass PT and PT_BYTE | |
1301 | to these functions and get the same results as we would | |
1302 | have got earlier on. Meanwhile, PT_ADDR does point to | |
1303 | the text that has been stored by copy_text. */ | |
1304 | ||
1305 | combined_before_bytes | |
1f90a790 | 1306 | = count_combining_before (GPT_ADDR, outgoing_nbytes, PT, PT_BYTE); |
432f78d2 | 1307 | combined_after_bytes |
1f90a790 | 1308 | = count_combining_after (GPT_ADDR, outgoing_nbytes, PT, PT_BYTE); |
9f3ede3c KH |
1309 | { |
1310 | unsigned char save = *(GPT_ADDR); | |
039af53a | 1311 | *(GPT_ADDR) = 0; |
9f3ede3c KH |
1312 | CHECK_BYTE_COMBINING_FOR_INSERT (PT); |
1313 | *(GPT_ADDR) = save; | |
1314 | } | |
432f78d2 RS |
1315 | |
1316 | /* Record deletion of the surrounding text that combines with | |
1317 | the insertion. This, together with recording the insertion, | |
1318 | will add up to the right stuff in the undo list. | |
1319 | ||
1320 | But there is no need to actually delete the combining bytes | |
1321 | from the buffer and reinsert them. */ | |
1322 | ||
1323 | if (combined_after_bytes) | |
7cc3983f | 1324 | { |
0aa8c4b2 RS |
1325 | Lisp_Object deletion; |
1326 | deletion = Qnil; | |
1327 | ||
1328 | if (! EQ (current_buffer->undo_list, Qt)) | |
1329 | deletion = make_buffer_string_both (PT, PT_BYTE, | |
1330 | PT + combined_after_bytes, | |
1331 | PT_BYTE + combined_after_bytes, 1); | |
628cea90 | 1332 | |
7cc3983f RS |
1333 | adjust_markers_for_record_delete (PT, PT_BYTE, |
1334 | PT + combined_after_bytes, | |
1335 | PT_BYTE + combined_after_bytes); | |
0aa8c4b2 RS |
1336 | if (! EQ (current_buffer->undo_list, Qt)) |
1337 | record_delete (PT, deletion); | |
7cc3983f | 1338 | } |
432f78d2 RS |
1339 | |
1340 | if (combined_before_bytes) | |
7cc3983f | 1341 | { |
0aa8c4b2 RS |
1342 | Lisp_Object deletion; |
1343 | deletion = Qnil; | |
1344 | ||
1345 | if (! EQ (current_buffer->undo_list, Qt)) | |
1346 | deletion = make_buffer_string_both (PT - 1, CHAR_TO_BYTE (PT - 1), | |
1347 | PT, PT_BYTE, 1); | |
7cc3983f RS |
1348 | adjust_markers_for_record_delete (PT - 1, CHAR_TO_BYTE (PT - 1), |
1349 | PT, PT_BYTE); | |
0aa8c4b2 RS |
1350 | if (! EQ (current_buffer->undo_list, Qt)) |
1351 | record_delete (PT - 1, deletion); | |
7cc3983f | 1352 | } |
432f78d2 | 1353 | |
e0c0ed58 RS |
1354 | record_insert (PT - !!combined_before_bytes, |
1355 | nchars - combined_before_bytes + !!combined_before_bytes); | |
432f78d2 RS |
1356 | MODIFF++; |
1357 | ||
7792090e | 1358 | GAP_SIZE -= outgoing_nbytes; |
1f90a790 RS |
1359 | GPT += nchars; |
1360 | ZV += nchars; | |
1361 | Z += nchars; | |
2b083808 RS |
1362 | GPT_BYTE += outgoing_nbytes; |
1363 | ZV_BYTE += outgoing_nbytes; | |
1364 | Z_BYTE += outgoing_nbytes; | |
469ff680 | 1365 | if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */ |
3be11131 | 1366 | |
432f78d2 | 1367 | if (combined_after_bytes) |
1f90a790 RS |
1368 | move_gap_both (GPT + combined_after_bytes, |
1369 | GPT_BYTE + combined_after_bytes); | |
432f78d2 | 1370 | |
3be11131 RS |
1371 | if (GPT_BYTE < GPT) |
1372 | abort (); | |
679194a6 | 1373 | |
1f90a790 RS |
1374 | adjust_overlays_for_insert (PT, nchars); |
1375 | adjust_markers_for_insert (PT, PT_BYTE, PT + nchars, | |
1376 | PT_BYTE + outgoing_nbytes, | |
1377 | combined_before_bytes, combined_after_bytes, | |
1378 | before_markers); | |
ce97a2d7 | 1379 | |
1f90a790 RS |
1380 | /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */ |
1381 | offset_intervals (current_buffer, PT, nchars); | |
1382 | ||
1383 | intervals = XSTRING (string)->intervals; | |
ce97a2d7 RS |
1384 | /* Get the intervals for the part of the string we are inserting-- |
1385 | not including the combined-before bytes. */ | |
fc932ac6 | 1386 | if (nbytes < STRING_BYTES (XSTRING (string))) |
1f90a790 | 1387 | intervals = copy_intervals (intervals, pos, nchars); |
ce97a2d7 RS |
1388 | |
1389 | /* Insert those intervals. */ | |
1f90a790 | 1390 | graft_intervals_into_buffer (intervals, PT, nchars, |
9391e591 | 1391 | current_buffer, inherit); |
ce97a2d7 | 1392 | |
1f90a790 RS |
1393 | { |
1394 | int pos = PT, pos_byte = PT_BYTE; | |
1395 | ||
1396 | adjust_point (nchars + combined_after_bytes, | |
1397 | outgoing_nbytes + combined_after_bytes); | |
1398 | ||
1399 | if (combined_after_bytes) | |
1400 | combine_bytes (pos + nchars, pos_byte + outgoing_nbytes, | |
1401 | combined_after_bytes); | |
1402 | ||
1403 | if (combined_before_bytes) | |
1404 | combine_bytes (pos, pos_byte, combined_before_bytes); | |
1405 | } | |
b45433b3 | 1406 | } |
3be11131 RS |
1407 | \f |
1408 | /* Insert text from BUF, NCHARS characters starting at CHARPOS, into the | |
ef29f213 KH |
1409 | current buffer. If the text in BUF has properties, they are absorbed |
1410 | into the current buffer. | |
1411 | ||
1412 | It does not work to use `insert' for this, because a malloc could happen | |
1413 | and relocate BUF's text before the bcopy happens. */ | |
1414 | ||
1415 | void | |
3be11131 | 1416 | insert_from_buffer (buf, charpos, nchars, inherit) |
ef29f213 | 1417 | struct buffer *buf; |
3be11131 | 1418 | int charpos, nchars; |
ef29f213 KH |
1419 | int inherit; |
1420 | { | |
62b82678 | 1421 | int opoint = PT; |
3be11131 | 1422 | |
62b82678 RS |
1423 | insert_from_buffer_1 (buf, charpos, nchars, inherit); |
1424 | signal_after_change (opoint, 0, PT - opoint); | |
ef29f213 KH |
1425 | } |
1426 | ||
1427 | static void | |
3be11131 | 1428 | insert_from_buffer_1 (buf, from, nchars, inherit) |
ef29f213 | 1429 | struct buffer *buf; |
3be11131 | 1430 | int from, nchars; |
ef29f213 KH |
1431 | int inherit; |
1432 | { | |
0aa8c4b2 | 1433 | register Lisp_Object temp; |
4468c4f1 | 1434 | int chunk, chunk_expanded; |
3be11131 RS |
1435 | int from_byte = buf_charpos_to_bytepos (buf, from); |
1436 | int to_byte = buf_charpos_to_bytepos (buf, from + nchars); | |
2b083808 RS |
1437 | int incoming_nbytes = to_byte - from_byte; |
1438 | int outgoing_nbytes = incoming_nbytes; | |
432f78d2 RS |
1439 | int combined_before_bytes, combined_after_bytes; |
1440 | int adjusted_nchars; | |
ce97a2d7 | 1441 | INTERVAL intervals; |
2b083808 RS |
1442 | |
1443 | /* Make OUTGOING_NBYTES describe the text | |
1444 | as it will be inserted in this buffer. */ | |
1445 | ||
1446 | if (NILP (current_buffer->enable_multibyte_characters)) | |
1447 | outgoing_nbytes = nchars; | |
1448 | else if (NILP (buf->enable_multibyte_characters)) | |
4468c4f1 KH |
1449 | { |
1450 | int outgoing_before_gap = 0; | |
1451 | int outgoing_after_gap = 0; | |
ef29f213 | 1452 | |
4468c4f1 KH |
1453 | if (from < BUF_GPT (buf)) |
1454 | { | |
1455 | chunk = BUF_GPT_BYTE (buf) - from_byte; | |
1456 | if (chunk > incoming_nbytes) | |
1457 | chunk = incoming_nbytes; | |
1458 | outgoing_before_gap | |
1459 | = count_size_as_multibyte (BUF_BYTE_ADDRESS (buf, from_byte), | |
1460 | chunk); | |
1461 | } | |
1462 | else | |
1463 | chunk = 0; | |
1464 | ||
1465 | if (chunk < incoming_nbytes) | |
1466 | outgoing_after_gap | |
1467 | = count_size_as_multibyte (BUF_BYTE_ADDRESS (buf, | |
1468 | from_byte + chunk), | |
1469 | incoming_nbytes - chunk); | |
1470 | ||
1471 | outgoing_nbytes = outgoing_before_gap + outgoing_after_gap; | |
1472 | } | |
1473 | ||
ef29f213 | 1474 | /* Make sure point-max won't overflow after this insertion. */ |
2b083808 RS |
1475 | XSETINT (temp, outgoing_nbytes + Z); |
1476 | if (outgoing_nbytes + Z != XINT (temp)) | |
3be11131 | 1477 | error ("Maximum buffer size exceeded"); |
ef29f213 | 1478 | |
35d63725 RS |
1479 | /* Do this before moving and increasing the gap, |
1480 | because the before-change hooks might move the gap | |
1481 | or make it smaller. */ | |
d206af14 | 1482 | prepare_to_modify_buffer (PT, PT, NULL); |
ef29f213 KH |
1483 | |
1484 | if (PT != GPT) | |
3be11131 | 1485 | move_gap_both (PT, PT_BYTE); |
2b083808 RS |
1486 | if (GAP_SIZE < outgoing_nbytes) |
1487 | make_gap (outgoing_nbytes - GAP_SIZE); | |
ef29f213 | 1488 | |
3be11131 | 1489 | if (from < BUF_GPT (buf)) |
ef29f213 | 1490 | { |
3be11131 | 1491 | chunk = BUF_GPT_BYTE (buf) - from_byte; |
2b083808 RS |
1492 | if (chunk > incoming_nbytes) |
1493 | chunk = incoming_nbytes; | |
4468c4f1 KH |
1494 | /* Record number of output bytes, so we know where |
1495 | to put the output from the second copy_text. */ | |
1496 | chunk_expanded | |
1497 | = copy_text (BUF_BYTE_ADDRESS (buf, from_byte), | |
1498 | GPT_ADDR, chunk, | |
1499 | ! NILP (buf->enable_multibyte_characters), | |
1500 | ! NILP (current_buffer->enable_multibyte_characters)); | |
ef29f213 KH |
1501 | } |
1502 | else | |
4468c4f1 KH |
1503 | chunk_expanded = chunk = 0; |
1504 | ||
2b083808 RS |
1505 | if (chunk < incoming_nbytes) |
1506 | copy_text (BUF_BYTE_ADDRESS (buf, from_byte + chunk), | |
4468c4f1 | 1507 | GPT_ADDR + chunk_expanded, incoming_nbytes - chunk, |
2b083808 RS |
1508 | ! NILP (buf->enable_multibyte_characters), |
1509 | ! NILP (current_buffer->enable_multibyte_characters)); | |
ef29f213 | 1510 | |
432f78d2 RS |
1511 | /* We have copied text into the gap, but we have not altered |
1512 | PT or PT_BYTE yet. So we can pass PT and PT_BYTE | |
1513 | to these functions and get the same results as we would | |
1f90a790 | 1514 | have got earlier on. Meanwhile, GPT_ADDR does point to |
432f78d2 RS |
1515 | the text that has been stored by copy_text. */ |
1516 | combined_before_bytes | |
1f90a790 | 1517 | = count_combining_before (GPT_ADDR, outgoing_nbytes, PT, PT_BYTE); |
432f78d2 | 1518 | combined_after_bytes |
9f3ede3c KH |
1519 | = count_combining_after (GPT_ADDR, outgoing_nbytes, PT, PT_BYTE); |
1520 | { | |
1521 | unsigned char save = *(GPT_ADDR); | |
039af53a | 1522 | *(GPT_ADDR) = 0; |
9f3ede3c KH |
1523 | CHECK_BYTE_COMBINING_FOR_INSERT (PT); |
1524 | *(GPT_ADDR) = save; | |
1525 | } | |
432f78d2 | 1526 | |
432f78d2 RS |
1527 | /* Record deletion of the surrounding text that combines with |
1528 | the insertion. This, together with recording the insertion, | |
1529 | will add up to the right stuff in the undo list. | |
1530 | ||
1531 | But there is no need to actually delete the combining bytes | |
1532 | from the buffer and reinsert them. */ | |
1533 | ||
1534 | if (combined_after_bytes) | |
7cc3983f | 1535 | { |
0aa8c4b2 RS |
1536 | Lisp_Object deletion; |
1537 | deletion = Qnil; | |
1538 | ||
1539 | if (! EQ (current_buffer->undo_list, Qt)) | |
1540 | deletion = make_buffer_string_both (PT, PT_BYTE, | |
1541 | PT + combined_after_bytes, | |
1542 | PT_BYTE + combined_after_bytes, 1); | |
628cea90 | 1543 | |
7cc3983f RS |
1544 | adjust_markers_for_record_delete (PT, PT_BYTE, |
1545 | PT + combined_after_bytes, | |
1546 | PT_BYTE + combined_after_bytes); | |
0aa8c4b2 RS |
1547 | if (! EQ (current_buffer->undo_list, Qt)) |
1548 | record_delete (PT, deletion); | |
7cc3983f | 1549 | } |
432f78d2 RS |
1550 | |
1551 | if (combined_before_bytes) | |
7cc3983f | 1552 | { |
0aa8c4b2 RS |
1553 | Lisp_Object deletion; |
1554 | deletion = Qnil; | |
1555 | ||
1556 | if (! EQ (current_buffer->undo_list, Qt)) | |
1557 | deletion = make_buffer_string_both (PT - 1, CHAR_TO_BYTE (PT - 1), | |
1558 | PT, PT_BYTE, 1); | |
7cc3983f RS |
1559 | adjust_markers_for_record_delete (PT - 1, CHAR_TO_BYTE (PT - 1), |
1560 | PT, PT_BYTE); | |
0aa8c4b2 RS |
1561 | if (! EQ (current_buffer->undo_list, Qt)) |
1562 | record_delete (PT - 1, deletion); | |
7cc3983f | 1563 | } |
432f78d2 | 1564 | |
e0c0ed58 RS |
1565 | record_insert (PT - !!combined_before_bytes, |
1566 | nchars - combined_before_bytes + !!combined_before_bytes); | |
432f78d2 RS |
1567 | MODIFF++; |
1568 | ||
2b083808 | 1569 | GAP_SIZE -= outgoing_nbytes; |
1f90a790 RS |
1570 | GPT += nchars; |
1571 | ZV += nchars; | |
1572 | Z += nchars; | |
2b083808 RS |
1573 | GPT_BYTE += outgoing_nbytes; |
1574 | ZV_BYTE += outgoing_nbytes; | |
1575 | Z_BYTE += outgoing_nbytes; | |
469ff680 | 1576 | if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */ |
1f90a790 RS |
1577 | |
1578 | if (combined_after_bytes) | |
1579 | move_gap_both (GPT + combined_after_bytes, | |
1580 | GPT_BYTE + combined_after_bytes); | |
1581 | ||
1582 | if (GPT_BYTE < GPT) | |
1583 | abort (); | |
1584 | ||
1585 | adjust_overlays_for_insert (PT, nchars); | |
1586 | adjust_markers_for_insert (PT, PT_BYTE, PT + nchars, | |
432f78d2 RS |
1587 | PT_BYTE + outgoing_nbytes, |
1588 | combined_before_bytes, combined_after_bytes, 0); | |
ce97a2d7 | 1589 | |
1f90a790 RS |
1590 | #ifdef USE_TEXT_PROPERTIES |
1591 | if (BUF_INTERVALS (current_buffer) != 0) | |
1592 | offset_intervals (current_buffer, PT, nchars); | |
1593 | #endif | |
ce97a2d7 RS |
1594 | |
1595 | /* Get the intervals for the part of the string we are inserting-- | |
1596 | not including the combined-before bytes. */ | |
1597 | intervals = BUF_INTERVALS (buf); | |
1f90a790 RS |
1598 | if (outgoing_nbytes < BUF_Z_BYTE (buf) - BUF_BEG_BYTE (buf)) |
1599 | intervals = copy_intervals (intervals, from, nchars); | |
ce97a2d7 RS |
1600 | |
1601 | /* Insert those intervals. */ | |
1f90a790 | 1602 | graft_intervals_into_buffer (intervals, PT, nchars, current_buffer, inherit); |
ce97a2d7 | 1603 | |
1f90a790 RS |
1604 | { |
1605 | int pos = PT, pos_byte = PT_BYTE; | |
ce97a2d7 | 1606 | |
1f90a790 RS |
1607 | adjust_point (nchars + combined_after_bytes, |
1608 | outgoing_nbytes + combined_after_bytes); | |
432f78d2 | 1609 | |
1f90a790 RS |
1610 | if (combined_after_bytes) |
1611 | combine_bytes (pos + nchars, pos_byte + outgoing_nbytes, | |
1612 | combined_after_bytes); | |
3be11131 | 1613 | |
1f90a790 RS |
1614 | if (combined_before_bytes) |
1615 | combine_bytes (pos, pos_byte, combined_before_bytes); | |
1616 | } | |
b45433b3 JB |
1617 | } |
1618 | \f | |
2d9eea44 | 1619 | /* This function should be called after moving gap to FROM and before |
59a52d50 KH |
1620 | altering text between FROM and TO. This adjusts various position |
1621 | keepers and markers as if the text is deleted. Don't forget to | |
1622 | call adjust_after_replace after you actually alter the text. */ | |
2d9eea44 | 1623 | |
1e9c7b7d KH |
1624 | void |
1625 | adjust_before_replace (from, from_byte, to, to_byte) | |
1626 | int from, from_byte, to, to_byte; | |
1627 | { | |
628cea90 | 1628 | Lisp_Object deletion; |
0aa8c4b2 RS |
1629 | |
1630 | if (! EQ (current_buffer->undo_list, Qt)) | |
1631 | deletion = make_buffer_string_both (from, from_byte, to, to_byte, 1); | |
628cea90 | 1632 | |
60ea6052 RS |
1633 | CHECK_MARKERS (); |
1634 | ||
1e9c7b7d | 1635 | adjust_markers_for_delete (from, from_byte, to, to_byte); |
0aa8c4b2 RS |
1636 | |
1637 | if (! EQ (current_buffer->undo_list, Qt)) | |
1638 | record_delete (from, deletion); | |
1639 | ||
61415a25 | 1640 | adjust_overlays_for_delete (from, to - from); |
1e9c7b7d KH |
1641 | } |
1642 | ||
652838b5 KH |
1643 | /* Record undo information and adjust markers and position keepers for |
1644 | a replacement of a text PREV_TEXT at FROM to a new text of LEN | |
1645 | chars (LEN_BYTE bytes) which resides in the gap just after | |
1646 | GPT_ADDR. | |
1647 | ||
1648 | PREV_TEXT nil means the new text was just inserted. */ | |
2d9eea44 | 1649 | |
1e9c7b7d | 1650 | void |
652838b5 KH |
1651 | adjust_after_replace (from, from_byte, prev_text, len, len_byte) |
1652 | int from, from_byte, len, len_byte; | |
1653 | Lisp_Object prev_text; | |
1e9c7b7d | 1654 | { |
61415a25 KH |
1655 | int combined_before_bytes |
1656 | = count_combining_before (GPT_ADDR, len_byte, from, from_byte); | |
1657 | int combined_after_bytes | |
1658 | = count_combining_after (GPT_ADDR, len_byte, from, from_byte); | |
039af53a KH |
1659 | /* This flag tells if we combine some bytes with a character before |
1660 | FROM. This happens even if combined_before_bytes is zero. */ | |
1661 | int combine_before = (combined_before_bytes | |
1662 | || (len == 0 && combined_after_bytes)); | |
1663 | ||
652838b5 | 1664 | int nchars_del = 0, nbytes_del = 0; |
61415a25 | 1665 | |
828f1ed3 KH |
1666 | if (STRINGP (prev_text)) |
1667 | { | |
1668 | nchars_del = XSTRING (prev_text)->size; | |
1669 | nbytes_del = STRING_BYTES (XSTRING (prev_text)); | |
1670 | } | |
1671 | ||
039af53a | 1672 | if (combine_before && from == BEGV |
9f3ede3c KH |
1673 | || combined_after_bytes && from == ZV) |
1674 | { | |
1675 | /* We can't combine bytes nor signal an error here. So, let's | |
1676 | pretend that the new text is just a single space. */ | |
1677 | len = len_byte = 1; | |
1678 | combined_before_bytes = combined_after_bytes = 0; | |
1679 | *(GPT_ADDR) = ' '; | |
1680 | } | |
1681 | ||
61415a25 | 1682 | if (combined_after_bytes) |
7cc3983f | 1683 | { |
0aa8c4b2 RS |
1684 | Lisp_Object deletion; |
1685 | deletion = Qnil; | |
1686 | ||
1687 | if (! EQ (current_buffer->undo_list, Qt)) | |
1688 | deletion = make_buffer_string_both (from, from_byte, | |
1689 | from + combined_after_bytes, | |
1690 | from_byte + combined_after_bytes, | |
1691 | 1); | |
628cea90 | 1692 | |
7cc3983f RS |
1693 | adjust_markers_for_record_delete (from, from_byte, |
1694 | from + combined_after_bytes, | |
1695 | from_byte + combined_after_bytes); | |
0aa8c4b2 RS |
1696 | |
1697 | if (! EQ (current_buffer->undo_list, Qt)) | |
828f1ed3 | 1698 | record_delete (from + nchars_del, deletion); |
7cc3983f | 1699 | } |
61415a25 | 1700 | |
828f1ed3 KH |
1701 | if (combined_before_bytes |
1702 | || len_byte == 0 && combined_after_bytes > 0) | |
7cc3983f | 1703 | { |
0aa8c4b2 RS |
1704 | Lisp_Object deletion; |
1705 | deletion = Qnil; | |
1706 | ||
1707 | if (! EQ (current_buffer->undo_list, Qt)) | |
1708 | deletion = make_buffer_string_both (from - 1, CHAR_TO_BYTE (from - 1), | |
1709 | from, from_byte, 1); | |
7cc3983f RS |
1710 | adjust_markers_for_record_delete (from - 1, CHAR_TO_BYTE (from - 1), |
1711 | from, from_byte); | |
0aa8c4b2 RS |
1712 | if (! EQ (current_buffer->undo_list, Qt)) |
1713 | record_delete (from - 1, deletion); | |
7cc3983f | 1714 | } |
61415a25 KH |
1715 | |
1716 | /* Update various buffer positions for the new text. */ | |
1717 | GAP_SIZE -= len_byte; | |
1718 | ZV += len; Z+= len; | |
1719 | ZV_BYTE += len_byte; Z_BYTE += len_byte; | |
1720 | GPT += len; GPT_BYTE += len_byte; | |
1721 | if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */ | |
1722 | ||
828f1ed3 | 1723 | /* The gap should be at character boundary. */ |
61415a25 KH |
1724 | if (combined_after_bytes) |
1725 | move_gap_both (GPT + combined_after_bytes, | |
1726 | GPT_BYTE + combined_after_bytes); | |
1727 | ||
652838b5 KH |
1728 | adjust_markers_for_replace (from, from_byte, nchars_del, nbytes_del, |
1729 | len, len_byte, | |
1730 | combined_before_bytes, combined_after_bytes); | |
828f1ed3 KH |
1731 | if (! EQ (current_buffer->undo_list, Qt)) |
1732 | { | |
828f1ed3 KH |
1733 | if (nchars_del > 0) |
1734 | record_delete (from - combine_before, prev_text); | |
1735 | if (combine_before) | |
1736 | record_insert (from - 1, len - combined_before_bytes + 1); | |
1737 | else | |
1738 | record_insert (from, len); | |
1739 | } | |
652838b5 KH |
1740 | |
1741 | if (len > nchars_del) | |
1742 | adjust_overlays_for_insert (from, len - nchars_del); | |
1743 | else if (len < nchars_del) | |
1744 | adjust_overlays_for_delete (from, nchars_del - len); | |
61415a25 KH |
1745 | #ifdef USE_TEXT_PROPERTIES |
1746 | if (BUF_INTERVALS (current_buffer) != 0) | |
4a7cf15f KH |
1747 | { |
1748 | offset_intervals (current_buffer, from, len - nchars_del); | |
4a7cf15f | 1749 | } |
61415a25 KH |
1750 | #endif |
1751 | ||
1752 | { | |
1753 | int pos = PT, pos_byte = PT_BYTE; | |
1754 | ||
1755 | if (from < PT) | |
8bedbe9d | 1756 | adjust_point (len - nchars_del, len_byte - nbytes_del); |
61415a25 KH |
1757 | |
1758 | if (combined_after_bytes) | |
f6ecdae5 KH |
1759 | { |
1760 | if (combined_before_bytes == len_byte) | |
1761 | /* This is the case that all new bytes are combined. */ | |
1762 | combined_before_bytes += combined_after_bytes; | |
1763 | else | |
1764 | combine_bytes (from + len, from_byte + len_byte, | |
1765 | combined_after_bytes); | |
1766 | } | |
61415a25 KH |
1767 | if (combined_before_bytes) |
1768 | combine_bytes (from, from_byte, combined_before_bytes); | |
1769 | } | |
1770 | ||
9f3ede3c | 1771 | /* As byte combining will decrease Z, we must check this again. */ |
a50df55b GM |
1772 | if (Z - GPT < END_UNCHANGED) |
1773 | END_UNCHANGED = Z - GPT; | |
9f3ede3c | 1774 | |
60ea6052 RS |
1775 | CHECK_MARKERS (); |
1776 | ||
1e9c7b7d KH |
1777 | if (len == 0) |
1778 | evaporate_overlays (from); | |
1779 | MODIFF++; | |
1e9c7b7d KH |
1780 | } |
1781 | ||
652838b5 KH |
1782 | /* Record undo information, adjust markers and position keepers for an |
1783 | insertion of a text from FROM (FROM_BYTE) to TO (TO_BYTE). The | |
1784 | text already exists in the current buffer but character length (TO | |
1785 | - FROM) may be incorrect, the correct length is NEWLEN. */ | |
1786 | ||
1787 | void | |
1788 | adjust_after_insert (from, from_byte, to, to_byte, newlen) | |
1789 | int from, from_byte, to, to_byte, newlen; | |
1790 | { | |
1791 | int len = to - from, len_byte = to_byte - from_byte; | |
1792 | ||
1793 | if (GPT != to) | |
1794 | move_gap_both (to, to_byte); | |
1795 | GAP_SIZE += len_byte; | |
1796 | GPT -= len; GPT_BYTE -= len_byte; | |
1797 | ZV -= len; ZV_BYTE -= len_byte; | |
1798 | Z -= len; Z_BYTE -= len_byte; | |
1799 | adjust_after_replace (from, from_byte, Qnil, newlen, len_byte); | |
1800 | } | |
1801 | ||
3be11131 | 1802 | /* Replace the text from character positions FROM to TO with NEW, |
c5ca4d3a RS |
1803 | If PREPARE is nonzero, call prepare_to_modify_buffer. |
1804 | If INHERIT, the newly inserted text should inherit text properties | |
1805 | from the surrounding non-deleted text. */ | |
1806 | ||
1807 | /* Note that this does not yet handle markers quite right. | |
1808 | Also it needs to record a single undo-entry that does a replacement | |
1809 | rather than a separate delete and insert. | |
60aa777a RS |
1810 | That way, undo will also handle markers properly. |
1811 | ||
1812 | But if MARKERS is 0, don't relocate markers. */ | |
c5ca4d3a RS |
1813 | |
1814 | void | |
60aa777a | 1815 | replace_range (from, to, new, prepare, inherit, markers) |
c5ca4d3a | 1816 | Lisp_Object new; |
60aa777a | 1817 | int from, to, prepare, inherit, markers; |
c5ca4d3a | 1818 | { |
2b083808 | 1819 | int inschars = XSTRING (new)->size; |
fc932ac6 | 1820 | int insbytes = STRING_BYTES (XSTRING (new)); |
3be11131 RS |
1821 | int from_byte, to_byte; |
1822 | int nbytes_del, nchars_del; | |
c5ca4d3a RS |
1823 | register Lisp_Object temp; |
1824 | struct gcpro gcpro1; | |
432f78d2 RS |
1825 | int combined_before_bytes, combined_after_bytes; |
1826 | int adjusted_inschars; | |
ce97a2d7 | 1827 | INTERVAL intervals; |
1f90a790 | 1828 | int outgoing_insbytes = insbytes; |
23b20a70 | 1829 | Lisp_Object deletion; |
c5ca4d3a | 1830 | |
60ea6052 RS |
1831 | CHECK_MARKERS (); |
1832 | ||
c5ca4d3a RS |
1833 | GCPRO1 (new); |
1834 | ||
1835 | if (prepare) | |
1836 | { | |
1837 | int range_length = to - from; | |
1838 | prepare_to_modify_buffer (from, to, &from); | |
1839 | to = from + range_length; | |
1840 | } | |
1841 | ||
3be11131 RS |
1842 | UNGCPRO; |
1843 | ||
c5ca4d3a RS |
1844 | /* Make args be valid */ |
1845 | if (from < BEGV) | |
1846 | from = BEGV; | |
1847 | if (to > ZV) | |
1848 | to = ZV; | |
1849 | ||
3be11131 RS |
1850 | from_byte = CHAR_TO_BYTE (from); |
1851 | to_byte = CHAR_TO_BYTE (to); | |
c5ca4d3a | 1852 | |
3be11131 RS |
1853 | nchars_del = to - from; |
1854 | nbytes_del = to_byte - from_byte; | |
1855 | ||
1856 | if (nbytes_del <= 0 && insbytes == 0) | |
1857 | return; | |
c5ca4d3a | 1858 | |
1f90a790 RS |
1859 | /* Make OUTGOING_INSBYTES describe the text |
1860 | as it will be inserted in this buffer. */ | |
1861 | ||
1862 | if (NILP (current_buffer->enable_multibyte_characters)) | |
1863 | outgoing_insbytes = inschars; | |
2a1d8be0 | 1864 | else if (! STRING_MULTIBYTE (new)) |
1f90a790 RS |
1865 | outgoing_insbytes |
1866 | = count_size_as_multibyte (XSTRING (new)->data, insbytes); | |
1867 | ||
c5ca4d3a | 1868 | /* Make sure point-max won't overflow after this insertion. */ |
3be11131 RS |
1869 | XSETINT (temp, Z_BYTE - nbytes_del + insbytes); |
1870 | if (Z_BYTE - nbytes_del + insbytes != XINT (temp)) | |
1871 | error ("Maximum buffer size exceeded"); | |
c5ca4d3a | 1872 | |
c5ca4d3a RS |
1873 | GCPRO1 (new); |
1874 | ||
1875 | /* Make sure the gap is somewhere in or next to what we are deleting. */ | |
1876 | if (from > GPT) | |
3be11131 | 1877 | gap_right (from, from_byte); |
c5ca4d3a | 1878 | if (to < GPT) |
3be11131 | 1879 | gap_left (to, to_byte, 0); |
c5ca4d3a | 1880 | |
039af53a KH |
1881 | /* Even if we don't record for undo, we must keep the original text |
1882 | because we may have to recover it because of inappropriate byte | |
1883 | combining. */ | |
1884 | deletion = make_buffer_string_both (from, from_byte, to, to_byte, 1); | |
c5ca4d3a | 1885 | |
23b20a70 KH |
1886 | if (markers) |
1887 | /* Relocate all markers pointing into the new, larger gap | |
1888 | to point at the end of the text before the gap. | |
1889 | Do this before recording the deletion, | |
1890 | so that undo handles this after reinserting the text. */ | |
1891 | adjust_markers_for_delete (from, from_byte, to, to_byte); | |
c5ca4d3a | 1892 | |
3be11131 RS |
1893 | GAP_SIZE += nbytes_del; |
1894 | ZV -= nchars_del; | |
1895 | Z -= nchars_del; | |
1896 | ZV_BYTE -= nbytes_del; | |
1897 | Z_BYTE -= nbytes_del; | |
c5ca4d3a | 1898 | GPT = from; |
3be11131 | 1899 | GPT_BYTE = from_byte; |
c5ca4d3a RS |
1900 | *(GPT_ADDR) = 0; /* Put an anchor. */ |
1901 | ||
3be11131 RS |
1902 | if (GPT_BYTE < GPT) |
1903 | abort (); | |
1904 | ||
a50df55b GM |
1905 | if (GPT - BEG < BEG_UNCHANGED) |
1906 | BEG_UNCHANGED = GPT - BEG; | |
1907 | if (Z - GPT < END_UNCHANGED) | |
1908 | END_UNCHANGED = Z - GPT; | |
c5ca4d3a | 1909 | |
3be11131 RS |
1910 | if (GAP_SIZE < insbytes) |
1911 | make_gap (insbytes - GAP_SIZE); | |
c5ca4d3a | 1912 | |
1f90a790 RS |
1913 | /* Copy the string text into the buffer, perhaps converting |
1914 | between single-byte and multibyte. */ | |
1915 | copy_text (XSTRING (new)->data, GPT_ADDR, insbytes, | |
2a1d8be0 | 1916 | STRING_MULTIBYTE (new), |
1f90a790 RS |
1917 | ! NILP (current_buffer->enable_multibyte_characters)); |
1918 | ||
255c7dae RS |
1919 | /* We have copied text into the gap, but we have not marked |
1920 | it as part of the buffer. So we can use the old FROM and FROM_BYTE | |
1921 | here, for both the previous text and the following text. | |
1922 | Meanwhile, GPT_ADDR does point to | |
432f78d2 RS |
1923 | the text that has been stored by copy_text. */ |
1924 | ||
1925 | combined_before_bytes | |
255c7dae | 1926 | = count_combining_before (GPT_ADDR, outgoing_insbytes, from, from_byte); |
432f78d2 | 1927 | combined_after_bytes |
255c7dae | 1928 | = count_combining_after (GPT_ADDR, outgoing_insbytes, from, from_byte); |
039af53a KH |
1929 | |
1930 | if (combined_before_bytes && from == BEGV | |
1931 | || combined_after_bytes && from == ZV) | |
1932 | { | |
1933 | /* Bytes are being combined across the region boundary. We | |
1934 | should avoid it. We recover the original contents before | |
1935 | signaling an error. */ | |
1936 | bcopy (XSTRING (deletion)->data, GPT_ADDR, nbytes_del); | |
1937 | GAP_SIZE -= nbytes_del; | |
1938 | ZV += nchars_del; | |
1939 | Z += nchars_del; | |
1940 | ZV_BYTE += nbytes_del; | |
1941 | Z_BYTE += nbytes_del; | |
1942 | GPT = from + nchars_del; | |
1943 | GPT_BYTE = from_byte + nbytes_del; | |
1944 | *(GPT_ADDR) = 0; /* Put an anchor. */ | |
1945 | if (markers) | |
1946 | adjust_markers_for_insert (from, from_byte, to, to_byte, 0, 0, 0); | |
b80f1b20 | 1947 | UNGCPRO; |
039af53a | 1948 | byte_combining_error (); |
b80f1b20 | 1949 | GCPRO1 (new); |
039af53a | 1950 | } |
432f78d2 RS |
1951 | |
1952 | /* Record deletion of the surrounding text that combines with | |
1953 | the insertion. This, together with recording the insertion, | |
1954 | will add up to the right stuff in the undo list. | |
1955 | ||
1956 | But there is no need to actually delete the combining bytes | |
1957 | from the buffer and reinsert them. */ | |
1958 | ||
1959 | if (combined_after_bytes) | |
7cc3983f | 1960 | { |
0aa8c4b2 RS |
1961 | Lisp_Object deletion; |
1962 | deletion = Qnil; | |
1963 | ||
1964 | if (! EQ (current_buffer->undo_list, Qt)) | |
255c7dae RS |
1965 | deletion = make_buffer_string_both (from, from_byte, |
1966 | from + combined_after_bytes, | |
828f1ed3 KH |
1967 | from_byte + combined_after_bytes, |
1968 | 1); | |
628cea90 | 1969 | |
255c7dae RS |
1970 | adjust_markers_for_record_delete (from, from_byte, |
1971 | from + combined_after_bytes, | |
1972 | from_byte + combined_after_bytes); | |
0aa8c4b2 | 1973 | if (! EQ (current_buffer->undo_list, Qt)) |
828f1ed3 | 1974 | record_delete (from + nchars_del, deletion); |
7cc3983f | 1975 | } |
432f78d2 RS |
1976 | |
1977 | if (combined_before_bytes) | |
7cc3983f | 1978 | { |
0aa8c4b2 RS |
1979 | Lisp_Object deletion; |
1980 | deletion = Qnil; | |
1981 | ||
1982 | if (! EQ (current_buffer->undo_list, Qt)) | |
255c7dae RS |
1983 | deletion = make_buffer_string_both (from - 1, CHAR_TO_BYTE (from - 1), |
1984 | from, from_byte, 1); | |
1985 | adjust_markers_for_record_delete (from - 1, CHAR_TO_BYTE (from - 1), | |
1986 | from, from_byte); | |
0aa8c4b2 | 1987 | if (! EQ (current_buffer->undo_list, Qt)) |
255c7dae | 1988 | record_delete (from - 1, deletion); |
7cc3983f | 1989 | } |
432f78d2 | 1990 | |
23b20a70 KH |
1991 | if (! EQ (current_buffer->undo_list, Qt)) |
1992 | { | |
1993 | record_delete (from - !!combined_before_bytes, deletion); | |
1994 | record_insert (from - !!combined_before_bytes, | |
1995 | (inschars - combined_before_bytes | |
1996 | + !!combined_before_bytes)); | |
1997 | } | |
c5ca4d3a | 1998 | |
1f90a790 RS |
1999 | GAP_SIZE -= outgoing_insbytes; |
2000 | GPT += inschars; | |
2001 | ZV += inschars; | |
2002 | Z += inschars; | |
2003 | GPT_BYTE += outgoing_insbytes; | |
2004 | ZV_BYTE += outgoing_insbytes; | |
2005 | Z_BYTE += outgoing_insbytes; | |
c5ca4d3a RS |
2006 | if (GAP_SIZE > 0) *(GPT_ADDR) = 0; /* Put an anchor. */ |
2007 | ||
1f90a790 RS |
2008 | if (combined_after_bytes) |
2009 | move_gap_both (GPT + combined_after_bytes, | |
2010 | GPT_BYTE + combined_after_bytes); | |
2011 | ||
3be11131 RS |
2012 | if (GPT_BYTE < GPT) |
2013 | abort (); | |
2014 | ||
c5ca4d3a RS |
2015 | /* Adjust the overlay center as needed. This must be done after |
2016 | adjusting the markers that bound the overlays. */ | |
3be11131 | 2017 | adjust_overlays_for_delete (from, nchars_del); |
1f90a790 | 2018 | adjust_overlays_for_insert (from, inschars); |
60aa777a | 2019 | if (markers) |
2db5082f RS |
2020 | adjust_markers_for_insert (from, from_byte, |
2021 | from + inschars, from_byte + outgoing_insbytes, | |
2022 | combined_before_bytes, combined_after_bytes, 0); | |
c5ca4d3a | 2023 | |
1f90a790 | 2024 | #ifdef USE_TEXT_PROPERTIES |
255c7dae | 2025 | offset_intervals (current_buffer, from, inschars - nchars_del); |
ce97a2d7 RS |
2026 | |
2027 | /* Get the intervals for the part of the string we are inserting-- | |
2028 | not including the combined-before bytes. */ | |
2029 | intervals = XSTRING (new)->intervals; | |
ce97a2d7 | 2030 | /* Insert those intervals. */ |
1f90a790 | 2031 | graft_intervals_into_buffer (intervals, from, inschars, |
ce97a2d7 | 2032 | current_buffer, inherit); |
1f90a790 | 2033 | #endif |
c5ca4d3a | 2034 | |
1f90a790 RS |
2035 | /* Relocate point as if it were a marker. */ |
2036 | if (from < PT) | |
8bedbe9d | 2037 | adjust_point ((from + inschars - (PT < to ? PT : to)), |
1f90a790 | 2038 | (from_byte + outgoing_insbytes |
8bedbe9d | 2039 | - (PT_BYTE < to_byte ? PT_BYTE : to_byte))); |
c5ca4d3a | 2040 | |
93b882e8 | 2041 | if (combined_after_bytes) |
f6ecdae5 KH |
2042 | { |
2043 | if (combined_before_bytes == outgoing_insbytes) | |
2044 | /* This is the case that all new bytes are combined. */ | |
2045 | combined_before_bytes += combined_after_bytes; | |
2046 | else | |
2047 | combine_bytes (from + inschars, from_byte + outgoing_insbytes, | |
2048 | combined_after_bytes); | |
2049 | } | |
1f90a790 RS |
2050 | if (combined_before_bytes) |
2051 | combine_bytes (from, from_byte, combined_before_bytes); | |
2052 | ||
9f3ede3c | 2053 | /* As byte combining will decrease Z, we must check this again. */ |
a50df55b GM |
2054 | if (Z - GPT < END_UNCHANGED) |
2055 | END_UNCHANGED = Z - GPT; | |
9f3ede3c | 2056 | |
1f90a790 RS |
2057 | if (outgoing_insbytes == 0) |
2058 | evaporate_overlays (from); | |
93b882e8 | 2059 | |
60ea6052 RS |
2060 | CHECK_MARKERS (); |
2061 | ||
c5ca4d3a RS |
2062 | MODIFF++; |
2063 | UNGCPRO; | |
2064 | ||
255c7dae | 2065 | signal_after_change (from, nchars_del, GPT - from); |
c5ca4d3a RS |
2066 | } |
2067 | \f | |
b45433b3 | 2068 | /* Delete characters in current buffer |
3be11131 RS |
2069 | from FROM up to (but not including) TO. |
2070 | If TO comes before FROM, we delete nothing. */ | |
b45433b3 | 2071 | |
c660b094 | 2072 | void |
b45433b3 JB |
2073 | del_range (from, to) |
2074 | register int from, to; | |
47c64747 | 2075 | { |
c660b094 | 2076 | del_range_1 (from, to, 1); |
47c64747 RS |
2077 | } |
2078 | ||
2079 | /* Like del_range; PREPARE says whether to call prepare_to_modify_buffer. */ | |
2080 | ||
c660b094 | 2081 | void |
47c64747 | 2082 | del_range_1 (from, to, prepare) |
d206af14 | 2083 | int from, to, prepare; |
b45433b3 | 2084 | { |
3be11131 RS |
2085 | int from_byte, to_byte; |
2086 | ||
2087 | /* Make args be valid */ | |
2088 | if (from < BEGV) | |
2089 | from = BEGV; | |
2090 | if (to > ZV) | |
2091 | to = ZV; | |
2092 | ||
2093 | if (to <= from) | |
2094 | return; | |
2095 | ||
2096 | if (prepare) | |
2097 | { | |
2098 | int range_length = to - from; | |
2099 | prepare_to_modify_buffer (from, to, &from); | |
2100 | to = from + range_length; | |
2101 | } | |
2102 | ||
2103 | from_byte = CHAR_TO_BYTE (from); | |
2104 | to_byte = CHAR_TO_BYTE (to); | |
2105 | ||
a66afea0 | 2106 | del_range_2 (from, from_byte, to, to_byte); |
9c36993a | 2107 | signal_after_change (from, to - from, 0); |
3be11131 RS |
2108 | } |
2109 | ||
2110 | /* Like del_range_1 but args are byte positions, not char positions. */ | |
2111 | ||
2112 | void | |
2113 | del_range_byte (from_byte, to_byte, prepare) | |
2114 | int from_byte, to_byte, prepare; | |
2115 | { | |
2116 | int from, to; | |
2117 | ||
2118 | /* Make args be valid */ | |
2119 | if (from_byte < BEGV_BYTE) | |
2120 | from_byte = BEGV_BYTE; | |
2121 | if (to_byte > ZV_BYTE) | |
2122 | to_byte = ZV_BYTE; | |
2123 | ||
2124 | if (to_byte <= from_byte) | |
2125 | return; | |
2126 | ||
2127 | from = BYTE_TO_CHAR (from_byte); | |
2128 | to = BYTE_TO_CHAR (to_byte); | |
b45433b3 | 2129 | |
d206af14 RS |
2130 | if (prepare) |
2131 | { | |
3be11131 | 2132 | int old_from = from, old_to = Z - to; |
d206af14 RS |
2133 | int range_length = to - from; |
2134 | prepare_to_modify_buffer (from, to, &from); | |
2135 | to = from + range_length; | |
3be11131 RS |
2136 | |
2137 | if (old_from != from) | |
2138 | from_byte = CHAR_TO_BYTE (from); | |
2139 | if (old_to == Z - to) | |
2140 | to_byte = CHAR_TO_BYTE (to); | |
d206af14 RS |
2141 | } |
2142 | ||
a66afea0 | 2143 | del_range_2 (from, from_byte, to, to_byte); |
9c36993a | 2144 | signal_after_change (from, to - from, 0); |
3be11131 RS |
2145 | } |
2146 | ||
2147 | /* Like del_range_1, but positions are specified both as charpos | |
2148 | and bytepos. */ | |
2149 | ||
2150 | void | |
353800c7 KH |
2151 | del_range_both (from, from_byte, to, to_byte, prepare) |
2152 | int from, from_byte, to, to_byte, prepare; | |
3be11131 | 2153 | { |
b45433b3 | 2154 | /* Make args be valid */ |
3be11131 RS |
2155 | if (from_byte < BEGV_BYTE) |
2156 | from_byte = BEGV_BYTE; | |
2157 | if (to_byte > ZV_BYTE) | |
2158 | to_byte = ZV_BYTE; | |
2159 | ||
2160 | if (to_byte <= from_byte) | |
2161 | return; | |
2162 | ||
b45433b3 JB |
2163 | if (from < BEGV) |
2164 | from = BEGV; | |
2165 | if (to > ZV) | |
2166 | to = ZV; | |
2167 | ||
3be11131 RS |
2168 | if (prepare) |
2169 | { | |
2170 | int old_from = from, old_to = Z - to; | |
2171 | int range_length = to - from; | |
2172 | prepare_to_modify_buffer (from, to, &from); | |
2173 | to = from + range_length; | |
2174 | ||
2175 | if (old_from != from) | |
2176 | from_byte = CHAR_TO_BYTE (from); | |
2177 | if (old_to == Z - to) | |
2178 | to_byte = CHAR_TO_BYTE (to); | |
2179 | } | |
2180 | ||
a66afea0 | 2181 | del_range_2 (from, from_byte, to, to_byte); |
9c36993a | 2182 | signal_after_change (from, to - from, 0); |
3be11131 RS |
2183 | } |
2184 | ||
2185 | /* Delete a range of text, specified both as character positions | |
2186 | and byte positions. FROM and TO are character positions, | |
2187 | while FROM_BYTE and TO_BYTE are byte positions. */ | |
2188 | ||
2189 | void | |
a66afea0 KH |
2190 | del_range_2 (from, from_byte, to, to_byte) |
2191 | int from, from_byte, to, to_byte; | |
3be11131 RS |
2192 | { |
2193 | register int nbytes_del, nchars_del; | |
1f90a790 | 2194 | int combined_after_bytes; |
628cea90 RS |
2195 | Lisp_Object deletion; |
2196 | int from_byte_1; | |
3be11131 | 2197 | |
60ea6052 RS |
2198 | CHECK_MARKERS (); |
2199 | ||
3be11131 RS |
2200 | nchars_del = to - from; |
2201 | nbytes_del = to_byte - from_byte; | |
b45433b3 JB |
2202 | |
2203 | /* Make sure the gap is somewhere in or next to what we are deleting. */ | |
2204 | if (from > GPT) | |
3be11131 | 2205 | gap_right (from, from_byte); |
b45433b3 | 2206 | if (to < GPT) |
3be11131 | 2207 | gap_left (to, to_byte, 0); |
b45433b3 | 2208 | |
e0c0ed58 | 2209 | combined_after_bytes |
e3a87305 | 2210 | = count_combining_before (BUF_BYTE_ADDRESS (current_buffer, to_byte), |
9f3ede3c | 2211 | Z_BYTE - to_byte, from, from_byte); |
628cea90 RS |
2212 | if (combined_after_bytes) |
2213 | { | |
039af53a KH |
2214 | if (from == BEGV || to == ZV) |
2215 | byte_combining_error (); | |
628cea90 RS |
2216 | from_byte_1 = from_byte; |
2217 | DEC_POS (from_byte_1); | |
2218 | } | |
2219 | else | |
2220 | from_byte_1 = from_byte; | |
2221 | ||
0aa8c4b2 RS |
2222 | if (! EQ (current_buffer->undo_list, Qt)) |
2223 | deletion | |
2224 | = make_buffer_string_both (from - !!combined_after_bytes, | |
2225 | from_byte_1, | |
2226 | to + combined_after_bytes, | |
2227 | to_byte + combined_after_bytes, 1); | |
242beafe KH |
2228 | if (combined_after_bytes) |
2229 | /* COMBINED_AFTER_BYTES nonzero means that the above code moved | |
2230 | the gap. We must move the gap again to a proper place. */ | |
2231 | move_gap_both (from, from_byte); | |
e0c0ed58 | 2232 | |
8948d317 RS |
2233 | /* Relocate all markers pointing into the new, larger gap |
2234 | to point at the end of the text before the gap. | |
3be11131 RS |
2235 | Do this before recording the deletion, |
2236 | so that undo handles this after reinserting the text. */ | |
2237 | adjust_markers_for_delete (from, from_byte, to, to_byte); | |
7cc3983f RS |
2238 | if (combined_after_bytes) |
2239 | { | |
7cc3983f RS |
2240 | /* Adjust markers for the phony deletion |
2241 | that we are about to call record_undo for. */ | |
2242 | ||
2243 | /* Here we delete the markers that formerly | |
2244 | pointed at TO ... TO + COMBINED_AFTER_BYTES. | |
2245 | But because of the call to adjust_markers_for_delete, above, | |
2246 | they now point at FROM ... FROM + COMBINED_AFTER_BYTES. */ | |
2247 | adjust_markers_for_record_delete (from, from_byte, | |
2248 | from + combined_after_bytes, | |
2249 | from_byte + combined_after_bytes); | |
2250 | ||
2251 | adjust_markers_for_record_delete (from - 1, from_byte_1, | |
2252 | from, from_byte); | |
2253 | } | |
0aa8c4b2 RS |
2254 | if (! EQ (current_buffer->undo_list, Qt)) |
2255 | record_delete (from - !!combined_after_bytes, deletion); | |
be09561e RS |
2256 | MODIFF++; |
2257 | ||
b45433b3 | 2258 | /* Relocate point as if it were a marker. */ |
2bcaed71 | 2259 | if (from < PT) |
3be11131 RS |
2260 | adjust_point (from - (PT < to ? PT : to), |
2261 | from_byte - (PT_BYTE < to_byte ? PT_BYTE : to_byte)); | |
b45433b3 | 2262 | |
16032db6 | 2263 | /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */ |
3be11131 | 2264 | offset_intervals (current_buffer, from, - nchars_del); |
16032db6 | 2265 | |
adde4858 | 2266 | /* Adjust the overlay center as needed. This must be done after |
a7f38d28 | 2267 | adjusting the markers that bound the overlays. */ |
e3a87305 | 2268 | adjust_overlays_for_delete (from, nchars_del); |
adde4858 | 2269 | |
3be11131 RS |
2270 | GAP_SIZE += nbytes_del; |
2271 | ZV_BYTE -= nbytes_del; | |
2272 | Z_BYTE -= nbytes_del; | |
2273 | ZV -= nchars_del; | |
2274 | Z -= nchars_del; | |
b45433b3 | 2275 | GPT = from; |
3be11131 | 2276 | GPT_BYTE = from_byte; |
b45433b3 | 2277 | |
e0c0ed58 RS |
2278 | if (combined_after_bytes) |
2279 | move_gap_both (GPT + combined_after_bytes, | |
2280 | GPT_BYTE + combined_after_bytes); | |
2281 | ||
e3a87305 KH |
2282 | *(GPT_ADDR) = 0; /* Put an anchor. */ |
2283 | ||
3be11131 RS |
2284 | if (GPT_BYTE < GPT) |
2285 | abort (); | |
2286 | ||
a50df55b GM |
2287 | if (GPT - BEG < BEG_UNCHANGED) |
2288 | BEG_UNCHANGED = GPT - BEG; | |
2289 | if (Z - GPT < END_UNCHANGED) | |
2290 | END_UNCHANGED = Z - GPT; | |
b45433b3 | 2291 | |
1f90a790 | 2292 | if (combined_after_bytes) |
7cc3983f | 2293 | { |
828f1ed3 KH |
2294 | /* Adjust markers for byte combining. As we have already |
2295 | adjuted markers without concerning byte combining, here we | |
2296 | must concern only byte combining. */ | |
2297 | adjust_markers_for_replace (from, from_byte, 0, 0, 0, 0, | |
2298 | 0, combined_after_bytes); | |
7cc3983f | 2299 | combine_bytes (from, from_byte, combined_after_bytes); |
1f90a790 | 2300 | |
7cc3983f | 2301 | record_insert (GPT - 1, 1); |
9f3ede3c | 2302 | |
a50df55b GM |
2303 | if (Z - GPT < END_UNCHANGED) |
2304 | END_UNCHANGED = Z - GPT; | |
7cc3983f | 2305 | } |
1f90a790 | 2306 | |
60ea6052 RS |
2307 | CHECK_MARKERS (); |
2308 | ||
d386034e | 2309 | evaporate_overlays (from); |
b45433b3 JB |
2310 | } |
2311 | \f | |
3be11131 RS |
2312 | /* Call this if you're about to change the region of BUFFER from |
2313 | character positions START to END. This checks the read-only | |
2314 | properties of the region, calls the necessary modification hooks, | |
2315 | and warns the next redisplay that it should pay attention to that | |
2316 | area. */ | |
2317 | ||
c660b094 | 2318 | void |
04a759c8 JB |
2319 | modify_region (buffer, start, end) |
2320 | struct buffer *buffer; | |
b45433b3 JB |
2321 | int start, end; |
2322 | { | |
04a759c8 JB |
2323 | struct buffer *old_buffer = current_buffer; |
2324 | ||
2325 | if (buffer != old_buffer) | |
2326 | set_buffer_internal (buffer); | |
2327 | ||
d206af14 | 2328 | prepare_to_modify_buffer (start, end, NULL); |
b45433b3 | 2329 | |
a50df55b | 2330 | BUF_COMPUTE_UNCHANGED (buffer, start - 1, end); |
83010cd6 | 2331 | |
9fbf87cd | 2332 | if (MODIFF <= SAVE_MODIFF) |
83010cd6 | 2333 | record_first_change (); |
b45433b3 | 2334 | MODIFF++; |
04a759c8 | 2335 | |
069cdc4f RS |
2336 | buffer->point_before_scroll = Qnil; |
2337 | ||
04a759c8 JB |
2338 | if (buffer != old_buffer) |
2339 | set_buffer_internal (old_buffer); | |
b45433b3 | 2340 | } |
d206af14 | 2341 | \f |
3be11131 RS |
2342 | /* Check that it is okay to modify the buffer between START and END, |
2343 | which are char positions. | |
2344 | ||
679194a6 JA |
2345 | Run the before-change-function, if any. If intervals are in use, |
2346 | verify that the text to be modified is not read-only, and call | |
d206af14 RS |
2347 | any modification properties the text may have. |
2348 | ||
2349 | If PRESERVE_PTR is nonzero, we relocate *PRESERVE_PTR | |
2350 | by holding its value temporarily in a marker. */ | |
b45433b3 | 2351 | |
c660b094 | 2352 | void |
d206af14 | 2353 | prepare_to_modify_buffer (start, end, preserve_ptr) |
fb4ee5cd | 2354 | int start, end; |
d206af14 | 2355 | int *preserve_ptr; |
b45433b3 | 2356 | { |
d427b66a | 2357 | if (!NILP (current_buffer->read_only)) |
b45433b3 JB |
2358 | Fbarf_if_buffer_read_only (); |
2359 | ||
2e9f55fd GM |
2360 | /* Let redisplay consider other windows than selected_window |
2361 | if modifying another buffer. */ | |
2362 | if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer) | |
2363 | ++windows_or_buffers_changed; | |
2364 | ||
679194a6 | 2365 | /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */ |
9fbf87cd | 2366 | if (BUF_INTERVALS (current_buffer) != 0) |
d206af14 RS |
2367 | { |
2368 | if (preserve_ptr) | |
2369 | { | |
2370 | Lisp_Object preserve_marker; | |
2371 | struct gcpro gcpro1; | |
2372 | preserve_marker = Fcopy_marker (make_number (*preserve_ptr), Qnil); | |
2373 | GCPRO1 (preserve_marker); | |
2374 | verify_interval_modification (current_buffer, start, end); | |
2375 | *preserve_ptr = marker_position (preserve_marker); | |
2376 | unchain_marker (preserve_marker); | |
2377 | UNGCPRO; | |
2378 | } | |
2379 | else | |
2380 | verify_interval_modification (current_buffer, start, end); | |
2381 | } | |
b45433b3 JB |
2382 | |
2383 | #ifdef CLASH_DETECTION | |
f173b650 | 2384 | if (!NILP (current_buffer->file_truename) |
ab6c5c0c RS |
2385 | /* Make binding buffer-file-name to nil effective. */ |
2386 | && !NILP (current_buffer->filename) | |
9fbf87cd | 2387 | && SAVE_MODIFF >= MODIFF) |
f173b650 | 2388 | lock_file (current_buffer->file_truename); |
b45433b3 JB |
2389 | #else |
2390 | /* At least warn if this file has changed on disk since it was visited. */ | |
d427b66a | 2391 | if (!NILP (current_buffer->filename) |
9fbf87cd | 2392 | && SAVE_MODIFF >= MODIFF |
d427b66a JB |
2393 | && NILP (Fverify_visited_file_modtime (Fcurrent_buffer ())) |
2394 | && !NILP (Ffile_exists_p (current_buffer->filename))) | |
b45433b3 JB |
2395 | call1 (intern ("ask-user-about-supersession-threat"), |
2396 | current_buffer->filename); | |
2397 | #endif /* not CLASH_DETECTION */ | |
2398 | ||
d206af14 | 2399 | signal_before_change (start, end, preserve_ptr); |
2f545eea | 2400 | |
56e1065e JB |
2401 | if (current_buffer->newline_cache) |
2402 | invalidate_region_cache (current_buffer, | |
2403 | current_buffer->newline_cache, | |
2404 | start - BEG, Z - end); | |
2405 | if (current_buffer->width_run_cache) | |
2406 | invalidate_region_cache (current_buffer, | |
2407 | current_buffer->width_run_cache, | |
2408 | start - BEG, Z - end); | |
2409 | ||
2f545eea | 2410 | Vdeactivate_mark = Qt; |
b45433b3 JB |
2411 | } |
2412 | \f | |
d206af14 RS |
2413 | /* These macros work with an argument named `preserve_ptr' |
2414 | and a local variable named `preserve_marker'. */ | |
2415 | ||
2416 | #define PRESERVE_VALUE \ | |
2417 | if (preserve_ptr && NILP (preserve_marker)) \ | |
2418 | preserve_marker = Fcopy_marker (make_number (*preserve_ptr), Qnil) | |
2419 | ||
2420 | #define RESTORE_VALUE \ | |
2421 | if (! NILP (preserve_marker)) \ | |
2422 | { \ | |
2423 | *preserve_ptr = marker_position (preserve_marker); \ | |
2424 | unchain_marker (preserve_marker); \ | |
2425 | } | |
2426 | ||
b86e0aaf RS |
2427 | #define PRESERVE_START_END \ |
2428 | if (NILP (start_marker)) \ | |
2429 | start_marker = Fcopy_marker (start, Qnil); \ | |
2430 | if (NILP (end_marker)) \ | |
2431 | end_marker = Fcopy_marker (end, Qnil); | |
2432 | ||
2433 | #define FETCH_START \ | |
2434 | (! NILP (start_marker) ? Fmarker_position (start_marker) : start) | |
2435 | ||
2436 | #define FETCH_END \ | |
2437 | (! NILP (end_marker) ? Fmarker_position (end_marker) : end) | |
2438 | ||
eb8c3be9 | 2439 | /* Signal a change to the buffer immediately before it happens. |
d206af14 RS |
2440 | START_INT and END_INT are the bounds of the text to be changed. |
2441 | ||
2442 | If PRESERVE_PTR is nonzero, we relocate *PRESERVE_PTR | |
2443 | by holding its value temporarily in a marker. */ | |
b45433b3 | 2444 | |
c660b094 | 2445 | void |
d206af14 | 2446 | signal_before_change (start_int, end_int, preserve_ptr) |
6022d493 | 2447 | int start_int, end_int; |
d206af14 | 2448 | int *preserve_ptr; |
b45433b3 | 2449 | { |
fb4ee5cd | 2450 | Lisp_Object start, end; |
b86e0aaf | 2451 | Lisp_Object start_marker, end_marker; |
d206af14 | 2452 | Lisp_Object preserve_marker; |
b86e0aaf | 2453 | struct gcpro gcpro1, gcpro2, gcpro3; |
fb4ee5cd | 2454 | |
fd16a4c6 KH |
2455 | if (inhibit_modification_hooks) |
2456 | return; | |
2457 | ||
fb4ee5cd RS |
2458 | start = make_number (start_int); |
2459 | end = make_number (end_int); | |
d206af14 | 2460 | preserve_marker = Qnil; |
b86e0aaf RS |
2461 | start_marker = Qnil; |
2462 | end_marker = Qnil; | |
2463 | GCPRO3 (preserve_marker, start_marker, end_marker); | |
fb4ee5cd | 2464 | |
b45433b3 | 2465 | /* If buffer is unmodified, run a special hook for that case. */ |
9fbf87cd | 2466 | if (SAVE_MODIFF >= MODIFF |
dbc4e1c1 JB |
2467 | && !NILP (Vfirst_change_hook) |
2468 | && !NILP (Vrun_hooks)) | |
d206af14 RS |
2469 | { |
2470 | PRESERVE_VALUE; | |
b86e0aaf | 2471 | PRESERVE_START_END; |
d206af14 RS |
2472 | call1 (Vrun_hooks, Qfirst_change_hook); |
2473 | } | |
dbc4e1c1 | 2474 | |
3d1e2d9c RS |
2475 | /* Run the before-change-function if any. |
2476 | We don't bother "binding" this variable to nil | |
2477 | because it is obsolete anyway and new code should not use it. */ | |
d427b66a | 2478 | if (!NILP (Vbefore_change_function)) |
d206af14 RS |
2479 | { |
2480 | PRESERVE_VALUE; | |
b86e0aaf RS |
2481 | PRESERVE_START_END; |
2482 | call2 (Vbefore_change_function, FETCH_START, FETCH_END); | |
d206af14 | 2483 | } |
e45fb8bf | 2484 | |
3d1e2d9c | 2485 | /* Now run the before-change-functions if any. */ |
e45fb8bf RS |
2486 | if (!NILP (Vbefore_change_functions)) |
2487 | { | |
3d1e2d9c RS |
2488 | Lisp_Object args[3]; |
2489 | Lisp_Object before_change_functions; | |
2490 | Lisp_Object after_change_functions; | |
2491 | struct gcpro gcpro1, gcpro2; | |
2492 | ||
d206af14 | 2493 | PRESERVE_VALUE; |
b86e0aaf | 2494 | PRESERVE_START_END; |
d206af14 | 2495 | |
3d1e2d9c RS |
2496 | /* "Bind" before-change-functions and after-change-functions |
2497 | to nil--but in a way that errors don't know about. | |
2498 | That way, if there's an error in them, they will stay nil. */ | |
2499 | before_change_functions = Vbefore_change_functions; | |
2500 | after_change_functions = Vafter_change_functions; | |
c82c1da0 KH |
2501 | Vbefore_change_functions = Qnil; |
2502 | Vafter_change_functions = Qnil; | |
3d1e2d9c RS |
2503 | GCPRO2 (before_change_functions, after_change_functions); |
2504 | ||
2505 | /* Actually run the hook functions. */ | |
2506 | args[0] = Qbefore_change_functions; | |
b86e0aaf RS |
2507 | args[1] = FETCH_START; |
2508 | args[2] = FETCH_END; | |
3d1e2d9c RS |
2509 | run_hook_list_with_args (before_change_functions, 3, args); |
2510 | ||
2511 | /* "Unbind" the variables we "bound" to nil. */ | |
2512 | Vbefore_change_functions = before_change_functions; | |
2513 | Vafter_change_functions = after_change_functions; | |
2514 | UNGCPRO; | |
e45fb8bf | 2515 | } |
d07c0804 RS |
2516 | |
2517 | if (!NILP (current_buffer->overlays_before) | |
2518 | || !NILP (current_buffer->overlays_after)) | |
d206af14 RS |
2519 | { |
2520 | PRESERVE_VALUE; | |
b86e0aaf RS |
2521 | report_overlay_modification (FETCH_START, FETCH_END, 0, |
2522 | FETCH_START, FETCH_END, Qnil); | |
d206af14 RS |
2523 | } |
2524 | ||
b86e0aaf RS |
2525 | if (! NILP (start_marker)) |
2526 | free_marker (start_marker); | |
2527 | if (! NILP (end_marker)) | |
2528 | free_marker (end_marker); | |
d206af14 RS |
2529 | RESTORE_VALUE; |
2530 | UNGCPRO; | |
b45433b3 JB |
2531 | } |
2532 | ||
eb8c3be9 | 2533 | /* Signal a change immediately after it happens. |
3be11131 | 2534 | CHARPOS is the character position of the start of the changed text. |
b45433b3 JB |
2535 | LENDEL is the number of characters of the text before the change. |
2536 | (Not the whole buffer; just the part that was changed.) | |
8b09e5d0 RS |
2537 | LENINS is the number of characters in that part of the text |
2538 | after the change. */ | |
b45433b3 | 2539 | |
c660b094 | 2540 | void |
3be11131 RS |
2541 | signal_after_change (charpos, lendel, lenins) |
2542 | int charpos, lendel, lenins; | |
b45433b3 | 2543 | { |
fd16a4c6 KH |
2544 | if (inhibit_modification_hooks) |
2545 | return; | |
2546 | ||
fb2e7d14 RS |
2547 | /* If we are deferring calls to the after-change functions |
2548 | and there are no before-change functions, | |
2549 | just record the args that we were going to use. */ | |
2550 | if (! NILP (Vcombine_after_change_calls) | |
2551 | && NILP (Vbefore_change_function) && NILP (Vbefore_change_functions) | |
2552 | && NILP (current_buffer->overlays_before) | |
2553 | && NILP (current_buffer->overlays_after)) | |
2554 | { | |
2555 | Lisp_Object elt; | |
2556 | ||
2557 | if (!NILP (combine_after_change_list) | |
2558 | && current_buffer != XBUFFER (combine_after_change_buffer)) | |
2559 | Fcombine_after_change_execute (); | |
2560 | ||
3be11131 RS |
2561 | elt = Fcons (make_number (charpos - BEG), |
2562 | Fcons (make_number (Z - (charpos - lendel + lenins)), | |
fb2e7d14 RS |
2563 | Fcons (make_number (lenins - lendel), Qnil))); |
2564 | combine_after_change_list | |
2565 | = Fcons (elt, combine_after_change_list); | |
2566 | combine_after_change_buffer = Fcurrent_buffer (); | |
2567 | ||
2568 | return; | |
2569 | } | |
2570 | ||
2571 | if (!NILP (combine_after_change_list)) | |
2572 | Fcombine_after_change_execute (); | |
2573 | ||
3d1e2d9c RS |
2574 | /* Run the after-change-function if any. |
2575 | We don't bother "binding" this variable to nil | |
2576 | because it is obsolete anyway and new code should not use it. */ | |
d427b66a | 2577 | if (!NILP (Vafter_change_function)) |
3d1e2d9c | 2578 | call3 (Vafter_change_function, |
3be11131 | 2579 | make_number (charpos), make_number (charpos + lenins), |
3d1e2d9c | 2580 | make_number (lendel)); |
b45433b3 | 2581 | |
e45fb8bf RS |
2582 | if (!NILP (Vafter_change_functions)) |
2583 | { | |
3d1e2d9c RS |
2584 | Lisp_Object args[4]; |
2585 | Lisp_Object before_change_functions; | |
2586 | Lisp_Object after_change_functions; | |
2587 | struct gcpro gcpro1, gcpro2; | |
2588 | ||
2589 | /* "Bind" before-change-functions and after-change-functions | |
2590 | to nil--but in a way that errors don't know about. | |
2591 | That way, if there's an error in them, they will stay nil. */ | |
2592 | before_change_functions = Vbefore_change_functions; | |
2593 | after_change_functions = Vafter_change_functions; | |
c82c1da0 KH |
2594 | Vbefore_change_functions = Qnil; |
2595 | Vafter_change_functions = Qnil; | |
3d1e2d9c RS |
2596 | GCPRO2 (before_change_functions, after_change_functions); |
2597 | ||
2598 | /* Actually run the hook functions. */ | |
2599 | args[0] = Qafter_change_functions; | |
3be11131 RS |
2600 | XSETFASTINT (args[1], charpos); |
2601 | XSETFASTINT (args[2], charpos + lenins); | |
3d1e2d9c RS |
2602 | XSETFASTINT (args[3], lendel); |
2603 | run_hook_list_with_args (after_change_functions, | |
2604 | 4, args); | |
2605 | ||
2606 | /* "Unbind" the variables we "bound" to nil. */ | |
2607 | Vbefore_change_functions = before_change_functions; | |
2608 | Vafter_change_functions = after_change_functions; | |
2609 | UNGCPRO; | |
e45fb8bf | 2610 | } |
d07c0804 RS |
2611 | |
2612 | if (!NILP (current_buffer->overlays_before) | |
2613 | || !NILP (current_buffer->overlays_after)) | |
3be11131 RS |
2614 | report_overlay_modification (make_number (charpos), |
2615 | make_number (charpos + lenins), | |
d07c0804 | 2616 | 1, |
3be11131 RS |
2617 | make_number (charpos), |
2618 | make_number (charpos + lenins), | |
d07c0804 | 2619 | make_number (lendel)); |
c5ca0786 RS |
2620 | |
2621 | /* After an insertion, call the text properties | |
2622 | insert-behind-hooks or insert-in-front-hooks. */ | |
2623 | if (lendel == 0) | |
d6b81c0f AS |
2624 | report_interval_modification (make_number (charpos), |
2625 | make_number (charpos + lenins)); | |
b45433b3 | 2626 | } |
fb2e7d14 RS |
2627 | |
2628 | Lisp_Object | |
2629 | Fcombine_after_change_execute_1 (val) | |
2630 | Lisp_Object val; | |
2631 | { | |
2632 | Vcombine_after_change_calls = val; | |
2633 | return val; | |
2634 | } | |
2635 | ||
2636 | DEFUN ("combine-after-change-execute", Fcombine_after_change_execute, | |
2637 | Scombine_after_change_execute, 0, 0, 0, | |
2638 | "This function is for use internally in `combine-after-change-calls'.") | |
2639 | () | |
2640 | { | |
fb2e7d14 RS |
2641 | int count = specpdl_ptr - specpdl; |
2642 | int beg, end, change; | |
2643 | int begpos, endpos; | |
2644 | Lisp_Object tail; | |
2645 | ||
101e446f KH |
2646 | if (NILP (combine_after_change_list)) |
2647 | return Qnil; | |
2648 | ||
fb2e7d14 RS |
2649 | record_unwind_protect (Fset_buffer, Fcurrent_buffer ()); |
2650 | ||
2651 | Fset_buffer (combine_after_change_buffer); | |
2652 | ||
2653 | /* # chars unchanged at beginning of buffer. */ | |
2654 | beg = Z - BEG; | |
2655 | /* # chars unchanged at end of buffer. */ | |
2656 | end = beg; | |
2657 | /* Total amount of insertion (negative for deletion). */ | |
2658 | change = 0; | |
2659 | ||
2660 | /* Scan the various individual changes, | |
2661 | accumulating the range info in BEG, END and CHANGE. */ | |
2662 | for (tail = combine_after_change_list; CONSP (tail); | |
03699b14 | 2663 | tail = XCDR (tail)) |
fb2e7d14 | 2664 | { |
e688a080 KH |
2665 | Lisp_Object elt; |
2666 | int thisbeg, thisend, thischange; | |
fb2e7d14 RS |
2667 | |
2668 | /* Extract the info from the next element. */ | |
03699b14 | 2669 | elt = XCAR (tail); |
fb2e7d14 RS |
2670 | if (! CONSP (elt)) |
2671 | continue; | |
03699b14 | 2672 | thisbeg = XINT (XCAR (elt)); |
fb2e7d14 | 2673 | |
03699b14 | 2674 | elt = XCDR (elt); |
fb2e7d14 RS |
2675 | if (! CONSP (elt)) |
2676 | continue; | |
03699b14 | 2677 | thisend = XINT (XCAR (elt)); |
fb2e7d14 | 2678 | |
03699b14 | 2679 | elt = XCDR (elt); |
fb2e7d14 RS |
2680 | if (! CONSP (elt)) |
2681 | continue; | |
03699b14 | 2682 | thischange = XINT (XCAR (elt)); |
fb2e7d14 RS |
2683 | |
2684 | /* Merge this range into the accumulated range. */ | |
2685 | change += thischange; | |
2686 | if (thisbeg < beg) | |
2687 | beg = thisbeg; | |
2688 | if (thisend < end) | |
2689 | end = thisend; | |
2690 | } | |
2691 | ||
2692 | /* Get the current start and end positions of the range | |
2693 | that was changed. */ | |
2694 | begpos = BEG + beg; | |
2695 | endpos = Z - end; | |
2696 | ||
2697 | /* We are about to handle these, so discard them. */ | |
2698 | combine_after_change_list = Qnil; | |
2699 | ||
2700 | /* Now run the after-change functions for real. | |
2701 | Turn off the flag that defers them. */ | |
2702 | record_unwind_protect (Fcombine_after_change_execute_1, | |
2703 | Vcombine_after_change_calls); | |
2704 | signal_after_change (begpos, endpos - begpos - change, endpos - begpos); | |
2705 | ||
101e446f | 2706 | return unbind_to (count, Qnil); |
fb2e7d14 RS |
2707 | } |
2708 | \f | |
dfcf069d | 2709 | void |
fb2e7d14 RS |
2710 | syms_of_insdel () |
2711 | { | |
2712 | staticpro (&combine_after_change_list); | |
2713 | combine_after_change_list = Qnil; | |
101e446f | 2714 | combine_after_change_buffer = Qnil; |
fb2e7d14 | 2715 | |
60ea6052 RS |
2716 | DEFVAR_BOOL ("check-markers-debug-flag", &check_markers_debug_flag, |
2717 | "Non-nil means enable debugging checks for invalid marker positions."); | |
2718 | check_markers_debug_flag = 0; | |
fb2e7d14 | 2719 | DEFVAR_LISP ("combine-after-change-calls", &Vcombine_after_change_calls, |
60ea6052 | 2720 | "Used internally by the `combine-after-change-calls' macro."); |
fb2e7d14 RS |
2721 | Vcombine_after_change_calls = Qnil; |
2722 | ||
7baf49cf RS |
2723 | DEFVAR_BOOL ("inhibit-modification-hooks", &inhibit_modification_hooks, |
2724 | "Non-nil means don't run any of the hooks that respond to buffer changes.\n\ | |
2725 | This affects `before-change-functions' and `after-change-functions',\n\ | |
2726 | as well as hooks attached to text properties and overlays."); | |
2727 | inhibit_modification_hooks = 0; | |
2728 | ||
fb2e7d14 RS |
2729 | defsubr (&Scombine_after_change_execute); |
2730 | } |