Fix bug #9221 with memory leak in bidi display.
[bpt/emacs.git] / src / undo.c
CommitLineData
c6953be1 1/* undo handling for GNU Emacs.
73b0cd50 2 Copyright (C) 1990, 1993-1994, 2000-2011 Free Software Foundation, Inc.
c6953be1
JB
3
4This file is part of GNU Emacs.
5
9ec0b715 6GNU Emacs is free software: you can redistribute it and/or modify
3b7ad313 7it under the terms of the GNU General Public License as published by
9ec0b715
GM
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
3b7ad313 10
c6953be1 11GNU Emacs is distributed in the hope that it will be useful,
3b7ad313
EN
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
9ec0b715 17along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
c6953be1
JB
18
19
18160b98 20#include <config.h>
d7306fe6 21#include <setjmp.h>
c6953be1
JB
22#include "lisp.h"
23#include "buffer.h"
4e665715 24#include "commands.h"
91e25f5e 25#include "window.h"
c6953be1
JB
26
27/* Last buffer for which undo information was recorded. */
4591d6cb 28/* BEWARE: This is not traced by the GC, so never dereference it! */
2b96acb7 29static struct buffer *last_undo_buffer;
4591d6cb
SM
30
31/* Position of point last time we inserted a boundary. */
2b96acb7
PE
32static struct buffer *last_boundary_buffer;
33static EMACS_INT last_boundary_position;
c6953be1 34
f87a68b3
RS
35Lisp_Object Qinhibit_read_only;
36
49be18c9
KS
37/* Marker for function call undo list elements. */
38
39Lisp_Object Qapply;
40
c58632fc
RS
41/* The first time a command records something for undo.
42 it also allocates the undo-boundary object
43 which will be added to the list at the end of the command.
44 This ensures we can't run out of space while trying to make
45 an undo-boundary. */
2b96acb7 46static Lisp_Object pending_boundary;
c58632fc 47
6396140a 48/* Record point as it was at beginning of this command (if necessary)
8abe0f97 49 and prepare the undo info for recording a change.
6396140a
SM
50 PT is the position of point that will naturally occur as a result of the
51 undo record that will be added just after this command terminates. */
c6953be1 52
6396140a 53static void
c8a66ab8 54record_point (EMACS_INT pt)
c6953be1 55{
6396140a 56 int at_boundary;
bdbe6f28 57
4591d6cb 58 /* Don't record position of pt when undo_inhibit_record_point holds. */
8abe0f97
MR
59 if (undo_inhibit_record_point)
60 return;
61
c58632fc
RS
62 /* Allocate a cons cell to be the undo boundary after this command. */
63 if (NILP (pending_boundary))
64 pending_boundary = Fcons (Qnil, Qnil);
65
3ecc1163
MR
66 if ((current_buffer != last_undo_buffer)
67 /* Don't call Fundo_boundary for the first change. Otherwise we
68 risk overwriting last_boundary_position in Fundo_boundary with
69 PT of the current buffer and as a consequence not insert an
70 undo boundary because last_boundary_position will equal pt in
71 the test at the end of the present function (Bug#731). */
72 && (MODIFF > SAVE_MODIFF))
c6953be1 73 Fundo_boundary ();
4591d6cb 74 last_undo_buffer = current_buffer;
c6953be1 75
4b4deea2 76 if (CONSP (BVAR (current_buffer, undo_list)))
6396140a
SM
77 {
78 /* Set AT_BOUNDARY to 1 only when we have nothing other than
79 marker adjustment before undo boundary. */
80
4b4deea2 81 Lisp_Object tail = BVAR (current_buffer, undo_list), elt;
6396140a
SM
82
83 while (1)
84 {
85 if (NILP (tail))
86 elt = Qnil;
87 else
88 elt = XCAR (tail);
89 if (NILP (elt) || ! (CONSP (elt) && MARKERP (XCAR (elt))))
90 break;
91 tail = XCDR (tail);
92 }
93 at_boundary = NILP (elt);
94 }
95 else
96 at_boundary = 1;
97
ad9cdce4 98 if (MODIFF <= SAVE_MODIFF)
c6953be1
JB
99 record_first_change ();
100
177c0ea7 101 /* If we are just after an undo boundary, and
6396140a
SM
102 point wasn't at start of deleted range, record where it was. */
103 if (at_boundary
4591d6cb
SM
104 && current_buffer == last_boundary_buffer
105 && last_boundary_position != pt)
4b4deea2
TT
106 BVAR (current_buffer, undo_list)
107 = Fcons (make_number (last_boundary_position), BVAR (current_buffer, undo_list));
6396140a
SM
108}
109
110/* Record an insertion that just happened or is about to happen,
111 for LENGTH characters at position BEG.
112 (It is possible to record an insertion before or after the fact
113 because we don't need to record the contents.) */
114
115void
c8a66ab8 116record_insert (EMACS_INT beg, EMACS_INT length)
6396140a
SM
117{
118 Lisp_Object lbeg, lend;
119
4b4deea2 120 if (EQ (BVAR (current_buffer, undo_list), Qt))
6396140a
SM
121 return;
122
123 record_point (beg);
124
c6953be1
JB
125 /* If this is following another insertion and consecutive with it
126 in the buffer, combine the two. */
4b4deea2 127 if (CONSP (BVAR (current_buffer, undo_list)))
c6953be1
JB
128 {
129 Lisp_Object elt;
4b4deea2 130 elt = XCAR (BVAR (current_buffer, undo_list));
38c0d37c 131 if (CONSP (elt)
c1d497be
KR
132 && INTEGERP (XCAR (elt))
133 && INTEGERP (XCDR (elt))
134 && XINT (XCDR (elt)) == beg)
c6953be1 135 {
f3fbd155 136 XSETCDR (elt, make_number (beg + length));
c6953be1
JB
137 return;
138 }
139 }
140
53480e99
KH
141 XSETFASTINT (lbeg, beg);
142 XSETINT (lend, beg + length);
4b4deea2
TT
143 BVAR (current_buffer, undo_list) = Fcons (Fcons (lbeg, lend),
144 BVAR (current_buffer, undo_list));
c6953be1
JB
145}
146
147/* Record that a deletion is about to take place,
e928d437 148 of the characters in STRING, at location BEG. */
c6953be1 149
ff1aa840 150void
c8a66ab8 151record_delete (EMACS_INT beg, Lisp_Object string)
c6953be1 152{
e928d437 153 Lisp_Object sbeg;
c6953be1 154
4b4deea2 155 if (EQ (BVAR (current_buffer, undo_list), Qt))
bdbe6f28
RS
156 return;
157
d5db4077 158 if (PT == beg + SCHARS (string))
cbc1b668 159 {
6396140a
SM
160 XSETINT (sbeg, -beg);
161 record_point (PT);
cbc1b668
KH
162 }
163 else
6396140a
SM
164 {
165 XSETFASTINT (sbeg, beg);
166 record_point (beg);
167 }
350bce56 168
4b4deea2
TT
169 BVAR (current_buffer, undo_list)
170 = Fcons (Fcons (string, sbeg), BVAR (current_buffer, undo_list));
c6953be1
JB
171}
172
714bced9
RS
173/* Record the fact that MARKER is about to be adjusted by ADJUSTMENT.
174 This is done only when a marker points within text being deleted,
175 because that's the only case where an automatic marker adjustment
176 won't be inverted automatically by undoing the buffer modification. */
177
ff1aa840 178void
c8a66ab8 179record_marker_adjustment (Lisp_Object marker, EMACS_INT adjustment)
714bced9 180{
4b4deea2 181 if (EQ (BVAR (current_buffer, undo_list), Qt))
714bced9
RS
182 return;
183
184 /* Allocate a cons cell to be the undo boundary after this command. */
185 if (NILP (pending_boundary))
186 pending_boundary = Fcons (Qnil, Qnil);
187
4591d6cb 188 if (current_buffer != last_undo_buffer)
714bced9 189 Fundo_boundary ();
4591d6cb 190 last_undo_buffer = current_buffer;
714bced9 191
4b4deea2 192 BVAR (current_buffer, undo_list)
714bced9 193 = Fcons (Fcons (marker, make_number (adjustment)),
4b4deea2 194 BVAR (current_buffer, undo_list));
714bced9
RS
195}
196
c6953be1
JB
197/* Record that a replacement is about to take place,
198 for LENGTH characters at location BEG.
e928d437 199 The replacement must not change the number of characters. */
c6953be1 200
ff1aa840 201void
c8a66ab8 202record_change (EMACS_INT beg, EMACS_INT length)
c6953be1 203{
e928d437 204 record_delete (beg, make_buffer_string (beg, beg + length, 1));
c6953be1
JB
205 record_insert (beg, length);
206}
207\f
208/* Record that an unmodified buffer is about to be changed.
209 Record the file modification date so that when undoing this entry
210 we can tell whether it is obsolete because the file was saved again. */
211
90dd3e4f 212void
971de7fb 213record_first_change (void)
c6953be1 214{
ad9cdce4 215 struct buffer *base_buffer = current_buffer;
0736cafe 216
4b4deea2 217 if (EQ (BVAR (current_buffer, undo_list), Qt))
0736cafe
RS
218 return;
219
4591d6cb 220 if (current_buffer != last_undo_buffer)
0736cafe 221 Fundo_boundary ();
4591d6cb 222 last_undo_buffer = current_buffer;
0736cafe 223
ad9cdce4
RS
224 if (base_buffer->base_buffer)
225 base_buffer = base_buffer->base_buffer;
226
be44ca6c
PE
227 BVAR (current_buffer, undo_list) =
228 Fcons (Fcons (Qt, INTEGER_TO_CONS (base_buffer->modtime)),
229 BVAR (current_buffer, undo_list));
c6953be1
JB
230}
231
da9319d5
RS
232/* Record a change in property PROP (whose old value was VAL)
233 for LENGTH characters starting at position BEG in BUFFER. */
234
90dd3e4f 235void
c8a66ab8
EZ
236record_property_change (EMACS_INT beg, EMACS_INT length,
237 Lisp_Object prop, Lisp_Object value,
238 Lisp_Object buffer)
da9319d5
RS
239{
240 Lisp_Object lbeg, lend, entry;
4591d6cb 241 struct buffer *obuf = current_buffer, *buf = XBUFFER (buffer);
da9319d5
RS
242 int boundary = 0;
243
4b4deea2 244 if (EQ (BVAR (buf, undo_list), Qt))
bdbe6f28
RS
245 return;
246
c58632fc
RS
247 /* Allocate a cons cell to be the undo boundary after this command. */
248 if (NILP (pending_boundary))
249 pending_boundary = Fcons (Qnil, Qnil);
250
4591d6cb 251 if (buf != last_undo_buffer)
da9319d5 252 boundary = 1;
4591d6cb 253 last_undo_buffer = buf;
da9319d5 254
da9319d5 255 /* Switch temporarily to the buffer that was changed. */
4591d6cb 256 current_buffer = buf;
da9319d5
RS
257
258 if (boundary)
259 Fundo_boundary ();
260
ad9cdce4 261 if (MODIFF <= SAVE_MODIFF)
da9319d5
RS
262 record_first_change ();
263
552bdbcf
KH
264 XSETINT (lbeg, beg);
265 XSETINT (lend, beg + length);
da9319d5 266 entry = Fcons (Qnil, Fcons (prop, Fcons (value, Fcons (lbeg, lend))));
4b4deea2 267 BVAR (current_buffer, undo_list) = Fcons (entry, BVAR (current_buffer, undo_list));
da9319d5
RS
268
269 current_buffer = obuf;
270}
271
a7ca3326 272DEFUN ("undo-boundary", Fundo_boundary, Sundo_boundary, 0, 0, 0,
8c1a1077
PJ
273 doc: /* Mark a boundary between units of undo.
274An undo command will stop at this point,
275but another undo command will undo to the previous boundary. */)
5842a27b 276 (void)
c6953be1
JB
277{
278 Lisp_Object tem;
4b4deea2 279 if (EQ (BVAR (current_buffer, undo_list), Qt))
c6953be1 280 return Qnil;
4b4deea2 281 tem = Fcar (BVAR (current_buffer, undo_list));
265a9e55 282 if (!NILP (tem))
c58632fc
RS
283 {
284 /* One way or another, cons nil onto the front of the undo list. */
285 if (!NILP (pending_boundary))
286 {
287 /* If we have preallocated the cons cell to use here,
288 use that one. */
4b4deea2
TT
289 XSETCDR (pending_boundary, BVAR (current_buffer, undo_list));
290 BVAR (current_buffer, undo_list) = pending_boundary;
c58632fc
RS
291 pending_boundary = Qnil;
292 }
293 else
4b4deea2 294 BVAR (current_buffer, undo_list) = Fcons (Qnil, BVAR (current_buffer, undo_list));
c58632fc 295 }
4591d6cb
SM
296 last_boundary_position = PT;
297 last_boundary_buffer = current_buffer;
c6953be1
JB
298 return Qnil;
299}
300
301/* At garbage collection time, make an undo list shorter at the end,
137e23ea
RS
302 returning the truncated list. How this is done depends on the
303 variables undo-limit, undo-strong-limit and undo-outer-limit.
304 In some cases this works by calling undo-outer-limit-function. */
305
306void
971de7fb 307truncate_undo_list (struct buffer *b)
c6953be1 308{
137e23ea 309 Lisp_Object list;
c6953be1
JB
310 Lisp_Object prev, next, last_boundary;
311 int size_so_far = 0;
312
137e23ea
RS
313 /* Make sure that calling undo-outer-limit-function
314 won't cause another GC. */
315 int count = inhibit_garbage_collection ();
316
317 /* Make the buffer current to get its local values of variables such
318 as undo_limit. Also so that Vundo_outer_limit_function can
319 tell which buffer to operate on. */
320 record_unwind_protect (set_buffer_if_live, Fcurrent_buffer ());
321 set_buffer_internal (b);
322
4b4deea2 323 list = BVAR (b, undo_list);
137e23ea 324
c6953be1
JB
325 prev = Qnil;
326 next = list;
327 last_boundary = Qnil;
328
137e23ea 329 /* If the first element is an undo boundary, skip past it. */
c1d497be 330 if (CONSP (next) && NILP (XCAR (next)))
c6953be1
JB
331 {
332 /* Add in the space occupied by this element and its chain link. */
333 size_so_far += sizeof (struct Lisp_Cons);
334
335 /* Advance to next element. */
336 prev = next;
c1d497be 337 next = XCDR (next);
c6953be1 338 }
e3d5ca1e 339
137e23ea
RS
340 /* Always preserve at least the most recent undo record
341 unless it is really horribly big.
342
343 Skip, skip, skip the undo, skip, skip, skip the undo,
344 Skip, skip, skip the undo, skip to the undo bound'ry. */
345
c1d497be 346 while (CONSP (next) && ! NILP (XCAR (next)))
c6953be1
JB
347 {
348 Lisp_Object elt;
c1d497be 349 elt = XCAR (next);
c6953be1
JB
350
351 /* Add in the space occupied by this element and its chain link. */
352 size_so_far += sizeof (struct Lisp_Cons);
38c0d37c 353 if (CONSP (elt))
c6953be1
JB
354 {
355 size_so_far += sizeof (struct Lisp_Cons);
c1d497be 356 if (STRINGP (XCAR (elt)))
c6953be1 357 size_so_far += (sizeof (struct Lisp_String) - 1
d5db4077 358 + SCHARS (XCAR (elt)));
c6953be1
JB
359 }
360
361 /* Advance to next element. */
362 prev = next;
c1d497be 363 next = XCDR (next);
c6953be1 364 }
e3d5ca1e 365
137e23ea
RS
366 /* If by the first boundary we have already passed undo_outer_limit,
367 we're heading for memory full, so offer to clear out the list. */
81c1cf71
RS
368 if (INTEGERP (Vundo_outer_limit)
369 && size_so_far > XINT (Vundo_outer_limit)
137e23ea
RS
370 && !NILP (Vundo_outer_limit_function))
371 {
4591d6cb
SM
372 Lisp_Object tem;
373 struct buffer *temp = last_undo_buffer;
137e23ea
RS
374
375 /* Normally the function this calls is undo-outer-limit-truncate. */
88fde92a
KR
376 tem = call1 (Vundo_outer_limit_function, make_number (size_so_far));
377 if (! NILP (tem))
137e23ea
RS
378 {
379 /* The function is responsible for making
380 any desired changes in buffer-undo-list. */
381 unbind_to (count, Qnil);
382 return;
383 }
384 /* That function probably used the minibuffer, and if so, that
385 changed last_undo_buffer. Change it back so that we don't
386 force next change to make an undo boundary here. */
387 last_undo_buffer = temp;
388 }
389
38c0d37c 390 if (CONSP (next))
c6953be1
JB
391 last_boundary = prev;
392
137e23ea 393 /* Keep additional undo data, if it fits in the limits. */
38c0d37c 394 while (CONSP (next))
c6953be1
JB
395 {
396 Lisp_Object elt;
c1d497be 397 elt = XCAR (next);
c6953be1
JB
398
399 /* When we get to a boundary, decide whether to truncate
137e23ea 400 either before or after it. The lower threshold, undo_limit,
c6953be1 401 tells us to truncate after it. If its size pushes past
137e23ea 402 the higher threshold undo_strong_limit, we truncate before it. */
265a9e55 403 if (NILP (elt))
c6953be1 404 {
137e23ea 405 if (size_so_far > undo_strong_limit)
c6953be1
JB
406 break;
407 last_boundary = prev;
137e23ea 408 if (size_so_far > undo_limit)
c6953be1
JB
409 break;
410 }
411
412 /* Add in the space occupied by this element and its chain link. */
413 size_so_far += sizeof (struct Lisp_Cons);
38c0d37c 414 if (CONSP (elt))
c6953be1
JB
415 {
416 size_so_far += sizeof (struct Lisp_Cons);
c1d497be 417 if (STRINGP (XCAR (elt)))
c6953be1 418 size_so_far += (sizeof (struct Lisp_String) - 1
d5db4077 419 + SCHARS (XCAR (elt)));
c6953be1
JB
420 }
421
422 /* Advance to next element. */
423 prev = next;
c1d497be 424 next = XCDR (next);
c6953be1
JB
425 }
426
427 /* If we scanned the whole list, it is short enough; don't change it. */
265a9e55 428 if (NILP (next))
137e23ea 429 ;
c6953be1 430 /* Truncate at the boundary where we decided to truncate. */
137e23ea
RS
431 else if (!NILP (last_boundary))
432 XSETCDR (last_boundary, Qnil);
433 /* There's nothing we decided to keep, so clear it out. */
c6953be1 434 else
4b4deea2 435 BVAR (b, undo_list) = Qnil;
137e23ea
RS
436
437 unbind_to (count, Qnil);
c6953be1
JB
438}
439\f
440DEFUN ("primitive-undo", Fprimitive_undo, Sprimitive_undo, 2, 2, 0,
8c1a1077
PJ
441 doc: /* Undo N records from the front of the list LIST.
442Return what remains of the list. */)
5842a27b 443 (Lisp_Object n, Lisp_Object list)
c6953be1 444{
de65837b
KH
445 struct gcpro gcpro1, gcpro2;
446 Lisp_Object next;
331379bf 447 int count = SPECPDL_INDEX ();
de65837b 448 register int arg;
4ac03187
KS
449 Lisp_Object oldlist;
450 int did_apply = 0;
177c0ea7 451
c6953be1
JB
452#if 0 /* This is a good feature, but would make undo-start
453 unable to do what is expected. */
454 Lisp_Object tem;
455
456 /* If the head of the list is a boundary, it is the boundary
457 preceding this command. Get rid of it and don't count it. */
458 tem = Fcar (list);
265a9e55 459 if (NILP (tem))
c6953be1
JB
460 list = Fcdr (list);
461#endif
462
b7826503 463 CHECK_NUMBER (n);
de65837b
KH
464 arg = XINT (n);
465 next = Qnil;
466 GCPRO2 (next, list);
4ac03187
KS
467 /* I don't think we need to gcpro oldlist, as we use it only
468 to check for EQ. ++kfs */
de65837b 469
38d56be3
GM
470 /* In a writable buffer, enable undoing read-only text that is so
471 because of text properties. */
4b4deea2 472 if (NILP (BVAR (current_buffer, read_only)))
f87a68b3
RS
473 specbind (Qinhibit_read_only, Qt);
474
8c757fd7
GM
475 /* Don't let `intangible' properties interfere with undo. */
476 specbind (Qinhibit_point_motion_hooks, Qt);
477
4b4deea2 478 oldlist = BVAR (current_buffer, undo_list);
4ac03187 479
c6953be1
JB
480 while (arg > 0)
481 {
c3b09bbf 482 while (CONSP (list))
c6953be1 483 {
c3b09bbf
SM
484 next = XCAR (list);
485 list = XCDR (list);
350bce56 486 /* Exit inner loop at undo boundary. */
265a9e55 487 if (NILP (next))
c6953be1 488 break;
350bce56 489 /* Handle an integer by setting point to that value. */
38c0d37c 490 if (INTEGERP (next))
350bce56 491 SET_PT (clip_to_bounds (BEGV, XINT (next), ZV));
38c0d37c 492 else if (CONSP (next))
c6953be1 493 {
350bce56
RS
494 Lisp_Object car, cdr;
495
c3b09bbf
SM
496 car = XCAR (next);
497 cdr = XCDR (next);
350bce56 498 if (EQ (car, Qt))
c6953be1 499 {
350bce56 500 /* Element (t high . low) records previous modtime. */
ad9cdce4 501 struct buffer *base_buffer = current_buffer;
be44ca6c
PE
502 time_t mod_time;
503 CONS_TO_INTEGER (cdr, time_t, mod_time);
ad9cdce4
RS
504
505 if (current_buffer->base_buffer)
506 base_buffer = current_buffer->base_buffer;
507
350bce56
RS
508 /* If this records an obsolete save
509 (not matching the actual disk file)
510 then don't mark unmodified. */
ad9cdce4 511 if (mod_time != base_buffer->modtime)
103dcb38 512 continue;
e6dd6080 513#ifdef CLASH_DETECTION
350bce56 514 Funlock_buffer ();
e6dd6080 515#endif /* CLASH_DETECTION */
350bce56 516 Fset_buffer_modified_p (Qnil);
c6953be1 517 }
d8552b2f 518 else if (EQ (car, Qnil))
da9319d5 519 {
6887bce5 520 /* Element (nil PROP VAL BEG . END) is property change. */
da9319d5
RS
521 Lisp_Object beg, end, prop, val;
522
523 prop = Fcar (cdr);
524 cdr = Fcdr (cdr);
525 val = Fcar (cdr);
526 cdr = Fcdr (cdr);
527 beg = Fcar (cdr);
528 end = Fcdr (cdr);
529
9e568684
CY
530 if (XINT (beg) < BEGV || XINT (end) > ZV)
531 error ("Changes to be undone are outside visible portion of buffer");
da9319d5
RS
532 Fput_text_property (beg, end, prop, val, Qnil);
533 }
38c0d37c 534 else if (INTEGERP (car) && INTEGERP (cdr))
c6953be1 535 {
350bce56 536 /* Element (BEG . END) means range was inserted. */
350bce56
RS
537
538 if (XINT (car) < BEGV
539 || XINT (cdr) > ZV)
c6953be1 540 error ("Changes to be undone are outside visible portion of buffer");
f28f04cc
RS
541 /* Set point first thing, so that undoing this undo
542 does not send point back to where it is now. */
350bce56 543 Fgoto_char (car);
f28f04cc 544 Fdelete_region (car, cdr);
350bce56 545 }
49be18c9 546 else if (EQ (car, Qapply))
6887bce5 547 {
3419757d 548 /* Element (apply FUN . ARGS) means call FUN to undo. */
a7a39468
KS
549 struct buffer *save_buffer = current_buffer;
550
49be18c9 551 car = Fcar (cdr);
3419757d 552 cdr = Fcdr (cdr);
49be18c9
KS
553 if (INTEGERP (car))
554 {
3419757d
SM
555 /* Long format: (apply DELTA START END FUN . ARGS). */
556 Lisp_Object delta = car;
557 Lisp_Object start = Fcar (cdr);
558 Lisp_Object end = Fcar (Fcdr (cdr));
559 Lisp_Object start_mark = Fcopy_marker (start, Qnil);
560 Lisp_Object end_mark = Fcopy_marker (end, Qt);
561
562 cdr = Fcdr (Fcdr (cdr));
563 apply1 (Fcar (cdr), Fcdr (cdr));
564
565 /* Check that the function did what the entry said it
566 would do. */
567 if (!EQ (start, Fmarker_position (start_mark))
568 || (XINT (delta) + XINT (end)
569 != marker_position (end_mark)))
570 error ("Changes to be undone by function different than announced");
571 Fset_marker (start_mark, Qnil, Qnil);
572 Fset_marker (end_mark, Qnil, Qnil);
49be18c9 573 }
3419757d
SM
574 else
575 apply1 (car, cdr);
a7a39468
KS
576
577 if (save_buffer != current_buffer)
578 error ("Undo function switched buffer");
4ac03187 579 did_apply = 1;
6887bce5 580 }
38c0d37c 581 else if (STRINGP (car) && INTEGERP (cdr))
350bce56
RS
582 {
583 /* Element (STRING . POS) means STRING was deleted. */
584 Lisp_Object membuf;
c8a66ab8 585 EMACS_INT pos = XINT (cdr);
350bce56
RS
586
587 membuf = car;
588 if (pos < 0)
589 {
590 if (-pos < BEGV || -pos > ZV)
591 error ("Changes to be undone are outside visible portion of buffer");
592 SET_PT (-pos);
593 Finsert (1, &membuf);
594 }
595 else
596 {
597 if (pos < BEGV || pos > ZV)
598 error ("Changes to be undone are outside visible portion of buffer");
599 SET_PT (pos);
600
b2adc409
RS
601 /* Now that we record marker adjustments
602 (caused by deletion) for undo,
603 we should always insert after markers,
604 so that undoing the marker adjustments
605 put the markers back in the right place. */
606 Finsert (1, &membuf);
350bce56
RS
607 SET_PT (pos);
608 }
c6953be1 609 }
714bced9
RS
610 else if (MARKERP (car) && INTEGERP (cdr))
611 {
612 /* (MARKER . INTEGER) means a marker MARKER
613 was adjusted by INTEGER. */
614 if (XMARKER (car)->buffer)
615 Fset_marker (car,
616 make_number (marker_position (car) - XINT (cdr)),
617 Fmarker_buffer (car));
618 }
c6953be1
JB
619 }
620 }
621 arg--;
622 }
623
4ac03187
KS
624
625 /* Make sure an apply entry produces at least one undo entry,
626 so the test in `undo' for continuing an undo series
627 will work right. */
628 if (did_apply
4b4deea2
TT
629 && EQ (oldlist, BVAR (current_buffer, undo_list)))
630 BVAR (current_buffer, undo_list)
631 = Fcons (list3 (Qapply, Qcdr, Qnil), BVAR (current_buffer, undo_list));
4ac03187 632
de65837b 633 UNGCPRO;
f87a68b3 634 return unbind_to (count, list);
c6953be1 635}
6887bce5 636\f
dfcf069d 637void
971de7fb 638syms_of_undo (void)
c6953be1 639{
cd3520a4
JB
640 DEFSYM (Qinhibit_read_only, "inhibit-read-only");
641 DEFSYM (Qapply, "apply");
49be18c9 642
c58632fc
RS
643 pending_boundary = Qnil;
644 staticpro (&pending_boundary);
645
4591d6cb
SM
646 last_undo_buffer = NULL;
647 last_boundary_buffer = NULL;
648
c6953be1
JB
649 defsubr (&Sprimitive_undo);
650 defsubr (&Sundo_boundary);
137e23ea 651
29208e82 652 DEFVAR_INT ("undo-limit", undo_limit,
137e23ea
RS
653 doc: /* Keep no more undo information once it exceeds this size.
654This limit is applied when garbage collection happens.
655When a previous command increases the total undo list size past this
656value, the earlier commands that came before it are forgotten.
657
658The size is counted as the number of bytes occupied,
659which includes both saved text and other data. */);
2159bd06 660 undo_limit = 80000;
137e23ea 661
29208e82 662 DEFVAR_INT ("undo-strong-limit", undo_strong_limit,
137e23ea
RS
663 doc: /* Don't keep more than this much size of undo information.
664This limit is applied when garbage collection happens.
665When a previous command increases the total undo list size past this
666value, that command and the earlier commands that came before it are forgotten.
667However, the most recent buffer-modifying command's undo info
668is never discarded for this reason.
669
670The size is counted as the number of bytes occupied,
671which includes both saved text and other data. */);
2159bd06 672 undo_strong_limit = 120000;
137e23ea 673
29208e82 674 DEFVAR_LISP ("undo-outer-limit", Vundo_outer_limit,
137e23ea
RS
675 doc: /* Outer limit on size of undo information for one command.
676At garbage collection time, if the current command has produced
62d776fd
LT
677more than this much undo information, it discards the info and displays
678a warning. This is a last-ditch limit to prevent memory overflow.
137e23ea 679
62d776fd
LT
680The size is counted as the number of bytes occupied, which includes
681both saved text and other data. A value of nil means no limit. In
682this case, accumulating one huge undo entry could make Emacs crash as
683a result of memory overflow.
137e23ea
RS
684
685In fact, this calls the function which is the value of
686`undo-outer-limit-function' with one argument, the size.
687The text above describes the behavior of the function
688that variable usually specifies. */);
2159bd06 689 Vundo_outer_limit = make_number (12000000);
137e23ea 690
29208e82 691 DEFVAR_LISP ("undo-outer-limit-function", Vundo_outer_limit_function,
137e23ea
RS
692 doc: /* Function to call when an undo list exceeds `undo-outer-limit'.
693This function is called with one argument, the current undo list size
694for the most recent command (since the last undo boundary).
695If the function returns t, that means truncation has been fully handled.
696If it returns nil, the other forms of truncation are done.
697
698Garbage collection is inhibited around the call to this function,
699so it must make sure not to do a lot of consing. */);
700 Vundo_outer_limit_function = Qnil;
8abe0f97 701
29208e82 702 DEFVAR_BOOL ("undo-inhibit-record-point", undo_inhibit_record_point,
8abe0f97
MR
703 doc: /* Non-nil means do not record `point' in `buffer-undo-list'. */);
704 undo_inhibit_record_point = 0;
c6953be1 705}