Subject: Re: bug#72460: [patch] add commands for setting keyboard translations interactively

From: [email-masked]
Date: Sat, 28 Sep 2024 16:33:09 +0100

Hi all,

sorry, I was working on this last night , had the patch sorted, and
then somehow my browser crashed and I couldn't get to my email.
Apologies for all the delays.

> Rewriting a whole new `key-translate-selection-function` function for
> that is not significantly easier than rewriting a whole new
> `key-translate-remove`, so I think this is firmly in the 
> overengineering
> side of the camp.

Fair enough, I've got rid of the defcustom.

> You can't trust `get-text-property` here (especially since you don't
> even force `completing-read` to `require-match`).
> Instead you should do something like `key-parse`.

Good spot.

> In the case of `key-translate-remove` I don't expect the arg to be
> a literal constant in the code, so "nice/uniform syntax to write the
> argument value" shouldn't be a concern.  🙂

Nice, removing the defcustom makes the whole thing simpler anyway.

The way it works now is that `key-select-translation' returns a string
(which passes `key-valid-p'). I went with this because then it's very
straightforward to pass the result to `key-translate' in
`key-translate-remove'. The alternative would be to parse a key vector
out of the string at the end of `key-select-translation', but then
immediately convert this back into a string (a string like the one I
went with in the end) in the interactive form of `key-translate-remove'.

New patch attached.

Hugo
From 56e9270dc202b940d18f5c34807a6f719faa9909 Mon Sep 17 00:00:00 2001
From: Hugo Heagren <[email-masked]>
Date: Sun, 4 Aug 2024 12:54:27 +0100
Subject: [PATCH] Add commands to interactively set/unset keyboard translations

* lisp/keymap.el (key-translate): Add an interactive form, prompting for
keys to translate, and update docstring to reflect this.
(key-translate-selection-function): New custom option.
(key-select-translation): New function, default value of above option.
(key-translate-remove): New command, for removing entries from
`keyboard-translate-table'.
---
 lisp/keymap.el | 51 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 50 insertions(+), 1 deletion(-)

diff --git a/lisp/keymap.el b/lisp/keymap.el
index 861d6724c9e..4e1deecff51 100644
--- a/lisp/keymap.el
+++ b/lisp/keymap.el
@@ -392,9 +392,16 @@ key-translate
 and then modifies one entry in it.
 
 Both FROM and TO should be specified by strings that satisfy `key-valid-p'.
-If TO is nil, remove any existing translation for FROM."
+If TO is nil, remove any existing translation for FROM.
+
+Interactively, prompt for FROM and TO with `read-char'."
   (declare (compiler-macro
             (lambda (form) (keymap--compile-check from to) form)))
+  ;; Using `key-description' is a necessary evil here, so that the
+  ;; values can be passed to keymap-* functions, even though those
+  ;; functions immediately undo it with `key-parse'.
+  (interactive `(,(key-description `[,(read-char "From: ")])
+                 ,(key-description `[,(read-char "To: ")])))
   (keymap--check from)
   (when to
     (keymap--check to))
@@ -417,6 +424,48 @@ key-translate
           (aref from-key 0)
           (and to (aref to-key 0)))))
 
+(defun key-select-translation ()
+  "Prompt for a current keyboard translation pair with `'completing-read'.
+
+Each pair is formatted as \"FROM -> TO\".
+
+Return the \"FROM\" as a key string."
+  (let* ((minibuffer-allow-text-properties t)
+         (collection)
+         ;; Alignment helpers
+         (pad 0)
+         (_ (map-char-table
+             (lambda (k _)
+               (when (> (length (key-description `[,k])) pad)
+                 (setq pad (length (key-description `[,k])))))
+             keyboard-translate-table
+             ))
+         (format-func
+          (lambda (k v)
+            (setq collection
+                  (cons
+                   (propertize
+                    (format
+                     "%s -> %s"
+                     (string-pad (key-description `[,k]) pad)
+                     (key-description `[,v]))
+                    'key-translate-from k)
+                   collection)))))
+    ;; Populate collection
+    (map-char-table format-func keyboard-translate-table)
+    (car
+     (split-string
+      (completing-read
+       "Key Translation: " collection nil t)))))
+
+(defun key-translate-remove (from)
+  "Remove translation of FROM from `keyboard-translate-table'.
+
+FROM must satisfy `key-valid-p'.  If FROM has no entry in
+`keyboard-translate-table', this has no effect."
+  (interactive (list (key-select-translation)))
+  (key-translate from nil))
+
 (defun keymap-lookup (keymap key &optional accept-default no-remap position)
   "Return the binding for command KEY in KEYMAP.
 KEY is a string that satisfies `key-valid-p'.
-- 
2.20.1