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