branch: externals/keymap-popup
commit b723f8634accadab0c23bac5c3299467b66475d9
Author: Thanos Apollo <[email protected]>
Commit: Thanos Apollo <[email protected]>
refactor: eliminate annotated flag, single-pass classify
---
keymap-popup.el | 109 ++++++++++++++++++++------------------------
tests/keymap-popup-tests.el | 62 +++++++++++++------------
2 files changed, 84 insertions(+), 87 deletions(-)
diff --git a/keymap-popup.el b/keymap-popup.el
index 8e29733a4f..cbb76993cb 100644
--- a/keymap-popup.el
+++ b/keymap-popup.el
@@ -429,7 +429,6 @@ time, so the popup always reflects the user's current
bindings."
`(progn
(setf (keymap-popup--meta ,keymap 'descriptions)
,(keymap-popup--build-descriptions-form rows))
- (setf (keymap-popup--meta ,keymap 'annotated) 'yes)
,@(and popup-key
`((keymap-set ,keymap ,popup-key
(lambda () (interactive) (keymap-popup ,keymap)))))
@@ -933,43 +932,33 @@ its parent group plist; non-nil return values are
collected."
row))
descriptions))
-(defun keymap-popup--inapt-keys (descriptions)
- "Return key-strings that may be inapt in DESCRIPTIONS.
-Includes keys with entry-level or group-level :inapt-if."
- (keymap-popup--collect-entries
- descriptions
- (lambda (entry group)
- (and-let* ((key (plist-get entry :key))
- (_ (or (plist-get entry :inapt-if)
- (plist-get group :inapt-if))))
- key))))
-
-(defun keymap-popup--stay-open-suffix-keys (descriptions)
- "Return key-strings for :stay-open suffix entries in DESCRIPTIONS."
- (keymap-popup--collect-entries
- descriptions
- (lambda (entry _group)
- (and-let* ((key (plist-get entry :key))
- (_ (eq (plist-get entry :type) 'suffix))
- (_ (plist-get entry :stay-open)))
- key))))
-
-(defun keymap-popup--switch-keys (descriptions)
- "Return key-strings for switch entries in DESCRIPTIONS."
- (keymap-popup--collect-entries
- descriptions
- (lambda (entry _group)
- (and (eq (plist-get entry :type) 'switch)
- (plist-get entry :key)))))
-
-(defun keymap-popup--submenu-keys (descriptions)
- "Return alist of (KEY-STRING . TARGET-KEYMAP) from DESCRIPTIONS."
- (keymap-popup--collect-entries
- descriptions
- (lambda (entry _group)
- (when (eq (plist-get entry :type) 'keymap)
- (cons (plist-get entry :key)
- (plist-get entry :target))))))
+(defun keymap-popup--classify-entries (descriptions)
+ "Walk DESCRIPTIONS once, classify entries by type and properties.
+Returns plist (:inapt KEYS :switches KEYS :submenus PAIRS :stay-open KEYS)."
+ (let ((entries (keymap-popup--collect-entries
+ descriptions
+ (lambda (entry group)
+ (and-let* ((key (plist-get entry :key)))
+ (list :key key
+ :type (plist-get entry :type)
+ :target (plist-get entry :target)
+ :inapt (or (plist-get entry :inapt-if)
+ (plist-get group :inapt-if))
+ :stay-open (plist-get entry :stay-open)))))))
+ (list :inapt (cl-loop for e in entries
+ when (plist-get e :inapt)
+ collect (plist-get e :key))
+ :switches (cl-loop for e in entries
+ when (eq (plist-get e :type) 'switch)
+ collect (plist-get e :key))
+ :submenus (cl-loop for e in entries
+ when (eq (plist-get e :type) 'keymap)
+ collect (cons (plist-get e :key)
+ (plist-get e :target)))
+ :stay-open (cl-loop for e in entries
+ when (and (eq (plist-get e :type) 'suffix)
+ (plist-get e :stay-open))
+ collect (plist-get e :key)))))
(defun keymap-popup--push-submenu (buf child-keymap)
"Push current popup state in BUF and activate CHILD-KEYMAP's transient map."
@@ -979,10 +968,9 @@ Includes keys with entry-level or group-level :inapt-if."
:docstring keymap-popup--active-docstring
:exit-key keymap-popup--active-exit-key)
keymap-popup--stack)
- (let* ((raw (keymap-popup--collect-descriptions child-keymap))
- (descs (if (keymap-popup--meta child-keymap 'annotated)
- (keymap-popup--resolve-descriptions raw child-keymap)
- raw))
+ (let* ((descs (keymap-popup--resolve-descriptions
+ (keymap-popup--collect-descriptions child-keymap)
+ child-keymap))
(doc (keymap-popup--meta child-keymap 'description))
(exit-key (or (keymap-popup--meta child-keymap 'exit-key)
keymap-popup-default-exit-key)))
@@ -1032,17 +1020,17 @@ When not inapt, calls CMD."
(setq prefix-arg '(4))))
(funcall cmd)))))
-(defun keymap-popup--submenu-overrides (descriptions buf)
- "Return alist of submenu key overrides from DESCRIPTIONS for BUF."
+(defun keymap-popup--submenu-overrides (submenu-pairs buf)
+ "Return alist of submenu key overrides from SUBMENU-PAIRS for BUF."
(mapcar (lambda (pair)
(cons (car pair)
(let ((target (cdr pair)))
(lambda () (interactive)
(keymap-popup--push-submenu buf target)))))
- (keymap-popup--submenu-keys descriptions)))
+ submenu-pairs))
-(defun keymap-popup--switch-overrides (keymap descriptions buf)
- "Return alist of switch key overrides for KEYMAP DESCRIPTIONS in BUF.
+(defun keymap-popup--switch-overrides (keymap switch-keys buf)
+ "Return alist of switch key overrides for KEYMAP's SWITCH-KEYS in BUF.
Wraps the toggle command with prefix-mode consumption."
(mapcar (lambda (key-str)
(cons key-str
@@ -1053,27 +1041,31 @@ Wraps the toggle command with prefix-mode consumption."
(setq-local keymap-popup--prefix-mode nil))
(setq prefix-arg nil))
(keymap-popup--refresh buf))))
- (keymap-popup--switch-keys descriptions)))
+ switch-keys))
-(defun keymap-popup--stay-open-overrides (keymap descriptions buf)
- "Return alist of stay-open suffix overrides for KEYMAP DESCRIPTIONS in BUF.
+(defun keymap-popup--stay-open-overrides (keymap stay-open-keys buf)
+ "Return alist of stay-open suffix overrides for KEYMAP's STAY-OPEN-KEYS in
BUF.
Each command executes and refreshes the popup in place."
(mapcar (lambda (key-str)
(cons key-str
(lambda () (interactive)
(call-interactively (keymap-lookup keymap key-str))
(keymap-popup--refresh buf))))
- (keymap-popup--stay-open-suffix-keys descriptions)))
+ stay-open-keys))
(defun keymap-popup--build-wrapper-map (keymap descriptions buf exit-key)
"Build wrapper keymap over KEYMAP with DESCRIPTIONS for BUF.
EXIT-KEY and inapt guards are applied as a layer over specialized handlers."
(let* ((map (make-sparse-keymap))
- (inapt (keymap-popup--inapt-keys descriptions))
+ (classified (keymap-popup--classify-entries descriptions))
+ (inapt (plist-get classified :inapt))
(overrides (append (keymap-popup--core-overrides exit-key)
- (keymap-popup--switch-overrides keymap
descriptions buf)
- (keymap-popup--submenu-overrides descriptions buf)
- (keymap-popup--stay-open-overrides keymap
descriptions buf))))
+ (keymap-popup--switch-overrides
+ keymap (plist-get classified :switches) buf)
+ (keymap-popup--submenu-overrides
+ (plist-get classified :submenus) buf)
+ (keymap-popup--stay-open-overrides
+ keymap (plist-get classified :stay-open) buf))))
(set-keymap-parent map keymap)
(pcase-dolist (`(,key . ,cmd) overrides)
(keymap-set map key
@@ -1100,10 +1092,9 @@ navigation stack. \\[universal-argument] toggles prefix
mode."
(let* ((source (current-buffer))
(buf (keymap-popup--prepare-buffer))
(backend (funcall keymap-popup-backend))
- (raw (keymap-popup--collect-descriptions keymap))
- (descriptions (if (keymap-popup--meta keymap 'annotated)
- (keymap-popup--resolve-descriptions raw keymap)
- raw))
+ (descriptions (keymap-popup--resolve-descriptions
+ (keymap-popup--collect-descriptions keymap)
+ keymap))
(docstring (keymap-popup--meta keymap 'description))
(exit-key (or (keymap-popup--meta keymap 'exit-key)
keymap-popup-default-exit-key))
diff --git a/tests/keymap-popup-tests.el b/tests/keymap-popup-tests.el
index c969b72791..ecd6425a56 100644
--- a/tests/keymap-popup-tests.el
+++ b/tests/keymap-popup-tests.el
@@ -649,31 +649,39 @@
(should (functionp (keymap-lookup map "C-u")))
(kill-buffer buf))))
-(ert-deftest keymap-popup-test-inapt-keys-collected ()
- (let ((descs (list (list (list :name nil
- :entries (list (list :key "m" :type 'suffix
- :inapt-if (lambda () t))
- (list :key "c" :type
'suffix)))))))
- (should (equal (keymap-popup--inapt-keys descs) '("m")))))
-
-(ert-deftest keymap-popup-test-inapt-keys-from-group ()
- (let ((descs (list (list (list :name "G" :inapt-if (lambda () t)
- :entries (list (list :key "a" :type 'suffix)
- (list :key "b" :type
'suffix)))))))
- (should (equal (keymap-popup--inapt-keys descs) '("a" "b")))))
-
-(ert-deftest keymap-popup-test-submenu-keys-collected ()
- (let ((descs (list (list (list :name nil
- :entries (list (list :key "a" :type 'keymap
:target 'sub)
- (list :key "c" :type
'suffix)))))))
- (should (equal (keymap-popup--submenu-keys descs) '(("a" . sub))))))
-
-(ert-deftest keymap-popup-test-stay-open-suffix-keys ()
- (let ((descs (list (list (list :name nil
- :entries (list (list :key "g" :type 'suffix
:stay-open t)
- (list :key "v" :type 'switch
:variable 'x)
- (list :key "c" :type
'suffix)))))))
- (should (equal (keymap-popup--stay-open-suffix-keys descs) '("g")))))
+(ert-deftest keymap-popup-test-classify-inapt ()
+ "Entry-level :inapt-if is classified."
+ (let* ((descs (list (list (list :name nil
+ :entries (list (list :key "m" :type 'suffix
+ :inapt-if (lambda () t))
+ (list :key "c" :type
'suffix))))))
+ (classified (keymap-popup--classify-entries descs)))
+ (should (equal (plist-get classified :inapt) '("m")))))
+
+(ert-deftest keymap-popup-test-classify-inapt-from-group ()
+ "Group-level :inapt-if classifies all entries in the group."
+ (let* ((descs (list (list (list :name "G" :inapt-if (lambda () t)
+ :entries (list (list :key "a" :type 'suffix)
+ (list :key "b" :type
'suffix))))))
+ (classified (keymap-popup--classify-entries descs)))
+ (should (equal (plist-get classified :inapt) '("a" "b")))))
+
+(ert-deftest keymap-popup-test-classify-submenus ()
+ "Keymap entries are classified as submenus."
+ (let* ((descs (list (list (list :name nil
+ :entries (list (list :key "a" :type 'keymap
:target 'sub)
+ (list :key "c" :type
'suffix))))))
+ (classified (keymap-popup--classify-entries descs)))
+ (should (equal (plist-get classified :submenus) '(("a" . sub))))))
+
+(ert-deftest keymap-popup-test-classify-stay-open ()
+ "Stay-open suffix entries are classified."
+ (let* ((descs (list (list (list :name nil
+ :entries (list (list :key "g" :type 'suffix
:stay-open t)
+ (list :key "v" :type 'switch
:variable 'x)
+ (list :key "c" :type
'suffix))))))
+ (classified (keymap-popup--classify-entries descs)))
+ (should (equal (plist-get classified :stay-open) '("g")))))
;;; Add/remove entry tests
@@ -728,6 +736,7 @@
(should (eq (plist-get entry :command) 'forward-char))
(should (equal (plist-get entry :description) "Forward"))))
+
(ert-deftest keymap-popup-test-resolve-key ()
(let* ((entry (list :key nil :description "Forward" :type 'suffix
:command 'forward-char))
@@ -757,9 +766,6 @@
forward-char "Forward"
backward-char "Backward")
t)
- (should (eq (keymap-popup--meta keymap-popup--test-annotate-map
- 'annotated)
- 'yes))
(let* ((descs (keymap-popup--meta keymap-popup--test-annotate-map
'descriptions))
(entries (plist-get (car (car descs)) :entries)))