unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Is there a plan to record kbd macro as elisp code?
@ 2007-10-27  9:28 yzhh
  2007-10-27 15:48 ` Robert J. Chassell
                   ` (2 more replies)
  0 siblings, 3 replies; 37+ messages in thread
From: yzhh @ 2007-10-27  9:28 UTC (permalink / raw)
  To: emacs-devel

Hi,

Recording kbd macro as elisp code can be useful. The following are some 
benefits:
1. Editing elisp code is more clear than editing key sequences, and supports 
complex controlstructures. 
2. elisp code is more portable than key sequences. Sharing with others who 
have different key bindings is ok for elisp, but not for key sequences.
3. It can be used as a means ot learn emacs commands in elisp form.

I tried to build a modified emacs that stores every command sent to 
'execute-command' into a list, when 'defining-kbd-macro' is on. But the 
result is a list that still leaves out things like horizontal movements. 
And isearch is not recorded right (one search recorded as many isearch 
commands, without information of what's being searched).

So I know the modification required is not simple, far beyond a quick and 
dirty patch.

Out of curiosity I want to know whether there is a plan for this feature in 
the future.

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-27  9:28 Is there a plan to record kbd macro as elisp code? yzhh
@ 2007-10-27 15:48 ` Robert J. Chassell
  2007-10-27 17:30   ` yzhh
  2007-10-27 19:26   ` Jay Belanger
  2007-10-27 16:20 ` Drew Adams
  2007-10-29  6:41 ` Klaus Zeitler
  2 siblings, 2 replies; 37+ messages in thread
From: Robert J. Chassell @ 2007-10-27 15:48 UTC (permalink / raw)
  To: emacs-devel

yezonghui@gmail.com wrote:

    Recording kbd macro as elisp code can be useful.

It certainly can be.  More than a dozen years ago an early
distribution of Calc mode did this.  Unfortunately, as far as I
remember, its functionality did no more than you have done.  Worse, it
vanished from my distribution a decade or so ago and by the time I
looked again, perhaps five years ago, it was gone.

Even the little bit you have done could be helpful.

Please write up what you have as an Emacs Lisp library that can be
loaded by `emacs -q', with a name such as
yzhh-define-elisp-interactively.el, and submit it.

Thank you!

(Jay Belanger: do you have really old copies of Calc mode, such as the
first that Dave Gillespie distributed?  I think that has the
capability, but I could be wrong.  It has been a very long time.)

-- 
    Robert J. Chassell                          GnuPG Key ID: 004B4AC8
    bob@rattlesnake.com                         bob@gnu.org
    http://www.rattlesnake.com                  http://www.teak.cc

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

* RE: Is there a plan to record kbd macro as elisp code?
  2007-10-27  9:28 Is there a plan to record kbd macro as elisp code? yzhh
  2007-10-27 15:48 ` Robert J. Chassell
@ 2007-10-27 16:20 ` Drew Adams
  2007-10-27 17:13   ` yzhh
  2007-10-28 13:50   ` Richard Stallman
  2007-10-29  6:41 ` Klaus Zeitler
  2 siblings, 2 replies; 37+ messages in thread
From: Drew Adams @ 2007-10-27 16:20 UTC (permalink / raw)
  To: yzhh, emacs-devel

> Recording kbd macro as elisp code can be useful. The following are some
> benefits:
> 1. Editing elisp code is more clear than editing key sequences,
> and supports complex controlstructures.
> 2. elisp code is more portable than key sequences. Sharing with
> others who have different key bindings is ok for elisp, but not
> for key sequences.
> 3. It can be used as a means ot learn emacs commands in elisp form.
>
> I tried to build a modified emacs that stores every command sent to
> 'execute-command' into a list, when 'defining-kbd-macro' is on. But the
> result is a list that still leaves out things like horizontal movements.
> And isearch is not recorded right (one search recorded as many isearch
> commands, without information of what's being searched).
>
> So I know the modification required is not simple, far beyond a quick and
> dirty patch.
>
> Out of curiosity I want to know whether there is a plan for this
> feature in the future.

IIRC, there used to be such a feature, bound to `C-x [' and `C-x ]' I think.
It generated Elisp for the defined macro. Worked pretty well - gave you at
least a skeleton you could complete to make a proper command definition.

Unless it was in Epoch or Gosling Emacs. It's been a while...

I think the command name was `gen-' something, but I can't find anything
about this in Google - perhaps I'm not a good googler.

The Emacs Lisp List has this entry, but the link appears to be dead:
macro-generate.el --- [Turn a keyboard macro into lisp code.] Contact:
[unknown]. Perhaps that was what I was thinking of. This is the (dead?) URL:
http://www.dtek.chalmers.se/~d3rydma/Hack/emacs/Archive/macro-generate.el.

And this page (http://www.bookshelf.jp/soft/meadow_46.html#SEC669) mentions
in connection with macro-generate.el, commands `gen-start-generating',
`gen-stop-generating', and `gen-expand-macro'. I think this was what I used
to use. Perhaps you can find it somewhere else on the Web - I couldn't.

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-27 16:20 ` Drew Adams
@ 2007-10-27 17:13   ` yzhh
  2007-10-27 17:40     ` Drew Adams
  2007-10-28 13:50   ` Richard Stallman
  1 sibling, 1 reply; 37+ messages in thread
From: yzhh @ 2007-10-27 17:13 UTC (permalink / raw)
  To: emacs-devel

Drew Adams <drew.adams <at> oracle.com> writes:

> IIRC, there used to be such a feature, bound to `C-x [' and `C-x ]' I think.
> It generated Elisp for the defined macro. Worked pretty well - gave you at
> least a skeleton you could complete to make a proper command definition.
> 
> Unless it was in Epoch or Gosling Emacs. It's been a while...
> 
> I think the command name was `gen-' something, but I can't find anything
> about this in Google - perhaps I'm not a good googler.
> 
> The Emacs Lisp List has this entry, but the link appears to be dead:
> macro-generate.el --- [Turn a keyboard macro into lisp code.] Contact:
> [unknown]. Perhaps that was what I was thinking of. This is the (dead?) URL:
> http://www.dtek.chalmers.se/~d3rydma/Hack/emacs/Archive/macro-generate.el.
> 
> And this page (http://www.bookshelf.jp/soft/meadow_46.html#SEC669) mentions
> in connection with macro-generate.el, commands `gen-start-generating',
> `gen-stop-generating', and `gen-expand-macro'. I think this was what I used
> to use. Perhaps you can find it somewhere else on the Web - I couldn't.
> 

I'm sorry I didn't mention the path I've gone through. Actually I've found 
a version of generate.el, which is made in 1989. It includes those functions 
with similar names you cited (without 'gen-' prefix). And I runs without an
error in emacs22. But it leaves out too much commands in the generated code.
I looked into generated.el's implementation, and found it actually reads 
command-history to get the code. And command-history itself is leaving out
a lot commands.

That's why I made those modifications, trying to get a complete command
history. And then the story you've read.

Please also read my reply to Robert.

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-27 15:48 ` Robert J. Chassell
@ 2007-10-27 17:30   ` yzhh
  2007-10-27 18:01     ` Drew Adams
  2007-10-27 20:04     ` Stefan Monnier
  2007-10-27 19:26   ` Jay Belanger
  1 sibling, 2 replies; 37+ messages in thread
From: yzhh @ 2007-10-27 17:30 UTC (permalink / raw)
  To: emacs-devel

Robert J. Chassell <bob <at> rattlesnake.com> writes:

> It certainly can be.  More than a dozen years ago an early
> distribution of Calc mode did this.  Unfortunately, as far as I
> remember, its functionality did no more than you have done.  Worse, it
> vanished from my distribution a decade or so ago and by the time I
> looked again, perhaps five years ago, it was gone.

I didn't find things relating to Calc mode when I searched the web on 
this topic. Hope you remember it right and get it back. Please let me
known when you do.

> Even the little bit you have done could be helpful.
> 
> Please write up what you have as an Emacs Lisp library that can be
> loaded by `emacs -q', with a name such as
> yzhh-define-elisp-interactively.el, and submit it.
> 

Thank you for your appreciation. But my modification is in the C code of 
emacs, because 'execute-command' and 'call-interactively' are in C code.
And I don't think my dirty code would be a valid patch for the emacs 
developers.

As far as I can see, recording everything including isearch, query-replace
and alike in a general way would need modification in C code. And that
modification very probably require quite some re-design of emacs internal
control structure (the command loop and kbd macro implementation). All 
these are out of my reach for the moment.

> Thank you!

Thank you too. And please read my reply to Drew.

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

* RE: Is there a plan to record kbd macro as elisp code?
  2007-10-27 17:13   ` yzhh
@ 2007-10-27 17:40     ` Drew Adams
  2007-10-27 18:05       ` yzhh
  2007-10-27 19:22       ` Robert J. Chassell
  0 siblings, 2 replies; 37+ messages in thread
From: Drew Adams @ 2007-10-27 17:40 UTC (permalink / raw)
  To: yzhh, emacs-devel

> I'm sorry I didn't mention the path I've gone through. Actually
> I've found a version of generate.el, which is made in 1989. It includes
> those functions with similar names you cited (without 'gen-' prefix).
> And I runs without an error in emacs22. But it leaves out too much
> commands in the generated code. I looked into generated.el's
> implementation, and found it actually reads command-history to get the
> code. And command-history itself is leaving out a lot commands.
>
> That's why I made those modifications, trying to get a complete command
> history. And then the story you've read.
>
> Please also read my reply to Robert.

I didn't see your reply to Robert.

Yes, I think now that it was generate.el I was thinking of. There appear to
be different kinds of files with this same name, however (e.g. one that
generates MPEG files). I guess the one you found is this?
http://mirrors.wikifusion.info/gnu/elisp-archive/as-is/generate.el.Z

Doesn't generate.el give you enough of a code skeleton to complete the
command? You mention missing horizontal movement commands and a fragmented
treatment of isearch, but it should be possible to patch up the code in
those areas, no? Of course, if you could improve it, that would be even
better. Good luck, and please post what you've got when you're done
somewhere (e.g. gnu-emacs-sources, Emacs Wiki).

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

* RE: Is there a plan to record kbd macro as elisp code?
  2007-10-27 17:30   ` yzhh
@ 2007-10-27 18:01     ` Drew Adams
  2007-10-28 13:50       ` Richard Stallman
  2007-10-27 20:04     ` Stefan Monnier
  1 sibling, 1 reply; 37+ messages in thread
From: Drew Adams @ 2007-10-27 18:01 UTC (permalink / raw)
  To: yzhh, emacs-devel

> > Even the little bit you have done could be helpful.
> >
> > Please write up what you have as an Emacs Lisp library that can be
> > loaded by `emacs -q', with a name such as
> > yzhh-define-elisp-interactively.el, and submit it.
> >
>
> Thank you for your appreciation. But my modification is in the C code of
> emacs, because 'execute-command' and 'call-interactively' are in C code.
> And I don't think my dirty code would be a valid patch for the emacs
> developers.
>
> As far as I can see, recording everything including isearch, query-replace
> and alike in a general way would need modification in C code. And that
> modification very probably require quite some re-design of emacs internal
> control structure (the command loop and kbd macro implementation). All
> these are out of my reach for the moment.

Are you sure what you want is worth messing with the C code? If so, why
couldn't it be a valid C patch to Emacs? Other people here (not I) can
perhaps help you with the coding style (e.g. vs "dirty").

Why is it important to handle the cases you mentioned: isearch and
horizontal movement? I can see that it would be good to handle them better,
but if that means code that no one else can take advantage of, then the
benefit is limited. Maybe you could, as Robert suggested, at least post the
Lisp code part, unless it absolutely depends on the "dirty" C code part.

Wrt isearch, I think you said that the problem was that the code generated
multiple little searches (with missing search strings) instead of a single
big search (or something like that). Couldn't the tiny searches be combined
into an overall search, by hand (given knowledge of the search string)?

I don't mean to discourage you; I'm just looking for a way for you to make
your work into a useful contribution. Perhaps aim for something less than
100% complete, something that helps a user define a command based on a
keyboard macro, but doesn't do that completely automatically.

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-27 17:40     ` Drew Adams
@ 2007-10-27 18:05       ` yzhh
  2007-10-27 19:22       ` Robert J. Chassell
  1 sibling, 0 replies; 37+ messages in thread
From: yzhh @ 2007-10-27 18:05 UTC (permalink / raw)
  To: emacs-devel

Drew Adams <drew.adams <at> oracle.com> writes:
 
> I didn't see your reply to Robert.

I wrote the one for you first. And you are so quick...
 
> Yes, I think now that it was generate.el I was thinking of. There appear to
> be different kinds of files with this same name, however (e.g. one that
> generates MPEG files). I guess the one you found is this?
> http://mirrors.wikifusion.info/gnu/elisp-archive/as-is/generate.el.Z

Yes, that's exactly the one I have.

> Doesn't generate.el give you enough of a code skeleton to complete the
> command? You mention missing horizontal movement commands and a fragmented
> treatment of isearch, but it should be possible to patch up the code in
> those areas, no? Of course, if you could improve it, that would be even
> better. Good luck, and please post what you've got when you're done
> somewhere (e.g. gnu-emacs-sources, Emacs Wiki).
> 

Yes, it's a good skeleton, which relies on command history. Now you should have
saw my reply to Robert and understand the difficulties I see is not in
generate.el. It's about a complete and correct command history that emacs seems 
not having been designed to provide.

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-27 17:40     ` Drew Adams
  2007-10-27 18:05       ` yzhh
@ 2007-10-27 19:22       ` Robert J. Chassell
  2007-10-27 20:11         ` Drew Adams
  1 sibling, 1 reply; 37+ messages in thread
From: Robert J. Chassell @ 2007-10-27 19:22 UTC (permalink / raw)
  To: emacs-devel

Thanks, Drew -- it turned out I had it, but I never thought of the
name generate.el so I never discovered it.

yzhh, I am glad you brought this up.

It was not part of Calc but earlier.  I was wrong to think it was part
of Calc -- my apologies.

My copy says

    ;;; module: 	generate.el
    ;;;; version: 	2.0
    ;;;; author: 	Ciaran A Byrne ciaran@gec-rl-hrc.co.uk
    ;;;; date:	2:Sept:87

That is 20 years ago!

    http://mirrors.wikifusion.info/gnu/elisp-archive/as-is/generate.el.Z

provides the same library.  It works both in Emacs 22 and in this
morning's CVS snapshot of GNU Emacs 23.0.50!

As Drew says,

    ... I'm just looking for a way for you to make your work into a
    useful contribution.  Perhaps aim for something less than 100%
    complete, something that helps a user define a command based on a
    keyboard macro, but doesn't do that completely automatically.

yzhh, doing that would be helpful.

Many of my macros involve searches, but in Emacs Lisp I can change
those instances to search-forward and re-search-forward.

-- 
    Robert J. Chassell                          GnuPG Key ID: 004B4AC8
    bob@rattlesnake.com                         bob@gnu.org
    http://www.rattlesnake.com                  http://www.teak.cc

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-27 15:48 ` Robert J. Chassell
  2007-10-27 17:30   ` yzhh
@ 2007-10-27 19:26   ` Jay Belanger
  1 sibling, 0 replies; 37+ messages in thread
From: Jay Belanger @ 2007-10-27 19:26 UTC (permalink / raw)
  To: emacs-devel; +Cc: jay.p.belanger


"Robert J. Chassell" <bob@rattlesnake.com> writes:
...
> (Jay Belanger: do you have really old copies of Calc mode, such as
> the first that Dave Gillespie distributed?

No, but in the past I've looked for old copies.  comp.sources.misc, at
least the Google archives, have Calc 2.00 sources, and patches between
earlier versions, but not the sources for any earlier version.  If
anyone knows where to get old copies of Calc, please let me know.

> I think that has the capability, but I could be wrong.  It has been
> a very long time.

The files README and README.prev, which mention the changes between
the various Calc versions, sometimes mention things that are removed.
Those files don't mention any macro to lisp features,  but that
certainly isn't conclusive.  The removal of macedit.el in favor of
Emacs's edmacro is mentioned.

Jay

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-27 17:30   ` yzhh
  2007-10-27 18:01     ` Drew Adams
@ 2007-10-27 20:04     ` Stefan Monnier
  2007-10-27 21:22       ` Kim F. Storm
  2007-10-27 21:45       ` Juri Linkov
  1 sibling, 2 replies; 37+ messages in thread
From: Stefan Monnier @ 2007-10-27 20:04 UTC (permalink / raw)
  To: yzhh; +Cc: emacs-devel

> Thank you for your appreciation. But my modification is in the C code of 
> emacs, because 'execute-command' and 'call-interactively' are in C code.
> And I don't think my dirty code would be a valid patch for the emacs 
> developers.

I think what was expected was to first record a keyboard macro and later to
turn that into elisp code.  Another approach is to use a pre-command-hook to
record the value of `this-command' for each command run.


        Stefan

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

* RE: Is there a plan to record kbd macro as elisp code?
  2007-10-27 19:22       ` Robert J. Chassell
@ 2007-10-27 20:11         ` Drew Adams
  0 siblings, 0 replies; 37+ messages in thread
From: Drew Adams @ 2007-10-27 20:11 UTC (permalink / raw)
  To: bob, emacs-devel

> Thanks, Drew -- it turned out I had it, but I never thought of the
> name generate.el so I never discovered it.

De nada. Bits and pieces of collective oldbie memory can be almost as good
as a single newbie memory sometimes. I remembered the key bindings and the
"gen" part of the command names; that's all. And I was wrong about the key
bindings - I had probably bound them to `C-x [' and `C-x ]' because of the
conflict with (the suggested) `C-x (' and `C-x )'.

I no longer had the file myself. I tossed all Emacs files that weren't my
own when I swam across the Atlantic many moon ago - too much baggage, and
some of the files would have attracted sharks.

I was thinking that this feature was part of Emacs, but that was mistaken.
Perhaps Yzhh will fix up something that could be added to Emacs. I remember
using this quite a bit back in the Middle Ages.

> That is 20 years ago!

Yup. We should get a gold medal just for surviving Emacs this long. Emacs
should get a medal for surviving us this long too...

Hey, I hear Richard's having a big 35th birthday party for Emacs in 2011 at
his house! Ya'll come!

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-27 20:04     ` Stefan Monnier
@ 2007-10-27 21:22       ` Kim F. Storm
  2007-10-28 13:50         ` Richard Stallman
  2007-10-27 21:45       ` Juri Linkov
  1 sibling, 1 reply; 37+ messages in thread
From: Kim F. Storm @ 2007-10-27 21:22 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: yzhh, emacs-devel

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> Thank you for your appreciation. But my modification is in the C code of 
>> emacs, because 'execute-command' and 'call-interactively' are in C code.
>> And I don't think my dirty code would be a valid patch for the emacs 
>> developers.
>
> I think what was expected was to first record a keyboard macro and later to
> turn that into elisp code.  Another approach is to use a pre-command-hook to
> record the value of `this-command' for each command run.

Which reminds me that there is a big difference between replaying a keyboard
macro and running the corresponding functions as a single command:

- the pre-command-hook and post-command-hook are run for each key in
the keyboard macro, but only once for the single command.

This doesn't mean that the elisp code cannot be equivalent to the keyboard
macro, but it may be much harder to do right.  E.g. if you use modes
like delete-selection-mode or cua-mode which do major work in the hooks.

-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-27 20:04     ` Stefan Monnier
  2007-10-27 21:22       ` Kim F. Storm
@ 2007-10-27 21:45       ` Juri Linkov
  2007-10-28  1:14         ` Stefan Monnier
                           ` (2 more replies)
  1 sibling, 3 replies; 37+ messages in thread
From: Juri Linkov @ 2007-10-27 21:45 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: yzhh, emacs-devel

>> Thank you for your appreciation. But my modification is in the C code of
>> emacs, because 'execute-command' and 'call-interactively' are in C code.
>> And I don't think my dirty code would be a valid patch for the emacs
>> developers.
>
> I think what was expected was to first record a keyboard macro and later to
> turn that into elisp code.

That's was exactly my first attempt when I tried to implement this feature.
However, this approach doesn't work because a macro highly depends on its
context, and will fail when repeating it in different buffers, modes, etc.

> Another approach is to use a pre-command-hook to record the value of
> `this-command' for each command run.

After failing with the first approach, I tried to do this, but this doesn't
work because `this-command' doesn't record the arguments of the last
command.  So when I added a new variable `this-command-args' that records
the arguments of the command being executed, this approach produced
good results.

Also I added a new variable `last-kbd-macro-commands', and a new command
`insert-last-kbd-macro-commands' to convert the recorded commands with
their arguments to a Lisp function.  A change in isearch was also required
to convert all isearch subcommands into one search function.

Since yzhh doesn't want to post his code, I will post mine.
I ask yzhh to comment on this code, compare with his own,
and suggest further improvements:

Index: src/callint.c
===================================================================
RCS file: /sources/emacs/emacs/src/callint.c,v
retrieving revision 1.157
diff -c -r1.157 callint.c
*** src/callint.c	13 Sep 2007 05:50:11 -0000	1.157
--- src/callint.c	27 Oct 2007 21:44:37 -0000
***************
*** 42,47 ****
--- 42,48 ----
  
  extern Lisp_Object Vhistory_length;
  extern Lisp_Object Vthis_original_command, real_this_command;
+ extern Lisp_Object Vthis_command_args;
  
  Lisp_Object Vcommand_debug_status, Qcommand_debug_status;
  Lisp_Object Qenable_recursive_minibuffers;
***************
*** 364,369 ****
--- 365,373 ----
  	     and turn them into things we can eval.  */
  	  values = quotify_args (Fcopy_sequence (specs));
  	  fix_command (input, values);
+ 
+ 	  Vthis_command_args = values;
+ 
  	  Vcommand_history
  	    = Fcons (Fcons (function, values), Vcommand_history);
  
***************
*** 808,813 ****
--- 812,820 ----
  	  else
  	    visargs[i] = quotify_arg (args[i]);
  	}
+ 
+       Vthis_command_args = XCDR (Flist (count + 1, visargs));
+ 
        Vcommand_history = Fcons (Flist (count + 1, visargs),
  				Vcommand_history);
        /* Don't keep command history around forever.  */
***************
*** 832,837 ****
--- 839,846 ----
    Vthis_original_command = save_this_original_command;
    real_this_command= save_real_this_command;
    current_kboard->Vlast_command = save_last_command;
+   if (NILP (Vthis_command_args))
+     Vthis_command_args = XCDR (Flist (count + 1, args));
  
    {
      Lisp_Object val;
Index: src/keyboard.c
===================================================================
RCS file: /sources/emacs/emacs/src/keyboard.c,v
retrieving revision 1.924
diff -c -r1.924 keyboard.c
*** src/keyboard.c	18 Oct 2007 22:07:33 -0000	1.924
--- src/keyboard.c	27 Oct 2007 21:44:41 -0000
***************
*** 371,376 ****
--- 371,379 ----
     command is stored in this-original-command.  It is nil otherwise.  */
  Lisp_Object Vthis_original_command;
  
+ /* The 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;
  
***************
*** 1765,1770 ****
--- 1768,1774 ----
  
        Vthis_command = cmd;
        real_this_command = cmd;
+       Vthis_command_args = Qnil;
        /* Note that the value cell will never directly contain nil
  	 if the symbol is a local variable.  */
        if (!NILP (Vpre_command_hook) && !NILP (Vrun_hooks))
***************
*** 1798,1803 ****
--- 1802,1808 ----
  		    = window_display_table (XWINDOW (selected_window));
  		  lose = FETCH_CHAR (PT_BYTE);
  		  SET_PT (PT + 1);
+ 		  Vthis_command_args = Fcons (Vcurrent_prefix_arg, Qnil);
  		  if (! NILP (Vpost_command_hook))
  		    /* Put this before calling adjust_point_for_property
  		       so it will only get called once in any case.  */
***************
*** 1838,1843 ****
--- 1843,1849 ----
  		    = window_display_table (XWINDOW (selected_window));
  		  SET_PT (PT - 1);
  		  lose = FETCH_CHAR (PT_BYTE);
+ 		  Vthis_command_args = Fcons (Vcurrent_prefix_arg, Qnil);
  		  if (! NILP (Vpost_command_hook))
  		    goto directly_done;
  		  if (current_buffer == prev_buffer
***************
*** 1905,1910 ****
--- 1911,1917 ----
  		  if (value == 2)
  		    nonundocount = 0;
  
+ 		  Vthis_command_args = Fcons (make_number (c), Fcons (Vcurrent_prefix_arg, Qnil));
  		  if (! NILP (Vpost_command_hook))
  		    /* Put this before calling adjust_point_for_property
  		       so it will only get called once in any case.  */
***************
*** 3183,3189 ****
  #endif
        
        last_input_char = c;
!       Fcommand_execute (tem, Qnil, Fvector (1, &last_input_char), Qt);
  
        if (CONSP (c) && EQ (XCAR (c), Qselect_window) && !end_time)
  	/* We stopped being idle for this event; undo that.  This
--- 3190,3197 ----
  #endif
        
        last_input_char = c;
!       Fcommand_execute (tem, Qnil, /* Qt, */
! 			Fvector (1, &last_input_char), Qt);
  
        if (CONSP (c) && EQ (XCAR (c), Qselect_window) && !end_time)
  	/* We stopped being idle for this event; undo that.  This
***************
*** 12000,12005 ****
--- 12008,12017 ----
  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.  */);

Index: lisp/kmacro.el
===================================================================
RCS file: /sources/emacs/emacs/lisp/kmacro.el,v
retrieving revision 1.40
diff -c -r1.40 kmacro.el
*** lisp/kmacro.el	26 Jul 2007 05:26:27 -0000	1.40
--- lisp/kmacro.el	27 Oct 2007 21:44:40 -0000
***************
*** 538,545 ****
  
  (put 'kmacro-delete-ring-head 'kmacro-repeat 'head)
  
! ;;; Traditional bindings:
  
  
  ;;;###autoload
  (defun kmacro-start-macro (arg)
--- 538,548 ----
  
  (put 'kmacro-delete-ring-head 'kmacro-repeat 'head)
  
! (defvar last-kbd-macro-commands nil
!   "List of recorded commands executed during macro definition.
! Each command is represented as a form to evaluate.")
  
+ ;;; Traditional bindings:
  
  ;;;###autoload
  (defun kmacro-start-macro (arg)
***************
*** 580,592 ****
  	      kmacro-counter-format kmacro-default-counter-format
  	      kmacro-counter-format-start kmacro-default-counter-format))
  
        (start-kbd-macro append
  		       (and append
  			    (if kmacro-execute-before-append
  				(> (car arg) 4)
  			      (= (car arg) 4))))
        (if (and defining-kbd-macro append)
! 	  (setq defining-kbd-macro 'append)))))
  
  
  ;;;###autoload
--- 583,599 ----
  	      kmacro-counter-format kmacro-default-counter-format
  	      kmacro-counter-format-start kmacro-default-counter-format))
  
+       (add-hook 'post-command-hook 'kmacro-record-command t)
+       (add-hook 'kbd-macro-termination-hook 'kmacro-record-termination)
+ 
        (start-kbd-macro append
  		       (and append
  			    (if kmacro-execute-before-append
  				(> (car arg) 4)
  			      (= (car arg) 4))))
        (if (and defining-kbd-macro append)
! 	  (setq defining-kbd-macro 'append)
! 	(setq last-kbd-macro-commands nil)))))
  
  
  ;;;###autoload
***************
*** 605,610 ****
--- 612,618 ----
     ;; Just ignore it when executing the macro.
    (unless executing-kbd-macro
      (end-kbd-macro arg #'kmacro-loop-setup-function)
+     (kmacro-record-termination)
      (when (and last-kbd-macro (= (length last-kbd-macro) 0))
        (setq last-kbd-macro nil)
        (message "Ignore empty macro")
***************
*** 901,906 ****
--- 909,955 ----
    (kmacro-push-ring)
    (edit-kbd-macro "\C-hl"))
  
+ ;;; Macro commands recording
+ 
+ (defun kmacro-record-command ()
+   (unless (active-minibuffer-window)
+     (setq last-kbd-macro-commands (cons (cons this-command this-command-args)
+ 					last-kbd-macro-commands))))
+ 
+ (defun kmacro-record-termination ()
+   (remove-hook 'post-command-hook 'kmacro-record-command)
+   (remove-hook 'kbd-macro-termination-hook 'kmacro-record-termination))
+ 
+ (defun insert-last-kbd-macro-commands ()
+   (interactive)
+   (insert (pp-to-string
+ 	   `(defun last-kbd-macro-commands ()
+ 	      "Command created from the last keyboard macro."
+ 	      (interactive)
+ 	      ,@(kmacro-convert-macro-commands last-kbd-macro-commands)))))
+ 
+ (defun kmacro-convert-macro-commands (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
+ 		     universal-argument universal-argument-other-key
+ 		     digit-argument
+ 		     isearch-forward isearch-backward
+ 		     isearch-forward-regexp isearch-backward-regexp
+ 		     isearch-printing-char isearch-other-control-char
+ 		     isearch-repeat-forward isearch-repeat-backward
+ 		     isearch-delete-char isearch-exit
+ 		     )))
+        ((eq name 'self-insert-command)
+ 	(push `(insert-char ,(nth 1 cmd) ,(or (nth 2 cmd) 1) ) ret))
+        (t (push cmd ret)))
+       (setq cmds (cdr cmds)))
+     ret))
  
  ;;; Single-step editing of keyboard macros

Index: lisp/isearch.el
===================================================================
RCS file: /sources/emacs/emacs/lisp/isearch.el,v
retrieving revision 1.304
diff -u -r1.304 isearch.el
--- lisp/isearch.el	22 Oct 2007 23:44:29 -0000	1.304
+++ lisp/isearch.el	27 Oct 2007 21:44:03 -0000
*** 761,766 ****
--- 761,768 ----
    ;; part of the composition has just been searched.
    (setq disable-point-adjustment t))
  
+ (defvar last-kbd-macro-commands)
+ 
  (defun isearch-done (&optional nopush edit)
    "Exit Isearch mode.
  For successful search, pass no args.
***************
*** 776,781 ****
--- 778,794 ----
  	(unless (equal (car command-history) command)
  	  (setq command-history (cons command command-history)))))
  
+   (if (and (boundp 'last-kbd-macro-commands) defining-kbd-macro)
+       (push (list
+ 	     (cond (isearch-regexp
+ 		    (if isearch-forward 're-search-forward 're-search-backward))
+ 		   (isearch-word
+ 		    (if isearch-forward 'word-search-forward 'word-search-backward))
+ 		   (t
+ 		    (if isearch-forward 'search-forward 'search-backward)))
+ 	     isearch-string nil t)
+ 	    last-kbd-macro-commands))
+ 
    (remove-hook 'mouse-leave-buffer-hook 'isearch-done)
    (remove-hook 'kbd-macro-termination-hook 'isearch-done)
    (setq isearch-lazy-highlight-start nil)
  
-- 
Juri Linkov
http://www.jurta.org/emacs/

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-27 21:45       ` Juri Linkov
@ 2007-10-28  1:14         ` Stefan Monnier
  2007-10-28  1:34           ` Juri Linkov
  2007-10-28  6:49         ` yzhh
  2007-10-28 13:50         ` Richard Stallman
  2 siblings, 1 reply; 37+ messages in thread
From: Stefan Monnier @ 2007-10-28  1:14 UTC (permalink / raw)
  To: Juri Linkov; +Cc: yzhh, emacs-devel

>>> Thank you for your appreciation. But my modification is in the C code of
>>> emacs, because 'execute-command' and 'call-interactively' are in C code.
>>> And I don't think my dirty code would be a valid patch for the emacs
>>> developers.
>> 
>> I think what was expected was to first record a keyboard macro and later to
>> turn that into elisp code.

> That's was exactly my first attempt when I tried to implement this feature.
> However, this approach doesn't work because a macro highly depends on its
> context, and will fail when repeating it in different buffers, modes, etc.

I think this doesn't matter: the same holds for the keyboard macros
themselves and yet they're quite usable.  The limitation of the approach
(that the macro needs to be converted to Elisp in the same context where it
was recorded) doesn't seem to be too serious: at least not a show-stopper.

OTOH I do expect that it can be very tricky to recover the structure from
just the key sequence: e.g. after a keybinding that may or may not present
a minibuffer prompt, figuring out whether the rest of the keys were sent to
the minibuffer or to the next command can be impossible without guessing.

>> Another approach is to use a pre-command-hook to record the value of
>> `this-command' for each command run.

> After failing with the first approach, I tried to do this, but this doesn't
> work because `this-command' doesn't record the arguments of the last
> command.  So when I added a new variable `this-command-args' that records
> the arguments of the command being executed, this approach produced
> good results.

> Also I added a new variable `last-kbd-macro-commands', and a new command
> `insert-last-kbd-macro-commands' to convert the recorded commands with
> their arguments to a Lisp function.  A change in isearch was also required
> to convert all isearch subcommands into one search function.

> Since yzhh doesn't want to post his code, I will post mine.
> I ask yzhh to comment on this code, compare with his own,
> and suggest further improvements:

This doesn't sound too bad.  Another approach would be to advise
`call-interactively'.

This may require changes at the C level so as to make sure that calls to
Fcall_interactively are never made directly but always go through the
`call-interactively' symbol.

With an exhaustive around advice on call-interactively, you should be
able to get a fairly reliable trace.

But even a reliable trace will encounter the problems mentioned by Kim, and
in order to get /good/ Elisp code (rather than just /working/ Elisp code),
a fair bit of post-processing will be needed with ad-hoc rewrites.


        Stefan

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-28  1:14         ` Stefan Monnier
@ 2007-10-28  1:34           ` Juri Linkov
  2007-10-29  0:11             ` Richard Stallman
  0 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2007-10-28  1:34 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: yzhh, emacs-devel

> OTOH I do expect that it can be very tricky to recover the structure from
> just the key sequence: e.g. after a keybinding that may or may not present
> a minibuffer prompt, figuring out whether the rest of the keys were sent to
> the minibuffer or to the next command can be impossible without guessing.

Yes, and in the converted Lisp programs emulating the logic of minibuffer
processing is useless.  What would be useful to generate in Lisp programs
are executed commands with their arguments no matter how these arguments
were specified by the user.

> This doesn't sound too bad.  Another approach would be to advise
> `call-interactively'.
>
> This may require changes at the C level so as to make sure that calls to
> Fcall_interactively are never made directly but always go through the
> `call-interactively' symbol.
>
> With an exhaustive around advice on call-interactively, you should be
> able to get a fairly reliable trace.

But `call-interactively' doesn't have an argument that contains the
arguments of the called command.  I think we should avoid generating
Lisp code that read command arguments.

> But even a reliable trace will encounter the problems mentioned by Kim, and
> in order to get /good/ Elisp code (rather than just /working/ Elisp code),
> a fair bit of post-processing will be needed with ad-hoc rewrites.

I think the goal is not to produce Lisp code exactly equivalent to the
keyboard macro, but a useful basis for writing a new Lisp function.

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

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-27 21:45       ` Juri Linkov
  2007-10-28  1:14         ` Stefan Monnier
@ 2007-10-28  6:49         ` yzhh
  2007-10-28  7:13           ` yzhh
  2007-10-28 10:54           ` Juri Linkov
  2007-10-28 13:50         ` Richard Stallman
  2 siblings, 2 replies; 37+ messages in thread
From: yzhh @ 2007-10-28  6:49 UTC (permalink / raw)
  To: emacs-devel

Juri Linkov <juri <at> jurta.org> writes:

> > I think what was expected was to first record a keyboard macro and later to
> > turn that into elisp code.
> 
> That's was exactly my first attempt when I tried to implement this feature.
> However, this approach doesn't work because a macro highly depends on its
> context, and will fail when repeating it in different buffers, modes, etc.

I agree. Keymap changes caused by mode/buffer changes DURING the recording
can messup the "translation". So I didn't try this in the first place :)

> > Another approach is to use a pre-command-hook to record the value of
> > `this-command' for each command run.
> 
> After failing with the first approach, I tried to do this, but this doesn't
> work because `this-command' doesn't record the arguments of the last
> command.  So when I added a new variable `this-command-args' that records
> the arguments of the command being executed, this approach produced
> good results.
> 
> Also I added a new variable `last-kbd-macro-commands', and a new command
> `insert-last-kbd-macro-commands' to convert the recorded commands with
> their arguments to a Lisp function.  A change in isearch was also required
> to convert all isearch subcommands into one search function.

This approach looks quite promising. I vote for this.

> Since yzhh doesn't want to post his code, I will post mine.
> I ask yzhh to comment on this code, compare with his own,
> and suggest further improvements:

Great work Juri!
I'm actually busy on work these days. As soon as I have time I'll investigate
your code and give any suggestion I can. Hope this will progress into something
in the emacs CVS.

And inspired by you and others, I post my code here.

Basically, I did these:
Add a variable (V)kbd-macro-command-history, insert commands into it on ervey
ocurrence of possible insertion into command-history (that's guarded by
record_flag), when defining-kbd-macro is on. So it's not complete. You have to
M-x eval-expression kbd-macro-command-history to see the recorded thing, in
reverse order. And its length is guarded by history-length.

    regards,
yzhh

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-28  6:49         ` yzhh
@ 2007-10-28  7:13           ` yzhh
  2007-10-28 10:54           ` Juri Linkov
  1 sibling, 0 replies; 37+ messages in thread
From: yzhh @ 2007-10-28  7:13 UTC (permalink / raw)
  To: emacs-devel

Ah, I forgot the code:

Index: src/keyboard.c
===================================================================
--- src/keyboard.c      (revision 4)
+++ src/keyboard.c      (revision 7)
@@ -10020,6 +10020,24 @@
            }
        }

This approach looks quite promising. 


Index: src/keyboard.c
===================================================================
--- src/keyboard.c	(revision 4)
+++ src/keyboard.c	(revision 7)
@@ -10020,6 +10020,24 @@
 	    }
 	}
 
+      /* Record every command for kbd macro's purpose. */
+      if (!NILP (current_kboard->defining_kbd_macro)
+          && NILP (Vexecuting_kbd_macro))
+        {
+          Vkbd_macro_command_history
+            = Fcons (Fcons (Qexecute_kbd_macro,
+                            Fcons (final, Fcons (prefixarg, Qnil))),
+                     Vkbd_macro_command_history);
+
+          /* Don't keep command history around forever.  */
+          if (NUMBERP (Vhistory_length) && XINT (Vhistory_length) > 0)
+            {
+              tem = Fnthcdr (Vhistory_length, Vkbd_macro_command_history);
+              if (CONSP (tem))
+                XSETCDR (tem, Qnil);
+            }
+        }
+  
       return Fexecute_kbd_macro (final, prefixarg, Qnil);
     }
 
Index: src/lisp.h
===================================================================
--- src/lisp.h	(revision 4)
+++ src/lisp.h	(revision 7)
@@ -2945,6 +2945,7 @@
 
 extern Lisp_Object Qminus, Qplus, Vcurrent_prefix_arg;
 extern Lisp_Object Vcommand_history;
+extern Lisp_Object Vkbd_macro_command_history;
 extern Lisp_Object Qcall_interactively, Qmouse_leave_buffer_hook;
 EXFUN (Fcall_interactively, 3);
 EXFUN (Fprefix_numeric_value, 1);
Index: src/callint.c
===================================================================
--- src/callint.c	(revision 4)
+++ src/callint.c	(revision 7)
@@ -39,6 +39,7 @@
 Lisp_Object Vcurrent_prefix_arg, Qminus, Qplus;
 Lisp_Object Qcall_interactively;
 Lisp_Object Vcommand_history;
+Lisp_Object Vkbd_macro_command_history;
 
 extern Lisp_Object Vhistory_length;
 extern Lisp_Object Vthis_original_command, real_this_command;
@@ -377,6 +378,7 @@
       GCPRO2 (input, filter_specs);
       specs = Feval (specs);
       UNGCPRO;
+
       if (i != num_input_events || !NILP (record_flag))
 	{
 	  /* We should record this command on the command history.  */
@@ -397,6 +399,28 @@
 	    }
 	}
 
+      /* Record every command for kbd macro's purpose. */
+      if ((i != num_input_events)
+          || (!NILP (current_kboard->defining_kbd_macro)
+              && NILP (Vexecuting_kbd_macro)))
+        {
+	  Lisp_Object values;
+	  /* 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);
+	  Vkbd_macro_command_history
+	    = Fcons (Fcons (function, values), Vkbd_macro_command_history);
+
+	  /* Don't keep command history around forever.  */
+	  if (INTEGERP (Vhistory_length) && XINT (Vhistory_length) > 0)
+	    {
+	      teml = Fnthcdr (Vhistory_length, Vkbd_macro_command_history);
+	      if (CONSP (teml))
+		XSETCDR (teml, Qnil);
+	    }
+        }
+
       Vthis_command = save_this_command;
       Vthis_original_command = save_this_original_command;
       real_this_command= save_real_this_command;
@@ -837,6 +861,30 @@
 	}
     }
 
+  /* Record every command for kbd macro's purpose. */
+  if (arg_from_tty || (!NILP (current_kboard->defining_kbd_macro)
+                       && NILP (Vexecuting_kbd_macro)))
+    {
+      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]);
+	}
+      Vkbd_macro_command_history = Fcons (Flist (count + 1, visargs),
+				Vkbd_macro_command_history);
+      /* Don't keep command history around forever.  */
+      if (INTEGERP (Vhistory_length) && XINT (Vhistory_length) > 0)
+	{
+	  teml = Fnthcdr (Vhistory_length, Vkbd_macro_command_history);
+	  if (CONSP (teml))
+	    XSETCDR (teml, Qnil);
+	}
+    }
+
+
   /* 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++)
@@ -963,6 +1011,11 @@
 Each command is represented as a form to evaluate.  */);
   Vcommand_history = Qnil;
 
+  DEFVAR_LISP ("kbd-macro-command-history", &Vkbd_macro_command_history,
+	       doc: /* List of commands recorded in the last keyboard macro.
+Each command is represented as a form to evaluate.  */);
+  Vkbd_macro_command_history = Qnil;
+
   DEFVAR_LISP ("command-debug-status", &Vcommand_debug_status,
 	       doc: /* Debugging status of current interactive command.
 Bound each time `call-interactively' is called;

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-28  6:49         ` yzhh
  2007-10-28  7:13           ` yzhh
@ 2007-10-28 10:54           ` Juri Linkov
  1 sibling, 0 replies; 37+ messages in thread
From: Juri Linkov @ 2007-10-28 10:54 UTC (permalink / raw)
  To: yzhh; +Cc: emacs-devel

> Basically, I did these:
> Add a variable (V)kbd-macro-command-history, insert commands into it on ervey
> ocurrence of possible insertion into command-history (that's guarded by
> record_flag), when defining-kbd-macro is on. So it's not complete. You have to
> M-x eval-expression kbd-macro-command-history to see the recorded thing, in
> reverse order. And its length is guarded by history-length.

Thanks for your code!  I see you collect executed commands together
with their arguments into a new list of commands.  This is fine.
But I think it's better to add a new variable `this-command-args'
that contains the arguments of the current command because this variable
could be useful for other purposes as well, and it allows collecting
commands with their arguments in Lisp that improves the flexibility of
this approach.

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

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-27 16:20 ` Drew Adams
  2007-10-27 17:13   ` yzhh
@ 2007-10-28 13:50   ` Richard Stallman
  2007-10-28 16:45     ` Juri Linkov
  1 sibling, 1 reply; 37+ messages in thread
From: Richard Stallman @ 2007-10-28 13:50 UTC (permalink / raw)
  To: Drew Adams; +Cc: yezonghui, emacs-devel

I think someone said within the past year that he had written
such a feature.  We did not install it at the time because
we wanted to release 22.1.  But we could install it now.

Can anyone find old mail about that?

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-27 18:01     ` Drew Adams
@ 2007-10-28 13:50       ` Richard Stallman
  0 siblings, 0 replies; 37+ messages in thread
From: Richard Stallman @ 2007-10-28 13:50 UTC (permalink / raw)
  To: Drew Adams; +Cc: yezonghui, emacs-devel

There is no need to change the C code
to convert a keyboard macro into Lisp.
The keyboard macro is already a sequence of events.

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-27 21:22       ` Kim F. Storm
@ 2007-10-28 13:50         ` Richard Stallman
  2007-10-28 22:00           ` Kim F. Storm
  0 siblings, 1 reply; 37+ messages in thread
From: Richard Stallman @ 2007-10-28 13:50 UTC (permalink / raw)
  To: Kim F. Storm; +Cc: yezonghui, monnier, emacs-devel

    Which reminds me that there is a big difference between replaying a keyboard
    macro and running the corresponding functions as a single command:

    - the pre-command-hook and post-command-hook are run for each key in
    the keyboard macro, but only once for the single command.

    This doesn't mean that the elisp code cannot be equivalent to the keyboard
    macro, but it may be much harder to do right.

There are various ideas of what is "right" for such a conversion.
I think the converted code should ignore these hooks, and if the
results are different, in most cases that will make sense.

Delete Selection mode is an exception.  In Delete Selection mode,
if these hooks are not run, the results will clearly be wrong.
The same may be true of CUA mode.

The conversion program could test for the presence of these specific
hook functions in pre-command-hook, and generate appropriate code in
the output Lisp function.  Rather than calling these hook functions
before each command, it should call them only in the places where they
would do real work.  And it wouldn't call the same function, but
rather a related one.  Here's what it could look like:

(put 'delete-selection-pre-hook 'lisp-conversion-function
     (lambda (function)
       (let ((type (and (symbolp this-command)
	                (get this-command 'delete-selection))))
	 (when type
	   `(delete-selection-pre-command-processing ,type)))))

