From 9ed0baf9f889821f37ef6f661a440dab4761978f Mon Sep 17 00:00:00 2001 From: Stefan Kangas Date: Sun, 21 Nov 2021 14:12:26 +0100 Subject: [PATCH] Add new format for literal key sequences to substitute-command-keys * lisp/help.el (substitute-command-keys): Add new format "\\`f'" for literal key sequences. * doc/lispref/help.texi (Keys in Documentation): Document the above new substitution. * test/lisp/help-tests.el (help-tests-substitute-command-keys/literal-key-sequence): (help-tests-substitute-command-keys/literal-key-sequence-errors): New tests. (help-tests-substitute-key-bindings/face-help-key-binding): Extend test. --- doc/lispref/help.texi | 7 +++++++ etc/NEWS | 9 +++++++++ lisp/help.el | 20 ++++++++++++++++++++ test/lisp/help-tests.el | 19 +++++++++++++++++++ 4 files changed, 55 insertions(+) diff --git a/doc/lispref/help.texi b/doc/lispref/help.texi index a788852de7..1a9eb30fde 100644 --- a/doc/lispref/help.texi +++ b/doc/lispref/help.texi @@ -333,6 +333,13 @@ Keys in Documentation specifies @var{mapvar}'s value as the keymap for any following @samp{\[@var{command}]} sequences in this documentation string. +@item \`@var{KEYSEQ}' +stands for a key sequence @var{KEYSEQ}, which will use the same face +as a command substitution. This should be used only when a key +sequence has no corresponding command, for example when it is read +directly with @code{read-key-sequence}. It must be a valid key +sequence according to @code{key-valid-p}. + @item ` (grave accent) stands for a left quote. This generates a left single quotation mark, an apostrophe, or a grave diff --git a/etc/NEWS b/etc/NEWS index bfea4da8b9..afcc438001 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -716,6 +716,15 @@ syntax. This is like 'kbd', but only returns vectors instead of a mix of vectors and strings. ++++ +** New substitution in docstrings and 'substitute-command-keys'. Use +Use "\\`KEYSEQ'" to insert a literal key sequence "KEYSEQ" +(e.g. "C-k") in a docstring or when calling 'substitute-command-keys', +which will use the same face as a command substitution. This should +be used only when a key sequence has no corresponding command, for +example when it is read directly with 'read-key-sequence'. It must be +a valid key sequence according to 'key-valid-p'. + +++ ** New function 'file-name-split'. This returns a list of all the components of a file name. diff --git a/lisp/help.el b/lisp/help.el index bc3d4773da..9122d96271 100644 --- a/lisp/help.el +++ b/lisp/help.el @@ -1078,6 +1078,9 @@ substitute-command-keys keystroke sequence that invokes COMMAND, or \"M-x COMMAND\" if COMMAND is not on any keys. Keybindings will use the face `help-key-binding'. +Each substring of the form \\\\=`KEYBINDING' will be replaced by +KEYBINDING and use the `help-key-binding' face. + Each substring of the form \\\\={MAPVAR} is replaced by a summary of the value of MAPVAR as a keymap. This summary is similar to the one produced by ‘describe-bindings’. The summary ends in two newlines @@ -1130,6 +1133,23 @@ substitute-command-keys (delete-char 2) (ignore-errors (forward-char 1))) + ((and (= (following-char) ?`) + (save-excursion + (prog1 (search-forward "'" nil t) + (setq end-point (- (point) 2))))) + (goto-char orig-point) + (delete-char 2) + (goto-char (1- end-point)) + (delete-char 1) + ;; (backward-char 1) + (let ((k (buffer-substring-no-properties orig-point (point)))) + (cond ((= (length k) 0) + (error "Empty key sequence in substitution")) + ((not (key-valid-p k)) + (error "Invalid key sequence in substitution: `%s'" k)))) + (add-text-properties orig-point (point) + '( face help-key-binding + font-lock-face help-key-binding))) ;; 1C. \[foo] is replaced with the keybinding. ((and (= (following-char) ?\[) (save-excursion diff --git a/test/lisp/help-tests.el b/test/lisp/help-tests.el index 982750f479..281d97ee92 100644 --- a/test/lisp/help-tests.el +++ b/test/lisp/help-tests.el @@ -88,6 +88,25 @@ help-tests-substitute-command-keys/commands (test "\\[emacs-version]\\[next-line]" "M-x emacs-versionC-n") (test-re "\\[emacs-version]`foo'" "M-x emacs-version[`'‘]foo['’]"))) +(ert-deftest help-tests-substitute-command-keys/literal-key-sequence () + "Literal replacement." + (with-substitute-command-keys-test + (test "\\`C-m'" "C-m") + (test "\\`C-m'\\`C-j'" "C-mC-j") + (test "foo\\`C-m'bar\\`C-j'baz" "fooC-mbarC-jbaz"))) + +(ert-deftest help-tests-substitute-command-keys/literal-key-sequence-errors () + (should-error (substitute-command-keys "\\`'")) + (should-error (substitute-command-keys "\\`c-c'")) + (should-error (substitute-command-keys "\\`'"))) + +(ert-deftest help-tests-substitute-key-bindings/face-help-key-binding () + (should (eq (get-text-property 0 'face (substitute-command-keys "\\[next-line]")) + 'help-key-binding)) + (should (eq (get-text-property 0 'face (substitute-command-keys "\\`f'")) + 'help-key-binding))) + + (ert-deftest help-tests-substitute-command-keys/keymaps () (with-substitute-command-keys-test (test-re "\\{minibuffer-local-must-match-map}" -- 2.30.2