X-Git-Url: https://git.notmuchmail.org/git?a=blobdiff_plain;f=emacs%2Fnotmuch.el;h=6081245560134446ea362b686b1dec17bafec481;hb=22172daa1768fff08046b4ccb82ceb2f3a38ac30;hp=e098bd7bb1b98a8a3d700b2ce8ed69c7452707da;hpb=c52fee6bcb3565ce19801b86d83d5783e48df320;p=notmuch diff --git a/emacs/notmuch.el b/emacs/notmuch.el index e098bd7b..60812455 100644 --- a/emacs/notmuch.el +++ b/emacs/notmuch.el @@ -140,21 +140,35 @@ This is basically just `format-kbd-macro' but we also convert ESC to M-." "M-" (concat desc " ")))) -(defun notmuch-describe-keymap (keymap &optional prefix tail) - "Return a list of strings, each describing one key in KEYMAP. +(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 the -first line of documentation for the bound function." +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 (notmuch-prefix-key-description key) tail))) + 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" - (notmuch-documentation-first-line binding)) + (or (and (symbolp binding) (get binding 'notmuch-doc)) + (notmuch-documentation-first-line binding))) tail)))) keymap) tail) @@ -165,14 +179,24 @@ first line of documentation for the bound function." (while (string-match "\\\\{\\([^}[:space:]]*\\)}" doc beg) (let* ((keymap-name (substring doc (match-beginning 1) (match-end 1))) (keymap (symbol-value (intern keymap-name))) - (desc-list (notmuch-describe-keymap keymap)) + (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." + "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))))) @@ -199,8 +223,6 @@ first line of documentation for the bound function." (defvar notmuch-search-mode-map (let ((map (make-sparse-keymap))) (set-keymap-parent map notmuch-common-keymap) - (define-key map "?" 'notmuch-help) - (define-key map "q" 'notmuch-kill-this-buffer) (define-key map "x" 'notmuch-kill-this-buffer) (define-key map (kbd "") 'notmuch-search-scroll-down) (define-key map "b" 'notmuch-search-scroll-down) @@ -211,12 +233,8 @@ first line of documentation for the bound function." (define-key map "n" 'notmuch-search-next-thread) (define-key map "r" 'notmuch-search-reply-to-thread-sender) (define-key map "R" 'notmuch-search-reply-to-thread) - (define-key map "m" 'notmuch-mua-new-mail) - (define-key map "s" 'notmuch-search) (define-key map "o" 'notmuch-search-toggle-order) (define-key map "c" 'notmuch-search-stash-map) - (define-key map "=" 'notmuch-refresh-this-buffer) - (define-key map "G" 'notmuch-poll-and-refresh-this-buffer) (define-key map "t" 'notmuch-search-filter-by-tag) (define-key map "f" 'notmuch-search-filter) (define-key map [mouse-1] 'notmuch-search-show-thread) @@ -492,13 +510,14 @@ If BARE is set then do not prefix with \"thread:\"" "Return a list of authors for the current region" (notmuch-search-properties-in-region :subject beg end)) -(defun notmuch-search-show-thread () +(defun notmuch-search-show-thread (&optional elide-toggle) "Display the currently selected thread." - (interactive) + (interactive "P") (let ((thread-id (notmuch-search-find-thread-id)) (subject (notmuch-search-find-subject))) (if (> (length thread-id) 0) (notmuch-show thread-id + elide-toggle (current-buffer) notmuch-search-query-string ;; Name the buffer based on the subject. @@ -542,37 +561,62 @@ will be signaled." (setq output (append output (notmuch-search-get-tags pos))))) output)) -(defun notmuch-search-tag-region (beg end &optional tag-changes) - "Change tags for threads in the given region." +(defun notmuch-search-interactive-region () + "Return the bounds of the current interactive region. + +This returns (BEG END), where BEG and END are the bounds of the +region if the region is active, or both `point' otherwise." + (if (region-active-p) + (list (region-beginning) (region-end)) + (list (point) (point)))) + +(defun notmuch-search-interactive-tag-changes (&optional initial-input) + "Prompt for tag changes for the current thread or region. + +Returns (TAG-CHANGES REGION-BEGIN REGION-END)." + (let* ((region (notmuch-search-interactive-region)) + (beg (first region)) (end (second region)) + (prompt (if (= beg end) "Tag thread" "Tag region"))) + (cons (notmuch-read-tag-changes + (notmuch-search-get-tags-region beg end) prompt initial-input) + region))) + +(defun notmuch-search-tag (tag-changes &optional beg end) + "Change tags for the currently selected thread or region. + +See `notmuch-tag' for information on the format of TAG-CHANGES. +When called interactively, this uses the region if the region is +active. When called directly, BEG and END provide the region. +If these are nil or not provided, this applies to the thread at +point." + (interactive (notmuch-search-interactive-tag-changes)) + (unless (and beg end) (setq beg (point) end (point))) (let ((search-string (notmuch-search-find-thread-id-region-search beg end))) - (setq tag-changes (notmuch-tag search-string tag-changes)) + (notmuch-tag search-string tag-changes) (notmuch-search-foreach-result beg end (lambda (pos) (notmuch-search-set-tags (notmuch-update-tags (notmuch-search-get-tags pos) tag-changes) pos))))) -(defun notmuch-search-tag (&optional tag-changes) - "Change tags for the currently selected thread or region. +(defun notmuch-search-add-tag (tag-changes &optional beg end) + "Change tags for the current thread or region (defaulting to add). -See `notmuch-tag' for information on the format of TAG-CHANGES." - (interactive) - (let* ((beg (if (region-active-p) (region-beginning) (point))) - (end (if (region-active-p) (region-end) (point)))) - (notmuch-search-tag-region beg end tag-changes))) +Same as `notmuch-search-tag' but sets initial input to '+'." + (interactive (notmuch-search-interactive-tag-changes "+")) + (notmuch-search-tag tag-changes beg end)) -(defun notmuch-search-add-tag () - "Same as `notmuch-search-tag' but sets initial input to '+'." - (interactive) - (notmuch-search-tag "+")) +(defun notmuch-search-remove-tag (tag-changes &optional beg end) + "Change tags for the current thread or region (defaulting to remove). -(defun notmuch-search-remove-tag () - "Same as `notmuch-search-tag' but sets initial input to '-'." - (interactive) - (notmuch-search-tag "-")) +Same as `notmuch-search-tag' but sets initial input to '-'." + (interactive (notmuch-search-interactive-tag-changes "-")) + (notmuch-search-tag tag-changes beg end)) -(defun notmuch-search-archive-thread (&optional unarchive) - "Archive the currently selected thread. +(put 'notmuch-search-archive-thread 'notmuch-prefix-doc + "Un-archive the currently selected thread.") +(defun notmuch-search-archive-thread (&optional unarchive beg end) + "Archive the currently selected thread or region. Archive each message in the currently selected thread by applying the tag changes in `notmuch-archive-tags' to each (remove the @@ -581,10 +625,10 @@ messages will be \"unarchived\" (i.e. the tag changes in `notmuch-archive-tags' will be reversed). This function advances the next thread when finished." - (interactive "P") + (interactive (cons current-prefix-arg (notmuch-search-interactive-region))) (when notmuch-archive-tags (notmuch-search-tag - (notmuch-tag-change-list notmuch-archive-tags unarchive))) + (notmuch-tag-change-list notmuch-archive-tags unarchive) beg end)) (notmuch-search-next-thread)) (defun notmuch-search-update-result (result &optional pos) @@ -808,12 +852,14 @@ non-authors is found, assume that all of the authors match." (notmuch-sexp-parse-partial-list 'notmuch-search-show-result results-buf))))) -(defun notmuch-search-tag-all (&optional tag-changes) +(defun notmuch-search-tag-all (tag-changes) "Add/remove tags from all messages in current search buffer. See `notmuch-tag' for information on the format of TAG-CHANGES." - (interactive) - (apply 'notmuch-tag notmuch-search-query-string tag-changes)) + (interactive + (list (notmuch-read-tag-changes + (notmuch-search-get-tags-region (point-min) (point-max)) "Tag all"))) + (notmuch-tag notmuch-search-query-string tag-changes)) (defun notmuch-search-buffer-title (query) "Returns the title for a buffer with notmuch search results." @@ -874,16 +920,17 @@ PROMPT is the string to prompt with." 'notmuch-search-history nil nil))))) ;;;###autoload +(put 'notmuch-search 'notmuch-doc "Search for messages.") (defun notmuch-search (&optional query oldest-first target-thread target-line) - "Run \"notmuch search\" with the given `query' and display results. + "Display threads matching QUERY in a notmuch-search buffer. -If `query' is nil, it is read interactively from the minibuffer. +If QUERY is nil, it is read interactively from the minibuffer. Other optional parameters are used as follows: - oldest-first: A Boolean controlling the sort order of returned threads - target-thread: A thread ID (without the thread: prefix) that will be made + OLDEST-FIRST: A Boolean controlling the sort order of returned threads + TARGET-THREAD: A thread ID (without the thread: prefix) that will be made current if it appears in the search results. - target-line: The line number to move to if the target thread does not + TARGET-LINE: The line number to move to if the target thread does not appear in the search results. When called interactively, this will prompt for a query and use @@ -894,7 +941,7 @@ the configured default sort order." nil ;; Use the default search order (if we're doing a search from a ;; search buffer, ignore any buffer-local overrides) - (default-value notmuch-search-oldest-first))) + (default-value 'notmuch-search-oldest-first))) (let* ((query (or query (notmuch-read-query "Notmuch search: "))) (buffer (get-buffer-create (notmuch-search-buffer-title query))))