where `delete-selection-pre-command-processing' would be
a new function that does the same work as `delete-selection-pre-hook'
but gets `type' as an argument.

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-27 21:45       ` Juri Linkov
  2007-10-28  1:14         ` Stefan Monnier
  2007-10-28  6:49         ` yzhh
@ 2007-10-28 13:50         ` Richard Stallman
  2007-10-28 15:09           ` Juri Linkov
  2007-10-28 16:13           ` yzhh
  2 siblings, 2 replies; 37+ messages in thread
From: Richard Stallman @ 2007-10-28 13:50 UTC (permalink / raw)
  To: Juri Linkov; +Cc: yezonghui, monnier, emacs-devel

    That's was exactly my first attempt when I tried to implement this feature.
    However, this approach doesn't work because a macro highly depends on its
    context, and will fail when repeating it in different buffers, modes, etc.

We expect this conversion to use the keymaps that Emacs has when you
do the conversion.  That is a feature, not a bug.

    Also I added a new variable `last-kbd-macro-commands', and a new command
    `insert-last-kbd-macro-commands' to convert the recorded commands with
    their arguments to a Lisp function.

The way you have written this, it looks like it cannot convert an
existing keyboard macro.  The user has to type the definition over
again.  That is a big drawback.

Can you make this work by replaying the macro?  At least then
it would be possible to convert an existing macro.

We want to do more simplification of the generated Lisp code;
for instance, to combine multiple calls to self-insert-command
into something more elegant.

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-28 13:50         ` Richard Stallman
@ 2007-10-28 15:09           ` Juri Linkov
  2007-10-29  9:21             ` Richard Stallman
  2007-10-28 16:13           ` yzhh
  1 sibling, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2007-10-28 15:09 UTC (permalink / raw)
  To: rms; +Cc: yezonghui, monnier, emacs-devel

>     Also I added a new variable `last-kbd-macro-commands', and a new command
>     `insert-last-kbd-macro-commands' to convert the recorded commands with
>     their arguments to a Lisp function.
>
> The way you have written this, it looks like it cannot convert an
> existing keyboard macro.  The user has to type the definition over
> again.  That is a big drawback.

It preserves Lisp code of the last defined macro.  I think this is enough
for this feature to be useful.  If not, we could keep the converted Lisp
code with every macro definition.

> Can you make this work by replaying the macro?  At least then
> it would be possible to convert an existing macro.

This is easy to implement, but replaying the macro is not always possible.

> We want to do more simplification of the generated Lisp code;
> for instance, to combine multiple calls to self-insert-command
> into something more elegant.

I agree.  A function `kmacro-convert-macro-commands' in my patch is
intended for such simplifications.

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

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-28 13:50         ` Richard Stallman
  2007-10-28 15:09           ` Juri Linkov
