From: Juri Linkov <juri@jurta.org>
To: emacs-devel@gnu.org
Subject: Convert a keyboard macro to equivalent Lisp code
Date: Sat, 05 Jun 2010 22:57:04 +0300 [thread overview]
Message-ID: <87fx11mfd3.fsf@mail.jurta.org> (raw)
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/
next reply other threads:[~2010-06-05 19:57 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-06-05 19:57 Juri Linkov [this message]
2010-06-07 9:27 ` Convert a keyboard macro to equivalent Lisp code Richard Stallman
2010-06-07 9:27 ` Richard Stallman
2010-06-07 13:36 ` Stefan Monnier
2010-06-07 18:33 ` Juri Linkov
2010-06-07 18:35 ` Juri Linkov
2010-06-07 20:11 ` Stefan Monnier
2010-06-08 8:05 ` Juri Linkov
2010-06-09 1:36 ` Stefan Monnier
2010-06-09 8:34 ` Juri Linkov
2010-06-09 14:17 ` Stefan Monnier
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87fx11mfd3.fsf@mail.jurta.org \
--to=juri@jurta.org \
--cc=emacs-devel@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).