X-Git-Url: https://git.notmuchmail.org/git?a=blobdiff_plain;ds=sidebyside;f=emacs%2Fnotmuch.el;h=ba9488ca42d5b80f1e69a21843718274c063f96a;hb=fc4cda07a9afbbb545dcc6cd835ca697f6ef2a1b;hp=93e92b391fde9753ae6d15f4a869fc19f89fb995;hpb=09f6533c3781b61ea634790d4bad38aadf89115c;p=notmuch diff --git a/emacs/notmuch.el b/emacs/notmuch.el index 93e92b39..ba9488ca 100644 --- a/emacs/notmuch.el +++ b/emacs/notmuch.el @@ -1,4 +1,4 @@ -;;; notmuch.el --- run notmuch within emacs +;;; notmuch.el --- run notmuch within emacs -*- lexical-binding: t -*- ;; ;; Copyright © Carl Worth ;; @@ -18,7 +18,7 @@ ;; along with Notmuch. If not, see . ;; ;; Authors: Carl Worth -;; Homepage: https://notmuchmail.org/ +;; Homepage: https://notmuchmail.org ;;; Commentary: @@ -62,7 +62,7 @@ ;; ;; TL;DR: notmuch-emacs from MELPA and notmuch from distro packages is ;; NOT SUPPORTED. -;; + ;;; Code: (eval-when-compile (require 'cl-lib)) @@ -80,6 +80,8 @@ (require 'notmuch-message) (require 'notmuch-parser) +;;; Options + (defcustom notmuch-search-result-format `(("date" . "%12s ") ("count" . "%-7s ") @@ -115,6 +117,8 @@ there will be called at other points of notmuch execution." (defvar notmuch-query-history nil "Variable to store minibuffer history for notmuch queries.") +;;; Mime Utilities + (defun notmuch-foreach-mime-part (function mm-handle) (cond ((stringp (car mm-handle)) (dolist (part (cdr mm-handle)) @@ -151,6 +155,8 @@ there will be called at other points of notmuch execution." (mm-save-part p)))) mm-handle)) +;;; Integrations + (require 'hl-line) (defun notmuch-hl-line-mode () @@ -158,6 +164,8 @@ there will be called at other points of notmuch execution." (when hl-line-overlay (overlay-put hl-line-overlay 'priority 1)))) +;;; Options + (defcustom notmuch-search-hook '(notmuch-hl-line-mode) "List of functions to call when notmuch displays the search results." :type 'hook @@ -165,6 +173,8 @@ there will be called at other points of notmuch execution." :group 'notmuch-search :group 'notmuch-hooks) +;;; Keymap + (defvar notmuch-search-mode-map (let ((map (make-sparse-keymap))) (set-keymap-parent map notmuch-common-keymap) @@ -194,7 +204,8 @@ there will be called at other points of notmuch execution." (define-key map "U" 'notmuch-unthreaded-from-search-current-query) map) "Keymap for \"notmuch search\" buffers.") -(fset 'notmuch-search-mode-map notmuch-search-mode-map) + +;;; Stashing (defvar notmuch-search-stash-map (let ((map (make-sparse-keymap))) @@ -215,12 +226,16 @@ there will be called at other points of notmuch execution." (interactive) (notmuch-common-do-stash (notmuch-search-get-query))) +;;; Variables + (defvar notmuch-search-query-string) (defvar notmuch-search-target-thread) (defvar notmuch-search-target-line) (defvar notmuch-search-disjunctive-regexp "\\<[oO][rR]\\>") +;;; Movement + (defun notmuch-search-scroll-up () "Move forward through search results by one window's worth." (interactive) @@ -272,9 +287,15 @@ there will be called at other points of notmuch execution." (interactive) (goto-char (point-min))) +;;; Faces + (defface notmuch-message-summary-face - '((((class color) (background light)) (:background "#f0f0f0")) - (((class color) (background dark)) (:background "#303030"))) + `((((class color) (background light)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :background "#f0f0f0") + (((class color) (background dark)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :background "#303030")) "Face for the single-line message summary in notmuch-show-mode." :group 'notmuch-show :group 'notmuch-faces) @@ -339,7 +360,7 @@ there will be called at other points of notmuch execution." "Face used in search mode face for flagged threads. This face is the default value for the \"flagged\" tag in -`notmuch-search-line-faces`." +`notmuch-search-line-faces'." :group 'notmuch-search :group 'notmuch-faces) @@ -349,10 +370,12 @@ This face is the default value for the \"flagged\" tag in "Face used in search mode for unread threads. This face is the default value for the \"unread\" tag in -`notmuch-search-line-faces`." +`notmuch-search-line-faces'." :group 'notmuch-search :group 'notmuch-faces) +;;; Mode + (define-derived-mode notmuch-search-mode fundamental-mode "notmuch-search" "Major mode displaying results of a notmuch search. @@ -388,7 +411,7 @@ Complete list of currently available key bindings: (make-local-variable 'notmuch-search-target-thread) (make-local-variable 'notmuch-search-target-line) (setq notmuch-buffer-refresh-function #'notmuch-search-refresh-view) - (set (make-local-variable 'scroll-preserve-screen-position) t) + (setq-local scroll-preserve-screen-position t) (add-to-invisibility-spec (cons 'ellipsis t)) (setq truncate-lines t) (setq buffer-read-only t) @@ -397,6 +420,8 @@ Complete list of currently available key bindings: (setq imenu-extract-index-name-function #'notmuch-search-imenu-extract-index-name-function)) +;;; Search Results + (defun notmuch-search-get-result (&optional pos) "Return the result object for the thread at POS (or point). @@ -428,11 +453,10 @@ returns nil." (defun notmuch-search-foreach-result (beg end fn) "Invoke FN for each result between BEG and END. -FN should take one argument. It will be applied to the -character position of the beginning of each result that overlaps -the region between points BEG and END. As a special case, if (= -BEG END), FN will be applied to the result containing point -BEG." +FN should take one argument. It will be applied to the character +position of the beginning of each result that overlaps the region +between points BEG and END. As a special case, if (= BEG END), +FN will be applied to the result containing point BEG." (let ((pos (notmuch-search-result-beginning beg)) ;; End must be a marker in case fn changes the ;; text. @@ -542,7 +566,7 @@ thread." notmuch-search-query-string nil (notmuch-prettify-subject (notmuch-search-find-subject)) - t)) + t nil (current-buffer))) (defun notmuch-search-reply-to-thread (&optional prompt-for-sender) "Begin composing a reply-all to the entire current thread in a new buffer." @@ -556,6 +580,8 @@ thread." (let ((message-id (notmuch-search-find-thread-id))) (notmuch-mua-new-reply message-id prompt-for-sender nil))) +;;; Tags + (defun notmuch-search-set-tags (tags &optional pos) (let ((new-result (plist-put (notmuch-search-get-result pos) :tags tags))) (notmuch-search-update-result new-result pos))) @@ -637,6 +663,8 @@ This function advances the next thread when finished." (when (eq beg end) (notmuch-search-next-thread))) +;;; Search Results + (defun notmuch-search-update-result (result &optional pos) "Replace the result object of the thread at POS (or point) by RESULT and redraw it. @@ -674,28 +702,28 @@ of the result." (when (memq status '(exit signal)) (catch 'return (kill-buffer (process-get proc 'parse-buf)) - (if (buffer-live-p buffer) - (with-current-buffer buffer - (save-excursion - (let ((inhibit-read-only t) - (atbob (bobp))) - (goto-char (point-max)) - (if (eq status 'signal) - (insert "Incomplete search results (search process was killed).\n")) - (when (eq status 'exit) - (insert "End of search results.\n") - ;; For version mismatch, there's no point in - ;; showing the search buffer - (when (or (= exit-status 20) (= exit-status 21)) - (kill-buffer) - (throw 'return nil)) - (if (and atbob + (when (buffer-live-p buffer) + (with-current-buffer buffer + (save-excursion + (let ((inhibit-read-only t) + (atbob (bobp))) + (goto-char (point-max)) + (when (eq status 'signal) + (insert "Incomplete search results (search process was killed).\n")) + (when (eq status 'exit) + (insert "End of search results.\n") + ;; For version mismatch, there's no point in + ;; showing the search buffer + (when (or (= exit-status 20) (= exit-status 21)) + (kill-buffer) + (throw 'return nil)) + (when (and atbob (not (string= notmuch-search-target-thread "found"))) - (set 'never-found-target-thread t))))) - (when (and never-found-target-thread - notmuch-search-target-line) - (goto-char (point-min)) - (forward-line (1- notmuch-search-target-line))))))))) + (setq never-found-target-thread t))))) + (when (and never-found-target-thread + notmuch-search-target-line) + (goto-char (point-min)) + (forward-line (1- notmuch-search-target-line))))))))) (define-widget 'notmuch--custom-face-edit 'lazy "Custom face edit with a tag Edit Face" @@ -760,31 +788,31 @@ non-authors is found, assume that all of the authors match." (invisible-string "") (padding "")) ;; Truncate the author string to fit the specification. - (if (> (length formatted-authors) - (length formatted-sample)) - (let ((visible-length (- (length formatted-sample) - (length "... ")))) - ;; Truncate the visible string according to the width of - ;; the display string. - (setq visible-string (substring formatted-authors 0 visible-length)) - (setq invisible-string (substring formatted-authors visible-length)) - ;; If possible, truncate the visible string at a natural - ;; break (comma or pipe), as incremental search doesn't - ;; match across the visible/invisible border. - (when (string-match "\\(.*\\)\\([,|] \\)\\([^,|]*\\)" visible-string) - ;; Second clause is destructive on `visible-string', so - ;; order is important. - (setq invisible-string (concat (match-string 3 visible-string) - invisible-string)) - (setq visible-string (concat (match-string 1 visible-string) - (match-string 2 visible-string)))) - ;; `visible-string' may be shorter than the space allowed - ;; by `format-string'. If so we must insert some padding - ;; after `invisible-string'. - (setq padding (make-string (- (length formatted-sample) - (length visible-string) - (length "...")) - ? )))) + (when (> (length formatted-authors) + (length formatted-sample)) + (let ((visible-length (- (length formatted-sample) + (length "... ")))) + ;; Truncate the visible string according to the width of + ;; the display string. + (setq visible-string (substring formatted-authors 0 visible-length)) + (setq invisible-string (substring formatted-authors visible-length)) + ;; If possible, truncate the visible string at a natural + ;; break (comma or pipe), as incremental search doesn't + ;; match across the visible/invisible border. + (when (string-match "\\(.*\\)\\([,|] \\)\\([^,|]*\\)" visible-string) + ;; Second clause is destructive on `visible-string', so + ;; order is important. + (setq invisible-string (concat (match-string 3 visible-string) + invisible-string)) + (setq visible-string (concat (match-string 1 visible-string) + (match-string 2 visible-string)))) + ;; `visible-string' may be shorter than the space allowed + ;; by `format-string'. If so we must insert some padding + ;; after `invisible-string'. + (setq padding (make-string (- (length formatted-sample) + (length visible-string) + (length "...")) + ? )))) ;; Use different faces to show matching and non-matching authors. (if (string-match "\\(.*\\)|\\(.*\\)" visible-string) ;; The visible string contains both matching and @@ -879,6 +907,8 @@ sets the :orig-tag property." (notmuch-sexp-parse-partial-list 'notmuch-search-append-result results-buf))))) +;;; Commands (and some helper functions used by them) + (defun notmuch-search-tag-all (tag-changes) "Add/remove tags from all messages in current search buffer. @@ -991,23 +1021,19 @@ the configured default sort order." (buffer (get-buffer-create (notmuch-search-buffer-title query)))) (if no-display (set-buffer buffer) - (switch-to-buffer buffer)) - ;; avoid wiping out third party buffer-local variables in the case - ;; where we're just refreshing or changing the sort order of an - ;; existing search results buffer - (unless (eq major-mode 'notmuch-search-mode) - (notmuch-search-mode)) + (pop-to-buffer-same-window buffer)) + (notmuch-search-mode) ;; Don't track undo information for this buffer - (set 'buffer-undo-list t) - (set 'notmuch-search-query-string query) - (set 'notmuch-search-oldest-first oldest-first) - (set 'notmuch-search-target-thread target-thread) - (set 'notmuch-search-target-line target-line) + (setq buffer-undo-list t) + (setq notmuch-search-query-string query) + (setq notmuch-search-oldest-first oldest-first) + (setq notmuch-search-target-thread target-thread) + (setq notmuch-search-target-line target-line) (notmuch-tag-clear-cache) (let ((proc (get-buffer-process (current-buffer))) (inhibit-read-only t)) - (if proc - (error "notmuch search process already running for query `%s'" query)) + (when proc + (error "notmuch search process already running for query `%s'" query)) (erase-buffer) (goto-char (point-min)) (save-excursion @@ -1050,7 +1076,7 @@ same relative position within the new buffer." This command toggles the sort order for the current search. The default sort order is defined by `notmuch-search-oldest-first'." (interactive) - (set 'notmuch-search-oldest-first (not notmuch-search-oldest-first)) + (setq notmuch-search-oldest-first (not notmuch-search-oldest-first)) (notmuch-search-refresh-view)) (defun notmuch-group-disjunctive-query-string (query-string) @@ -1131,10 +1157,10 @@ notmuch buffers exist, run `notmuch'." ;; If the first one we found is any other than the starting ;; buffer, switch to it. (unless (eq first start) - (switch-to-buffer first)) + (pop-to-buffer-same-window first)) (notmuch)))) -;;;; Imenu Support +;;; Imenu Support (defun notmuch-search-imenu-prev-index-position-function () "Move point to previous message in notmuch-search buffer. @@ -1151,12 +1177,14 @@ beginning of the line." (author (notmuch-search-find-authors))) (format "%s (%s)" subject author))) +;;; _ + (setq mail-user-agent 'notmuch-user-agent) (provide 'notmuch) ;; After provide to avoid loops if notmuch was require'd via notmuch-init-file. -(if init-file-user ; don't load init file if the -q option was used. - (load notmuch-init-file t t nil t)) +(when init-file-user ; don't load init file if the -q option was used. + (load notmuch-init-file t t nil t)) ;;; notmuch.el ends here