X-Git-Url: https://git.notmuchmail.org/git?p=notmuch;a=blobdiff_plain;f=emacs%2Fnotmuch.el;h=57b7fcf40e0bf790131a2871316fcebdba17adc8;hp=517c53a5d3784a5c2d8362f319b2e436ac640d19;hb=38c595738f229eda659853df34dee05cf618556c;hpb=fec5622add1a4e9f305c16e96143439ee22a5c58 diff --git a/emacs/notmuch.el b/emacs/notmuch.el index 517c53a5..57b7fcf4 100644 --- a/emacs/notmuch.el +++ b/emacs/notmuch.el @@ -54,6 +54,25 @@ (require 'notmuch-lib) (require 'notmuch-show) +(defcustom notmuch-search-authors-width 20 + "Number of columns to use to display authors in a notmuch-search buffer." + :type 'integer + :group 'notmuch) + +(defcustom notmuch-search-result-format + `(("date" . "%s ") + ("count" . "%-7s ") + ("authors" . ,(format "%%-%ds " notmuch-search-authors-width)) + ("subject" . "%s ") + ("tags" . "(%s)")) + "Search result formating. Supported fields are: + date, count, authors, subject, tags +For example: + (setq notmuch-search-result-format \(\(\"authors\" . \"%-40s\"\) + \(\"subject\" . \"%s\"\)\)\)" + :type '(alist :key-type (string) :value-type (string)) + :group 'notmuch) + (defun notmuch-select-tag-with-completion (prompt &rest search-terms) (let ((tag-list (with-output-to-string @@ -108,58 +127,6 @@ (forward-line))) (message-mode)) -(defun notmuch-toggle-invisible-action (cite-button) - (let ((invis-spec (button-get cite-button 'invisibility-spec))) - (if (invisible-p invis-spec) - (remove-from-invisibility-spec invis-spec) - (add-to-invisibility-spec invis-spec) - )) - (force-window-update) - (redisplay t)) - -(define-button-type 'notmuch-button-citation-toggle-type 'help-echo "mouse-1, RET: Show citation" - :supertype 'notmuch-button-invisibility-toggle-type) -(define-button-type 'notmuch-button-signature-toggle-type 'help-echo "mouse-1, RET: Show signature" - :supertype 'notmuch-button-invisibility-toggle-type) -(define-button-type 'notmuch-button-body-toggle-type - 'help-echo "mouse-1, RET: Show message" - 'face 'notmuch-message-summary-face - :supertype 'notmuch-button-invisibility-toggle-type) - -(defun notmuch-fontify-headers () - (while (looking-at "[[:space:]]") - (forward-char)) - (if (looking-at "[Tt]o:") - (progn - (overlay-put (make-overlay (point) (re-search-forward ":")) - 'face 'message-header-name) - (overlay-put (make-overlay (point) (re-search-forward ".*$")) - 'face 'message-header-to)) - (if (looking-at "[B]?[Cc][Cc]:") - (progn - (overlay-put (make-overlay (point) (re-search-forward ":")) - 'face 'message-header-name) - (overlay-put (make-overlay (point) (re-search-forward ".*$")) - 'face 'message-header-cc)) - (if (looking-at "[Ss]ubject:") - (progn - (overlay-put (make-overlay (point) (re-search-forward ":")) - 'face 'message-header-name) - (overlay-put (make-overlay (point) (re-search-forward ".*$")) - 'face 'message-header-subject)) - (if (looking-at "[Ff]rom:") - (progn - (overlay-put (make-overlay (point) (re-search-forward ":")) - 'face 'message-header-name) - (overlay-put (make-overlay (point) (re-search-forward ".*$")) - 'face 'message-header-other)) - (if (looking-at "[Dd]ate:") - (progn - (overlay-put (make-overlay (point) (re-search-forward ":")) - 'face 'message-header-name) - (overlay-put (make-overlay (point) (re-search-forward ".*$")) - 'face 'message-header-other)))))))) - (defun notmuch-documentation-first-line (symbol) "Return the first line of the documentation string for SYMBOL." (let ((doc (documentation symbol))) @@ -234,15 +201,12 @@ For a mouse binding, return nil." "Notmuch mail reader for Emacs." :group 'mail) -(defcustom notmuch-search-hook nil +(defcustom notmuch-search-hook '(hl-line-mode) "List of functions to call when notmuch displays the search results." :type 'hook :options '(hl-line-mode) :group 'notmuch) -(defvar notmuch-search-authors-width 20 - "Number of columns to use to display authors in a notmuch-search buffer.") - (defvar notmuch-search-mode-map (let ((map (make-sparse-keymap))) (define-key map "?" 'notmuch-help) @@ -268,7 +232,6 @@ For a mouse binding, return nil." (define-key map "-" 'notmuch-search-remove-tag) (define-key map "+" 'notmuch-search-add-tag) (define-key map (kbd "RET") 'notmuch-search-show-thread) - (define-key map "F" 'notmuch-folder) map) "Keymap for \"notmuch search\" buffers.") (fset 'notmuch-search-mode-map notmuch-search-mode-map) @@ -342,11 +305,6 @@ For a mouse binding, return nil." "Notmuch search mode face used to highligh tags." :group 'notmuch) -(defvar notmuch-tag-face-alist nil - "List containing the tag list that need to be highlighed") - -(defvar notmuch-search-font-lock-keywords nil) - ;;;###autoload (defun notmuch-search-mode () "Major mode displaying results of a notmuch search. @@ -384,25 +342,16 @@ Complete list of currently available key bindings: (setq truncate-lines t) (setq major-mode 'notmuch-search-mode mode-name "notmuch-search") - (setq buffer-read-only t) - (if (not notmuch-tag-face-alist) - (add-to-list 'notmuch-search-font-lock-keywords (list - "(\\([^()]*\\))$" '(1 'notmuch-tag-face))) - (let ((notmuch-search-tags (mapcar 'car notmuch-tag-face-alist))) - (loop for notmuch-search-tag in notmuch-search-tags - do (add-to-list 'notmuch-search-font-lock-keywords (list - (concat "([^)]*\\(" notmuch-search-tag "\\)[^)]*)$") - `(1 ,(cdr (assoc notmuch-search-tag notmuch-tag-face-alist)))))))) - (set (make-local-variable 'font-lock-defaults) - '(notmuch-search-font-lock-keywords t))) + (setq buffer-read-only t)) (defun notmuch-search-properties-in-region (property beg end) (save-excursion (let ((output nil) - (last-line (line-number-at-pos end))) + (last-line (line-number-at-pos end)) + (max-line (- (line-number-at-pos (point-max)) 2))) (goto-char beg) (beginning-of-line) - (while (<= (line-number-at-pos) last-line) + (while (<= (line-number-at-pos) (min last-line max-line)) (setq output (cons (get-text-property (point) property) output)) (forward-line 1)) output))) @@ -435,18 +384,19 @@ Complete list of currently available key bindings: "Display the currently selected thread." (interactive) (let ((thread-id (notmuch-search-find-thread-id)) - (subject (notmuch-search-find-subject)) - buffer-name) - (when (string-match "^[ \t]*$" subject) - (setq subject "[No Subject]")) - (setq buffer-name (concat "*" - (truncate-string-to-width subject 32 nil nil t) - "*")) + (subject (notmuch-search-find-subject))) (if (> (length thread-id) 0) (notmuch-show thread-id (current-buffer) notmuch-search-query-string - buffer-name) + ;; name the buffer based on notmuch-search-find-subject + (if (string-match "^[ \t]*$" subject) + "[No Subject]" + (truncate-string-to-width + (concat "*" + (truncate-string-to-width subject 32 nil nil t) + "*") + 32 nil nil t))) (error "End of search results")))) (defun notmuch-search-reply-to-thread () @@ -483,7 +433,8 @@ and will also appear in a buffer named \"*Notmuch errors*\"." (backward-char) (let ((end (point))) (delete-region beg end) - (insert (mapconcat 'identity tags " ")))))) + (insert (propertize (mapconcat 'identity tags " ") + 'font-lock-face 'notmuch-tag-face)))))) (defun notmuch-search-get-tags () (save-excursion @@ -497,38 +448,39 @@ and will also appear in a buffer named \"*Notmuch errors*\"." (defun notmuch-search-get-tags-region (beg end) (save-excursion (let ((output nil) - (last-line (line-number-at-pos end))) + (last-line (line-number-at-pos end)) + (max-line (- (line-number-at-pos (point-max)) 2))) (goto-char beg) - (while (<= (line-number-at-pos) last-line) + (while (<= (line-number-at-pos) (min last-line max-line)) (setq output (append output (notmuch-search-get-tags))) (forward-line 1)) output))) (defun notmuch-search-add-tag-thread (tag) - (notmuch-call-notmuch-process "tag" (concat "+" tag) (notmuch-search-find-thread-id)) - (notmuch-search-set-tags (delete-dups (sort (cons tag (notmuch-search-get-tags)) 'string<)))) + (notmuch-search-add-tag-region tag (point) (point))) (defun notmuch-search-add-tag-region (tag beg end) (let ((search-id-string (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or "))) (notmuch-call-notmuch-process "tag" (concat "+" tag) search-id-string) (save-excursion - (let ((last-line (line-number-at-pos end))) + (let ((last-line (line-number-at-pos end)) + (max-line (- (line-number-at-pos (point-max)) 2))) (goto-char beg) - (while (<= (line-number-at-pos) last-line) + (while (<= (line-number-at-pos) (min last-line max-line)) (notmuch-search-set-tags (delete-dups (sort (cons tag (notmuch-search-get-tags)) 'string<))) (forward-line)))))) (defun notmuch-search-remove-tag-thread (tag) - (notmuch-call-notmuch-process "tag" (concat "-" tag) (notmuch-search-find-thread-id)) - (notmuch-search-set-tags (delete tag (notmuch-search-get-tags)))) + (notmuch-search-remove-tag-region tag (point) (point))) (defun notmuch-search-remove-tag-region (tag beg end) (let ((search-id-string (mapconcat 'identity (notmuch-search-find-thread-id-region beg end) " or "))) (notmuch-call-notmuch-process "tag" (concat "-" tag) search-id-string) (save-excursion - (let ((last-line (line-number-at-pos end))) + (let ((last-line (line-number-at-pos end)) + (max-line (- (line-number-at-pos (point-max)) 2))) (goto-char beg) - (while (<= (line-number-at-pos) last-line) + (while (<= (line-number-at-pos) (min last-line max-line)) (notmuch-search-set-tags (delete tag (notmuch-search-get-tags))) (forward-line)))))) @@ -631,6 +583,26 @@ matching will be applied." (t (setq tags-faces (cdr tags-faces))))))))) +(defun notmuch-search-insert-field (field date count authors subject tags) + (cond + ((string-equal field "date") + (insert (format (cdr (assoc field notmuch-search-result-format)) date))) + ((string-equal field "count") + (insert (format (cdr (assoc field notmuch-search-result-format)) count))) + ((string-equal field "authors") + (insert (format (cdr (assoc field notmuch-search-result-format)) authors))) + ((string-equal field "subject") + (insert (format (cdr (assoc field notmuch-search-result-format)) subject))) + ((string-equal field "tags") + (insert (concat "(" (propertize tags 'font-lock-face 'notmuch-tag-face) ")"))))) + +(defun notmuch-search-show-result (date count authors subject tags) + (let ((fields) (field)) + (setq fields (mapcar 'car notmuch-search-result-format)) + (loop for field in fields + do (notmuch-search-insert-field field date count authors subject tags))) + (insert "\n")) + (defun notmuch-search-process-filter (proc string) "Process and filter the output of \"notmuch search\"" (let ((buffer (process-buffer proc)) @@ -654,9 +626,8 @@ matching will be applied." (if (> authors-length notmuch-search-authors-width) (set 'authors (concat (substring authors 0 (- notmuch-search-authors-width 3)) "..."))) (goto-char (point-max)) - (let ((beg (point-marker)) - (format-string (format "%%s %%-7s %%-%ds %%s (%%s)\n" notmuch-search-authors-width))) - (insert (format format-string date count authors subject tags)) + (let ((beg (point-marker))) + (notmuch-search-show-result date count authors subject tags) (notmuch-search-color-line beg (point-marker) tag-list) (put-text-property beg (point-marker) 'notmuch-search-thread-id thread-id) (put-text-property beg (point-marker) 'notmuch-search-authors authors) @@ -694,6 +665,32 @@ characters as well as `_.+-'. (apply 'notmuch-call-notmuch-process "tag" (append action-split (list notmuch-search-query-string) nil)))) +(defcustom notmuch-folders (quote (("inbox" . "tag:inbox") ("unread" . "tag:unread"))) + "List of searches for the notmuch folder view" + :type '(alist :key-type (string) :value-type (string)) + :group 'notmuch) + +(defun notmuch-search-buffer-title (query) + "Returns the title for a buffer with notmuch search results." + (let* ((folder (rassoc-if (lambda (key) + (string-match (concat "^" (regexp-quote key)) + query)) + notmuch-folders)) + (folder-name (car folder)) + (folder-query (cdr folder))) + (cond ((and folder (equal folder-query query)) + ;; Query is the same as folder search (ignoring case) + (concat "*notmuch-folder-" folder-name "*")) + (folder + (concat "*notmuch-search-" + (replace-regexp-in-string (concat "^" (regexp-quote folder-query)) + (concat "[ " folder-name " ]") + query) + "*")) + (t + (concat "*notmuch-search-" query "*")) + ))) + ;;;###autoload (defun notmuch-search (query &optional oldest-first target-thread target-line) "Run \"notmuch search\" with the given query string and display results. @@ -706,7 +703,7 @@ The optional parameters are used as follows: target-line: The line number to move to if the target thread does not appear in the search results." (interactive "sNotmuch search: ") - (let ((buffer (get-buffer-create (concat "*notmuch-search-" query "*")))) + (let ((buffer (get-buffer-create (notmuch-search-buffer-title query)))) (switch-to-buffer buffer) (notmuch-search-mode) (set 'notmuch-search-query-string query) @@ -771,8 +768,12 @@ search." Runs a new search matching only messages that match both the current search results AND the additional query string provided." (interactive "sFilter search: ") - (let ((grouped-query (if (string-match-p notmuch-search-disjunctive-regexp query) (concat "( " query " )") query))) - (notmuch-search (concat notmuch-search-query-string " and " grouped-query) notmuch-search-oldest-first))) + (let ((grouped-query (if (string-match-p notmuch-search-disjunctive-regexp query) + (concat "( " query " )") + query))) + (notmuch-search (if (string= notmuch-search-query-string "*") + grouped-query + (concat notmuch-search-query-string " and " grouped-query)) notmuch-search-oldest-first))) (defun notmuch-search-filter-by-tag (tag) "Filter the current search results based on a single tag. @@ -812,11 +813,6 @@ current search results AND that are tagged with the given tag." (fset 'notmuch-folder-mode-map notmuch-folder-mode-map) -(defcustom notmuch-folders (quote (("inbox" . "tag:inbox") ("unread" . "tag:unread"))) - "List of searches for the notmuch folder view" - :type '(alist :key-type (string) :value-type (string)) - :group 'notmuch) - (defun notmuch-folder-mode () "Major mode for showing notmuch 'folders'.