]> git.notmuchmail.org Git - notmuch/blobdiff - emacs/notmuch-lib.el
emacs: move notmuch-help to lib
[notmuch] / emacs / notmuch-lib.el
index 65412821251dfa189e16e8f5274f3755bb4a9111..e7c5c97144dc666787006cd4238ab89a99cbd588 100644 (file)
@@ -215,6 +215,93 @@ depending on the value of `notmuch-poll-script'."
   (interactive)
   (kill-buffer (current-buffer)))
 
+(defun notmuch-documentation-first-line (symbol)
+  "Return the first line of the documentation string for SYMBOL."
+  (let ((doc (documentation symbol)))
+    (if doc
+       (with-temp-buffer
+         (insert (documentation symbol t))
+         (goto-char (point-min))
+         (let ((beg (point)))
+           (end-of-line)
+           (buffer-substring beg (point))))
+      "")))
+
+(defun notmuch-prefix-key-description (key)
+  "Given a prefix key code, return a human-readable string representation.
+
+This is basically just `format-kbd-macro' but we also convert ESC to M-."
+  (let ((desc (format-kbd-macro (vector key))))
+    (if (string= desc "ESC")
+       "M-"
+      (concat desc " "))))
+
+(defun notmuch-describe-keymap (keymap ua-keys &optional prefix tail)
+  "Return a list of strings, each describing one binding in KEYMAP.
+
+Each string gives a human-readable description of the key and a
+one-line description of the bound function.  See `notmuch-help'
+for an overview of how this documentation is extracted.
+
+UA-KEYS should be a key sequence bound to `universal-argument'.
+It will be used to describe bindings of commands that support a
+prefix argument.  PREFIX and TAIL are used internally."
+  (map-keymap
+   (lambda (key binding)
+     (cond ((mouse-event-p key) nil)
+          ((keymapp binding)
+           (setq tail
+                 (notmuch-describe-keymap
+                  binding ua-keys (notmuch-prefix-key-description key) tail)))
+          (t
+           (when (and ua-keys (symbolp binding)
+                      (get binding 'notmuch-prefix-doc))
+             ;; Documentation for prefixed command
+             (let ((ua-desc (key-description ua-keys)))
+               (push (concat ua-desc " " prefix (format-kbd-macro (vector key))
+                             "\t" (get binding 'notmuch-prefix-doc))
+                     tail)))
+           ;; Documentation for command
+           (push (concat prefix (format-kbd-macro (vector key)) "\t"
+                         (or (and (symbolp binding) (get binding 'notmuch-doc))
+                             (notmuch-documentation-first-line binding)))
+                 tail))))
+   keymap)
+  tail)
+
+(defun notmuch-substitute-command-keys (doc)
+  "Like `substitute-command-keys' but with documentation, not function names."
+  (let ((beg 0))
+    (while (string-match "\\\\{\\([^}[:space:]]*\\)}" doc beg)
+      (let* ((keymap-name (substring doc (match-beginning 1) (match-end 1)))
+            (keymap (symbol-value (intern keymap-name)))
+            (ua-keys (where-is-internal 'universal-argument keymap t))
+            (desc-list (notmuch-describe-keymap keymap ua-keys))
+            (desc (mapconcat #'identity desc-list "\n")))
+       (setq doc (replace-match desc 1 1 doc)))
+      (setq beg (match-end 0)))
+    doc))
+
+(defun notmuch-help ()
+  "Display help for the current notmuch mode.
+
+This is similar to `describe-function' for the current major
+mode, but bindings tables are shown with documentation strings
+rather than command names.  By default, this uses the first line
+of each command's documentation string.  A command can override
+this by setting the 'notmuch-doc property of its command symbol.
+A command that supports a prefix argument can explicitly document
+its prefixed behavior by setting the 'notmuch-prefix-doc property
+of its command symbol."
+  (interactive)
+  (let* ((mode major-mode)
+        (doc (substitute-command-keys (notmuch-substitute-command-keys (documentation mode t)))))
+    (with-current-buffer (generate-new-buffer "*notmuch-help*")
+      (insert doc)
+      (goto-char (point-min))
+      (set-buffer-modified-p nil)
+      (view-buffer (current-buffer) 'kill-buffer-if-not-modified))))
+
 (defvar notmuch-buffer-refresh-function nil
   "Function to call to refresh the current buffer.")
 (make-variable-buffer-local 'notmuch-buffer-refresh-function)