aboutsummaryrefslogtreecommitdiffstats
path: root/src/undo.c
diff options
context:
space:
mode:
authorEli Zaretskii2013-09-05 11:01:04 +0300
committerEli Zaretskii2013-09-05 11:01:04 +0300
commit41306318777a942420bc4feadbfacf662ea179dc (patch)
tree669e5cca02f95d6064ce73c0d3fbbf91b8c8b563 /src/undo.c
parent141f1ff7a40cda10f0558e891dd196a943a5082e (diff)
parent257b3b03cb1cff917e0b3b7832ad3eab5b59f257 (diff)
downloademacs-41306318777a942420bc4feadbfacf662ea179dc.tar.gz
emacs-41306318777a942420bc4feadbfacf662ea179dc.zip
Merge from trunk after a lot of time.
Diffstat (limited to 'src/undo.c')
-rw-r--r--src/undo.c249
1 files changed, 26 insertions, 223 deletions
diff --git a/src/undo.c b/src/undo.c
index 9b763984d7f..234b8510f0a 100644
--- a/src/undo.c
+++ b/src/undo.c
@@ -1,5 +1,6 @@
1/* undo handling for GNU Emacs. 1/* undo handling for GNU Emacs.
2 Copyright (C) 1990, 1993-1994, 2000-2012 Free Software Foundation, Inc. 2 Copyright (C) 1990, 1993-1994, 2000-2013 Free Software Foundation,
3 Inc.
3 4
4This file is part of GNU Emacs. 5This file is part of GNU Emacs.
5 6
@@ -18,8 +19,9 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
18 19
19 20
20#include <config.h> 21#include <config.h>
21#include <setjmp.h> 22
22#include "lisp.h" 23#include "lisp.h"
24#include "character.h"
23#include "buffer.h" 25#include "buffer.h"
24#include "commands.h" 26#include "commands.h"
25#include "window.h" 27#include "window.h"
@@ -103,8 +105,9 @@ record_point (ptrdiff_t pt)
103 if (at_boundary 105 if (at_boundary
104 && current_buffer == last_boundary_buffer 106 && current_buffer == last_boundary_buffer
105 && last_boundary_position != pt) 107 && last_boundary_position != pt)
106 BVAR (current_buffer, undo_list) 108 bset_undo_list (current_buffer,
107 = Fcons (make_number (last_boundary_position), BVAR (current_buffer, undo_list)); 109 Fcons (make_number (last_boundary_position),
110 BVAR (current_buffer, undo_list)));
108} 111}
109 112
110/* Record an insertion that just happened or is about to happen, 113/* Record an insertion that just happened or is about to happen,
@@ -140,8 +143,8 @@ record_insert (ptrdiff_t beg, ptrdiff_t length)
140 143
141 XSETFASTINT (lbeg, beg); 144 XSETFASTINT (lbeg, beg);
142 XSETINT (lend, beg + length); 145 XSETINT (lend, beg + length);
143 BVAR (current_buffer, undo_list) = Fcons (Fcons (lbeg, lend), 146 bset_undo_list (current_buffer,
144 BVAR (current_buffer, undo_list)); 147 Fcons (Fcons (lbeg, lend), BVAR (current_buffer, undo_list)));
145} 148}
146 149
147/* Record that a deletion is about to take place, 150/* Record that a deletion is about to take place,
@@ -166,8 +169,9 @@ record_delete (ptrdiff_t beg, Lisp_Object string)
166 record_point (beg); 169 record_point (beg);
167 } 170 }
168 171
169 BVAR (current_buffer, undo_list) 172 bset_undo_list
170 = Fcons (Fcons (string, sbeg), BVAR (current_buffer, undo_list)); 173 (current_buffer,
174 Fcons (Fcons (string, sbeg), BVAR (current_buffer, undo_list)));
171} 175}
172 176
173/* Record the fact that MARKER is about to be adjusted by ADJUSTMENT. 177/* Record the fact that MARKER is about to be adjusted by ADJUSTMENT.
@@ -189,9 +193,10 @@ record_marker_adjustment (Lisp_Object marker, ptrdiff_t adjustment)
189 Fundo_boundary (); 193 Fundo_boundary ();
190 last_undo_buffer = current_buffer; 194 last_undo_buffer = current_buffer;
191 195
192 BVAR (current_buffer, undo_list) 196 bset_undo_list
193 = Fcons (Fcons (marker, make_number (adjustment)), 197 (current_buffer,
194 BVAR (current_buffer, undo_list)); 198 Fcons (Fcons (marker, make_number (adjustment)),
199 BVAR (current_buffer, undo_list)));
195} 200}
196 201
197/* Record that a replacement is about to take place, 202/* Record that a replacement is about to take place,
@@ -224,9 +229,9 @@ record_first_change (void)
224 if (base_buffer->base_buffer) 229 if (base_buffer->base_buffer)
225 base_buffer = base_buffer->base_buffer; 230 base_buffer = base_buffer->base_buffer;
226 231
227 BVAR (current_buffer, undo_list) = 232 bset_undo_list (current_buffer,
228 Fcons (Fcons (Qt, INTEGER_TO_CONS (base_buffer->modtime)), 233 Fcons (Fcons (Qt, Fvisited_file_modtime ()),
229 BVAR (current_buffer, undo_list)); 234 BVAR (current_buffer, undo_list)));
230} 235}
231 236
232/* Record a change in property PROP (whose old value was VAL) 237/* Record a change in property PROP (whose old value was VAL)
@@ -264,7 +269,8 @@ record_property_change (ptrdiff_t beg, ptrdiff_t length,
264 XSETINT (lbeg, beg); 269 XSETINT (lbeg, beg);
265 XSETINT (lend, beg + length); 270 XSETINT (lend, beg + length);
266 entry = Fcons (Qnil, Fcons (prop, Fcons (value, Fcons (lbeg, lend)))); 271 entry = Fcons (Qnil, Fcons (prop, Fcons (value, Fcons (lbeg, lend))));
267 BVAR (current_buffer, undo_list) = Fcons (entry, BVAR (current_buffer, undo_list)); 272 bset_undo_list (current_buffer,
273 Fcons (entry, BVAR (current_buffer, undo_list)));
268 274
269 current_buffer = obuf; 275 current_buffer = obuf;
270} 276}
@@ -287,11 +293,12 @@ but another undo command will undo to the previous boundary. */)
287 /* If we have preallocated the cons cell to use here, 293 /* If we have preallocated the cons cell to use here,
288 use that one. */ 294 use that one. */
289 XSETCDR (pending_boundary, BVAR (current_buffer, undo_list)); 295 XSETCDR (pending_boundary, BVAR (current_buffer, undo_list));
290 BVAR (current_buffer, undo_list) = pending_boundary; 296 bset_undo_list (current_buffer, pending_boundary);
291 pending_boundary = Qnil; 297 pending_boundary = Qnil;
292 } 298 }
293 else 299 else
294 BVAR (current_buffer, undo_list) = Fcons (Qnil, BVAR (current_buffer, undo_list)); 300 bset_undo_list (current_buffer,
301 Fcons (Qnil, BVAR (current_buffer, undo_list)));
295 } 302 }
296 last_boundary_position = PT; 303 last_boundary_position = PT;
297 last_boundary_buffer = current_buffer; 304 last_boundary_buffer = current_buffer;
@@ -317,7 +324,7 @@ truncate_undo_list (struct buffer *b)
317 /* Make the buffer current to get its local values of variables such 324 /* Make the buffer current to get its local values of variables such
318 as undo_limit. Also so that Vundo_outer_limit_function can 325 as undo_limit. Also so that Vundo_outer_limit_function can
319 tell which buffer to operate on. */ 326 tell which buffer to operate on. */
320 record_unwind_protect (set_buffer_if_live, Fcurrent_buffer ()); 327 record_unwind_current_buffer ();
321 set_buffer_internal (b); 328 set_buffer_internal (b);
322 329
323 list = BVAR (b, undo_list); 330 list = BVAR (b, undo_list);
@@ -432,214 +439,11 @@ truncate_undo_list (struct buffer *b)
432 XSETCDR (last_boundary, Qnil); 439 XSETCDR (last_boundary, Qnil);
433 /* There's nothing we decided to keep, so clear it out. */ 440 /* There's nothing we decided to keep, so clear it out. */
434 else 441 else
435 BVAR (b, undo_list) = Qnil; 442 bset_undo_list (b, Qnil);
436 443
437 unbind_to (count, Qnil); 444 unbind_to (count, Qnil);
438} 445}
439 446
440static void user_error (const char*) NO_RETURN;
441static void user_error (const char *msg)
442{
443 xsignal1 (Quser_error, build_string (msg));
444}
445
446
447DEFUN ("primitive-undo", Fprimitive_undo, Sprimitive_undo, 2, 2, 0,
448 doc: /* Undo N records from the front of the list LIST.
449Return what remains of the list. */)
450 (Lisp_Object n, Lisp_Object list)
451{
452 struct gcpro gcpro1, gcpro2;
453 Lisp_Object next;
454 ptrdiff_t count = SPECPDL_INDEX ();
455 register EMACS_INT arg;
456 Lisp_Object oldlist;
457 int did_apply = 0;
458
459#if 0 /* This is a good feature, but would make undo-start
460 unable to do what is expected. */
461 Lisp_Object tem;
462
463 /* If the head of the list is a boundary, it is the boundary
464 preceding this command. Get rid of it and don't count it. */
465 tem = Fcar (list);
466 if (NILP (tem))
467 list = Fcdr (list);
468#endif
469
470 CHECK_NUMBER (n);
471 arg = XINT (n);
472 next = Qnil;
473 GCPRO2 (next, list);
474 /* I don't think we need to gcpro oldlist, as we use it only
475 to check for EQ. ++kfs */
476
477 /* In a writable buffer, enable undoing read-only text that is so
478 because of text properties. */
479 if (NILP (BVAR (current_buffer, read_only)))
480 specbind (Qinhibit_read_only, Qt);
481
482 /* Don't let `intangible' properties interfere with undo. */
483 specbind (Qinhibit_point_motion_hooks, Qt);
484
485 oldlist = BVAR (current_buffer, undo_list);
486
487 while (arg > 0)
488 {
489 while (CONSP (list))
490 {
491 next = XCAR (list);
492 list = XCDR (list);
493 /* Exit inner loop at undo boundary. */
494 if (NILP (next))
495 break;
496 /* Handle an integer by setting point to that value. */
497 if (INTEGERP (next))
498 SET_PT (clip_to_bounds (BEGV, XINT (next), ZV));
499 else if (CONSP (next))
500 {
501 Lisp_Object car, cdr;
502
503 car = XCAR (next);
504 cdr = XCDR (next);
505 if (EQ (car, Qt))
506 {
507 /* Element (t high . low) records previous modtime. */
508 struct buffer *base_buffer = current_buffer;
509 time_t mod_time;
510 CONS_TO_INTEGER (cdr, time_t, mod_time);
511
512 if (current_buffer->base_buffer)
513 base_buffer = current_buffer->base_buffer;
514
515 /* If this records an obsolete save
516 (not matching the actual disk file)
517 then don't mark unmodified. */
518 if (mod_time != base_buffer->modtime)
519 continue;
520#ifdef CLASH_DETECTION
521 Funlock_buffer ();
522#endif /* CLASH_DETECTION */
523 Fset_buffer_modified_p (Qnil);
524 }
525 else if (EQ (car, Qnil))
526 {
527 /* Element (nil PROP VAL BEG . END) is property change. */
528 Lisp_Object beg, end, prop, val;
529
530 prop = Fcar (cdr);
531 cdr = Fcdr (cdr);
532 val = Fcar (cdr);
533 cdr = Fcdr (cdr);
534 beg = Fcar (cdr);
535 end = Fcdr (cdr);
536
537 if (XINT (beg) < BEGV || XINT (end) > ZV)
538 user_error ("Changes to be undone are outside visible portion of buffer");
539 Fput_text_property (beg, end, prop, val, Qnil);
540 }
541 else if (INTEGERP (car) && INTEGERP (cdr))
542 {
543 /* Element (BEG . END) means range was inserted. */
544
545 if (XINT (car) < BEGV
546 || XINT (cdr) > ZV)
547 user_error ("Changes to be undone are outside visible portion of buffer");
548 /* Set point first thing, so that undoing this undo
549 does not send point back to where it is now. */
550 Fgoto_char (car);
551 Fdelete_region (car, cdr);
552 }
553 else if (EQ (car, Qapply))
554 {
555 /* Element (apply FUN . ARGS) means call FUN to undo. */
556 struct buffer *save_buffer = current_buffer;
557
558 car = Fcar (cdr);
559 cdr = Fcdr (cdr);
560 if (INTEGERP (car))
561 {
562 /* Long format: (apply DELTA START END FUN . ARGS). */
563 Lisp_Object delta = car;
564 Lisp_Object start = Fcar (cdr);
565 Lisp_Object end = Fcar (Fcdr (cdr));
566 Lisp_Object start_mark = Fcopy_marker (start, Qnil);
567 Lisp_Object end_mark = Fcopy_marker (end, Qt);
568
569 cdr = Fcdr (Fcdr (cdr));
570 apply1 (Fcar (cdr), Fcdr (cdr));
571
572 /* Check that the function did what the entry said it
573 would do. */
574 if (!EQ (start, Fmarker_position (start_mark))
575 || (XINT (delta) + XINT (end)
576 != marker_position (end_mark)))
577 error ("Changes to be undone by function different than announced");
578 Fset_marker (start_mark, Qnil, Qnil);
579 Fset_marker (end_mark, Qnil, Qnil);
580 }
581 else
582 apply1 (car, cdr);
583
584 if (save_buffer != current_buffer)
585 error ("Undo function switched buffer");
586 did_apply = 1;
587 }
588 else if (STRINGP (car) && INTEGERP (cdr))
589 {
590 /* Element (STRING . POS) means STRING was deleted. */
591 Lisp_Object membuf;
592 EMACS_INT pos = XINT (cdr);
593
594 membuf = car;
595 if (pos < 0)
596 {
597 if (-pos < BEGV || -pos > ZV)
598 user_error ("Changes to be undone are outside visible portion of buffer");
599 SET_PT (-pos);
600 Finsert (1, &membuf);
601 }
602 else
603 {
604 if (pos < BEGV || pos > ZV)
605 user_error ("Changes to be undone are outside visible portion of buffer");
606 SET_PT (pos);
607
608 /* Now that we record marker adjustments
609 (caused by deletion) for undo,
610 we should always insert after markers,
611 so that undoing the marker adjustments
612 put the markers back in the right place. */
613 Finsert (1, &membuf);
614 SET_PT (pos);
615 }
616 }
617 else if (MARKERP (car) && INTEGERP (cdr))
618 {
619 /* (MARKER . INTEGER) means a marker MARKER
620 was adjusted by INTEGER. */
621 if (XMARKER (car)->buffer)
622 Fset_marker (car,
623 make_number (marker_position (car) - XINT (cdr)),
624 Fmarker_buffer (car));
625 }
626 }
627 }
628 arg--;
629 }
630
631
632 /* Make sure an apply entry produces at least one undo entry,
633 so the test in `undo' for continuing an undo series
634 will work right. */
635 if (did_apply
636 && EQ (oldlist, BVAR (current_buffer, undo_list)))
637 BVAR (current_buffer, undo_list)
638 = Fcons (list3 (Qapply, Qcdr, Qnil), BVAR (current_buffer, undo_list));
639
640 UNGCPRO;
641 return unbind_to (count, list);
642}
643 447
644void 448void
645syms_of_undo (void) 449syms_of_undo (void)
@@ -653,7 +457,6 @@ syms_of_undo (void)
653 last_undo_buffer = NULL; 457 last_undo_buffer = NULL;
654 last_boundary_buffer = NULL; 458 last_boundary_buffer = NULL;
655 459
656 defsubr (&Sprimitive_undo);
657 defsubr (&Sundo_boundary); 460 defsubr (&Sundo_boundary);
658 461
659 DEFVAR_INT ("undo-limit", undo_limit, 462 DEFVAR_INT ("undo-limit", undo_limit,