The key sequence M-x calls execute-extended-command
.
That command uses read-extended-command
for reading from minibuffer.
In read-extended-command
the c-function completing-read
does the main job.
But, the INITIAL-INPUT
argument for that command is hard-coded to nil.
We should not temporarily advise completing-read
since that function can be compiled-in. So we need to define our own my-read-extended-command
which is a copy of completing-read
up to the INITIAL-INPUT
argument "*"
instead of nil
.
But, we can temporarily advice read-extended-command
within execute-extended-command
.
The following code shows how. It defines a command my-execute-extended-command
that temporarily advices read-extended-command
with the help of cl-setf
and calls execute-extended-command
interactively within the body of this cl-setf
.
(require 'cl-lib)
(defun my-read-extended-command ()
"Read command name to invoke in `my-execute-extended-command'.
This is almost a copy of `read-extended-command'.
The only difference is ?* as initial input to M-x."
(minibuffer-with-setup-hook
(lambda ()
(add-hook 'post-self-insert-hook
(lambda ()
(setq execute-extended-command--last-typed
(minibuffer-contents)))
nil 'local)
(set (make-local-variable 'minibuffer-default-add-function)
(lambda ()
;; Get a command name at point in the original buffer
;; to propose it after M-n.
(with-current-buffer (window-buffer (minibuffer-selected-window))
(and (commandp (function-called-at-point))
(format "%S" (function-called-at-point)))))))
;; 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.
(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)))
;; This isn't strictly correct if `execute-extended-command'
;; is bound to anything else (e.g. [menu]).
;; It could use (key-description (this-single-command-keys)),
;; but actually a prompt other than "M-x" would be confusing,
;; because "M-x" is a well-known prompt to read a command
;; and it serves as a shorthand for "Extended command: ".
"M-x ")
(lambda (string pred action)
(let ((pred
(if (memq action '(nil t))
;; Exclude obsolete commands from completions.
(lambda (sym)
(and (funcall pred sym)
(or (equal string (symbol-name sym))
(not (get sym 'byte-obsolete-info)))))
pred)))
(complete-with-action action obarray string pred)))
#'commandp t
"*"
'extended-command-history)))
(defun my-execute-extended-command ()
"Run `execute-extended-command' interactively.
Thereby, replace `read-extended-command' by `my-read-extended-command', which see."
(interactive)
(cl-letf (((symbol-function 'read-extended-command) #'my-read-extended-command))
(call-interactively #'execute-extended-command)))
(bind-key "M-X" #'my-execute-extended-command)