From e3e3133f800cf4395dc4594b791276498e426c34 Mon Sep 17 00:00:00 2001 From: Lars Ingebrigtsen Date: Sat, 20 Feb 2021 15:12:45 +0100 Subject: [PATCH] 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'). --- doc/lispref/commands.texi | 9 +++++ etc/NEWS | 7 ++++ lisp/simple.el | 72 +++++++++++++++++++++++++++++---------- lisp/subr.el | 1 + 4 files changed, 71 insertions(+), 18 deletions(-) diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi index 1c762c27e8e..8199ece1101 100644 --- a/doc/lispref/commands.texi +++ b/doc/lispref/commands.texi @@ -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 diff --git a/etc/NEWS b/etc/NEWS index c0c292aebc8..b623b13b34f 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -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 diff --git a/lisp/simple.el b/lisp/simple.el index 7c0b6e1d745..0e3a1ee9053 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -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. diff --git a/lisp/subr.el b/lisp/subr.el index f9bb1bb3ad1..cf70b249cfc 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -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.") -- 2.39.2