@ 2007-10-28 16:13           ` yzhh
  2007-10-28 16:48             ` Juri Linkov
  2007-10-29  9:21             ` Richard Stallman
  1 sibling, 2 replies; 37+ messages in thread
From: yzhh @ 2007-10-28 16:13 UTC (permalink / raw)
  To: emacs-devel

Richard Stallman <rms <at> gnu.org> writes:

> We expect this conversion to use the keymaps that Emacs has when you
> do the conversion.  That is a feature, not a bug.

I can give an example that reveals another complication of the "translate using
keymaps" approach. The following:

M-x			;; execute-extended-command
repla			;; self-insert-command * 5
2*TAB			;; lisp-indent-line
str			;; self-insert-command * 3
TAB			;; lisp-indent-line
RET			;; newline
is			;; self-insert-command * 2
RET			;; newline
IS			;; self-insert-command * 2
RET			;; newline

is a kbd macro I recorded for M-x replace-string is -> IS. The complication is
with the TAB completion - it would require total knowledge about TAB completion
to reconstruct the command name - what edit-kbd-macro doesn't do.

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-28 13:50   ` Richard Stallman
@ 2007-10-28 16:45     ` Juri Linkov
  0 siblings, 0 replies; 37+ messages in thread
From: Juri Linkov @ 2007-10-28 16:45 UTC (permalink / raw)
  To: rms; +Cc: yezonghui, emacs-devel

> I think someone said within the past year that he had written
> such a feature.  We did not install it at the time because
> we wanted to release 22.1.  But we could install it now.
>
> Can anyone find old mail about that?

If no one else will replay to your request, then perhaps it was me.
And I already sent a patch that implements this feature.

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

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-28 16:13           ` yzhh
@ 2007-10-28 16:48             ` Juri Linkov
  2007-10-29  9:21             ` Richard Stallman
  1 sibling, 0 replies; 37+ messages in thread
