unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Convert a keyboard macro to equivalent Lisp code
@ 2010-06-05 19:57 Juri Linkov
  2010-06-07  9:27 ` Richard Stallman
                   ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Juri Linkov @ 2010-06-05 19:57 UTC (permalink / raw)
  To: emacs-devel

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/



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Convert a keyboard macro to equivalent Lisp code
  2010-06-05 19:57 Convert a keyboard macro to equivalent Lisp code Juri Linkov
@ 2010-06-07  9:27 ` Richard Stallman
  2010-06-07  9:27 ` Richard Stallman
  2010-06-07 18:35 ` Juri Linkov
  2 siblings, 0 replies; 11+ messages in thread
From: Richard Stallman @ 2010-06-07  9:27 UTC (permalink / raw)
  To: Juri Linkov; +Cc: emacs-devel

Could you please add comments explaining the new things that
the code in callint.c is doing?



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Convert a keyboard macro to equivalent Lisp code
  2010-06-05 19:57 Convert a keyboard macro to equivalent Lisp code Juri Linkov
  2010-06-07  9:27 ` 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
  2 siblings, 2 replies; 11+ messages in thread
From: Richard Stallman @ 2010-06-07  9:27 UTC (permalink / raw)
  To: Juri Linkov; +Cc: emacs-devel

Could you please add comments explaining the new things that
the code in callint.c is doing?

It is rather ugly that the conversion can only apply to the last
macro, not to other macros that were saved under names.  How about
saving the Lisp code when giving a name to a macro?



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Convert a keyboard macro to equivalent Lisp code
  2010-06-07  9:27 ` Richard Stallman
@ 2010-06-07 13:36   ` Stefan Monnier
  2010-06-07 18:33   ` Juri Linkov
  1 sibling, 0 replies; 11+ messages in thread
From: Stefan Monnier @ 2010-06-07 13:36 UTC (permalink / raw)
  To: rms; +Cc: Juri Linkov, emacs-devel

> It is rather ugly that the conversion can only apply to the last
> macro, not to other macros that were saved under names.

Agreed.  Given such a restriction, it would make more sense to do the
conversion directly while recording the macro (so you either record
a "keyboard macro" (the old thingy) or a "command macro" (the new
thingy)).  One advantage of this approach is that it makes it OK if it
behaves a bit differently than keyboard macros, since it's
a different beast.


        Stefan



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Convert a keyboard macro to equivalent Lisp code
  2010-06-07  9:27 ` Richard Stallman
  2010-06-07 13:36   ` Stefan Monnier
@ 2010-06-07 18:33   ` Juri Linkov
  1 sibling, 0 replies; 11+ messages in thread
From: Juri Linkov @ 2010-06-07 18:33 UTC (permalink / raw)
  To: rms; +Cc: emacs-devel

> Could you please add comments explaining the new things that
> the code in callint.c is doing?

Ok, will do.

> It is rather ugly that the conversion can only apply to the last
> macro, not to other macros that were saved under names.  How about
> saving the Lisp code when giving a name to a macro?

The following patch saves the Lisp code in the symbol property
of the keyboard macro in `name-last-kbd-macro', and uses it
in `insert-kbd-macro-commands' whose interactive spec now is
like the interactive spec of `insert-kbd-macro':

=== modified file 'lisp/macros.el'
--- lisp/macros.el	2010-03-03 17:31:50 +0000
+++ lisp/macros.el	2010-06-07 18:32:45 +0000
@@ -46,7 +46,8 @@ (defun name-last-kbd-macro (symbol)
 	      symbol))
   (if (string-equal symbol "")
       (error "No command name given"))
