diff options
| author | Aaron S. Hawley | 2013-01-08 14:13:31 -0500 |
|---|---|---|
| committer | Stefan Monnier | 2013-01-08 14:13:31 -0500 |
| commit | 3bace969f386056cedeaba7ac3661167d6d60190 (patch) | |
| tree | d4dddc07a157d2f2be055c1d0a879d23d292de68 | |
| parent | 1c851e98b60d08404e5138b67ccf5b9d72fb4e47 (diff) | |
| download | emacs-3bace969f386056cedeaba7ac3661167d6d60190.tar.gz emacs-3bace969f386056cedeaba7ac3661167d6d60190.zip | |
* lisp/simple.el (primitive-undo): Move from undo.c.
* src/undo.c (Fprimitive_undo): Move to simple.el.
(syms_of_undo): Remove declaration for Sprimitive_undo.
* test/automated/undo-tests.el: New file.
| -rw-r--r-- | lisp/ChangeLog | 4 | ||||
| -rw-r--r-- | lisp/simple.el | 135 | ||||
| -rw-r--r-- | src/ChangeLog | 5 | ||||
| -rw-r--r-- | src/undo.c | 212 | ||||
| -rw-r--r-- | test/ChangeLog | 4 | ||||
| -rw-r--r-- | test/automated/undo-tests.el | 231 |
6 files changed, 379 insertions, 212 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 18481cb5aa5..72390d1ff67 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,7 @@ | |||
| 1 | 2013-01-08 Aaron S. Hawley <aaron.s.hawley@gmail.com> | ||
| 2 | |||
| 3 | * simple.el (primitive-undo): Move from undo.c. | ||
| 4 | |||
| 1 | 2013-01-08 Stefan Monnier <monnier@iro.umontreal.ca> | 5 | 2013-01-08 Stefan Monnier <monnier@iro.umontreal.ca> |
| 2 | 6 | ||
| 3 | * vc/pcvs.el (cvs-cleanup-collection): Extend meaning of `rm-handled'. | 7 | * vc/pcvs.el (cvs-cleanup-collection): Extend meaning of `rm-handled'. |
diff --git a/lisp/simple.el b/lisp/simple.el index 19140cba496..86c71cd2130 100644 --- a/lisp/simple.el +++ b/lisp/simple.el | |||
| @@ -1979,6 +1979,141 @@ then call `undo-more' one or more times to undo them." | |||
| 1979 | (if (null pending-undo-list) | 1979 | (if (null pending-undo-list) |
| 1980 | (setq pending-undo-list t)))) | 1980 | (setq pending-undo-list t)))) |
| 1981 | 1981 | ||
| 1982 | (defun primitive-undo (n list) | ||
| 1983 | "Undo N records from the front of the list LIST. | ||
| 1984 | Return what remains of the list." | ||
| 1985 | |||
| 1986 | ;; This is a good feature, but would make undo-start | ||
| 1987 | ;; unable to do what is expected. | ||
| 1988 | ;;(when (null (car (list))) | ||
| 1989 | ;; ;; If the head of the list is a boundary, it is the boundary | ||
| 1990 | ;; ;; preceding this command. Get rid of it and don't count it. | ||
| 1991 | ;; (setq list (cdr list)))) | ||
| 1992 | |||
| 1993 | (let ((arg n) | ||
| 1994 | ;; In a writable buffer, enable undoing read-only text that is | ||
| 1995 | ;; so because of text properties. | ||
| 1996 | (inhibit-read-only t) | ||
| 1997 | ;; Don't let `intangible' properties interfere with undo. | ||
| 1998 | (inhibit-point-motion-hooks t) | ||
| 1999 | ;; We use oldlist only to check for EQ. ++kfs | ||
| 2000 | (oldlist buffer-undo-list) | ||
| 2001 | (did-apply nil) | ||
| 2002 | (next nil)) | ||
| 2003 | (while (> arg 0) | ||
| 2004 | (while (and (consp list) | ||
| 2005 | (progn | ||
| 2006 | (setq next (car list)) | ||
| 2007 | (setq list (cdr list)) | ||
| 2008 | ;; Exit inner loop at undo boundary. | ||
| 2009 | (not (null next)))) | ||
| 2010 | ;; Handle an integer by setting point to that value. | ||
| 2011 | (cond | ||
| 2012 | ((integerp next) (goto-char next)) | ||
| 2013 | ((consp next) | ||
| 2014 | (let ((car (car next)) | ||
| 2015 | (cdr (cdr next))) | ||
| 2016 | (cond | ||
| 2017 | ;; Element (t . TIME) records previous modtime. | ||
| 2018 | ;; Preserve any flag of NONEXISTENT_MODTIME_NSECS or | ||
| 2019 | ;; UNKNOWN_MODTIME_NSECS. | ||
| 2020 | ((eq t car) | ||
| 2021 | ;; If this records an obsolete save | ||
| 2022 | ;; (not matching the actual disk file) | ||
| 2023 | ;; then don't mark unmodified. | ||
| 2024 | (when (or (equal cdr (visited-file-modtime)) | ||
| 2025 | (and (consp cdr) | ||
| 2026 | (equal (list (car cdr) (cdr cdr)) | ||
| 2027 | (visited-file-modtime)))) | ||
| 2028 | (when (fboundp 'unlock-buffer) | ||
| 2029 | (unlock-buffer)) | ||
| 2030 | (set-buffer-modified-p nil))) | ||
| 2031 | ;; Element (nil PROP VAL BEG . END) is property change. | ||
| 2032 | ((eq nil car) | ||
| 2033 | (let ((beg (nth 2 cdr)) | ||
| 2034 | (end (nthcdr 3 cdr)) | ||
| 2035 | (prop (car cdr)) | ||
| 2036 | (val (cadr cdr))) | ||
| 2037 | (when (or (> (point-min) beg) | ||
| 2038 | (< (point-max) end)) | ||
| 2039 | (error "Changes to be undone are outside visible portion of buffer")) | ||
| 2040 | (put-text-property beg end prop val))) | ||
| 2041 | ((and (integerp car) (integerp cdr)) | ||
| 2042 | ;; Element (BEG . END) means range was inserted. | ||
| 2043 | (when (or (< car (point-min)) | ||
| 2044 | (> cdr (point-max))) | ||
| 2045 | (error "Changes to be undone are outside visible portion of buffer")) | ||
| 2046 | ;; Set point first thing, so that undoing this undo | ||
| 2047 | ;; does not send point back to where it is now. | ||
| 2048 | (goto-char car) | ||
| 2049 | (delete-region car cdr)) | ||
| 2050 | ((eq car 'apply) | ||
| 2051 | ;; Element (apply FUN . ARGS) means call FUN to undo. | ||
| 2052 | (let ((currbuff (current-buffer)) | ||
| 2053 | (car (car cdr)) | ||
| 2054 | (cdr (cdr cdr))) | ||
| 2055 | (if (integerp car) | ||
| 2056 | ;; Long format: (apply DELTA START END FUN . ARGS). | ||
| 2057 | (let* ((delta car) | ||
| 2058 | (start (car cdr)) | ||
| 2059 | (end (cadr cdr)) | ||
| 2060 | (start-mark (copy-marker start nil)) | ||
| 2061 | (end-mark (copy-marker end t)) | ||
| 2062 | (cdr (cddr cdr)) | ||
| 2063 | (fun (car cdr)) | ||
| 2064 | (args (cdr cdr))) | ||
| 2065 | (apply fun args) ;; Use `save-current-buffer'? | ||
| 2066 | ;; Check that the function did what the entry | ||
| 2067 | ;; said it would do. | ||
| 2068 | (unless (and (eq start | ||
| 2069 | (marker-position start-mark)) | ||
| 2070 | (eq (+ delta end) | ||
| 2071 | (marker-position end-mark))) | ||
| 2072 | (error "Changes to be undone by function different than announced")) | ||
| 2073 | (set-marker start-mark nil) | ||
| 2074 | (set-marker end-mark nil)) | ||
| 2075 | (apply car cdr)) | ||
| 2076 | (unless (eq currbuff (current-buffer)) | ||
| 2077 | (error "Undo function switched buffer")) | ||
| 2078 | (setq did-apply t))) | ||
| 2079 | ((and (stringp car) (integerp cdr)) | ||
| 2080 | ;; Element (STRING . POS) means STRING was deleted. | ||
| 2081 | (let ((membuf car) | ||
| 2082 | (pos cdr)) | ||
| 2083 | (when (or (< (abs pos) (point-min)) | ||
| 2084 | (> (abs pos) (point-max))) | ||
| 2085 | (error "Changes to be undone are outside visible portion of buffer")) | ||
| 2086 | (if (< pos 0) | ||
| 2087 | (progn | ||
| 2088 | (goto-char (- pos)) | ||
| 2089 | (insert membuf)) | ||
| 2090 | (goto-char pos) | ||
| 2091 | ;; Now that we record marker adjustments | ||
| 2092 | ;; (caused by deletion) for undo, | ||
| 2093 | ;; we should always insert after markers, | ||
| 2094 | ;; so that undoing the marker adjustments | ||
| 2095 | ;; put the markers back in the right place. | ||
| 2096 | (insert membuf) | ||
| 2097 | (goto-char pos)))) | ||
| 2098 | ((and (markerp car) (integerp cdr)) | ||
| 2099 | ;; (MARKER . INTEGER) means a marker MARKER | ||
| 2100 | ;; was adjusted by INTEGER. | ||
| 2101 | (when (marker-buffer car) | ||
| 2102 | (set-marker car | ||
| 2103 | (- (marker-position car) cdr) | ||
| 2104 | (marker-buffer car)))) | ||
| 2105 | (t (error "Unrecognized entry in undo list %S" next))))) | ||
| 2106 | (t (error "Unrecognized entry in undo list %S" next)))) | ||
| 2107 | (setq arg (1- arg))) | ||
| 2108 | ;; Make sure an apply entry produces at least one undo entry, | ||
| 2109 | ;; so the test in `undo' for continuing an undo series | ||
| 2110 | ;; will work right. | ||
| 2111 | (if (and did-apply | ||
| 2112 | (eq oldlist buffer-undo-list)) | ||
| 2113 | (setq buffer-undo-list | ||
| 2114 | (cons (list 'apply 'cdr nil) buffer-undo-list)))) | ||
| 2115 | list) | ||
| 2116 | |||
| 1982 | ;; Deep copy of a list | 2117 | ;; Deep copy of a list |
| 1983 | (defun undo-copy-list (list) | 2118 | (defun undo-copy-list (list) |
| 1984 | "Make a copy of undo list LIST." | 2119 | "Make a copy of undo list LIST." |
diff --git a/src/ChangeLog b/src/ChangeLog index f5dacabd130..9ab201c8be4 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,8 @@ | |||
| 1 | 2013-01-08 Aaron S. Hawley <aaron.s.hawley@gmail.com> | ||
| 2 | |||
| 3 | * undo.c (Fprimitive_undo): Move to simple.el. | ||
| 4 | (syms_of_undo): Remove declarations for Sprimitive_undo. | ||
| 5 | |||
| 1 | 2013-01-08 Stefan Monnier <monnier@iro.umontreal.ca> | 6 | 2013-01-08 Stefan Monnier <monnier@iro.umontreal.ca> |
| 2 | 7 | ||
| 3 | * keyboard.c (echo_add_key): Rename from echo_add_char. | 8 | * keyboard.c (echo_add_key): Rename from echo_add_char. |
diff --git a/src/undo.c b/src/undo.c index 2626fd4ccfe..63edc8e9b8d 100644 --- a/src/undo.c +++ b/src/undo.c | |||
| @@ -452,217 +452,6 @@ user_error (const char *msg) | |||
| 452 | } | 452 | } |
| 453 | 453 | ||
| 454 | 454 | ||
| 455 | DEFUN ("primitive-undo", Fprimitive_undo, Sprimitive_undo, 2, 2, 0, | ||
| 456 | doc: /* Undo N records from the front of the list LIST. | ||
| 457 | Return what remains of the list. */) | ||
| 458 | (Lisp_Object n, Lisp_Object list) | ||
| 459 | { | ||
| 460 | struct gcpro gcpro1, gcpro2; | ||
| 461 | Lisp_Object next; | ||
| 462 | ptrdiff_t count = SPECPDL_INDEX (); | ||
| 463 | register EMACS_INT arg; | ||
| 464 | Lisp_Object oldlist; | ||
| 465 | int did_apply = 0; | ||
| 466 | |||
| 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); | ||
| 474 | if (NILP (tem)) | ||
| 475 | list = Fcdr (list); | ||
| 476 | #endif | ||
| 477 | |||
| 478 | CHECK_NUMBER (n); | ||
| 479 | arg = XINT (n); | ||
| 480 | next = Qnil; | ||
| 481 | GCPRO2 (next, list); | ||
| 482 | /* I don't think we need to gcpro oldlist, as we use it only | ||
| 483 | to check for EQ. ++kfs */ | ||
| 484 | |||
| 485 | /* In a writable buffer, enable undoing read-only text that is so | ||
| 486 | because of text properties. */ | ||
| 487 | if (NILP (BVAR (current_buffer, read_only))) | ||
| 488 | specbind (Qinhibit_read_only, Qt); | ||
| 489 | |||
| 490 | /* Don't let `intangible' properties interfere with undo. */ | ||
| 491 | specbind (Qinhibit_point_motion_hooks, Qt); | ||
| 492 | |||
| 493 | oldlist = BVAR (current_buffer, undo_list); | ||
| 494 | |||
| 495 | while (arg > 0) | ||
| 496 | { | ||
| 497 | while (CONSP (list)) | ||
| 498 | { | ||
| 499 | next = XCAR (list); | ||
| 500 | list = XCDR (list); | ||
| 501 | /* Exit inner loop at undo boundary. */ | ||
| 502 | if (NILP (next)) | ||
| 503 | break; | ||
| 504 | /* Handle an integer by setting point to that value. */ | ||
| 505 | if (INTEGERP (next)) | ||
| 506 | SET_PT (clip_to_bounds (BEGV, XINT (next), ZV)); | ||
| 507 | else if (CONSP (next)) | ||
| 508 | { | ||
| 509 | Lisp_Object car, cdr; | ||
| 510 | |||
| 511 | car = XCAR (next); | ||
| 512 | cdr = XCDR (next); | ||
| 513 | if (EQ (car, Qt)) | ||
| 514 | { | ||
| 515 | /* Element (t . TIME) records previous modtime. | ||
| 516 | Preserve any flag of NONEXISTENT_MODTIME_NSECS or | ||
| 517 | UNKNOWN_MODTIME_NSECS. */ | ||
| 518 | struct buffer *base_buffer = current_buffer; | ||
| 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) | ||
| 527 | mod_time = | ||
| 528 | (make_emacs_time | ||
| 529 | (0, XINT (XCAR (XCDR (XCDR (XCDR (cdr))))) / 1000)); | ||
| 530 | else | ||
| 531 | mod_time = lisp_time_argument (cdr); | ||
| 532 | |||
| 533 | if (current_buffer->base_buffer) | ||
| 534 | base_buffer = current_buffer->base_buffer; | ||
| 535 | |||
| 536 | /* If this records an obsolete save | ||
| 537 | (not matching the actual disk file) | ||
| 538 | then don't mark unmodified. */ | ||
| 539 | if (EMACS_TIME_NE (mod_time, base_buffer->modtime)) | ||
| 540 | continue; | ||
| 541 | #ifdef CLASH_DETECTION | ||
| 542 | Funlock_buffer (); | ||
| 543 | #endif /* CLASH_DETECTION */ | ||
| 544 | Fset_buffer_modified_p (Qnil); | ||
| 545 | } | ||
| 546 | else if (EQ (car, Qnil)) | ||
| 547 | { | ||
| 548 | /* Element (nil PROP VAL BEG . END) is property change. */ | ||
| 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 | |||
| 558 | if (XINT (beg) < BEGV || XINT (end) > ZV) | ||
| 559 | user_error ("Changes to be undone are outside visible portion of buffer"); | ||
| 560 | Fput_text_property (beg, end, prop, val, Qnil); | ||
| 561 | } | ||
| 562 | else if (INTEGERP (car) && INTEGERP (cdr)) | ||
| 563 | { | ||
| 564 | /* Element (BEG . END) means range was inserted. */ | ||
| 565 | |||
| 566 | if (XINT (car) < BEGV | ||
| 567 | || XINT (cdr) > ZV) | ||
| 568 | user_error ("Changes to be undone are outside visible portion of buffer"); | ||
| 569 | /* Set point first thing, so that undoing this undo | ||
| 570 | does not send point back to where it is now. */ | ||
| 571 | Fgoto_char (car); | ||
| 572 | Fdelete_region (car, cdr); | ||
| 573 | } | ||
| 574 | else if (EQ (car, Qapply)) | ||
| 575 | { | ||
| 576 | /* Element (apply FUN . ARGS) means call FUN to undo. */ | ||
| 577 | struct buffer *save_buffer = current_buffer; | ||
| 578 | |||
| 579 | car = Fcar (cdr); | ||
| 580 | cdr = Fcdr (cdr); | ||
| 581 | if (INTEGERP (car)) | ||
| 582 | { | ||
| 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); | ||
| 601 | } | ||
| 602 | else | ||
| 603 | apply1 (car, cdr); | ||
| 604 | |||
| 605 | if (save_buffer != current_buffer) | ||
| 606 | error ("Undo function switched buffer"); | ||
| 607 | did_apply = 1; | ||
| 608 | } | ||
| 609 | else if (STRINGP (car) && INTEGERP (cdr)) | ||
| 610 | { | ||
| 611 | /* Element (STRING . POS) means STRING was deleted. */ | ||
| 612 | Lisp_Object membuf; | ||
| 613 | EMACS_INT pos = XINT (cdr); | ||
| 614 | |||
| 615 | membuf = car; | ||
| 616 | if (pos < 0) | ||
| 617 | { | ||
| 618 | if (-pos < BEGV || -pos > ZV) | ||
| 619 | user_error ("Changes to be undone are outside visible portion of buffer"); | ||
| 620 | SET_PT (-pos); | ||
| 621 | Finsert (1, &membuf); | ||
| 622 | } | ||
| 623 | else | ||
| 624 | { | ||
| 625 | if (pos < BEGV || pos > ZV) | ||
| 626 | user_error ("Changes to be undone are outside visible portion of buffer"); | ||
| 627 | SET_PT (pos); | ||
| 628 | |||
| 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); | ||
| 635 | SET_PT (pos); | ||
| 636 | } | ||
| 637 | } | ||
| 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 | } | ||
| 647 | } | ||
| 648 | } | ||
| 649 | arg--; | ||
| 650 | } | ||
| 651 | |||
| 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 | ||
| 657 | && EQ (oldlist, BVAR (current_buffer, undo_list))) | ||
| 658 | bset_undo_list | ||
| 659 | (current_buffer, | ||
| 660 | Fcons (list3 (Qapply, Qcdr, Qnil), BVAR (current_buffer, undo_list))); | ||
| 661 | |||
| 662 | UNGCPRO; | ||
| 663 | return unbind_to (count, list); | ||
| 664 | } | ||
| 665 | |||
| 666 | void | 455 | void |
| 667 | syms_of_undo (void) | 456 | syms_of_undo (void) |
| 668 | { | 457 | { |
| @@ -675,7 +464,6 @@ syms_of_undo (void) | |||
| 675 | last_undo_buffer = NULL; | 464 | last_undo_buffer = NULL; |
| 676 | last_boundary_buffer = NULL; | 465 | last_boundary_buffer = NULL; |
| 677 | 466 | ||
| 678 | defsubr (&Sprimitive_undo); | ||
| 679 | defsubr (&Sundo_boundary); | 467 | defsubr (&Sundo_boundary); |
| 680 | 468 | ||
| 681 | DEFVAR_INT ("undo-limit", undo_limit, | 469 | DEFVAR_INT ("undo-limit", undo_limit, |
diff --git a/test/ChangeLog b/test/ChangeLog index 43c783857f3..b7b628cce69 100644 --- a/test/ChangeLog +++ b/test/ChangeLog | |||
| @@ -1,3 +1,7 @@ | |||
| 1 | 2013-01-08 Aaron S. Hawley <aaron.s.hawley@gmail.com> | ||
| 2 | |||
| 3 | * automated/undo-tests.el: New file. | ||
| 4 | |||
| 1 | 2012-12-27 Dmitry Gutov <dgutov@yandex.ru> | 5 | 2012-12-27 Dmitry Gutov <dgutov@yandex.ru> |
| 2 | 6 | ||
| 3 | * automated/ruby-mode-tests.el | 7 | * automated/ruby-mode-tests.el |
diff --git a/test/automated/undo-tests.el b/test/automated/undo-tests.el new file mode 100644 index 00000000000..3e71d974e5b --- /dev/null +++ b/test/automated/undo-tests.el | |||
| @@ -0,0 +1,231 @@ | |||
| 1 | ;;; undo-tests.el --- Tests of primitive-undo | ||
| 2 | |||
| 3 | ;; Copyright (C) 2012 Aaron S. Hawley | ||
| 4 | |||
| 5 | ;; Author: Aaron S. Hawley <aaron.s.hawley@gmail.com> | ||
| 6 | |||
| 7 | ;; This program is free software: you can redistribute it and/or | ||
| 8 | ;; modify it under the terms of the GNU General Public License as | ||
| 9 | ;; published by the Free Software Foundation, either version 3 of the | ||
| 10 | ;; License, or (at your option) any later version. | ||
| 11 | ;; | ||
| 12 | ;; This program is distributed in the hope that it will be useful, but | ||
| 13 | ;; WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | ;; General Public License for more details. | ||
| 16 | ;; | ||
| 17 | ;; You should have received a copy of the GNU General Public License | ||
| 18 | ;; along with this program. If not, see `http://www.gnu.org/licenses/'. | ||
| 19 | |||
| 20 | ;;; Commentary: | ||
| 21 | |||
| 22 | ;; Profiling when the code was translate from C to Lisp on 2012-12-24. | ||
| 23 | |||
| 24 | ;;; C | ||
| 25 | |||
| 26 | ;; (elp-instrument-function 'primitive-undo) | ||
| 27 | ;; (load-file "undo-test.elc") | ||
| 28 | ;; (benchmark 100 '(let ((undo-test5-error nil)) (undo-test-all))) | ||
| 29 | ;; Elapsed time: 305.218000s (104.841000s in 14804 GCs) | ||
| 30 | ;; M-x elp-results | ||
| 31 | ;; Function Name Call Count Elapsed Time Average Time | ||
| 32 | ;; primitive-undo 2600 3.4889999999 0.0013419230 | ||
| 33 | |||
| 34 | ;;; Lisp | ||
| 35 | |||
| 36 | ;; (load-file "primundo.elc") | ||
| 37 | ;; (elp-instrument-function 'primitive-undo) | ||
| 38 | ;; (benchmark 100 '(undo-test-all)) | ||
| 39 | ;; Elapsed time: 295.974000s (104.582000s in 14704 GCs) | ||
| 40 | ;; M-x elp-results | ||
| 41 | ;; Function Name Call Count Elapsed Time Average Time | ||
| 42 | ;; primitive-undo 2700 3.6869999999 0.0013655555 | ||
| 43 | |||
| 44 | ;;; Code: | ||
| 45 | |||
| 46 | (require 'ert) | ||
| 47 | |||
| 48 | (ert-deftest undo-test0 () | ||
| 49 | "Test basics of \\[undo]." | ||
| 50 | (with-temp-buffer | ||
| 51 | (buffer-enable-undo) | ||
| 52 | (condition-case err | ||
| 53 | (undo) | ||
| 54 | (error | ||
| 55 | (unless (string= "No further undo information" | ||
| 56 | (cadr err)) | ||
| 57 | (error err)))) | ||
| 58 | (undo-boundary) | ||
| 59 | (insert "This") | ||
| 60 | (undo-boundary) | ||
| 61 | (erase-buffer) | ||
| 62 | (undo-boundary) | ||
| 63 | (insert "That") | ||
| 64 | (undo-boundary) | ||
| 65 | (forward-word -1) | ||
| 66 | (undo-boundary) | ||
| 67 | (insert "With ") | ||
| 68 | (undo-boundary) | ||
| 69 | (forward-word -1) | ||
| 70 | (undo-boundary) | ||
| 71 | (kill-word 1) | ||
| 72 | (undo-boundary) | ||
| 73 | (put-text-property (point-min) (point-max) 'face 'bold) | ||
| 74 | (undo-boundary) | ||
| 75 | (remove-text-properties (point-min) (point-max) '(face default)) | ||
| 76 | (undo-boundary) | ||
| 77 | (set-buffer-multibyte (not enable-multibyte-characters)) | ||
| 78 | (undo-boundary) | ||
| 79 | (undo) | ||
| 80 | (should | ||
| 81 | (equal (should-error (undo-more nil)) | ||
| 82 | '(wrong-type-argument integerp nil))) | ||
| 83 | (undo-more 7) | ||
| 84 | (should (string-equal "" (buffer-string))))) | ||
| 85 | |||
| 86 | (ert-deftest undo-test1 () | ||
| 87 | "Test undo of \\[undo] command (redo)." | ||
| 88 | (with-temp-buffer | ||
| 89 | (buffer-enable-undo) | ||
| 90 | (undo-boundary) | ||
| 91 | (insert "This") | ||
| 92 | (undo-boundary) | ||
| 93 | (erase-buffer) | ||
| 94 | (undo-boundary) | ||
| 95 | (insert "That") | ||
| 96 | (undo-boundary) | ||
| 97 | (forward-word -1) | ||
| 98 | (undo-boundary) | ||
| 99 | (insert "With ") | ||
| 100 | (undo-boundary) | ||
| 101 | (forward-word -1) | ||
| 102 | (undo-boundary) | ||
| 103 | (kill-word 1) | ||
| 104 | (undo-boundary) | ||
| 105 | (facemenu-add-face 'bold (point-min) (point-max)) | ||
| 106 | (undo-boundary) | ||
| 107 | (set-buffer-multibyte (not enable-multibyte-characters)) | ||
| 108 | (undo-boundary) | ||
| 109 | (should | ||
| 110 | (string-equal (buffer-string) | ||
| 111 | (progn | ||
| 112 | (undo) | ||
| 113 | (undo-more 4) | ||
| 114 | (undo) | ||
| 115 | ;(undo-more -4) | ||
| 116 | (buffer-string)))))) | ||
| 117 | |||
| 118 | (ert-deftest undo-test2 () | ||
| 119 | "Test basic redoing with \\[undo] command." | ||
| 120 | (with-temp-buffer | ||
| 121 | (buffer-enable-undo) | ||
| 122 | (undo-boundary) | ||
| 123 | (insert "One") | ||
| 124 | (undo-boundary) | ||
| 125 | (insert " Zero") | ||
| 126 | (undo-boundary) | ||
| 127 | (push-mark) | ||
| 128 | (delete-region (save-excursion | ||
| 129 | (forward-word -1) | ||
| 130 | (point)) (point)) | ||
| 131 | (undo-boundary) | ||
| 132 | (beginning-of-line) | ||
| 133 | (insert "Zero") | ||
| 134 | (undo-boundary) | ||
| 135 | (undo) | ||
| 136 | (should | ||
| 137 | (string-equal (buffer-string) | ||
| 138 | (progn | ||
| 139 | (undo-more 2) | ||
| 140 | (undo) | ||
| 141 | (buffer-string)))))) | ||
| 142 | |||
| 143 | (ert-deftest undo-test3 () | ||
| 144 | "Test modtime with \\[undo] command." | ||
| 145 | (let ((tmpfile (make-temp-file "undo-test3"))) | ||
| 146 | (with-temp-file tmpfile | ||
| 147 | (let ((buffer-file-name tmpfile)) | ||
| 148 | (buffer-enable-undo) | ||
| 149 | (set (make-local-variable 'make-backup-files) nil) | ||
| 150 | (undo-boundary) | ||
| 151 | (insert ?\s) | ||
| 152 | (undo-boundary) | ||
| 153 | (basic-save-buffer) | ||
| 154 | (insert ?\t) | ||
| 155 | (undo) | ||
| 156 | (should | ||
| 157 | (string-equal (buffer-string) | ||
| 158 | (progn | ||
| 159 | (undo) | ||
| 160 | (buffer-string))))) | ||
| 161 | (delete-file tmpfile)))) | ||
| 162 | |||
| 163 | (ert-deftest undo-test4 () | ||
| 164 | "Test \\[undo] of \\[flush-lines]." | ||
| 165 | (with-temp-buffer | ||
| 166 | (buffer-enable-undo) | ||
| 167 | (dotimes (i 1048576) | ||
| 168 | (if (zerop (% i 2)) | ||
| 169 | (insert "Evenses") | ||
| 170 | (insert "Oddses"))) | ||
| 171 | (undo-boundary) | ||
| 172 | (should | ||
| 173 | ;; Avoid string-equal because ERT will save the `buffer-string' | ||
| 174 | ;; to the explanation. Using `not' will record nil or non-nil. | ||
| 175 | (not | ||
| 176 | (null | ||
| 177 | (string-equal (buffer-string) | ||
| 178 | (progn | ||
| 179 | (flush-lines "oddses" (point-min) (point-max)) | ||
| 180 | (undo-boundary) | ||
| 181 | (undo) | ||
| 182 | (undo) | ||
| 183 | (buffer-string)))))))) | ||
| 184 | |||
| 185 | (ert-deftest undo-test5 () | ||
| 186 | "Test basic redoing with \\[undo] command." | ||
| 187 | (with-temp-buffer | ||
| 188 | (buffer-enable-undo) | ||
| 189 | (undo-boundary) | ||
| 190 | (insert "AYE") | ||
| 191 | (undo-boundary) | ||
| 192 | (insert " BEE") | ||
| 193 | (undo-boundary) | ||
| 194 | (setq buffer-undo-list (cons '(0.0 bogus) buffer-undo-list)) | ||
| 195 | (push-mark) | ||
| 196 | (delete-region (save-excursion | ||
| 197 | (forward-word -1) | ||
| 198 | (point)) (point)) | ||
| 199 | (undo-boundary) | ||
| 200 | (beginning-of-line) | ||
| 201 | (insert "CEE") | ||
| 202 | (undo-boundary) | ||
| 203 | (undo) | ||
| 204 | (setq buffer-undo-list (cons "bogus" buffer-undo-list)) | ||
| 205 | (should | ||
| 206 | (string-equal | ||
| 207 | (buffer-string) | ||
| 208 | (progn | ||
| 209 | (if (and (boundp 'undo-test5-error) (not undo-test5-error)) | ||
| 210 | (progn | ||
| 211 | (should (null (undo-more 2))) | ||
| 212 | (should (undo))) | ||
| 213 | ;; Errors are generated by new Lisp version of | ||
| 214 | ;; `primitive-undo' not by built-in C version. | ||
| 215 | (should | ||
| 216 | (equal (should-error (undo-more 2)) | ||
| 217 | '(error "Unrecognized entry in undo list (0.0 bogus)"))) | ||
| 218 | (should | ||
| 219 | (equal (should-error (undo)) | ||
| 220 | '(error "Unrecognized entry in undo list \"bogus\"")))) | ||
| 221 | (buffer-string)))))) | ||
| 222 | |||
| 223 | (defun undo-test-all (&optional interactive) | ||
| 224 | "Run all tests for \\[undo]." | ||
| 225 | (interactive "p") | ||
| 226 | (if interactive | ||
| 227 | (ert-run-tests-interactively "^undo-") | ||
| 228 | (ert-run-tests-batch "^undo-"))) | ||
| 229 | |||
| 230 | (provide 'undo-tests) | ||
| 231 | ;;; undo-tests.el ends here | ||