From: Juri Linkov @ 2007-10-28 16:48 UTC (permalink / raw)
  To: yzhh; +Cc: emacs-devel

> I can give an example that reveals another complication of the "translate using
> keymaps" approach. The following:
>
> M-x			;; execute-extended-command
> repla			;; self-insert-command * 5
> 2*TAB			;; lisp-indent-line
> str			;; self-insert-command * 3
> TAB			;; lisp-indent-line
> RET			;; newline
> is			;; self-insert-command * 2
> RET			;; newline
> IS			;; self-insert-command * 2
> RET			;; newline
>
> is a kbd macro I recorded for M-x replace-string is -> IS. The complication is
> with the TAB completion - it would require total knowledge about TAB completion
> to reconstruct the command name - what edit-kbd-macro doesn't do.

I agree.  It makes no sense to generate Lisp code for minibuffer
completion and other minibuffer reading functions.  What would be
useful to generate in Lisp code is the final command with its arguments:
(replace-string "is" "IS")

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

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-28 13:50         ` Richard Stallman
@ 2007-10-28 22:00           ` Kim F. Storm
  2007-10-29  5:20             ` yzhh
                               ` (2 more replies)
  0 siblings, 3 replies; 37+ messages in thread
From: Kim F. Storm @ 2007-10-28 22:00 UTC (permalink / raw)
  To: rms; +Cc: yezonghui, monnier, emacs-devel

