diff --git a/lisp/simple.el b/lisp/simple.el index c48e644345..1bd8ba5993 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -1949,7 +1949,46 @@ read-extended-command-predicate command-completion-default-include-p) (function :tag "Other function"))) -(defun read-extended-command () +(defun execute-extended-command--cycle () + (interactive) + (throw 'cycle + (cons 'cycle (cons (minibuffer-contents) + (- (point) (minibuffer-prompt-end)))))) + +(defun read-extended-command (&optional prompt) + (let ((minibuffer-local-must-match-map minibuffer-local-must-match-map) + (read-extended-command-predicate read-extended-command-predicate) + initial-input ret) + (define-key minibuffer-local-must-match-map + (kbd "M-x") #'execute-extended-command--cycle) + (while (not ret) + (setq ret (catch 'cycle + (read-extended-command-1 prompt initial-input))) + (when (and (consp ret) (eq 'cycle (car ret))) + ;; Cycle to the next setting. There's only two, so it's easy to do. + (if read-extended-command-predicate + (setq prompt "M-x " + read-extended-command-predicate nil) + (let ((keymaps + ;; The major mode's keymap and any active minor modes. + (cons + (current-local-map) + (mapcar + #'cdr + (seq-filter + (lambda (elem) + (symbol-value (car elem))) + minor-mode-map-alist))))) + (setq prompt "M-X ") + (setq read-extended-command-predicate + (lambda (symbol buffer) + (or (command-completion-using-modes-p symbol buffer) + (where-is-internal symbol keymaps)))))) + (setq initial-input (cdr ret)) + (setq ret nil))) + ret)) + +(defun read-extended-command-1 (prompt initial-input) "Read command name to invoke in `execute-extended-command'. This function uses the `read-extended-command-predicate' user option." (let ((buffer (current-buffer))) @@ -1976,8 +2015,8 @@ read-extended-command (cons def (delete def all)) all))))) ;; 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. + ;; all defined commands. Save the command read on the + ;; extended-command history list. (completing-read (concat (cond ((eq current-prefix-arg '-) "- ") @@ -1994,9 +2033,7 @@ read-extended-command ;; 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: ". - (if (memq 'shift (event-modifiers last-command-event)) - "M-X " - "M-x ")) + (or prompt "M-x ")) (lambda (string pred action) (if (and suggest-key-bindings (eq action 'metadata)) '(metadata @@ -2013,7 +2050,7 @@ read-extended-command (funcall read-extended-command-predicate sym buffer) (error (message "read-extended-command-predicate: %s: %s" sym (error-message-string err)))))))) - t nil 'extended-command-history)))) + t initial-input 'extended-command-history)))) (defun command-completion-using-modes-p (symbol buffer) "Say whether SYMBOL has been marked as a mode-specific command in BUFFER." @@ -2241,7 +2278,7 @@ execute-extended-command-for-buffer (or (command-completion-using-modes-p symbol buffer) (where-is-internal symbol keymaps))))) (list current-prefix-arg - (read-extended-command) + (read-extended-command "M-X ") execute-extended-command--last-typed))) (with-suppressed-warnings ((interactive-only execute-extended-command)) (execute-extended-command prefixarg command-name typed)))