X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/9e7c370a5b574d55b5f9996fed99b1494818ea2a..5078c8abf35fd1166acd6e2251a65831cc87611d:/src/macros.c diff --git a/src/macros.c b/src/macros.c index e63ea2be2e..4f5c77f6fb 100644 --- a/src/macros.c +++ b/src/macros.c @@ -1,5 +1,5 @@ /* Keyboard macros. - Copyright (C) 1985, 1986, 1993 Free Software Foundation, Inc. + Copyright (C) 1985, 1986, 1993, 2000, 2001 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -27,11 +27,32 @@ Boston, MA 02111-1307, USA. */ #include "window.h" #include "keyboard.h" -Lisp_Object Qexecute_kbd_macro; +Lisp_Object Qexecute_kbd_macro, Qkbd_macro_termination_hook; + +/* Kbd macro currently being executed (a string or vector). */ Lisp_Object Vexecuting_macro; + +/* Index of next character to fetch from that macro. */ + int executing_macro_index; +/* Number of successful iterations so far + for innermost keyboard macro. + This is not bound at each level, + so after an error, it describes the innermost interrupted macro. */ + +int executing_macro_iterations; + +/* This is the macro that was executing. + This is not bound at each level, + so after an error, it describes the innermost interrupted macro. + We use it only as a kind of flag, so no need to protect it. */ + +Lisp_Object executing_macro; + +extern Lisp_Object real_this_command; + Lisp_Object Fexecute_kbd_macro (); DEFUN ("start-kbd-macro", Fstart_kbd_macro, Sstart_kbd_macro, 1, 1, "P", @@ -40,7 +61,7 @@ The commands are recorded even as they are executed.\n\ Use \\[end-kbd-macro] to finish recording and make the macro available.\n\ Use \\[name-last-kbd-macro] to give it a permanent name.\n\ Non-nil arg (prefix arg) means append to last macro defined;\n\ - This begins by re-executing that macro as if you typed it again.") +this begins by re-executing that macro as if you typed it again.") (append) Lisp_Object append; { @@ -60,7 +81,8 @@ Non-nil arg (prefix arg) means append to last macro defined;\n\ { current_kboard->kbd_macro_bufsize = 30; current_kboard->kbd_macro_buffer - = (Lisp_Object *)xrealloc (30 * sizeof (Lisp_Object)); + = (Lisp_Object *)xrealloc (current_kboard->kbd_macro_buffer, + 30 * sizeof (Lisp_Object)); } current_kboard->kbd_macro_ptr = current_kboard->kbd_macro_buffer; current_kboard->kbd_macro_end = current_kboard->kbd_macro_buffer; @@ -68,10 +90,38 @@ Non-nil arg (prefix arg) means append to last macro defined;\n\ } else { - message ("Appending to kbd macro..."); - current_kboard->kbd_macro_ptr = current_kboard->kbd_macro_end; + int i, len; + + /* Check the type of last-kbd-macro in case Lisp code changed it. */ + if (!STRINGP (current_kboard->Vlast_kbd_macro) + && !VECTORP (current_kboard->Vlast_kbd_macro)) + current_kboard->Vlast_kbd_macro + = wrong_type_argument (Qarrayp, current_kboard->Vlast_kbd_macro); + + len = XINT (Flength (current_kboard->Vlast_kbd_macro)); + + /* Copy last-kbd-macro into the buffer, in case the Lisp code + has put another macro there. */ + if (current_kboard->kbd_macro_bufsize < len + 30) + { + current_kboard->kbd_macro_bufsize = len + 30; + current_kboard->kbd_macro_buffer + = (Lisp_Object *)xrealloc (current_kboard->kbd_macro_buffer, + (len + 30) * sizeof (Lisp_Object)); + } + for (i = 0; i < len; i++) + current_kboard->kbd_macro_buffer[i] + = Faref (current_kboard->Vlast_kbd_macro, make_number (i)); + + current_kboard->kbd_macro_ptr = current_kboard->kbd_macro_buffer + len; + current_kboard->kbd_macro_end = current_kboard->kbd_macro_ptr; + + /* Re-execute the macro we are appending to, + for consistency of behavior. */ Fexecute_kbd_macro (current_kboard->Vlast_kbd_macro, make_number (1)); + + message ("Appending to kbd macro..."); } current_kboard->defining_kbd_macro = Qt; @@ -92,7 +142,7 @@ An argument of zero means repeat until error.") Lisp_Object repeat; { if (NILP (current_kboard->defining_kbd_macro)) - error ("Not defining kbd macro."); + error ("Not defining kbd macro"); if (NILP (repeat)) XSETFASTINT (repeat, 1); @@ -123,6 +173,7 @@ An argument of zero means repeat until error.") /* Store character c into kbd macro being defined */ +void store_kbd_macro_char (c) Lisp_Object c; { @@ -132,17 +183,20 @@ store_kbd_macro_char (c) - current_kboard->kbd_macro_buffer) == current_kboard->kbd_macro_bufsize) { - register Lisp_Object *new; + int offset = (current_kboard->kbd_macro_ptr + - current_kboard->kbd_macro_buffer); current_kboard->kbd_macro_bufsize *= 2; - new = (Lisp_Object *)xrealloc (current_kboard->kbd_macro_buffer, - (current_kboard->kbd_macro_bufsize - * sizeof (Lisp_Object))); + current_kboard->kbd_macro_buffer + = (Lisp_Object *)xrealloc (current_kboard->kbd_macro_buffer, + (current_kboard->kbd_macro_bufsize + * sizeof (Lisp_Object))); current_kboard->kbd_macro_ptr - += new - current_kboard->kbd_macro_buffer; + = current_kboard->kbd_macro_buffer + offset; current_kboard->kbd_macro_end - += new - current_kboard->kbd_macro_buffer; - current_kboard->kbd_macro_buffer = new; + = (current_kboard->kbd_macro_buffer + + current_kboard->kbd_macro_bufsize); } + *current_kboard->kbd_macro_ptr++ = c; } } @@ -150,6 +204,7 @@ store_kbd_macro_char (c) /* Declare that all chars stored so far in the kbd macro being defined really belong to it. This is done in between editor commands. */ +void finalize_kbd_macro_chars () { current_kboard->kbd_macro_end = current_kboard->kbd_macro_ptr; @@ -161,6 +216,7 @@ DEFUN ("cancel-kbd-macro-events", Fcancel_kbd_macro_events, () { current_kboard->kbd_macro_ptr = current_kboard->kbd_macro_end; + return Qnil; } DEFUN ("store-kbd-macro-event", Fstore_kbd_macro_event, @@ -184,25 +240,40 @@ defining others, use \\[name-last-kbd-macro].") (prefix) Lisp_Object prefix; { + /* Don't interfere with recognition of the previous command + from before this macro started. */ + Vthis_command = current_kboard->Vlast_command; + /* C-x z after the macro should repeat the macro. */ + real_this_command = current_kboard->Vlast_kbd_macro; + if (! NILP (current_kboard->defining_kbd_macro)) error ("Can't execute anonymous macro while defining one"); else if (NILP (current_kboard->Vlast_kbd_macro)) error ("No kbd macro has been defined"); else Fexecute_kbd_macro (current_kboard->Vlast_kbd_macro, prefix); + + /* command_loop_1 sets this to nil before it returns; + get back the last command within the macro + so that it can be last, again, after we return. */ + Vthis_command = current_kboard->Vlast_command; + return Qnil; } /* Restore Vexecuting_macro and executing_macro_index - called when the unwind-protect in Fexecute_kbd_macro gets invoked. */ + static Lisp_Object pop_kbd_macro (info) Lisp_Object info; { Lisp_Object tem; - Vexecuting_macro = Fcar (info); - tem = Fcdr (info); - executing_macro_index = XINT (tem); + Vexecuting_macro = XCAR (info); + tem = XCDR (info); + executing_macro_index = XINT (XCAR (tem)); + real_this_command = XCDR (tem); + Frun_hooks (1, &Qkbd_macro_termination_hook); return Qnil; } @@ -218,6 +289,9 @@ COUNT is a repeat count, or nil for once, or 0 for infinite loop.") int pdlcount = specpdl_ptr - specpdl; int repeat = 1; struct gcpro gcpro1; + int success_count = 0; + + executing_macro_iterations = 0; if (!NILP (count)) { @@ -227,39 +301,52 @@ COUNT is a repeat count, or nil for once, or 0 for infinite loop.") final = indirect_function (macro); if (!STRINGP (final) && !VECTORP (final)) - error ("Keyboard macros must be strings or vectors."); + error ("Keyboard macros must be strings or vectors"); - XSETFASTINT (tem, executing_macro_index); - tem = Fcons (Vexecuting_macro, tem); + tem = Fcons (Vexecuting_macro, + Fcons (make_number (executing_macro_index), + real_this_command)); record_unwind_protect (pop_kbd_macro, tem); GCPRO1 (final); do { Vexecuting_macro = final; + executing_macro = final; executing_macro_index = 0; current_kboard->Vprefix_arg = Qnil; command_loop_1 (); + executing_macro_iterations = ++success_count; + QUIT; } while (--repeat && (STRINGP (Vexecuting_macro) || VECTORP (Vexecuting_macro))); + executing_macro = Qnil; + + real_this_command = Vexecuting_macro; + UNGCPRO; return unbind_to (pdlcount, Qnil); } +void init_macros () { Vexecuting_macro = Qnil; + executing_macro = Qnil; } +void syms_of_macros () { Qexecute_kbd_macro = intern ("execute-kbd-macro"); staticpro (&Qexecute_kbd_macro); + Qkbd_macro_termination_hook = intern ("kbd-macro-termination-hook"); + staticpro (&Qkbd_macro_termination_hook); defsubr (&Sstart_kbd_macro); defsubr (&Send_kbd_macro); @@ -281,6 +368,7 @@ syms_of_macros () "Last kbd macro defined, as a string or vector; nil if none defined."); } +void keys_of_macros () { initial_define_key (control_x_map, ('e'), "call-last-kbd-macro");