Richard Stallman <rms@gnu.org> writes:

>     Which reminds me that there is a big difference between replaying a keyboard
>     macro and running the corresponding functions as a single command:
>
>     - the pre-command-hook and post-command-hook are run for each key in
>     the keyboard macro, but only once for the single command.
>
>     This doesn't mean that the elisp code cannot be equivalent to the keyboard
>     macro, but it may be much harder to do right.
>
> There are various ideas of what is "right" for such a conversion.
> I think the converted code should ignore these hooks, and if the
> results are different, in most cases that will make sense.

Maybe, but there are many things that can go wrong...

Perhaps some of the work could be done by analyzing the undo
history ...

> Delete Selection mode is an exception.  In Delete Selection mode,
> if these hooks are not run, the results will clearly be wrong.
> The same may be true of CUA mode.

It is even more complex I think:

With CUA mode, the interpretation of C-x and C-c depends on 
whether the region is active or not.  That is not done through
pre-command-hook (but setting/extending the region is), but rather
through the keymaps which are active at the time.

> The conversion program could test for the presence of these specific
> hook functions in pre-command-hook, and generate appropriate code in
> the output Lisp function.  

This will only work if the conversion is done while recording the
keyboard macro - as one keystroke may modify the hooks.

>                            Rather than calling these hook functions
> before each command, it should call them only in the places where they
> would do real work.  And it wouldn't call the same function, but
> rather a related one.  Here's what it could look like:
>
> (put 'delete-selection-pre-hook 'lisp-conversion-function
>      (lambda (function)
>        (let ((type (and (symbolp this-command)
> 	                (get this-command 'delete-selection))))
> 	 (when type
> 	   `(delete-selection-pre-command-processing ,type)))))
>
> where `delete-selection-pre-command-processing' would be
> a new function that does the same work as `delete-selection-pre-hook'
> but gets `type' as an argument.

That might work.

IMO, the only real solution is to record the elisp code while recording
the keyboard macro - as it is possible to cather for changes in
the mark-active state and insert suitable set-mark commands etc.

Still, I fail to see the real need for the functionality.

It may be ok as a way to get a starting point for an editing command,
but only very trivial functions can be written that way anyway - and
they are just as well written and saved as a series of keystrokes as
they do now.

-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-28  1:34           ` Juri Linkov
@ 2007-10-29  0:11             ` Richard Stallman
  0 siblings, 0 replies; 37+ messages in thread
From: Richard Stallman @ 2007-10-29  0:11 UTC (permalink / raw)
  To: Juri Linkov; +Cc: yezonghui, monnier, emacs-devel

    I think the goal is not to produce Lisp code exactly equivalent to the
    keyboard macro, but a useful basis for writing a new Lisp function.

That is right.  Thus, we don't want all the effects of all
pre-command-hooks and post-command-hooks to be included.

We want that only for cases like Delete Selection mode
where the user will think of them as part of the meaning of the command.

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-28 22:00           ` Kim F. Storm
@ 2007-10-29  5:20             ` yzhh
  2007-10-29  9:22             ` Richard Stallman
  2007-10-29  9:22             ` Richard Stallman
  2 siblings, 0 replies; 37+ messages in thread
From: yzhh @ 2007-10-29  5:20 UTC (permalink / raw)
  To: emacs-devel

Kim F. Storm <storm <at> cua.dk> writes:
 
> IMO, the only real solution is to record the elisp code while recording
> the keyboard macro - as it is possible to cather for changes in
> the mark-active state and insert suitable set-mark commands etc.

I agree.
 
> Still, I fail to see the real need for the functionality.
> 
> It may be ok as a way to get a starting point for an editing command,
> but only very trivial functions can be written that way anyway - and
> they are just as well written and saved as a series of keystrokes as
> they do now.

These are some benefits I thought of:

1. When modifying these trivial functions, non-sequential control flow
(conditional branches and loops) are available for elisp code, but not for
keystrokes. In such cases a user who's familiar with elisp grammar but not with
emacs command names/args is well served by recorded elisp code.

2. Trivial functions in the form of elisp code is more suitable for sharing with
others - it's not dependent on the keymaps. (Not everyone use standard key
bindings and many have added bindings here and there.)

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-27  9:28 Is there a plan to record kbd macro as elisp code? yzhh
  2007-10-27 15:48 ` Robert J. Chassell
  2007-10-27 16:20 ` Drew Adams
@ 2007-10-29  6:41 ` Klaus Zeitler
  2 siblings, 0 replies; 37+ messages in thread
From: Klaus Zeitler @ 2007-10-29  6:41 UTC (permalink / raw)
  To: emacs-devel

There's also a package called power-macros.el from Jesper K. Pedersen.
http://www.blackie.dk/emacs/power-macros.el

Cheers
Klaus

-- 
 --------------------------------------------------
|  Klaus Zeitler      Alcatel-Lucent               |
|  Email:             kzeitler@alcatel-lucent.com  |
 --------------------------------------------------
---
God put me on earth to accomplish a certain number of things. Right now
I am so far behind I will never die. -- Bill Waterson, Calvin and Hobbes

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-28 15:09           ` Juri Linkov
@ 2007-10-29  9:21             ` Richard Stallman
  0 siblings, 0 replies; 37+ messages in thread
From: Richard Stallman @ 2007-10-29  9:21 UTC (permalink / raw)
  To: Juri Linkov; +Cc: yezonghui, monnier, emacs-devel

    > Can you make this work by replaying the macro?  At least then
    > it would be possible to convert an existing macro.

    This is easy to implement, but replaying the macro is not always possible.

Why not?  It seems to me that if you can define the macro over again,
you can replay it.  (Either way, it will carry out the actions of the
macro.)

Replaying the macro is less work than typing it again.  Therefore, if
this feature operates by executing the commands in the macro, it
should do so by replaying.

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-28 16:13           ` yzhh
  2007-10-28 16:48             ` Juri Linkov
@ 2007-10-29  9:21             ` Richard Stallman
  2007-10-30 14:14               ` Juri Linkov
  1 sibling, 1 reply; 37+ messages in thread
From: Richard Stallman @ 2007-10-29  9:21 UTC (permalink / raw)
  To: yzhh; +Cc: emacs-devel

    is a kbd macro I recorded for M-x replace-string is -> IS. The complication is
    with the TAB completion - it would require total knowledge about TAB completion
    to reconstruct the command name - what edit-kbd-macro doesn't do.

That is a real issue, which I had not thought about before.  This is a
case which is easier to handle if you record the actual arguments.

On the other hand, just recording the actual value of the argument
is also sometimes wrong.  Suppose you mark text in a buffer and
copy it into the minibuffer as part of the macro.  The Lisp program
ought to copy the text too.

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-28 22:00           ` Kim F. Storm
  2007-10-29  5:20             ` yzhh
@ 2007-10-29  9:22             ` Richard Stallman
  2007-10-29  9:22             ` Richard Stallman
  2 siblings, 0 replies; 37+ messages in thread
From: Richard Stallman @ 2007-10-29  9:22 UTC (permalink / raw)
  To: Kim F. Storm; +Cc: yezonghui, monnier, emacs-devel

    With CUA mode, the interpretation of C-x and C-c depends on 
    whether the region is active or not.  That is not done through
    pre-command-hook (but setting/extending the region is), but rather
    through the keymaps which are active at the time.

I don't see any easy way to handle that, except the method
of recording the commands that are run.

Perhaps this is a good reason to use the method of converting by
executing the macro.  If we do, it remains better to do so by
replaying the macro than by making the user type the definition again.

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-28 22:00           ` Kim F. Storm
  2007-10-29  5:20             ` yzhh
  2007-10-29  9:22             ` Richard Stallman
@ 2007-10-29  9:22             ` Richard Stallman
  2 siblings, 0 replies; 37+ messages in thread
From: Richard Stallman @ 2007-10-29  9:22 UTC (permalink / raw)
  To: Kim F. Storm; +Cc: yezonghui, monnier, emacs-devel

    Still, I fail to see the real need for the functionality.

    It may be ok as a way to get a starting point for an editing command,
    but only very trivial functions can be written that way anyway - and
    they are just as well written and saved as a series of keystrokes as
    they do now.

This feature would not be useful for people like you and me.
It is meant for people who are just starting to use Lisp.

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-29  9:21             ` Richard Stallman
@ 2007-10-30 14:14               ` Juri Linkov
  2007-10-31  7:46                 ` Richard Stallman
  0 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2007-10-30 14:14 UTC (permalink / raw)
  To: rms; +Cc: yzhh, emacs-devel

>     is a kbd macro I recorded for M-x replace-string is -> IS. The
>     complication is with the TAB completion - it would require total
>     knowledge about TAB completion to reconstruct the command name -
>     what edit-kbd-macro doesn't do.
>
> That is a real issue, which I had not thought about before.  This is a
> case which is easier to handle if you record the actual arguments.
>
> On the other hand, just recording the actual value of the argument
> is also sometimes wrong.  Suppose you mark text in a buffer and
> copy it into the minibuffer as part of the macro.  The Lisp program
> ought to copy the text too.

Recording the actual arguments is a useful and clean solution, but
trying to emulate the logic of minibuffer processing will produce
ugly and complicated Lisp code.

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

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

* Re: Is there a plan to record kbd macro as elisp code?
  2007-10-30 14:14               ` Juri Linkov
@ 2007-10-31  7:46                 ` Richard Stallman
  0 siblings, 0 replies; 37+ messages in thread
From: Richard Stallman @ 2007-10-31  7:46 UTC (permalink / raw)
  To: Juri Linkov; +Cc: yezonghui, emacs-devel

    > On the other hand, just recording the actual value of the argument
    > is also sometimes wrong.  Suppose you mark text in a buffer and
    > copy it into the minibuffer as part of the macro.  The Lisp program
    > ought to copy the text too.

    Recording the actual arguments is a useful and clean solution, but
    trying to emulate the logic of minibuffer processing will produce
    ugly and complicated Lisp code.

We need to give it a try.  If we avoid being perfectionist, it may be
easy to give good results in simple usual cases.

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

end of thread, other threads:[~2007-10-31  7:46 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-10-27  9:28 Is there a plan to record kbd macro as elisp code? yzhh
2007-10-27 15:48 ` Robert J. Chassell
2007-10-27 17:30   ` yzhh
2007-10-27 18:01     ` Drew Adams
2007-10-28 13:50       ` Richard Stallman
2007-10-27 20:04     ` Stefan Monnier
2007-10-27 21:22       ` Kim F. Storm
2007-10-28 13:50         ` Richard Stallman
2007-10-28 22:00           ` Kim F. Storm
2007-10-29  5:20             ` yzhh
2007-10-29  9:22             ` Richard Stallman
2007-10-29  9:22             ` Richard Stallman
2007-10-27 21:45       ` Juri Linkov
2007-10-28  1:14         ` Stefan Monnier
2007-10-28  1:34           ` Juri Linkov
2007-10-29  0:11             ` Richard Stallman
2007-10-28  6:49         ` yzhh
2007-10-28  7:13           ` yzhh
2007-10-28 10:54           ` Juri Linkov
2007-10-28 13:50         ` Richard Stallman
2007-10-28 15:09           ` Juri Linkov
2007-10-29  9:21             ` Richard Stallman
2007-10-28 16:13           ` yzhh
2007-10-28 16:48             ` Juri Linkov
2007-10-29  9:21             ` Richard Stallman
2007-10-30 14:14               ` Juri Linkov
2007-10-31  7:46                 ` Richard Stallman
2007-10-27 19:26   ` Jay Belanger
2007-10-27 16:20 ` Drew Adams
2007-10-27 17:13   ` yzhh
2007-10-27 17:40     ` Drew Adams
2007-10-27 18:05       ` yzhh
2007-10-27 19:22       ` Robert J. Chassell
2007-10-27 20:11         ` Drew Adams
2007-10-28 13:50   ` Richard Stallman
2007-10-28 16:45     ` Juri Linkov
2007-10-29  6:41 ` Klaus Zeitler

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