X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/6887bce515f7406765dda3bd8fc65d65a9cf207b..70360d0cab4f5e9fa351cd131e45fa86401896c0:/src/undo.c diff --git a/src/undo.c b/src/undo.c index ac7b4d8935..7a6ba37d0f 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, 2001, 2002, 2003, 2004, + 2005, 2006, 2007 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -15,14 +16,15 @@ 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 #include "lisp.h" #include "buffer.h" #include "commands.h" +#include "window.h" /* Limits controlling how much undo information to keep. */ @@ -40,6 +42,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. @@ -95,12 +101,19 @@ record_point (pt) /* If we are just after an undo boundary, and point wasn't at start of deleted range, record where it was. */ if (at_boundary - && last_point_position != pt - /* If we're called from batch mode, this could be nil. */ && BUFFERP (last_point_position_buffer) + /* If we're called from batch mode, this could be nil. */ && current_buffer == XBUFFER (last_point_position_buffer)) - current_buffer->undo_list - = Fcons (make_number (last_point_position), current_buffer->undo_list); + { + /* If we have switched windows, use the point value + from the window we are in. */ + if (! EQ (last_point_position_window, selected_window)) + last_point_position = marker_position (XWINDOW (selected_window)->pointm); + + if (last_point_position != pt) + current_buffer->undo_list + = Fcons (make_number (last_point_position), current_buffer->undo_list); + } } /* Record an insertion that just happened or is about to happen, @@ -373,11 +386,11 @@ truncate_undo_list (b) && size_so_far > XINT (Vundo_outer_limit) && !NILP (Vundo_outer_limit_function)) { - Lisp_Object temp = last_undo_buffer; + Lisp_Object temp = last_undo_buffer, tem; /* Normally the function this calls is undo-outer-limit-truncate. */ - if (! NILP (call1 (Vundo_outer_limit_function, - make_number (size_so_far)))) + tem = call1 (Vundo_outer_limit_function, make_number (size_so_far)); + if (! NILP (tem)) { /* The function is responsible for making any desired changes in buffer-undo-list. */ @@ -450,6 +463,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 +481,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 +492,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)) @@ -529,6 +548,8 @@ Return what remains of the list. */) beg = Fcar (cdr); end = Fcdr (cdr); + if (XINT (beg) < BEGV || XINT (end) > ZV) + error ("Changes to be undone are outside visible portion of buffer"); Fput_text_property (beg, end, prop, val, Qnil); } else if (INTEGERP (car) && INTEGERP (cdr)) @@ -543,17 +564,40 @@ Return what remains of the list. */) Fgoto_char (car); Fdelete_region (car, cdr); } - else if (SYMBOLP (car)) + else if (EQ (car, Qapply)) { - Lisp_Object oldlist = current_buffer->undo_list; - /* Element (FUNNAME . ARGS) means call FUNNAME to undo. */ - apply1 (car, cdr); - /* Make sure this produces at least one undo entry, - so the test in `undo' for continuing an undo series - will work right. */ - if (EQ (oldlist, current_buffer->undo_list)) - current_buffer->undo_list - = Fcons (list2 (Qcdr, Qnil), current_buffer->undo_list); + /* 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)) { @@ -598,6 +642,15 @@ 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); } @@ -608,6 +661,9 @@ 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); @@ -639,17 +695,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'.