From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Juri Linkov Newsgroups: gmane.emacs.devel Subject: Convert a keyboard macro to equivalent Lisp code Date: Sat, 05 Jun 2010 22:57:04 +0300 Organization: JURTA Message-ID: <87fx11mfd3.fsf@mail.jurta.org> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: dough.gmane.org 1275768685 6829 80.91.229.12 (5 Jun 2010 20:11:25 GMT) X-Complaints-To: usenet@dough.gmane.org NNTP-Posting-Date: Sat, 5 Jun 2010 20:11:25 +0000 (UTC) To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Sat Jun 05 22:11:23 2010 connect(): No such file or directory Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by lo.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1OKziE-0006SQ-DN for ged-emacs-devel@m.gmane.org; Sat, 05 Jun 2010 22:11:22 +0200 Original-Received: from localhost ([127.0.0.1]:33346 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OKziD-0003JN-GR for ged-emacs-devel@m.gmane.org; Sat, 05 Jun 2010 16:11:21 -0400 Original-Received: from [140.186.70.92] (port=52588 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OKzi2-0003Fv-Ma for emacs-devel@gnu.org; Sat, 05 Jun 2010 16:11:12 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1OKzi0-0004Xc-Gc for emacs-devel@gnu.org; Sat, 05 Jun 2010 16:11:10 -0400 Original-Received: from smtp-out1.starman.ee ([85.253.0.3]:47625 helo=mx1.starman.ee) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1OKzi0-0004XI-1u for emacs-devel@gnu.org; Sat, 05 Jun 2010 16:11:08 -0400 X-Virus-Scanned: by Amavisd-New at mx1.starman.ee Original-Received: from mail.starman.ee (82.131.52.94.cable.starman.ee [82.131.52.94]) by mx1.starman.ee (Postfix) with ESMTP id C0D203F41A4 for ; Sat, 5 Jun 2010 23:11:03 +0300 (EEST) User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.0.50 (x86_64-pc-linux-gnu) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6, seldom 2.4 (older, 4) X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:125550 Archived-At: There is no progress in implementing the task of conversion a keyboard macro to equivalent Lisp code because we approached this task with the "all-or-nothing" attitude. We tried to find the most difficult and controversial cases to justify not doing even basic and straightforward things. I propose to install the basic support for recording all commands and their arguments that will allow everyone to experiment with post-processing to convert the plain trace of executed Lisp commands into something more useful. (It's mainly the function `kmacro-convert-command-history' that could be modified to produce better results). === modified file 'lisp/macros.el' --- lisp/macros.el 2010-03-03 17:31:50 +0000 +++ lisp/macros.el 2010-06-05 19:32:24 +0000 @@ -280,6 +280,41 @@ ;;;###autoload (define-key ctl-x-map "q" 'kbd-macro-query) +;;; Convert a keyboard macro to Lisp code. + +;;;###autoload +(defun insert-last-kbd-macro-command-history () + (interactive) + (insert + "(defun last-kbd-macro-command-history ()\n" + " \"Command created from the last keyboard macro.\"\n") + (comment-region (prog1 (point) + (insert " Original keys: ") + (insert-kbd-macro (intern ""))) + (point)) + (insert " (interactive)\n") + (dolist (s (kmacro-convert-command-history + last-kbd-macro-command-history)) + (insert " " (pp-to-string s))) + (insert ")\n")) + +(defun kmacro-convert-command-history (commands) + (let ((cmds commands) cmd name ret) + (while cmds + (setq cmd (car cmds)) + (setq name (car cmd)) + (cond + ;; Skip next commands. + ((memq name '( + kmacro-start-macro kmacro-end-macro + universal-argument universal-argument-other-key + digit-argument + execute-extended-command + ))) + (t (push cmd ret))) + (setq cmds (cdr cmds))) + (nreverse ret))) + (provide 'macros) ;; arch-tag: 346ed1a5-1220-4bc8-b533-961ee704361f === modified file 'src/callint.c' --- src/callint.c 2010-03-23 16:25:12 +0000 +++ src/callint.c 2010-06-05 19:45:36 +0000 @@ -43,6 +43,7 @@ extern Lisp_Object Vhistory_length; extern Lisp_Object Vthis_original_command, real_this_command; +extern Lisp_Object Vthis_command_args; extern int history_delete_duplicates; Lisp_Object Vcommand_debug_status, Qcommand_debug_status; @@ -326,7 +327,7 @@ specs = Qnil; string = 0; - /* The idea of FILTER_SPECS is to provide away to + /* The idea of FILTER_SPECS is to provide a way to specify how to represent the arguments in command history. The feature is not fully implemented. */ filter_specs = Qnil; @@ -357,23 +358,24 @@ } else { - Lisp_Object input; + Lisp_Object input, values; i = num_input_events; input = specs; /* Compute the arg values using the user's expression. */ GCPRO2 (input, filter_specs); specs = Feval (specs); UNGCPRO; + + /* Make a copy of the list of values, for the command history, + and turn them into things we can eval. */ + values = quotify_args (Fcopy_sequence (specs)); + fix_command (input, values); + Vthis_command_args = values; + if (i != num_input_events || !NILP (record_flag)) { /* We should record this command on the command history. */ - Lisp_Object values; - Lisp_Object this_cmd; - /* Make a copy of the list of values, for the command history, - and turn them into things we can eval. */ - values = quotify_args (Fcopy_sequence (specs)); - fix_command (input, values); - this_cmd = Fcons (function, values); + Lisp_Object this_cmd = Fcons (function, values); if (history_delete_duplicates) Vcommand_history = Fdelete (this_cmd, Vcommand_history); Vcommand_history = Fcons (this_cmd, Vcommand_history); @@ -387,6 +389,15 @@ } } + if (!NILP (current_kboard->defining_kbd_macro) + && ! (minibuf_level > 0)) + { + /* We should record this command on the macro command history. */ + current_kboard->Vlast_kbd_macro_command_history + = Fcons (Fcons (function, values), + current_kboard->Vlast_kbd_macro_command_history); + } + Vthis_command = save_this_command; Vthis_original_command = save_this_original_command; real_this_command= save_real_this_command; @@ -831,18 +842,24 @@ args[0] = function; + /* Make a list of values, for the command history. */ + visargs[0] = function; + for (i = 1; i < count + 1; i++) + { + if (varies[i] > 0) + visargs[i] = Fcons (intern (callint_argfuns[varies[i]]), Qnil); + else + visargs[i] = quotify_arg (args[i]); + } + Vthis_command_args = Fcdr (Flist (count + 1, visargs)); + if (arg_from_tty || !NILP (record_flag)) { - visargs[0] = function; - for (i = 1; i < count + 1; i++) - { - if (varies[i] > 0) - visargs[i] = Fcons (intern (callint_argfuns[varies[i]]), Qnil); - else - visargs[i] = quotify_arg (args[i]); - } - Vcommand_history = Fcons (Flist (count + 1, visargs), - Vcommand_history); + /* We should record this command on the command history. */ + Lisp_Object this_cmd = Fcons (function, Vthis_command_args); + if (history_delete_duplicates) + Vcommand_history = Fdelete (this_cmd, Vcommand_history); + Vcommand_history = Fcons (this_cmd, Vcommand_history); /* Don't keep command history around forever. */ if (INTEGERP (Vhistory_length) && XINT (Vhistory_length) > 0) { @@ -852,6 +869,14 @@ } } + if (!NILP (current_kboard->defining_kbd_macro) + && ! (minibuf_level > 0)) + { + current_kboard->Vlast_kbd_macro_command_history + = Fcons (Fcons (function, Vthis_command_args), + current_kboard->Vlast_kbd_macro_command_history); + } + /* If we used a marker to hold point, mark, or an end of the region, temporarily, convert it to an integer now. */ for (i = 1; i <= count; i++) === modified file 'src/keyboard.c' --- src/keyboard.c 2010-05-25 09:36:21 +0000 +++ src/keyboard.c 2010-06-05 19:33:02 +0000 @@ -339,6 +339,9 @@ command is stored in this-original-command. It is nil otherwise. */ Lisp_Object Vthis_original_command; +/* Arguments of the command being executed by the command loop. */ +Lisp_Object Vthis_command_args; + /* The value of point when the last command was started. */ int last_point_position; @@ -1630,6 +1633,7 @@ Vthis_command = Qnil; real_this_command = Qnil; Vthis_original_command = Qnil; + Vthis_command_args = Qnil; Vthis_command_keys_shift_translated = Qnil; /* Read next key sequence; i gets its length. */ @@ -11471,6 +11475,7 @@ kb->kbd_macro_bufsize = 0; kb->defining_kbd_macro = Qnil; kb->Vlast_kbd_macro = Qnil; + kb->Vlast_kbd_macro_command_history = Qnil; kb->reference_count = 0; kb->Vsystem_key_alist = Qnil; kb->system_key_syms = Qnil; @@ -11990,6 +11995,10 @@ result of looking up the original command in the active keymaps. */); Vthis_original_command = Qnil; + DEFVAR_LISP ("this-command-args", &Vthis_command_args, + doc: /* Arguments of the command being executed. */); + Vthis_command_args = Qnil; + DEFVAR_INT ("auto-save-interval", &auto_save_interval, doc: /* *Number of input events between auto-saves. Zero means disable autosaving due to number of characters typed. */); @@ -12477,6 +12486,7 @@ mark_object (kb->kbd_queue); mark_object (kb->defining_kbd_macro); mark_object (kb->Vlast_kbd_macro); + mark_object (kb->Vlast_kbd_macro_command_history); mark_object (kb->Vsystem_key_alist); mark_object (kb->system_key_syms); mark_object (kb->Vwindow_system); === modified file 'src/keyboard.h' --- src/keyboard.h 2010-01-13 08:35:10 +0000 +++ src/keyboard.h 2010-06-05 19:32:07 +0000 @@ -122,6 +122,9 @@ /* Last anonymous kbd macro defined. */ Lisp_Object Vlast_kbd_macro; + /* Command history of last anonymous kbd macro defined. */ + Lisp_Object Vlast_kbd_macro_command_history; + /* Alist of system-specific X windows key symbols. */ Lisp_Object Vsystem_key_alist; === modified file 'src/macros.c' --- src/macros.c 2010-01-13 08:35:10 +0000 +++ src/macros.c 2010-06-05 19:35:19 +0000 @@ -133,6 +133,7 @@ message ("Appending to kbd macro..."); } current_kboard->defining_kbd_macro = Qt; + current_kboard->Vlast_kbd_macro_command_history = Qnil; return Qnil; } @@ -148,6 +149,8 @@ = make_event_array ((current_kboard->kbd_macro_end - current_kboard->kbd_macro_buffer), current_kboard->kbd_macro_buffer); + current_kboard->Vlast_kbd_macro_command_history + = Fnreverse (current_kboard->Vlast_kbd_macro_command_history); } DEFUN ("end-kbd-macro", Fend_kbd_macro, Send_kbd_macro, 0, 2, "p", @@ -402,6 +405,9 @@ DEFVAR_KBOARD ("last-kbd-macro", Vlast_kbd_macro, doc: /* Last kbd macro defined, as a string or vector; nil if none defined. */); + + DEFVAR_KBOARD ("last-kbd-macro-command-history", Vlast_kbd_macro_command_history, + doc: /* Command history of last kbd macro defined, as a list; nil if none defined. */); } /* arch-tag: d293fcc9-2266-4163-9198-7fa0de12ec9e -- Juri Linkov http://www.jurta.org/emacs/