Add a new command for mode-specific commands

* doc/lispref/commands.texi (Interactive Call): Document it.
* lisp/simple.el (command-completion-using-modes-p): Refactored
out into its own function for reuse...
(command-completion-default-include-p): ... from here.
(execute-extended-command-for-buffer): New command and keystroke
(`M-S-x').
This commit is contained in:
Lars Ingebrigtsen 2021-02-20 15:12:45 +01:00
parent 12578d6aca
commit e3e3133f80
4 changed files with 71 additions and 18 deletions

View file

@ -851,6 +851,15 @@ non-@code{nil} if the command is to be included when completing in
that buffer.
@end deffn
@deffn Command execute-extended-command-for-buffer prefix-argument
This is like @code{execute-extended-command}, but limits the commands
offered for completion to those commands that are of particular
relevance to the current major mode (and enabled minor modes). This
includes commands that are tagged with the modes (@pxref{Using
Interactive}), and also commands that are bound to locally active
keymaps.
@end deffn
@node Distinguish Interactive
@section Distinguish Interactive Calls
@cindex distinguish interactive calls

View file

@ -251,6 +251,13 @@ commands. The new keystrokes are 'C-x x g' ('revert-buffer'),
* Editing Changes in Emacs 28.1
+++
** New command 'execute-extended-command-for-buffer'.
This new command, bound to 'M-S-x', works like
'execute-extended-command', but limits the set of commands to the
commands that have been determined to be particularly of use to the
current mode.
+++
** New user option 'read-extended-command-predicate'.
This option controls how 'M-x' performs completion of commands when

View file

@ -1994,6 +1994,26 @@ This function uses the `read-extended-command-predicate' user option."
(funcall read-extended-command-predicate sym buffer)))))
t nil 'extended-command-history))))
(define-inline command-completion-using-modes-p (symbol buffer)
"Say whether SYMBOL has been marked as a mode-specific command in BUFFER."
;; Check the modes.
(let ((modes (command-modes symbol)))
;; Common case: Just a single mode.
(if (null (cdr modes))
(or (provided-mode-derived-p
(buffer-local-value 'major-mode buffer) (car modes))
(memq (car modes)
(buffer-local-value 'local-minor-modes buffer))
(memq (car modes) global-minor-modes))
;; Uncommon case: Multiple modes.
(apply #'provided-mode-derived-p
(buffer-local-value 'major-mode buffer)
modes)
(seq-intersection modes
(buffer-local-value 'local-minor-modes buffer)
#'eq)
(seq-intersection modes global-minor-modes #'eq))))
(defun command-completion-default-include-p (symbol buffer)
"Say whether SYMBOL should be offered as a completion.
If there's a `completion-predicate' for SYMBOL, the result from
@ -2004,24 +2024,8 @@ BUFFER."
(if (get symbol 'completion-predicate)
;; An explicit completion predicate takes precedence.
(funcall (get symbol 'completion-predicate) symbol buffer)
;; Check the modes.
(let ((modes (command-modes symbol)))
(or (null modes)
;; Common case: Just a single mode.
(if (null (cdr modes))
(or (provided-mode-derived-p
(buffer-local-value 'major-mode buffer) (car modes))
(memq (car modes)
(buffer-local-value 'local-minor-modes buffer))
(memq (car modes) global-minor-modes))
;; Uncommon case: Multiple modes.
(apply #'provided-mode-derived-p
(buffer-local-value 'major-mode buffer)
modes)
(seq-intersection modes
(buffer-local-value 'local-minor-modes buffer)
#'eq)
(seq-intersection modes global-minor-modes #'eq))))))
(or (null (command-modes symbol))
(command-completion-using-modes-p symbol buffer))))
(defun command-completion-with-modes-p (modes buffer)
"Say whether MODES are in action in BUFFER.
@ -2189,6 +2193,38 @@ invoking, give a prefix argument to `execute-extended-command'."
suggest-key-bindings
2))))))))
(defun execute-extended-command-for-buffer (prefixarg &optional
command-name typed)
"Query usert for a command relevant for the current mode and then execute it.
This is like `execute-extended-command', but limits the
completions to commands that are particularly relevant to the
current buffer. This includes commands that have been marked as
being specially designed for the current major mode (and enabled
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.
(cons
(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)
(where-is-internal symbol keymaps)))))
(list current-prefix-arg
(read-extended-command)
execute-extended-command--last-typed)))
(with-suppressed-warnings ((interactive-only execute-extended-command))
(execute-extended-command prefixarg command-name typed)))
(defun command-execute (cmd &optional record-flag keys special)
;; BEWARE: Called directly from the C code.
"Execute CMD as an editor command.

View file

@ -1305,6 +1305,7 @@ in a cleaner way with command remapping, like this:
(define-key map "l" #'downcase-word)
(define-key map "c" #'capitalize-word)
(define-key map "x" #'execute-extended-command)
(define-key map "X" #'execute-extended-command-for-buffer)
map)
"Default keymap for ESC (meta) commands.
The normal global definition of the character ESC indirects to this keymap.")