;;; Commentary:
-;;; This is a simple derivative of some functionality from
-;;; `longlines.el'. The key difference is that this version will
-;;; insert a prefix at the head of each wrapped line. The prefix is
-;;; calculated from the originating long line.
+;; This is a simple derivative of some functionality from
+;; `longlines.el'. The key difference is that this version will
+;; insert a prefix at the head of each wrapped line. The prefix is
+;; calculated from the originating long line.
-;;; No minor-mode is provided, the caller is expected to call
-;;; `coolj-wrap-region' to wrap the region of interest.
+;; No minor-mode is provided, the caller is expected to call
+;; `coolj-wrap-region' to wrap the region of interest.
;;; Code:
(require 'notmuch-parser)
(require 'notmuch-lib)
(require 'notmuch-company)
-;;
+
(declare-function company-manual-begin "company")
+;;; Cache internals
+
(defvar notmuch-address-last-harvest 0
"Time of last address harvest.")
(or notmuch-address-full-harvest-finished
(notmuch-address--load-address-hash)))
+;;; Options
+
(defcustom notmuch-address-command 'internal
"Determines how address completion candidates are generated.
:group 'notmuch-address
:group 'notmuch-hooks)
+(defcustom notmuch-address-use-company t
+ "If available, use company mode for address completion."
+ :type 'boolean
+ :group 'notmuch-send
+ :group 'notmuch-address)
+
+;;; Setup
+
(defun notmuch-address-selection-function (prompt collection initial-input)
"Call (`completing-read'
PROMPT COLLECTION nil nil INITIAL-INPUT 'notmuch-address-history)"
(defun notmuch-address-message-insinuate ()
(message "calling notmuch-address-message-insinuate is no longer needed"))
-(defcustom notmuch-address-use-company t
- "If available, use company mode for address completion."
- :type 'boolean
- :group 'notmuch-send
- :group 'notmuch-address)
-
(defun notmuch-address-setup ()
(let* ((setup-company (and notmuch-address-use-company
(require 'company nil t)))
(kill-local-variable 'company-idle-delay)
(setq-local company-idle-delay nil))))
+;;; Completion
+
(defun notmuch-address-matching (substring)
"Returns a list of completion candidates matching SUBSTRING.
The candidates are taken from `notmuch-address-completions'."
(ding))))
(t nil)))
+;;; Harvest
+
(defun notmuch-address-harvest-addr (result)
(let ((name-addr (plist-get result :name-addr)))
(puthash name-addr t notmuch-address-completions)))
(setq notmuch-address-full-harvest-finished t))
(setq notmuch-address-last-harvest 0)))))))
-;;
+;;; Standalone completion
(defun notmuch-address-from-minibuffer (prompt)
(if (not notmuch-address-command)
(let ((minibuffer-local-map rmap))
(read-string prompt)))))
-;;
+;;; _
(provide 'notmuch-address)
(run-hook-with-args 'notmuch-address-post-completion-functions arg))
(no-cache t))))
-
(provide 'notmuch-company)
;;; notmuch-company.el ends here
(unless (fboundp 'message--fold-long-headers)
(add-hook 'message-header-hook 'notmuch-message--fold-long-headers))
-;; End of compatibility functions
-
(provide 'notmuch-compat)
;;; notmuch-compat.el ends here
(declare-function notmuch-show-get-message-id "notmuch-show" (&optional bare))
+;;; Options
+
(defcustom notmuch-crypto-process-mime t
"Whether to process cryptographic MIME parts.
:type 'string
:group 'notmuch-crypto)
+;;; Faces
+
(defface notmuch-crypto-part-header
'((((class color)
(background dark))
:group 'notmuch-crypto
:group 'notmuch-faces)
+;;; Functions
+
(define-button-type 'notmuch-crypto-status-button-type
'action (lambda (button) (message (button-get button 'help-echo)))
'follow-link t
'mouse-face 'notmuch-crypto-decryption)
(insert "\n"))
-;;
+;;; _
(provide 'notmuch-crypto)
(declare-function notmuch-show-get-message-id "notmuch-show" (&optional bare))
(declare-function notmuch-message-mode "notmuch-mua")
+;;; Options
+
(defgroup notmuch-draft nil
"Saving and editing drafts in Notmuch."
:group 'notmuch)
:group 'notmuch-draft
:group 'notmuch-crypto)
+;;; Internal
+
(defvar notmuch-draft-encryption-tag-regex
"<#\\(part encrypt\\|secure.*mode=.*encrypt>\\)"
"Regular expression matching mml tags indicating encryption of part or message.")
;; but notmuch doesn't want that form, so remove them.
(concat "draft-" (substring (message-make-message-id) 1 -1)))
+;;; Commands
+
(defun notmuch-draft-save ()
"Save the current draft message in the notmuch database.
(defun notmuch-draft-resume (id)
"Resume editing of message with id ID."
+ ;; Used by command `notmuch-show-resume-message'.
(let* ((tags (process-lines notmuch-command "search" "--output=tags"
"--exclude=false" id))
(draft (equal tags (notmuch-update-tags tags notmuch-draft-tags))))
;; message is resaved or sent.
(setq notmuch-draft-id (and draft id)))))
+;;; _
(add-hook 'message-send-hook 'notmuch-draft--mark-deleted)
-
(provide 'notmuch-draft)
;;; notmuch-draft.el ends here
(&optional query query-context target buffer-name open-target))
+;;; Options
+
(defun notmuch-saved-search-get (saved-search field)
"Get FIELD from SAVED-SEARCH.
(defvar notmuch-hello-indent 4
"How much to indent non-headers.")
+(defimage notmuch-hello-logo ((:type png :file "notmuch-logo.png")))
+
(defcustom notmuch-show-logo t
"Should the notmuch logo be shown?"
:type 'boolean
:group 'notmuch-hello
:type 'boolean)
+;;; Internal variables
+
(defvar notmuch-hello-hidden-sections nil
"List of sections titles whose contents are hidden.")
(defvar notmuch-hello-first-run t
"True if `notmuch-hello' is run for the first time, set to nil afterwards.")
-(defun notmuch-hello-nice-number (n)
- (let (result)
- (while (> n 0)
- (push (% n 1000) result)
- (setq n (/ n 1000)))
- (setq result (or result '(0)))
- (apply #'concat
- (number-to-string (car result))
- (mapcar (lambda (elem)
- (format "%s%03d" notmuch-hello-thousands-separator elem))
- (cdr result)))))
+;;; Widgets for inserters
(define-widget 'notmuch-search-item 'item
"A recent search."
1 ; for the space before the [del] button
5))) ; for the [del] button
+;;; Widget actions
+
(defun notmuch-hello-search (widget &rest _event)
(let ((search (widget-value widget)))
(when search
(delete search notmuch-search-history)))
(notmuch-hello-update)))
+;;; Button utilities
+
+;; `notmuch-hello-query-counts', `notmuch-hello-nice-number' and
+;; `notmuch-hello-insert-buttons' are used outside this section.
+;; All other functions that are defined in this section are only
+;; used by these two functions.
+
(defun notmuch-hello-longest-label (searches-alist)
(or (cl-loop for elem in searches-alist
maximize (length (notmuch-saved-search-get elem :name)))
(list (plist-put elem-plist :count message-count)))))
query-list)))
+(defun notmuch-hello-nice-number (n)
+ (let (result)
+ (while (> n 0)
+ (push (% n 1000) result)
+ (setq n (/ n 1000)))
+ (setq result (or result '(0)))
+ (apply #'concat
+ (number-to-string (car result))
+ (mapcar (lambda (elem)
+ (format "%s%03d" notmuch-hello-thousands-separator elem))
+ (cdr result)))))
+
(defun notmuch-hello-insert-buttons (searches)
"Insert buttons for SEARCHES.
(unless (eq (% count tags-per-line) 0)
(widget-insert "\n"))))
-(defimage notmuch-hello-logo ((:type png :file "notmuch-logo.png")))
+;;; Mode
(defun notmuch-hello-update ()
"Update the notmuch-hello buffer."
;;(setq buffer-read-only t)
)
+;;; Inserters
+
(defun notmuch-hello-generate-tag-alist (&optional hide-tags)
"Return an alist from tags to queries to display in the all-tags section."
(cl-mapcan (lambda (tag)
(let ((fill-column (- (window-width) notmuch-hello-indent)))
(center-region start (point)))))
+;;; Hello!
+
;;;###autoload
(defun notmuch-hello (&optional no-display)
"Run notmuch and display saved searches, known tags, etc."
(run-hooks 'notmuch-hello-refresh-hook)
(setq notmuch-hello-first-run nil))
-;;
+;;; _
(provide 'notmuch-hello)
(exit-minibuffer)))))))
map))
-;;
-
(provide 'notmuch-jump)
;;; notmuch-jump.el ends here
(defconst notmuch-emacs-version "unknown"
"Placeholder variable when notmuch-version.el[c] is not available."))
+;;; Groups
+
(defgroup notmuch nil
"Notmuch mail reader for Emacs."
:group 'mail)
"Graphical attributes for displaying text"
:group 'notmuch)
+;;; Options
+
(defcustom notmuch-command "notmuch"
"Name of the notmuch binary.
(string :tag "Custom script"))
:group 'notmuch-external)
-;;
-
-(defvar notmuch-search-history nil
- "Variable to store notmuch searches history.")
-
(defcustom notmuch-archive-tags '("-inbox")
"List of tag changes to apply to a message or a thread when it is archived.
:group 'notmuch-search
:group 'notmuch-show)
+;;; Variables
+
+(defvar notmuch-search-history nil
+ "Variable to store notmuch searches history.")
+
(defvar notmuch-common-keymap
(let ((map (make-sparse-keymap)))
(define-key map "?" 'notmuch-help)
(select-window (posn-window (event-start last-input-event)))
(button-activate button)))
+;;; CLI Utilities
+
(defun notmuch-command-to-string (&rest args)
"Synchronously invoke \"notmuch\" with the given list of arguments.
(concat cli-version
" (emacs mua version " notmuch-emacs-version ")")))))
+;;; Notmuch Configuration
+
(defun notmuch-config-get (item)
"Return a value from the notmuch configuration."
(let* ((val (notmuch-command-to-string "config" "get" item))
(defun notmuch-user-emails ()
(cons (notmuch-user-primary-email) (notmuch-user-other-email)))
+;;; Commands
+
(defun notmuch-poll ()
"Run \"notmuch new\" or an external script to import mail.
(bury-buffer)
(kill-buffer)))
+;;; Describe Key Bindings
+
(defun notmuch-prefix-key-description (key)
"Given a prefix key code, return a human-readable string representation.
"M-"
(concat desc " "))))
-
(defun notmuch-describe-key (actual-key binding prefix ua-keys tail)
"Prepend cons cells describing prefix-arg ACTUAL-KEY and ACTUAL-KEY to TAIL.
(insert desc)))
(pop-to-buffer (help-buffer)))))
+;;; Refreshing Buffers
+
(defvar-local notmuch-buffer-refresh-function nil
"Function to call to refresh the current buffer.")
(with-current-buffer buffer
(notmuch-refresh-this-buffer))))))
+;;; String Utilities
+
(defun notmuch-prettify-subject (subject)
;; This function is used by `notmuch-search-process-filter' which
;; requires that we not disrupt its' matching state.
(replace-regexp-in-string
"[ %\"]" (lambda (match) (format "%%%02x" (aref match 0))) str))
-;;
-
(defun notmuch-common-do-stash (text)
"Common function to stash text in kill ring, and display in minibuffer."
(if text
(kill-new "")
(message "Nothing to stash!")))
-;;
+;;; Generic Utilities
(defun notmuch-plist-delete (plist property)
(let* ((xplist (cons nil plist))
(setq pred (cddr pred)))
(cdr xplist)))
+;;; MML Utilities
+
(defun notmuch-match-content-type (t1 t2)
"Return t if t1 and t2 are matching content types, taking wildcards into account."
(let ((st1 (split-string t1 "/"))
(mm-display-part handle)
t))))))
+;;; Generic Utilities
+
;; Converts a plist of headers to an alist of headers. The input plist should
;; have symbols of the form :Header as keys, and the resulting alist will have
;; symbols of the form 'Header as keys.
(put-text-property start next prop (funcall func value) object)
(setq start next))))
+;;; Running Notmuch
+
(defun notmuch-logged-error (msg &optional extra)
"Log MSG and EXTRA to *Notmuch errors* and signal MSG.
(defvar-local notmuch-show-process-crypto nil)
+;;; Generic Utilities
+
(defun notmuch-interactive-region ()
"Return the bounds of the current interactive region.
'notmuch-interactive-region
"notmuch 0.29")
+;;; _
+
(provide 'notmuch-lib)
;;; notmuch-lib.el ends here
(defvar notmuch-maildir-fcc-count 0)
+;;; Options
+
(defcustom notmuch-fcc-dirs "sent"
"Determines the Fcc Header which says where to save outgoing mail.
(const :tag "Use simple fcc" nil))
:group 'notmuch-send)
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Functions which set up the fcc header in the message buffer.
+;;; Functions which set up the fcc header in the message buffer.
(defun notmuch-fcc-header-setup ()
"Add an Fcc header to the current message buffer.
subdir
(concat (notmuch-database-path) "/" subdir))))))
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Functions for saving a message either using notmuch insert or file
-;; fcc. First functions common to the two cases.
+;;; Functions for saving a message using either method.
(defmacro with-temporary-notmuch-message-buffer (&rest body)
"Set-up a temporary copy of the current message-mode buffer."
(notmuch-maildir-fcc-with-notmuch-insert fcc-header)
(notmuch-maildir-fcc-file-fcc fcc-header)))
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Functions for saving a message using notmuch insert.
+;;; Functions for saving a message using notmuch insert.
(defun notmuch-maildir-notmuch-insert-current-buffer (folder &optional create tags)
"Use notmuch insert to put the current buffer in the database.
(?e (notmuch-maildir-fcc-with-notmuch-insert
(read-from-minibuffer "Fcc header: " fcc-header)))))))))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Functions for saving a message using file fcc.
+;;; Functions for saving a message using file fcc.
(defun notmuch-maildir-fcc-host-fixer (hostname)
(replace-regexp-in-string "/\\|:"
(delete-file (concat destdir "/tmp/" msg-id))))
t)))
+;;; _
+
(provide 'notmuch-maildir-fcc)
;;; notmuch-maildir-fcc.el ends here
(declare-function notmuch-draft-postpone "notmuch-draft" ())
(declare-function notmuch-draft-save "notmuch-draft" ())
-;;
+;;; Options
(defcustom notmuch-mua-send-hook nil
"Hook run before sending messages."
:type 'regexp
:group 'notmuch-send)
-;;
+;;; Various functions
(defun notmuch-mua-attachment-check ()
"Signal an error if the message text indicates that an
(funcall original-func header references)
(unless (bolp) (insert "\n")))
+;;; Mua reply
+
(defun notmuch-mua-reply (query-string &optional sender reply-all)
(let ((args '("reply" "--format=sexp" "--format-version=4"))
(process-crypto notmuch-show-process-crypto)
(message-goto-body)
(set-buffer-modified-p nil))
+;;; Mode and keymap
+
(defvar notmuch-message-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "C-c C-c") #'notmuch-mua-send-and-exit)
(put 'notmuch-message-mode 'flyspell-mode-predicate 'mail-mode-flyspell-verify)
+;;; New messages
+
(defun notmuch-mua-pop-to-buffer (name switch-function)
"Pop to buffer NAME, and warn if it already exists and is modified.
Like `message-pop-to-buffer' but enable `notmuch-message-mode'
(notmuch-mua-reply query-string sender reply-all)
(deactivate-mark)))
+;;; Checks
+
(defun notmuch-mua-check-no-misplaced-secure-tag ()
"Query user if there is a misplaced secure mml tag.
newline. It is likely that the message will be sent unsigned and
unencrypted. Really send? "))))
+;;; Finishing commands
+
(defun notmuch-mua-send-common (arg &optional exit)
(interactive "P")
(run-hooks 'notmuch-mua-send-hook)
(interactive)
(message-kill-buffer))
-;;
+;;; _
(define-mail-user-agent 'notmuch-user-agent
'notmuch-mua-mail 'notmuch-mua-send-and-exit
;; composing a message.
(notmuch-mua-add-more-hidden-headers)
-;;
-
(provide 'notmuch-mua)
;;; notmuch-mua.el ends here
(declare-function notmuch-show-get-prop "notmuch-show" (prop &optional props))
+;;; Options
+
(defcustom notmuch-print-mechanism 'notmuch-print-lpr
"How should printing be done?"
:group 'notmuch-show
(function :tag "Use muttprint then evince" notmuch-print-muttprint/evince)
(function :tag "Using a custom function")))
-;; Utility functions:
+;;; Utility functions
(defun notmuch-print-run-evince (file)
"View FILE using 'evince'."
"--printed-headers" "Date_To_From_CC_Newsgroups_*Subject*_/Tags/"
output))
-;; User-visible functions:
+;;; User-visible functions
(defun notmuch-print-lpr (msg)
"Print a message buffer using lpr."
(set-buffer-modified-p nil)
(funcall notmuch-print-mechanism msg))
+;;; _
+
(provide 'notmuch-print)
;;; notmuch-print.el ends here
(require 'notmuch-lib)
+;;; Basic query function
+
(defun notmuch-query-get-threads (search-terms)
"Return a list of threads of messages matching SEARCH-TERMS.
(setq args (append args search-terms))
(apply #'notmuch-call-notmuch-sexp args)))
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Mapping functions across collections of messages.
+;;; Mapping functions across collections of messages
(defun notmuch-query-map-aux (mapper function seq)
"Private function to do the actual mapping and flattening."
`notmuch-query-get-threads' for more information."
(cons (funcall fn (car tree)) (notmuch-query-map-forest fn (cadr tree))))
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Predefined queries
+;;; Predefined queries
(defun notmuch-query-get-message-ids (&rest search-terms)
"Return a list of message-ids of messages that match SEARCH-TERMS."
(declare-function notmuch-read-query "notmuch" (prompt))
(declare-function notmuch-draft-resume "notmuch-draft" (id))
+;;; Options
+
(defcustom notmuch-message-headers '("Subject" "To" "Cc" "Date")
"Headers that should be shown in a message, in this order.
:type '(choice (const nil) regexp)
:group 'notmuch-show)
+;;; Variables
+
(defvar-local notmuch-show-thread-id nil)
(defvar-local notmuch-show-parent-buffer nil)
each attachment handler is logged in buffers with names beginning
\" *notmuch-part*\".")
+;;; Options
+
(defcustom notmuch-show-stash-mlarchive-link-alist
'(("Gmane" . "https://mid.gmane.org/")
("MARC" . "https://marc.info/?i=")
:type 'boolean
:group 'notmuch-show)
+;;; Utilities
+
(defmacro with-current-notmuch-show-message (&rest body)
"Evaluate body with current buffer set to the text of current message."
`(save-excursion
"Enable Visual Line mode."
(visual-line-mode t))
+;;; Commands
+
;; DEPRECATED in Notmuch 0.16 since we now have convenient part
;; commands. We'll keep the command around for a version or two in
;; case people want to bind it themselves.
(interactive)
(notmuch-show-with-message-as-text 'notmuch-print-message))
+;;; Headers
+
(defun notmuch-show-fontify-header ()
(let ((face (cond
((looking-at "[Tt]o:")
(narrow-to-region start (point-max))
(run-hooks 'notmuch-show-markup-headers-hook)))))
+;;; Parts
+
(define-button-type 'notmuch-show-part-button-type
'action 'notmuch-show-part-button-default
'follow-link t
(overlay-put overlay 'invisible (not show))
t)))))))
-;; Part content ID handling
+;;; Part content ID handling
(defvar notmuch-show--cids nil
"Alist from raw content ID to (MSG PART).")
(gnus-blocked-images notmuch-show-text/html-blocked-images))
(notmuch-show-insert-part-*/* msg part content-type nth depth button))))
-;; These functions are used by notmuch-show--insert-part-text/html-shr
+;;; Functions used by notmuch-show--insert-part-text/html-shr
+
(declare-function libxml-parse-html-region "xml.c")
(declare-function shr-insert-document "shr")
(notmuch-mm-display-part-inline msg part content-type notmuch-show-process-crypto)
t)
-;; Functions for determining how to handle MIME parts.
+;;; Functions for determining how to handle MIME parts.
(defun notmuch-show-handlers-for (content-type)
"Return a list of content handlers for a part of type CONTENT-TYPE."
(intern (concat "notmuch-show-insert-part-" content-type))))
result))
-;; \f
+;;; Parts
(defun notmuch-show-insert-bodypart-internal (msg part content-type nth depth button)
;; Run the handlers until one of them succeeds.
(notmuch-show-message-visible msg (and (plist-get msg :match)
(not (plist-get msg :excluded))))))
+;;; Toggle commands
+
(defun notmuch-show-toggle-process-crypto ()
"Toggle the processing of cryptographic MIME parts."
(interactive)
"Content is not indented."))
(notmuch-show-refresh-view))
+;;; Main insert functions
+
(defun notmuch-show-insert-tree (tree depth)
"Insert the message tree TREE at depth DEPTH in the current thread."
(let ((msg (car tree))
"Insert the forest of threads FOREST."
(mapc (lambda (thread) (notmuch-show-insert-thread thread 0)) forest))
+;;; Link buttons
+
(defvar notmuch-id-regexp
(concat
;; Match the id: prefix only if it begins a word (to disallow, for
'help-echo "Mouse-1, RET: search for this message"
'face goto-address-mail-face)))))
+;;; Show command
+
;;;###autoload
(defun notmuch-show (thread-id &optional elide-toggle parent-buffer query-context buffer-name)
"Run \"notmuch show\" with the given thread ID and display results.
;; Report back to the caller whether any messages matched.
forest))
+;;; Refresh command
+
(defun notmuch-show-capture-state ()
"Capture the state of the current buffer.
(ding)
(message "Refreshing the buffer resulted in no messages!"))))
+;;; Keymaps
+
(defvar notmuch-show-stash-map
(let ((map (make-sparse-keymap)))
(define-key map "c" 'notmuch-show-stash-cc)
map)
"Keymap for \"notmuch show\" buffers.")
+;;; Mode
+
(define-derived-mode notmuch-show-mode fundamental-mode "notmuch-show"
"Major mode for viewing a thread with notmuch.
(setq imenu-extract-index-name-function
#'notmuch-show-imenu-extract-index-name-function))
+;;; Tree commands
+
(defun notmuch-tree-from-show-current-query ()
"Call notmuch tree with the current query."
(interactive)
notmuch-show-query-context
(notmuch-show-get-message-id)))
+;;; Movement related functions.
+
(defun notmuch-show-move-to-message-top ()
(goto-char (notmuch-show-message-top)))
(defun notmuch-show-move-to-message-bottom ()
(goto-char (notmuch-show-message-bottom)))
-(defun notmuch-show-message-adjust ()
- (recenter 0))
-
-;; Movement related functions.
-
;; There's some strangeness here where a text property applied to a
;; region a->b is not found when point is at b. We walk backwards
;; until finding the property.
(cl-loop do (funcall function)
while (notmuch-show-goto-message-next))))
-;; Functions relating to the visibility of messages and their
-;; components.
+;;; Functions relating to the visibility of messages and their components.
(defun notmuch-show-message-visible (props visible-p)
(overlay-put (plist-get props :message-overlay) 'invisible (not visible-p))
(overlay-put (plist-get props :headers-overlay) 'invisible (not visible-p))
(notmuch-show-set-prop :headers-visible visible-p props))
-;; Functions for setting and getting attributes of the current
-;; message.
+;;; Functions for setting and getting attributes of the current message.
(defun notmuch-show-set-message-properties (props)
(save-excursion
(notmuch-show-refresh-view t)
(notmuch-show-goto-message msg-id)))
-;; Functions for getting attributes of several messages in the current
-;; thread.
+;;; Functions for getting attributes of several messages in the current thread.
(defun notmuch-show-get-message-ids-for-open-messages ()
"Return a list of all id: queries for open messages in the current thread."
(setq done (not (notmuch-show-goto-message-next))))
message-ids)))
-;; Commands typically bound to keys.
+;;; Commands typically bound to keys.
(defun notmuch-show-advance ()
"Advance through thread.
(message-resend addresses)
(notmuch-bury-or-kill-this-buffer)))
+(defun notmuch-show-message-adjust ()
+ (recenter 0))
+
(defun notmuch-show-next-message (&optional pop-at-end)
"Show the next message.
(list (notmuch-show-get-message-id t)) "--in-reply-to="))))
" ")))
-;; Interactive part functions and their helpers
+;;; Interactive part functions and their helpers
(defun notmuch-show-generate-part-buffer (msg part)
"Return a temporary buffer containing the specified part's content."
(funcall fn (completing-read prompt urls nil nil nil nil (car urls)))
(message "No URLs found."))))
+;;; _
+
(provide 'notmuch-show)
;;; notmuch-show.el ends here
(declare-function notmuch-tree-tag "notmuch-tree" (tag-changes))
(declare-function notmuch-jump "notmuch-jump" (action-map prompt))
+;;; Keys
+
(define-widget 'notmuch-tag-key-type 'list
"A single key tagging binding."
:format "%v"
:type '(repeat notmuch-tag-key-type)
:group 'notmuch-tag)
+;;; Faces and Formats
+
(define-widget 'notmuch-tag-format-type 'lazy
"Customize widget for notmuch-tag-format and friends."
:type '(alist :key-type (regexp :tag "Tag")
:group 'notmuch-faces
:type 'notmuch-tag-format-type)
+;;; Icons
+
(defun notmuch-tag-format-image-data (tag data)
"Replace TAG with image DATA, if available.
</g>
</svg>")
+;;; Format Handling
+
(defvar notmuch-tag--format-cache (make-hash-table :test 'equal)
"Cache of tag format lookup. Internal to `notmuch-tag-format-tag'.")
face
t)))
+;;; Hooks
+
(defcustom notmuch-before-tag-hook nil
"Hooks that are run before tags of a message are modified.
:options '(notmuch-hl-line-mode)
:group 'notmuch-hooks)
+;;; User Input
+
(defvar notmuch-select-tag-history nil
"Variable to store minibuffer history for
`notmuch-select-tag-with-completion' function.")
nil nil initial-input
'notmuch-read-tag-changes-history))))
+;;; Tagging
+
(defun notmuch-update-tags (tags tag-changes)
"Return a copy of TAGS with additions and removals from TAG-CHANGES.
(setq action-map (nreverse action-map))
(notmuch-jump action-map "Tag: ")))
-;;
+;;; _
(provide 'notmuch-tag)
(defvar-local notmuch-tree-unthreaded nil
"A buffer local copy of argument unthreaded to the function notmuch-tree.")
+;;; Options
+
(defgroup notmuch-tree nil
"Showing message and thread structure."
:group 'notmuch)
notmuch-unthreaded-result-format
notmuch-tree-result-format))
-;; Faces for messages that match the query.
+;;; Faces
+;;;; Faces for messages that match the query
+
(defface notmuch-tree-match-face
'((t :inherit default))
"Default face used in tree mode face for matching messages"
:group 'notmuch-tree
:group 'notmuch-faces)
-;; Faces for messages that do not match the query.
+;;;; Faces for messages that do not match the query
+
(defface notmuch-tree-no-match-face
'((t (:foreground "gray")))
"Default face used in tree mode face for non-matching messages."
:group 'notmuch-tree
:group 'notmuch-faces)
+;;; Variables
+
(defvar-local notmuch-tree-previous-subject
"The subject of the most recent result shown during the async display.")
if the user has loaded a different buffer in that window.")
(put 'notmuch-tree-message-buffer 'permanent-local t)
+;;; Tree wrapper commands
+
(defmacro notmuch-tree--define-do-in-message-window (name cmd)
"Define NAME as a command that calls CMD interactively in the message window.
If the message pane is closed then this command does nothing.
notmuch-tree-view-raw-message
notmuch-show-view-raw-message)
+;;; Keymap
+
(defvar notmuch-tree-mode-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent map notmuch-common-keymap)
map)
"Keymap for \"notmuch tree\" buffers.")
+;;; Message properties
+
(defun notmuch-tree-get-message-properties ()
"Return the properties of the current message as a plist.
(interactive)
(notmuch-tree-get-prop :match))
+;;; Update display
+
(defun notmuch-tree-refresh-result ()
"Redisplay the current message line.
(when (string= tree-msg-id (notmuch-show-get-message-id))
(notmuch-show-update-tags new-tags)))))))
+;;; Commands (and some helper functions used by them)
+
(defun notmuch-tree-tag (tag-changes)
"Change tags for the current message."
(interactive
(notmuch-tree-tag-thread
(notmuch-tag-change-list notmuch-archive-tags unarchive))))
-;; Functions below here display the tree buffer itself.
+;;; Functions for displaying the tree buffer itself
(defun notmuch-tree-clean-address (address)
"Try to clean a single email ADDRESS for display. Return
(interactive)
(notmuch-tree query query-context target buffer-name open-target t))
-;;
+;;; _
(provide 'notmuch-tree)
(msg part depth &optional hide))
(defvar notmuch-show-indent-messages-width)
-;;
+;;; Options
(defgroup notmuch-wash nil
"Cleaning up messages for display."
(integer :tag "number of characters"))
:group 'notmuch-wash)
+;;; Faces
+
(defface notmuch-wash-toggle-button
'((t (:inherit font-lock-comment-face)))
"Face used for buttons toggling the visibility of washed away
:group 'notmuch-wash
:group 'notmuch-faces)
+;;; Buttons
+
(defun notmuch-wash-toggle-invisible-action (cite-button)
;; Toggle overlay visibility
(let ((overlay (button-get cite-button 'overlay)))
:type button-type)))
(overlay-put overlay 'notmuch-wash-button button))))))
+;;; Hook functions
+
(defun notmuch-wash-excerpt-citations (msg depth)
"Excerpt citations and up to one signature."
(goto-char (point-min))
msg sig-start-marker sig-end-marker
"signature"))))))
-;;
-
(defun notmuch-wash-elide-blank-lines (msg depth)
"Elide leading, trailing and successive blank lines."
;; Algorithm derived from `article-strip-multiple-blank-lines' in
(when (looking-at "\n")
(delete-region (match-beginning 0) (match-end 0))))
-;;
-
(defun notmuch-wash-tidy-citations (msg depth)
"Improve the display of cited regions of a message.
(while (re-search-forward "\\(^>[> ]*\n\\)\\(^$\\|^[^>].*\\)" nil t)
(replace-match "\\2")))
-;;
-
(defun notmuch-wash-wrap-long-lines (msg depth)
"Wrap long lines in the message.
2)))
(coolj-wrap-region (point-min) (point-max))))
-;;
+;;;; Convert Inline Patches
(require 'diff-mode)
(delete-region (point-min) (point-max))
(notmuch-show-insert-bodypart nil part depth)))))
-;;
+;;; _
(provide 'notmuch-wash)
(require 'notmuch-message)
(require 'notmuch-parser)
+;;; Options
+
(defcustom notmuch-search-result-format
`(("date" . "%12s ")
("count" . "%-7s ")
(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))
(mm-save-part p))))
mm-handle))
+;;; Integrations
+
(require 'hl-line)
(defun notmuch-hl-line-mode ()
(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
:group 'notmuch-search
:group 'notmuch-hooks)
+;;; Keymap
+
(defvar notmuch-search-mode-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent map notmuch-common-keymap)
map)
"Keymap for \"notmuch search\" buffers.")
+;;; Stashing
+
(defvar notmuch-search-stash-map
(let ((map (make-sparse-keymap)))
(define-key map "i" 'notmuch-search-stash-thread-id)
(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)
(interactive)
(goto-char (point-min)))
+;;; Faces
+
(defface notmuch-message-summary-face
`((((class color) (background light))
,@(and (>= emacs-major-version 27) '(:extend t))
: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.
(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).
(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)))
(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.
(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.
(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.
(author (notmuch-search-find-authors)))
(format "%s (%s)" subject author)))
+;;; _
+
(setq mail-user-agent 'notmuch-user-agent)
(provide 'notmuch)
-;; test-lib.el --- auxiliary stuff for Notmuch Emacs tests.
+;;; test-lib.el --- auxiliary stuff for Notmuch Emacs tests
;;
;; Copyright © Carl Worth
;; Copyright © David Edmondson
;;
;; Authors: Dmitry Kurochkin <dmitry.kurochkin@gmail.com>
+;;; Code:
+
(require 'cl-lib)
;; Ensure that the dynamic variables that are defined by this library