X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/52d9c1459d45ca1f37ba1a7c9baf159f34522a49..40aeecadb8fc54c941eb36c6584654627c300c39:/src/macros.c diff --git a/src/macros.c b/src/macros.c index 80e3025a9a..5c37f0daa3 100644 --- a/src/macros.c +++ b/src/macros.c @@ -15,7 +15,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, 675 Mass Ave, Cambridge, MA 02139, USA. */ +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ #include @@ -28,9 +29,30 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ Lisp_Object Qexecute_kbd_macro; +/* 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", @@ -50,21 +72,56 @@ 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 *)malloc (30 * sizeof (Lisp_Object)); + = (Lisp_Object *)xmalloc (30 * sizeof (Lisp_Object)); } update_mode_lines++; if (NILP (append)) { + if (current_kboard->kbd_macro_bufsize > 200) + { + current_kboard->kbd_macro_bufsize = 30; + current_kboard->kbd_macro_buffer + = (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; - message("Defining kbd macro..."); + message ("Defining kbd macro..."); } 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; @@ -85,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); @@ -100,7 +157,7 @@ An argument of zero means repeat until error.") = make_event_array ((current_kboard->kbd_macro_end - current_kboard->kbd_macro_buffer), current_kboard->kbd_macro_buffer); - message("Keyboard macro defined"); + message ("Keyboard macro defined"); } if (XFASTINT (repeat) == 0) @@ -116,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; { @@ -143,6 +201,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; @@ -177,25 +236,39 @@ 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); return Qnil; } @@ -211,43 +284,58 @@ 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)) { - count = Fprefix_numeric_value (count); - repeat = XINT (count); - } + if (!NILP (count)) + { + count = Fprefix_numeric_value (count); + repeat = XINT (count); + } 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"); @@ -273,6 +361,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");