Subject: Re: bug#5364: 23.1.91; execute-extended-command should do like FFAP

From: Juri Linkov <[email-masked]>
Date: Fri, 15 Jan 2010 03:12:05 +0200

> The behavior is OK, but the implementation sucks too much.  I think we
> can do better via minibuffer-with-setup-hook.  That might require to
> turn M-x's interactive spec into Elisp (moving the whole of M-x to Elisp
> would be good as well, but it's a much bigger effort).

This patch moves interactive spec into Elisp and also implements
the following task from comments in execute-extended-command:

  /* This isn't strictly correct if execute-extended-command
     is bound to anything else.  Perhaps it should use
     this_command_keys?  */

It uses `(key-description (this-single-command-keys))' to do this.

=== modified file 'src/keyboard.c'
--- src/keyboard.c	2010-01-13 08:35:10 +0000
+++ src/keyboard.c	2010-01-15 01:09:18 +0000
@@ -10512,7 +10512,30 @@
 
 
 DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_command,
-       1, 1, "P",
+       2, 2,
+       "(list current-prefix-arg \
+    (minibuffer-with-setup-hook \
+        (lambda () \
+          (set (make-local-variable 'minibuffer-default-add-function) \
+               (lambda () \
+                 (with-current-buffer (window-buffer \
+                                       (minibuffer-selected-window)) \
+                   (and (commandp (function-called-at-point)) \
+                        (format \"%S\" (function-called-at-point))))))) \
+      (completing-read (concat \
+                        (cond \
+                         ((eq current-prefix-arg '-) \"- \") \
+                         ((and (consp current-prefix-arg) \
+                               (eq (car current-prefix-arg) 4)) \"C-u \") \
+                         ((and (consp current-prefix-arg) \
+                               (integerp (car current-prefix-arg))) \
+                          (format \"%d \" (car current-prefix-arg))) \
+                         ((integerp current-prefix-arg) \
+                          (format \"%d \" current-prefix-arg))) \
+                        (key-description (this-single-command-keys)) \
+                        \" \") \
+                       obarray 'commandp t nil \
+                       'extended-command-history)))",
        doc: /* Read function name, then read its arguments and call it.
 
 To pass a numeric argument to the command you are invoking with, specify
@@ -10520,11 +10543,9 @@ (at your option) any later version.
 
 Noninteractively, the argument PREFIXARG is the prefix argument to
 give to the command you invoke, if it asks for an argument.  */)
-     (prefixarg)
-     Lisp_Object prefixarg;
+     (prefixarg, function)
+     Lisp_Object prefixarg, function;
 {
-  Lisp_Object function;
-  char buf[40];
   int saved_last_point_position;
   Lisp_Object saved_keys, saved_last_point_position_buffer;
   Lisp_Object bindings, value;
@@ -10543,32 +10564,8 @@ (at your option) any later version.
 			XVECTOR (this_command_keys)->contents);
   saved_last_point_position_buffer = last_point_position_buffer;
   saved_last_point_position = last_point_position;
-  buf[0] = 0;
   GCPRO3 (saved_keys, prefixarg, saved_last_point_position_buffer);
 
-  if (EQ (prefixarg, Qminus))
-    strcpy (buf, "- ");
-  else if (CONSP (prefixarg) && XINT (XCAR (prefixarg)) == 4)
-    strcpy (buf, "C-u ");
-  else if (CONSP (prefixarg) && INTEGERP (XCAR (prefixarg)))
-    sprintf (buf, "%ld ", (long) XINT (XCAR (prefixarg)));
-  else if (INTEGERP (prefixarg))
-    sprintf (buf, "%ld ", (long) XINT (prefixarg));
-
-  /* This isn't strictly correct if execute-extended-command
-     is bound to anything else.  Perhaps it should use
-     this_command_keys?  */
-  strcat (buf, "M-x ");
-
-  /* Prompt with buf, and then read a string, completing from and
-     restricting to the set of all defined commands.  Don't provide
-     any initial input.  Save the command read on the extended-command
-     history list. */
-  function = Fcompleting_read (build_string (buf),
-			       Vobarray, Qcommandp,
-			       Qt, Qnil, Qextended_command_history, Qnil,
-			       Qnil);
-
 #ifdef HAVE_WINDOW_SYSTEM
   if (hstarted) start_hourglass ();
 #endif

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