X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/81c1cf71feec0cd6f906141d741dccfb76aae3de..03da5d089a8ed035cec443a27259e7d21487a22e:/src/undo.c diff --git a/src/undo.c b/src/undo.c index df4b8d08cd..9839906ca7 100644 --- a/src/undo.c +++ b/src/undo.c @@ -1,5 +1,6 @@ /* undo handling for GNU Emacs. - Copyright (C) 1990, 1993, 1994, 2000 Free Software Foundation, Inc. + Copyright (C) 1990, 1993, 1994, 2000, 2002, 2003, 2004, + 2005 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -15,8 +16,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Emacs; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ #include @@ -40,6 +41,10 @@ Lisp_Object last_undo_buffer; Lisp_Object Qinhibit_read_only; +/* Marker for function call undo list elements. */ + +Lisp_Object Qapply; + /* The first time a command records something for undo. it also allocates the undo-boundary object which will be added to the list at the end of the command. @@ -450,6 +455,8 @@ Return what remains of the list. */) Lisp_Object next; int count = SPECPDL_INDEX (); register int arg; + Lisp_Object oldlist; + int did_apply = 0; #if 0 /* This is a good feature, but would make undo-start unable to do what is expected. */ @@ -466,6 +473,8 @@ Return what remains of the list. */) arg = XINT (n); next = Qnil; GCPRO2 (next, list); + /* I don't think we need to gcpro oldlist, as we use it only + to check for EQ. ++kfs */ /* In a writable buffer, enable undoing read-only text that is so because of text properties. */ @@ -475,6 +484,8 @@ Return what remains of the list. */) /* Don't let `intangible' properties interfere with undo. */ specbind (Qinhibit_point_motion_hooks, Qt); + oldlist = current_buffer->undo_list; + while (arg > 0) { while (CONSP (list)) @@ -519,7 +530,7 @@ Return what remains of the list. */) } else if (EQ (car, Qnil)) { - /* Element (nil prop val beg . end) is property change. */ + /* Element (nil PROP VAL BEG . END) is property change. */ Lisp_Object beg, end, prop, val; prop = Fcar (cdr); @@ -543,6 +554,41 @@ Return what remains of the list. */) Fgoto_char (car); Fdelete_region (car, cdr); } + else if (EQ (car, Qapply)) + { + /* Element (apply FUN . ARGS) means call FUN to undo. */ + struct buffer *save_buffer = current_buffer; + + car = Fcar (cdr); + cdr = Fcdr (cdr); + if (INTEGERP (car)) + { + /* Long format: (apply DELTA START END FUN . ARGS). */ + Lisp_Object delta = car; + Lisp_Object start = Fcar (cdr); + Lisp_Object end = Fcar (Fcdr (cdr)); + Lisp_Object start_mark = Fcopy_marker (start, Qnil); + Lisp_Object end_mark = Fcopy_marker (end, Qt); + + cdr = Fcdr (Fcdr (cdr)); + apply1 (Fcar (cdr), Fcdr (cdr)); + + /* Check that the function did what the entry said it + would do. */ + if (!EQ (start, Fmarker_position (start_mark)) + || (XINT (delta) + XINT (end) + != marker_position (end_mark))) + error ("Changes to be undone by function different than announced"); + Fset_marker (start_mark, Qnil, Qnil); + Fset_marker (end_mark, Qnil, Qnil); + } + else + apply1 (car, cdr); + + if (save_buffer != current_buffer) + error ("Undo function switched buffer"); + did_apply = 1; + } else if (STRINGP (car) && INTEGERP (cdr)) { /* Element (STRING . POS) means STRING was deleted. */ @@ -586,16 +632,28 @@ Return what remains of the list. */) arg--; } + + /* Make sure an apply entry produces at least one undo entry, + so the test in `undo' for continuing an undo series + will work right. */ + if (did_apply + && EQ (oldlist, current_buffer->undo_list)) + current_buffer->undo_list + = Fcons (list3 (Qapply, Qcdr, Qnil), current_buffer->undo_list); + UNGCPRO; return unbind_to (count, list); } - + void syms_of_undo () { Qinhibit_read_only = intern ("inhibit-read-only"); staticpro (&Qinhibit_read_only); + Qapply = intern ("apply"); + staticpro (&Qapply); + pending_boundary = Qnil; staticpro (&pending_boundary); @@ -627,17 +685,19 @@ which includes both saved text and other data. */); DEFVAR_LISP ("undo-outer-limit", &Vundo_outer_limit, doc: /* Outer limit on size of undo information for one command. At garbage collection time, if the current command has produced -more than this much undo information, it asks you whether to delete -the information. This is a last-ditch limit to prevent memory overflow. +more than this much undo information, it discards the info and displays +a warning. This is a last-ditch limit to prevent memory overflow. -The size is counted as the number of bytes occupied, -which includes both saved text and other data. +The size is counted as the number of bytes occupied, which includes +both saved text and other data. A value of nil means no limit. In +this case, accumulating one huge undo entry could make Emacs crash as +a result of memory overflow. In fact, this calls the function which is the value of `undo-outer-limit-function' with one argument, the size. The text above describes the behavior of the function that variable usually specifies. */); - Vundo_outer_limit = make_number (300000); + Vundo_outer_limit = make_number (3000000); DEFVAR_LISP ("undo-outer-limit-function", &Vundo_outer_limit_function, doc: /* Function to call when an undo list exceeds `undo-outer-limit'.