-  (fset symbol last-kbd-macro))
+  (fset symbol last-kbd-macro)
+  (put symbol 'kbd-macro-command-history last-kbd-macro-command-history))
 
 ;;;###autoload
 (defun insert-kbd-macro (macroname &optional keys)
@@ -280,6 +281,57 @@ (defun apply-macro-to-region-lines (top
 
 ;;;###autoload (define-key ctl-x-map "q" 'kbd-macro-query)
 
+;;; Convert a keyboard macro to Lisp code.
+
+;;;###autoload
+(defun insert-kbd-macro-commands (macroname)
+  "Insert in buffer the commands of kbd macro NAME, as Lisp code.
+
+To save a kbd macro, visit a file of Lisp code such as your `~/.emacs',
+use this command, and then save the file."
+  (interactive
+   (list (intern (completing-read
+		  "Insert Lisp commands of kbd macro (name): "
+		  obarray
+		  (lambda (elt)
+		    (and (fboundp elt)
+			 (get elt 'kbd-macro-command-history)))
+		  t))))
+  (let (definition)
+    (if (or (null macroname)
+	    (string= (symbol-name macroname) ""))
+	(setq macroname 'last-kbd-macro definition last-kbd-macro)
+      (setq definition (get macroname 'kbd-macro-command-history)))
+    (insert
+     "(defun " (format "%s" macroname) " ()\n"
+     "  \"Command created from the 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

-- 
Juri Linkov
http://www.jurta.org/emacs/



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Convert a keyboard macro to equivalent Lisp code
  2010-06-05 19:57 Convert a keyboard macro to equivalent Lisp code Juri Linkov
  2010-06-07  9:27 ` Richard Stallman
  2010-06-07  9:27 ` Richard Stallman
@ 2010-06-07 18:35 ` Juri Linkov
  2010-06-07 20:11   ` Stefan Monnier
  2 siblings, 1 reply; 11+ messages in thread
From: Juri Linkov @ 2010-06-07 18:35 UTC (permalink / raw)
  To: emacs-devel

To get useful results, some commands should provide their arguments
explicitly in the interactive spec instead of relying on global
variables.  So instead of useless `(self-insert-command 1)' typing `A'
will record `(self-insert-command 1 65)' with the following patch.
The same is for isearch.

=== modified file 'src/cmds.c'
--- src/cmds.c	2010-05-25 09:36:21 +0000
+++ src/cmds.c	2010-06-07 18:34:33 +0000
@@ -331,19 +331,23 @@
 
 /* Note that there's code in command_loop_1 which typically avoids
    calling this.  */
-DEFUN ("self-insert-command", Fself_insert_command, Sself_insert_command, 1, 1, "p",
+DEFUN ("self-insert-command", Fself_insert_command, Sself_insert_command, 1, 2,
+       "(list (prefix-numeric-value current-prefix-arg) last-command-event)",
        doc: /* Insert the character you type.
 Whichever character you type to run this command is inserted.
 Before insertion, `expand-abbrev' is executed if the inserted character does
 not have word syntax and the previous character in the buffer does.
 After insertion, the value of `auto-fill-function' is called if the
 `auto-fill-chars' table has a non-nil value for the inserted character.  */)
-     (n)
-     Lisp_Object n;
+     (n, last_char)
+     Lisp_Object n, last_char;
 {
   int remove_boundary = 1;
   CHECK_NUMBER (n);
 
+  if (NILP (last_char))
+    last_char = last_command_event;
+
   if (!EQ (Vthis_command, current_kboard->Vlast_command))
     nonundocount = 0;
 
@@ -365,11 +369,11 @@ (at your option) any later version.
     current_buffer->undo_list = XCDR (current_buffer->undo_list);
 
   /* Barf if the key that invoked this was not a character.  */
-  if (!CHARACTERP (last_command_event))
+  if (!CHARACTERP (last_char))
     bitch_at_user ();
   {
     int character = translate_char (Vtranslation_table_for_input,
-				    XINT (last_command_event));
+				    XINT (last_char));
     if (XINT (n) >= 2 && NILP (current_buffer->overwrite_mode))
       {
 	XSETFASTINT (n, XFASTINT (n) - 2);

=== modified file 'lisp/isearch.el'
--- lisp/isearch.el	2010-05-20 23:16:04 +0000
+++ lisp/isearch.el	2010-06-06 18:30:52 +0000
@@ -1995,10 +1995,10 @@ (defun isearch-return-char ()
   (isearch-process-search-char ?\n))
 (make-obsolete 'isearch-return-char 'isearch-printing-char "19.7")
 
-(defun isearch-printing-char ()
+(defun isearch-printing-char (&optional char)
   "Add this ordinary printing character to the search string and search."
-  (interactive)
-  (let ((char last-command-event))
+  (interactive (list last-command-event))
+  (let ((char (or char last-command-event)))
     (if (= char ?\S-\ )
 	(setq char ?\s))
     (if current-input-method

-- 
Juri Linkov
http://www.jurta.org/emacs/



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Convert a keyboard macro to equivalent Lisp code
  2010-06-07 18:35 ` Juri Linkov
@ 2010-06-07 20:11   ` Stefan Monnier
  2010-06-08  8:05     ` Juri Linkov
  0 siblings, 1 reply; 11+ messages in thread
From: Stefan Monnier @ 2010-06-07 20:11 UTC (permalink / raw)
  To: Juri Linkov; +Cc: emacs-devel

> To get useful results, some commands should provide their arguments
> explicitly in the interactive spec instead of relying on global
> variables.  So instead of useless `(self-insert-command 1)' typing `A'
> will record `(self-insert-command 1 65)' with the following patch.
> The same is for isearch.

This will break all Elisp calls to self-insert-command (grep finds more
than 100 of them in lisp/**/*.el) ;-(

So I think it's not an option.  Better would be to have your
command-recording code provide hooks such that commands like
self-insert-command can teach it how to turn them into Elisp code (in
the case of self-insert-command it should probably use `insert').

Of course, even better would be if the code run during macro recording
is the code generated (so if the behavior is different from the normal
command's behavior, you might see it during recording).


        Stefan



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Convert a keyboard macro to equivalent Lisp code
  2010-06-07 20:11   ` Stefan Monnier
@ 2010-06-08  8:05     ` Juri Linkov
  2010-06-09  1:36       ` Stefan Monnier
  0 siblings, 1 reply; 11+ messages in thread
From: Juri Linkov @ 2010-06-08  8:05 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

>> To get useful results, some commands should provide their arguments
>> explicitly in the interactive spec instead of relying on global
>> variables.  So instead of useless `(self-insert-command 1)' typing `A'
>> will record `(self-insert-command 1 65)' with the following patch.
>> The same is for isearch.
>
> This will break all Elisp calls to self-insert-command (grep finds more
> than 100 of them in lisp/**/*.el) ;-(

I don't understand how it breaks Elisp calls.  The new second arg `last_char'
is optional.  When it's nil, this code is executed to preserve the
original behavior:

  if (NILP (last_char))
    last_char = last_command_event;

Or maybe not calling `translate_char' will break `self-insert-command'?

> So I think it's not an option.  Better would be to have your
> command-recording code provide hooks such that commands like
> self-insert-command can teach it how to turn them into Elisp code (in
> the case of self-insert-command it should probably use `insert').

Yes, where adding a new optional argument is impossible,
it's easy to record the right command.  For instance, if
`self-insert-command' needs to call `translate_char' to
record the right translated character, then after the call
to `translate_char' in `Fself_insert_command' we could replace
the recorded useless command `(self-insert-command 1)'
with the right command `(insert-char 1 65)':

=== modified file 'src/cmds.c'
--- src/cmds.c	2010-05-25 09:36:21 +0000
+++ src/cmds.c	2010-06-08 08:04:05 +0000
@@ -365,3 +370,3 @@
     int character = translate_char (Vtranslation_table_for_input,
				    XINT (last_command_event));

+    if (!NILP (current_kboard->defining_kbd_macro) && ! (minibuf_level > 0))
+      XSETCAR (current_kboard->Vlast_kbd_macro_command_history,
+	       Fcons (intern ("insert-char"),
+		      Fcons (make_number (character), Fcons (n, Qnil))));
+
     if (XINT (n) >= 2 && NILP (current_buffer->overwrite_mode))
       {
 	XSETFASTINT (n, XFASTINT (n) - 2);

> Of course, even better would be if the code run during macro recording
> is the code generated (so if the behavior is different from the normal
> command's behavior, you might see it during recording).

We could later add an option to verify to macro during recording.

-- 
Juri Linkov
http://www.jurta.org/emacs/



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Convert a keyboard macro to equivalent Lisp code
  2010-06-08  8:05     ` Juri Linkov
@ 2010-06-09  1:36       ` Stefan Monnier
  2010-06-09  8:34         ` Juri Linkov
  0 siblings, 1 reply; 11+ messages in thread
From: Stefan Monnier @ 2010-06-09  1:36 UTC (permalink / raw)
  To: Juri Linkov; +Cc: emacs-devel

>>> To get useful results, some commands should provide their arguments
>>> explicitly in the interactive spec instead of relying on global
>>> variables.  So instead of useless `(self-insert-command 1)' typing `A'
>>> will record `(self-insert-command 1 65)' with the following patch.
>>> The same is for isearch.
>> This will break all Elisp calls to self-insert-command (grep finds more
>> than 100 of them in lisp/**/*.el) ;-(
> I don't understand how it breaks Elisp calls.

The part you don't understand is that I only noticed your

>   if (NILP (last_char))
>     last_char = last_command_event;

right *after* sending my email.

>> Of course, even better would be if the code run during macro recording
>> is the code generated (so if the behavior is different from the normal
>> command's behavior, you might see it during recording).
> We could later add an option to verify to macro during recording.

I'm heading towards a special "recording&running macro" mode where
various commands may have a slightly different behavior (less DWIMish,
more amenable to scripting, more amenable to transforming into Elisp
code), so "verifying" might not be the right approach since a different
behavior might not be a problem but a feature.


        Stefan



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Convert a keyboard macro to equivalent Lisp code
  2010-06-09  1:36       ` Stefan Monnier
@ 2010-06-09  8:34         ` Juri Linkov
  2010-06-09 14:17           ` Stefan Monnier
  0 siblings, 1 reply; 11+ messages in thread
From: Juri Linkov @ 2010-06-09  8:34 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

> The part you don't understand is that I only noticed your
>
>>   if (NILP (last_char))
>>     last_char = last_command_event;
>
> right *after* sending my email.

But your objection prompted me to look closely at `self-insert-command',
and I found another reason (`translate_char') why it won't work ;-)

>>> Of course, even better would be if the code run during macro recording
>>> is the code generated (so if the behavior is different from the normal
>>> command's behavior, you might see it during recording).
>> We could later add an option to verify to macro during recording.
>
> I'm heading towards a special "recording&running macro" mode where
> various commands may have a slightly different behavior (less DWIMish,
> more amenable to scripting, more amenable to transforming into Elisp
> code), so "verifying" might not be the right approach since a different
> behavior might not be a problem but a feature.

Then it's a different feature.  This is more like command translation
during recording and running a macro.  This is already possible to do
without core support with:

(add-hook 'pre-command-hook
	  (lambda ()
	    (when (or defining-kbd-macro executing-kbd-macro)
	      (cond ((eq this-command 'next-line)
		     (setq this-command 'forward-line))))))

and maybe better:

(add-hook 'pre-command-hook
	  (lambda ()
	    (when (or defining-kbd-macro executing-kbd-macro)
	      (cond ((memq this-command '(next-line previous-line))
		     (setq line-move-visual nil))))))

(add-hook 'post-command-hook
	  (lambda ()
	    (when (or defining-kbd-macro executing-kbd-macro)
	      (cond ((memq this-command '(next-line previous-line))
		     (setq line-move-visual t))))))

-- 
Juri Linkov
http://www.jurta.org/emacs/



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: Convert a keyboard macro to equivalent Lisp code
  2010-06-09  8:34         ` Juri Linkov
@ 2010-06-09 14:17           ` Stefan Monnier
  0 siblings, 0 replies; 11+ messages in thread
From: Stefan Monnier @ 2010-06-09 14:17 UTC (permalink / raw)
  To: Juri Linkov; +Cc: emacs-devel

> But your objection prompted me to look closely at `self-insert-command',
> and I found another reason (`translate_char') why it won't work ;-)

AFAIK translate-char is not used.  I suggested to get rid of it in
Emacs-23, so it's obsolete since Emacs-23.1.
AFAIK it's only ever been used for Emacs-22's char-unification support.

>> I'm heading towards a special "recording&running macro" mode where
>> various commands may have a slightly different behavior (less DWIMish,
>> more amenable to scripting, more amenable to transforming into Elisp
>> code), so "verifying" might not be the right approach since a different
>> behavior might not be a problem but a feature.
> Then it's a different feature.

Yes and no: yes, in the sense that the difference is considered
a feature, but no in the sense that it's *very* similar, used for the
same purpose, and could use the same keybindings.

> This is more like command translation during recording and running
> a macro.  This is already possible to do without core support with:

If it can be done without changing C code, that's an advantage.

> (add-hook 'pre-command-hook
> 	  (lambda ()
> 	    (when (or defining-kbd-macro executing-kbd-macro)
> 	      (cond ((eq this-command 'next-line)
> 		     (setq this-command 'forward-line))))))

Yuck.

> (add-hook 'pre-command-hook
> 	  (lambda ()
> 	    (when (or defining-kbd-macro executing-kbd-macro)
> 	      (cond ((memq this-command '(next-line previous-line))
> 		     (setq line-move-visual nil))))))

> (add-hook 'post-command-hook
> 	  (lambda ()
> 	    (when (or defining-kbd-macro executing-kbd-macro)
> 	      (cond ((memq this-command '(next-line previous-line))
> 		     (setq line-move-visual t))))))

Even more yuck!

Those settings would be enabled disabled when you enter/leave the macro
recording/running mode rather than around each command.  Still, the
above does not record the commands, so there's more work to do.


        Stefan



^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2010-06-09 14:17 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-06-05 19:57 Convert a keyboard macro to equivalent Lisp code Juri Linkov
2010-06-07  9:27 ` 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

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).