[PATCH] emacs: jump: make multilevel keys do multilevel jump

Mark Walters markwalters1009 at gmail.com
Sat Oct 8 16:00:19 PDT 2016


notmuch jump allows the user to specify a key sequence rather than
just a single key for its bindings. However, it doesn't show what has
already been typed so it can be difficult to see what has
happened. This makes each key press appear, and the jump menu reduce
to the possible follow up keys.
---

bremner pointed out that multi-key key sequences were unclear in
tag-jump (and other jump uses). This makes it clearer by displaying
the keys typed so far and reducing the displayed options based on what
has been typed so far. Backspace is bound to remove the last typed
character and return to the previous level. Slightly unfortunately
emacs likes to call backspace "DEL".

There is noticeable increase in the complexity of the jump
code. However, in the common case of all key sequences being single
keys then it looks exactly as before.

Finally there are a couple of corner cases that are of the form "don't
do that". The first is if the user specifies two bindings one of which
is a prefix of the other (I don't know what happens before but we now
just take the shorter one). The second is that the user can't bind
backspace in any submap (i.e. as the second or subsequent key of a
key-sequence) as it is used for going back up a level.

Best wishes

Mark




emacs/notmuch-jump.el | 40 ++++++++++++++++++++++++++++++++++------
 1 file changed, 34 insertions(+), 6 deletions(-)

diff --git a/emacs/notmuch-jump.el b/emacs/notmuch-jump.el
index 963253c..b7df1c2 100644
--- a/emacs/notmuch-jump.el
+++ b/emacs/notmuch-jump.el
@@ -104,7 +104,7 @@ not appear in the pop-up buffer.
 	   (copy-sequence minibuffer-prompt-properties)
 	   'face))
 	 ;; Build the keymap with our bindings
-	 (minibuffer-map (notmuch-jump--make-keymap action-map))
+	 (minibuffer-map (notmuch-jump--make-keymap action-map prompt))
 	 ;; The bindings save the the action in notmuch-jump--action
 	 (notmuch-jump--action nil))
     ;; Read the action
@@ -164,15 +164,43 @@ buffer."
     map)
   "Base keymap for notmuch-jump's minibuffer keymap.")
 
-(defun notmuch-jump--make-keymap (action-map)
+(defun notmuch-jump--make-keymap (action-map prompt)
   "Translate ACTION-MAP into a minibuffer keymap."
   (let ((map (make-sparse-keymap)))
     (set-keymap-parent map notmuch-jump-minibuffer-map)
     (dolist (action action-map)
-      (define-key map (first action)
-	`(lambda () (interactive)
-	   (setq notmuch-jump--action ',(third action))
-	   (exit-minibuffer))))
+      (if (= (length (first action)) 1)
+	  (define-key map (first action)
+	    `(lambda () (interactive)
+	       (setq notmuch-jump--action ',(third action))
+	       (exit-minibuffer)))))
+    ;; By doing this in two passes (and checking if we already have a
+    ;; binding) we avoid problems if the user specifies a binding which
+    ;; is a prefix of another binding.
+    (dolist (action action-map)
+      (if (> (length (first action)) 1)
+	  (let* ((key (elt (first action) 0))
+		 (keystr (string key))
+		 (new-prompt (concat prompt (format-kbd-macro keystr) " "))
+		 (action-submap nil))
+	    (unless (lookup-key map keystr)
+	      (dolist (act action-map)
+		(when (= key (elt (first act) 0))
+		  (push (list (substring (first act) 1)
+			      (second act)
+			      (third act))
+			action-submap)))
+	      ;; We deal with backspace specially
+	      (push (list (kbd "<backspace>")
+			  "Backup"
+			  `,(apply-partially #'notmuch-jump action-map prompt))
+		    action-submap)
+	      (setq action-submap (nreverse action-submap))
+	      (define-key map keystr
+		`(lambda () (interactive)
+		   (setq notmuch-jump--action
+			 ',(apply-partially #'notmuch-jump action-submap new-prompt))
+		   (exit-minibuffer)))))))
     map))
 
 ;;
-- 
2.1.4



More information about the notmuch mailing list