Merge from emacs-24; up to 2012-12-31T11:35:13Z!rudalics@gmx.at
[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
954b166e
PE
232 bset_undo_list (current_buffer,
233 Fcons (Fcons (Qt, Fvisited_file_modtime ()),
234 BVAR (current_buffer, undo_list)));
c6953be1
JB
235}
236
da9319d5
RS
237/* Record a change in property PROP (whose old value was VAL)
238 for LENGTH characters starting at position BEG in BUFFER. */
239
90dd3e4f 240void
d311d28c 241record_property_change (ptrdiff_t beg, ptrdiff_t length,
c8a66ab8
EZ
242 Lisp_Object prop, Lisp_Object value,
243 Lisp_Object buffer)
da9319d5
RS
244{
245 Lisp_Object lbeg, lend, entry;
4591d6cb 246 struct buffer *obuf = current_buffer, *buf = XBUFFER (buffer);
da9319d5
RS
247 int boundary = 0;
248
4b4deea2 249 if (EQ (BVAR (buf, undo_list), Qt))
bdbe6f28
RS
250 return;
251
c58632fc
RS
252 /* Allocate a cons cell to be the undo boundary after this command. */
253 if (NILP (pending_boundary))
254 pending_boundary = Fcons (Qnil, Qnil);
255
4591d6cb 256 if (buf != last_undo_buffer)
da9319d5 257 boundary = 1;
4591d6cb 258 last_undo_buffer = buf;
da9319d5 259
da9319d5 260 /* Switch temporarily to the buffer that was changed. */
4591d6cb 261 current_buffer = buf;
da9319d5
RS
262
263 if (boundary)
264 Fundo_boundary ();
265
ad9cdce4 266 if (MODIFF <= SAVE_MODIFF)
da9319d5
RS
267 record_first_change ();
268
552bdbcf
KH
269 XSETINT (lbeg, beg);
270 XSETINT (lend, beg + length);
da9319d5 271 entry = Fcons (Qnil, Fcons (prop, Fcons (value, Fcons (lbeg, lend))));
39eb03f1
PE
272 bset_undo_list (current_buffer,
273 Fcons (entry, BVAR (current_buffer, undo_list)));
da9319d5
RS
274
275 current_buffer = obuf;
276}
277
a7ca3326 278DEFUN ("undo-boundary", Fundo_boundary, Sundo_boundary, 0, 0, 0,
8c1a1077
PJ
279 doc: /* Mark a boundary between units of undo.
280An undo command will stop at this point,
281but another undo command will undo to the previous boundary. */)
5842a27b 282 (void)
c6953be1
JB
283{
284 Lisp_Object tem;
4b4deea2 285 if (EQ (BVAR (current_buffer, undo_list), Qt))
c6953be1 286 return Qnil;
4b4deea2 287 tem = Fcar (BVAR (current_buffer, undo_list));
265a9e55 288 if (!NILP (tem))
c58632fc
RS
289 {
290 /* One way or another, cons nil onto the front of the undo list. */
291 if (!NILP (pending_boundary))
292 {
293 /* If we have preallocated the cons cell to use here,
294 use that one. */
4b4deea2 295 XSETCDR (pending_boundary, BVAR (current_buffer, undo_list));
39eb03f1 296 bset_undo_list (current_buffer, pending_boundary);
c58632fc
RS
297 pending_boundary = Qnil;
298 }
299 else
39eb03f1
PE
300 bset_undo_list (current_buffer,
301 Fcons (Qnil, BVAR (current_buffer, undo_list)));
c58632fc 302 }
4591d6cb
SM
303 last_boundary_position = PT;
304 last_boundary_buffer = current_buffer;
c6953be1
JB
305 return Qnil;
306}
307
308/* At garbage collection time, make an undo list shorter at the end,
137e23ea
RS
309 returning the truncated list. How this is done depends on the
310 variables undo-limit, undo-strong-limit and undo-outer-limit.
311 In some cases this works by calling undo-outer-limit-function. */
312
313void
971de7fb 314truncate_undo_list (struct buffer *b)
c6953be1 315{
137e23ea 316 Lisp_Object list;
c6953be1 317 Lisp_Object prev, next, last_boundary;
d311d28c 318 EMACS_INT size_so_far = 0;
c6953be1 319
137e23ea
RS
320 /* Make sure that calling undo-outer-limit-function
321 won't cause another GC. */
d311d28c 322 ptrdiff_t count = inhibit_garbage_collection ();
137e23ea
RS
323
324 /* Make the buffer current to get its local values of variables such
325 as undo_limit. Also so that Vundo_outer_limit_function can
326 tell which buffer to operate on. */
66322887 327 record_unwind_current_buffer ();
137e23ea
RS
328 set_buffer_internal (b);
329
4b4deea2 330 list = BVAR (b, undo_list);
137e23ea 331
c6953be1
JB
332 prev = Qnil;
333 next = list;
334 last_boundary = Qnil;
335
137e23ea 336 /* If the first element is an undo boundary, skip past it. */
c1d497be 337 if (CONSP (next) && NILP (XCAR (next)))
c6953be1
JB
338 {
339 /* Add in the space occupied by this element and its chain link. */
340 size_so_far += sizeof (struct Lisp_Cons);
341
342 /* Advance to next element. */
343 prev = next;
c1d497be 344 next = XCDR (next);
c6953be1 345 }
e3d5ca1e 346
137e23ea
RS
347 /* Always preserve at least the most recent undo record
348 unless it is really horribly big.
349
350 Skip, skip, skip the undo, skip, skip, skip the undo,
351 Skip, skip, skip the undo, skip to the undo bound'ry. */
352
c1d497be 353 while (CONSP (next) && ! NILP (XCAR (next)))
c6953be1
JB
354 {
355 Lisp_Object elt;
c1d497be 356 elt = XCAR (next);
c6953be1
JB
357
358 /* Add in the space occupied by this element and its chain link. */
359 size_so_far += sizeof (struct Lisp_Cons);
38c0d37c 360 if (CONSP (elt))
c6953be1
JB
361 {
362 size_so_far += sizeof (struct Lisp_Cons);
c1d497be 363 if (STRINGP (XCAR (elt)))
c6953be1 364 size_so_far += (sizeof (struct Lisp_String) - 1
d5db4077 365 + SCHARS (XCAR (elt)));
c6953be1
JB
366 }
367
368 /* Advance to next element. */
369 prev = next;
c1d497be 370 next = XCDR (next);
c6953be1 371 }
e3d5ca1e 372
137e23ea
RS
373 /* If by the first boundary we have already passed undo_outer_limit,
374 we're heading for memory full, so offer to clear out the list. */
81c1cf71
RS
375 if (INTEGERP (Vundo_outer_limit)
376 && size_so_far > XINT (Vundo_outer_limit)
137e23ea
RS
377 && !NILP (Vundo_outer_limit_function))
378 {
4591d6cb
SM
379 Lisp_Object tem;
380 struct buffer *temp = last_undo_buffer;
137e23ea
RS
381
382 /* Normally the function this calls is undo-outer-limit-truncate. */
88fde92a
KR
383 tem = call1 (Vundo_outer_limit_function, make_number (size_so_far));
384 if (! NILP (tem))
137e23ea
RS
385 {
386 /* The function is responsible for making
387 any desired changes in buffer-undo-list. */
388 unbind_to (count, Qnil);
389 return;
390 }
391 /* That function probably used the minibuffer, and if so, that
392 changed last_undo_buffer. Change it back so that we don't
393 force next change to make an undo boundary here. */
394 last_undo_buffer = temp;
395 }
396
38c0d37c 397 if (CONSP (next))
c6953be1
JB
398 last_boundary = prev;
399
137e23ea 400 /* Keep additional undo data, if it fits in the limits. */
38c0d37c 401 while (CONSP (next))
c6953be1
JB
402 {
403 Lisp_Object elt;
c1d497be 404 elt = XCAR (next);
c6953be1
JB
405
406 /* When we get to a boundary, decide whether to truncate
137e23ea 407 either before or after it. The lower threshold, undo_limit,
c6953be1 408 tells us to truncate after it. If its size pushes past
137e23ea 409 the higher threshold undo_strong_limit, we truncate before it. */
265a9e55 410 if (NILP (elt))
c6953be1 411 {
137e23ea 412 if (size_so_far > undo_strong_limit)
c6953be1
JB
413 break;
414 last_boundary = prev;
137e23ea 415 if (size_so_far > undo_limit)
c6953be1
JB
416 break;
417 }
418
419 /* Add in the space occupied by this element and its chain link. */
420 size_so_far += sizeof (struct Lisp_Cons);
38c0d37c 421 if (CONSP (elt))
c6953be1
JB
422 {
423 size_so_far += sizeof (struct Lisp_Cons);
c1d497be 424 if (STRINGP (XCAR (elt)))
c6953be1 425 size_so_far += (sizeof (struct Lisp_String) - 1
d5db4077 426 + SCHARS (XCAR (elt)));
c6953be1
JB
427 }
428
429 /* Advance to next element. */
430 prev = next;
c1d497be 431 next = XCDR (next);
c6953be1
JB
432 }
433
434 /* If we scanned the whole list, it is short enough; don't change it. */
265a9e55 435 if (NILP (next))
137e23ea 436 ;
c6953be1 437 /* Truncate at the boundary where we decided to truncate. */
137e23ea
RS
438 else if (!NILP (last_boundary))
439 XSETCDR (last_boundary, Qnil);
440 /* There's nothing we decided to keep, so clear it out. */
c6953be1 441 else
39eb03f1 442 bset_undo_list (b, Qnil);
137e23ea
RS
443
444 unbind_to (count, Qnil);
c6953be1 445}
71873e2b 446
c6953be1 447\f
dfcf069d 448void
971de7fb 449syms_of_undo (void)
c6953be1 450{
cd3520a4
JB
451 DEFSYM (Qinhibit_read_only, "inhibit-read-only");
452 DEFSYM (Qapply, "apply");
49be18c9 453
c58632fc
RS
454 pending_boundary = Qnil;
455 staticpro (&pending_boundary);
456
4591d6cb
SM
457 last_undo_buffer = NULL;
458 last_boundary_buffer = NULL;
459
c6953be1 460 defsubr (&Sundo_boundary);
137e23ea 461
29208e82 462 DEFVAR_INT ("undo-limit", undo_limit,
137e23ea
RS
463 doc: /* Keep no more undo information once it exceeds this size.
464This limit is applied when garbage collection happens.
465When a previous command increases the total undo list size past this
466value, the earlier commands that came before it are forgotten.
467
468The size is counted as the number of bytes occupied,
469which includes both saved text and other data. */);
2159bd06 470 undo_limit = 80000;
137e23ea 471
29208e82 472 DEFVAR_INT ("undo-strong-limit", undo_strong_limit,
137e23ea
RS
473 doc: /* Don't keep more than this much size of undo information.
474This limit is applied when garbage collection happens.
475When a previous command increases the total undo list size past this
476value, that command and the earlier commands that came before it are forgotten.
477However, the most recent buffer-modifying command's undo info
478is never discarded for this reason.
479
480The size is counted as the number of bytes occupied,
481which includes both saved text and other data. */);
2159bd06 482 undo_strong_limit = 120000;
137e23ea 483
29208e82 484 DEFVAR_LISP ("undo-outer-limit", Vundo_outer_limit,
137e23ea
RS
485 doc: /* Outer limit on size of undo information for one command.
486At garbage collection time, if the current command has produced
62d776fd
LT
487more than this much undo information, it discards the info and displays
488a warning. This is a last-ditch limit to prevent memory overflow.
137e23ea 489
62d776fd
LT
490The size is counted as the number of bytes occupied, which includes
491both saved text and other data. A value of nil means no limit. In
492this case, accumulating one huge undo entry could make Emacs crash as
493a result of memory overflow.
137e23ea
RS
494
495In fact, this calls the function which is the value of
496`undo-outer-limit-function' with one argument, the size.
497The text above describes the behavior of the function
498that variable usually specifies. */);
2159bd06 499 Vundo_outer_limit = make_number (12000000);
137e23ea 500
29208e82 501 DEFVAR_LISP ("undo-outer-limit-function", Vundo_outer_limit_function,
137e23ea
RS
502 doc: /* Function to call when an undo list exceeds `undo-outer-limit'.
503This function is called with one argument, the current undo list size
504for the most recent command (since the last undo boundary).
505If the function returns t, that means truncation has been fully handled.
506If it returns nil, the other forms of truncation are done.
507
508Garbage collection is inhibited around the call to this function,
509so it must make sure not to do a lot of consing. */);
510 Vundo_outer_limit_function = Qnil;
8abe0f97 511
29208e82 512 DEFVAR_BOOL ("undo-inhibit-record-point", undo_inhibit_record_point,
8abe0f97
MR
513 doc: /* Non-nil means do not record `point' in `buffer-undo-list'. */);
514 undo_inhibit_record_point = 0;
c6953be1 515}