Allow toggling completion modes for M-x' with M-X'
* doc/lispref/commands.texi (Interactive Call): Document it. * lisp/minibuffer.el (minibuffer-local-must-match-map): Bind 'M-X'. * lisp/simple.el (execute-extended-command-cycle): New command. (read-extended-command): Use it to allow toggling (bug#47215). (read-extended-command-1): Renamed from `read-extended-command'. (execute-extended-command-for-buffer): Factored out most of the code... (command-completion--command-for-this-buffer-function): ... to here. (extended-command-versions): New variable. This code is based on a patch by Felician Nemeth <felician.nemeth@gmail.com>.
This commit is contained in:
parent
41c09d347f
commit
cdbb02a597
4 changed files with 90 additions and 32 deletions
|
|
@ -897,6 +897,10 @@ keymaps. This command is the normal definition of @kbd{M-S-x}
|
|||
(that's ``meta shift x'').
|
||||
@end deffn
|
||||
|
||||
Both these commands prompt for a command name, but with different
|
||||
completion rules. You can toggle between these two modes by using the
|
||||
@kbd{M-S-x} command while being prompted.
|
||||
|
||||
@node Distinguish Interactive
|
||||
@section Distinguish Interactive Calls
|
||||
@cindex distinguish interactive calls
|
||||
|
|
|
|||
10
etc/NEWS
10
etc/NEWS
|
|
@ -314,6 +314,16 @@ startup. Previously, these functions ignored
|
|||
|
||||
* Changes in Emacs 29.1
|
||||
|
||||
+++
|
||||
** New key binding after 'M-x' or 'M-X': 'M-X'.
|
||||
Emacs allows different completion predicates to be used with 'M-x'
|
||||
(i.e., 'execute-extended-command') via the
|
||||
'read-extended-command-predicate' user option. Emacs also has the
|
||||
'M-X' (note upper case) command, which only displays commands
|
||||
especially relevant to the current buffer. Emacs now allows toggling
|
||||
between these modes while the user is inputting a command by hitting
|
||||
'M-X' while in the minibuffer.
|
||||
|
||||
---
|
||||
** Interactively, 'kill-buffer' will now offer to save the buffer if unsaved.
|
||||
|
||||
|
|
|
|||
|
|
@ -2780,6 +2780,7 @@ The completion method is determined by `completion-at-point-functions'."
|
|||
(defvar-keymap minibuffer-local-must-match-map
|
||||
:doc "Local keymap for minibuffer input with completion, for exact match."
|
||||
:parent minibuffer-local-completion-map
|
||||
"M-X" #'execute-extended-command-cycle
|
||||
"RET" #'minibuffer-complete-and-exit
|
||||
"C-j" #'minibuffer-complete-and-exit)
|
||||
|
||||
|
|
|
|||
107
lisp/simple.el
107
lisp/simple.el
|
|
@ -2207,9 +2207,53 @@ in that buffer."
|
|||
command-completion-default-include-p)
|
||||
(function :tag "Other function")))
|
||||
|
||||
(defun read-extended-command ()
|
||||
(defun execute-extended-command-cycle ()
|
||||
"Choose the next version of the extended command predicates.
|
||||
See `extended-command-versions'."
|
||||
(interactive)
|
||||
(throw 'cycle
|
||||
(cons (minibuffer-contents)
|
||||
(- (point) (minibuffer-prompt-end)))))
|
||||
|
||||
(defvar extended-command-versions
|
||||
(list (list "M-x " (lambda () read-extended-command-predicate))
|
||||
(list "M-X " #'command-completion--command-for-this-buffer-function))
|
||||
"Alist of prompts and what the extended command predicate should be.
|
||||
This is used by the \\<minibuffer-local-must-match-map>\\[execute-extended-command-cycle] command when reading an extended command.")
|
||||
|
||||
(defun read-extended-command (&optional prompt)
|
||||
"Read command name to invoke in `execute-extended-command'.
|
||||
This function uses the `read-extended-command-predicate' user option."
|
||||
(let ((default-predicate read-extended-command-predicate)
|
||||
(read-extended-command-predicate read-extended-command-predicate)
|
||||
already-typed ret)
|
||||
;; If we have a prompt (which is the name of the version of the
|
||||
;; command), then set up the predicate from
|
||||
;; `extended-command-versions'.
|
||||
(if (not prompt)
|
||||
(setq prompt (caar extended-command-versions))
|
||||
(setq read-extended-command-predicate
|
||||
(funcall (cadr (assoc prompt extended-command-versions)))))
|
||||
;; Normally this will only execute once.
|
||||
(while (not (stringp ret))
|
||||
(when (consp (setq ret (catch 'cycle
|
||||
(read-extended-command-1 prompt
|
||||
already-typed))))
|
||||
;; But if the user hit `M-X', then we `throw'ed out to that
|
||||
;; `catch', and we cycle to the next setting.
|
||||
(let ((next (or (cadr (memq (assoc prompt extended-command-versions)
|
||||
extended-command-versions))
|
||||
;; Last one; cycle back to the first.
|
||||
(car extended-command-versions))))
|
||||
;; Restore the user's default predicate.
|
||||
(setq read-extended-command-predicate default-predicate)
|
||||
;; Then calculate the next.
|
||||
(setq prompt (car next)
|
||||
read-extended-command-predicate (funcall (cadr next))
|
||||
already-typed ret))))
|
||||
ret))
|
||||
|
||||
(defun read-extended-command-1 (prompt initial-input)
|
||||
(let ((buffer (current-buffer)))
|
||||
(minibuffer-with-setup-hook
|
||||
(lambda ()
|
||||
|
|
@ -2234,8 +2278,8 @@ This function uses the `read-extended-command-predicate' user option."
|
|||
(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 '-) "- ")
|
||||
|
|
@ -2253,9 +2297,7 @@ This function uses the `read-extended-command-predicate' user option."
|
|||
;; 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
|
||||
|
|
@ -2294,7 +2336,7 @@ This function uses the `read-extended-command-predicate' user option."
|
|||
(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."
|
||||
|
|
@ -2525,36 +2567,37 @@ minor modes), as well as commands bound in the active local key
|
|||
maps."
|
||||
(declare (interactive-only command-execute))
|
||||
(interactive
|
||||
(let* ((execute-extended-command--last-typed nil)
|
||||
(keymaps
|
||||
;; The major mode's keymap and any active minor modes.
|
||||
(nconc
|
||||
(and (current-local-map) (list (current-local-map)))
|
||||
(mapcar
|
||||
#'cdr
|
||||
(seq-filter
|
||||
(lambda (elem)
|
||||
(symbol-value (car elem)))
|
||||
minor-mode-map-alist))))
|
||||
(read-extended-command-predicate
|
||||
(lambda (symbol buffer)
|
||||
(or (command-completion-using-modes-p symbol buffer)
|
||||
;; Include commands that are bound in a keymap in the
|
||||
;; current buffer.
|
||||
(and (where-is-internal symbol keymaps)
|
||||
;; But not if they have a command predicate that
|
||||
;; says that they shouldn't. (This is the case
|
||||
;; for `ignore' and `undefined' and similar
|
||||
;; commands commonly found in keymaps.)
|
||||
(or (null (get symbol 'completion-predicate))
|
||||
(funcall (get symbol 'completion-predicate)
|
||||
symbol buffer)))))))
|
||||
(let ((execute-extended-command--last-typed nil))
|
||||
(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)))
|
||||
|
||||
(defun command-completion--command-for-this-buffer-function ()
|
||||
(let ((keymaps
|
||||
;; The major mode's keymap and any active minor modes.
|
||||
(nconc
|
||||
(and (current-local-map) (list (current-local-map)))
|
||||
(mapcar
|
||||
#'cdr
|
||||
(seq-filter
|
||||
(lambda (elem)
|
||||
(symbol-value (car elem)))
|
||||
minor-mode-map-alist)))))
|
||||
(lambda (symbol buffer)
|
||||
(or (command-completion-using-modes-p symbol buffer)
|
||||
;; Include commands that are bound in a keymap in the
|
||||
;; current buffer.
|
||||
(and (where-is-internal symbol keymaps)
|
||||
;; But not if they have a command predicate that
|
||||
;; says that they shouldn't. (This is the case
|
||||
;; for `ignore' and `undefined' and similar
|
||||
;; commands commonly found in keymaps.)
|
||||
(or (null (get symbol 'completion-predicate))
|
||||
(funcall (get symbol 'completion-predicate)
|
||||
symbol buffer)))))))
|
||||
|
||||
(cl-defgeneric function-documentation (function)
|
||||
"Extract the raw docstring info from FUNCTION.
|
||||
FUNCTION is expected to be a function value rather than, say, a mere symbol.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue