emacs: make headings outline-minor-mode compatible

`outline-minor-mode' treats comments that begin with three or more
semicolons as headings.  That makes it very convenient to navigate
code and to show/hide parts of a file.

Elips libraries typically have four top-level sections, e.g.:

;;; notmuch.el --- run notmuch within emacs...
;;; Commentary:...
;;; Code:...
;;; notmuch.el ends here

In this package many libraries lack a "Commentary:" section, which is
not optimal but okay for most libraries, except major entry points.

Depending on how one chooses to look at it, the "... ends here" line
is not really a heading that begins a section, because it should never
have a "section" body (after all it marks eof).

If the file is rather short, then I left "Code:" as the only section
that contains code.  Otherwise I split the file into multiple sibling
sections.  The "Code:" section continues to contain `require' and
`declare-function' forms and other such "front matter".

If and only if I have split the code into multiple sections anyway,
then I also added an additional section named just "_" before the
`provide' form and shortly before the "...end here" line.  This
section could also be called "Back matter", but I feel it would be
distracting to be that explicit about it.  (The IMO unnecessary but
unfortunately still obligatory "... ends here" line is already
distracting enough as far as I am concerned.)

Before this commit some libraries already uses section headings, some
of them consistently.  When a library already had some headings, then
this commit often sticks to that style, even at the cost inconsistent
styling across all libraries.

A very limited number of variable and function definitions have to be
moved around because they would otherwise end up in sections they do
not belong into.

Sections, including but not limited to their heading, can and should
be further improved in the future.
This commit is contained in:
Jonas Bernoulli 2021-01-10 15:00:46 +01:00 committed by David Bremner
parent adc123e4fd
commit 2ca941163d
19 changed files with 263 additions and 98 deletions

View file

@ -25,13 +25,13 @@
;;; 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:

View file

@ -25,9 +25,11 @@
(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.")
@ -47,6 +49,8 @@ If the hash is not present it attempts to load a saved hash."
(or notmuch-address-full-harvest-finished
(notmuch-address--load-address-hash)))
;;; Options
(defcustom notmuch-address-command 'internal
"Determines how address completion candidates are generated.
@ -133,6 +137,14 @@ matching `notmuch-address-completion-headers-regexp'."
: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)"
@ -147,12 +159,6 @@ matching `notmuch-address-completion-headers-regexp'."
(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)))
@ -178,6 +184,8 @@ toggles the setting in this buffer."
(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'."
@ -250,6 +258,8 @@ requiring external commands."
(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)))
@ -406,7 +416,7 @@ appear to be an address savefile. Not overwriting."
(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)
@ -425,7 +435,7 @@ appear to be an address savefile. Not overwriting."
(let ((minibuffer-local-map rmap))
(read-string prompt)))))
;;
;;; _
(provide 'notmuch-address)

View file

@ -102,7 +102,6 @@
(run-hook-with-args 'notmuch-address-post-completion-functions arg))
(no-cache t))))
(provide 'notmuch-company)
;;; notmuch-company.el ends here

View file

@ -41,8 +41,6 @@
(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

View file

@ -26,6 +26,8 @@
(declare-function notmuch-show-get-message-id "notmuch-show" (&optional bare))
;;; Options
(defcustom notmuch-crypto-process-mime t
"Whether to process cryptographic MIME parts.
@ -55,6 +57,8 @@ mode."
:type 'string
:group 'notmuch-crypto)
;;; Faces
(defface notmuch-crypto-part-header
'((((class color)
(background dark))
@ -96,6 +100,8 @@ mode."
: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
@ -259,7 +265,7 @@ corresponding key when the status button is pressed."
'mouse-face 'notmuch-crypto-decryption)
(insert "\n"))
;;
;;; _
(provide 'notmuch-crypto)

View file

@ -31,6 +31,8 @@
(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)
@ -85,6 +87,8 @@ like they are intended to be sent encrypted
: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.")
@ -169,6 +173,8 @@ Really save and index an unencrypted copy? ")
;; 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.
@ -226,6 +232,7 @@ applied to newly inserted messages)."
(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))))
@ -265,10 +272,10 @@ applied to newly inserted messages)."
;; 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

View file

@ -37,6 +37,8 @@
(&optional query query-context target buffer-name open-target))
;;; Options
(defun notmuch-saved-search-get (saved-search field)
"Get FIELD from SAVED-SEARCH.
@ -192,6 +194,8 @@ fields of the 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
@ -367,23 +371,15 @@ supported for \"Customized queries section\" items."
: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."
@ -419,6 +415,8 @@ supported for \"Customized queries section\" items."
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
@ -451,6 +449,13 @@ supported for \"Customized queries section\" items."
(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)))
@ -585,6 +590,18 @@ the CLI and emacs interface."))
(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.
@ -639,7 +656,7 @@ with `notmuch-hello-query-counts'."
(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."
@ -723,6 +740,8 @@ Complete list of currently available key bindings:
;;(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)
@ -922,6 +941,8 @@ following:
(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."
@ -973,7 +994,7 @@ following:
(run-hooks 'notmuch-hello-refresh-hook)
(setq notmuch-hello-first-run nil))
;;
;;; _
(provide 'notmuch-hello)

View file

@ -198,8 +198,6 @@ buffer."
(exit-minibuffer)))))))
map))
;;
(provide 'notmuch-jump)
;;; notmuch-jump.el ends here

View file

@ -33,6 +33,8 @@
(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)
@ -78,6 +80,8 @@
"Graphical attributes for displaying text"
:group 'notmuch)
;;; Options
(defcustom notmuch-command "notmuch"
"Name of the notmuch binary.
@ -125,11 +129,6 @@ the user's needs:
(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.
@ -144,6 +143,11 @@ For example, if you wanted to remove an \"inbox\" tag and add an
: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)
@ -177,6 +181,8 @@ For example, if you wanted to remove an \"inbox\" tag and add an
(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.
@ -234,6 +240,8 @@ displays both values separately."
(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))
@ -263,6 +271,8 @@ displays both values separately."
(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.
@ -287,6 +297,8 @@ it, in which case it is killed."
(bury-buffer)
(kill-buffer)))
;;; Describe Key Bindings
(defun notmuch-prefix-key-description (key)
"Given a prefix key code, return a human-readable string representation.
@ -297,7 +309,6 @@ This is basically just `format-kbd-macro' but we also convert ESC to M-."
"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.
@ -435,6 +446,8 @@ of its command symbol."
(insert desc)))
(pop-to-buffer (help-buffer)))))
;;; Refreshing Buffers
(defvar-local notmuch-buffer-refresh-function nil
"Function to call to refresh the current buffer.")
@ -466,6 +479,8 @@ be displayed."
(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.
@ -509,8 +524,6 @@ This replaces spaces, percents, and double quotes in STR with
(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
@ -522,7 +535,7 @@ This replaces spaces, percents, and double quotes in STR with
(kill-new "")
(message "Nothing to stash!")))
;;
;;; Generic Utilities
(defun notmuch-plist-delete (plist property)
(let* ((xplist (cons nil plist))
@ -533,6 +546,8 @@ This replaces spaces, percents, and double quotes in STR with
(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 "/"))
@ -673,6 +688,8 @@ current buffer, if possible."
(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.
@ -739,6 +756,8 @@ returned by FUNC."
(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.
@ -967,6 +986,8 @@ status."
(defvar-local notmuch-show-process-crypto nil)
;;; Generic Utilities
(defun notmuch-interactive-region ()
"Return the bounds of the current interactive region.
@ -981,6 +1002,8 @@ region if the region is active, or both `point' otherwise."
'notmuch-interactive-region
"notmuch 0.29")
;;; _
(provide 'notmuch-lib)
;;; notmuch-lib.el ends here

View file

@ -29,6 +29,8 @@
(defvar notmuch-maildir-fcc-count 0)
;;; Options
(defcustom notmuch-fcc-dirs "sent"
"Determines the Fcc Header which says where to save outgoing mail.
@ -83,8 +85,7 @@ directory if it does not exist yet when sending a 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.
@ -142,9 +143,7 @@ Insert header anyway? " subdir)))
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."
@ -204,8 +203,7 @@ normal fcc."
(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.
@ -251,9 +249,7 @@ If CREATE is non-nil then create the folder if necessary."
(?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 "/\\|:"
@ -362,6 +358,8 @@ return t if successful, and nil otherwise."
(delete-file (concat destdir "/tmp/" msg-id))))
t)))
;;; _
(provide 'notmuch-maildir-fcc)
;;; notmuch-maildir-fcc.el ends here

View file

@ -38,7 +38,7 @@
(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."
@ -120,7 +120,7 @@ to `notmuch-mua-send-hook'."
:type 'regexp
:group 'notmuch-send)
;;
;;; Various functions
(defun notmuch-mua-attachment-check ()
"Signal an error if the message text indicates that an
@ -215,6 +215,8 @@ Typically this is added to `notmuch-mua-send-hook'."
(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)
@ -318,6 +320,8 @@ Typically this is added to `notmuch-mua-send-hook'."
(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)
@ -333,6 +337,8 @@ Typically this is added to `notmuch-mua-send-hook'."
(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'
@ -528,6 +534,8 @@ will be addressed to all recipients of the source message."
(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.
@ -570,6 +578,8 @@ The <#secure> tag at the start of the body is not followed by a
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)
@ -593,7 +603,7 @@ unencrypted. Really send? "))))
(interactive)
(message-kill-buffer))
;;
;;; _
(define-mail-user-agent 'notmuch-user-agent
'notmuch-mua-mail 'notmuch-mua-send-and-exit
@ -603,8 +613,6 @@ unencrypted. Really send? "))))
;; composing a message.
(notmuch-mua-add-more-hidden-headers)
;;
(provide 'notmuch-mua)
;;; notmuch-mua.el ends here

View file

@ -25,6 +25,8 @@
(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
@ -36,7 +38,7 @@
(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'."
@ -54,7 +56,7 @@ Optional OUTPUT allows passing a list of flags to muttprint."
"--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."
@ -91,6 +93,8 @@ Optional OUTPUT allows passing a list of flags to muttprint."
(set-buffer-modified-p nil)
(funcall notmuch-print-mechanism msg))
;;; _
(provide 'notmuch-print)
;;; notmuch-print.el ends here

View file

@ -23,6 +23,8 @@
(require 'notmuch-lib)
;;; Basic query function
(defun notmuch-query-get-threads (search-terms)
"Return a list of threads of messages matching SEARCH-TERMS.
@ -35,8 +37,7 @@ is a possibly empty forest of replies."
(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."
@ -64,8 +65,7 @@ Flatten results to a list. See the function
`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."

View file

@ -59,6 +59,8 @@
(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.
@ -162,6 +164,8 @@ indentation."
:type '(choice (const nil) regexp)
:group 'notmuch-show)
;;; Variables
(defvar-local notmuch-show-thread-id nil)
(defvar-local notmuch-show-parent-buffer nil)
@ -182,6 +186,8 @@ handlers is discarded. When set to t the stdout and stderr from
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=")
@ -260,6 +266,8 @@ position of the message in the thread."
: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
@ -275,6 +283,8 @@ position of the message in the thread."
"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.
@ -355,6 +365,8 @@ operation on the contents of the current buffer."
(interactive)
(notmuch-show-with-message-as-text 'notmuch-print-message))
;;; Headers
(defun notmuch-show-fontify-header ()
(let ((face (cond
((looking-at "[Tt]o:")
@ -493,6 +505,8 @@ message at DEPTH in the current thread."
(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
@ -548,7 +562,7 @@ message at DEPTH in the current thread."
(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).")
@ -811,7 +825,8 @@ will return nil if the CID is unknown or cannot be retrieved."
(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")
@ -836,7 +851,7 @@ will return nil if the CID is unknown or cannot be retrieved."
(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."
@ -852,7 +867,7 @@ will return nil if the CID is unknown or cannot be retrieved."
(intern (concat "notmuch-show-insert-part-" content-type))))
result))
;;
;;; Parts
(defun notmuch-show-insert-bodypart-internal (msg part content-type nth depth button)
;; Run the handlers until one of them succeeds.
@ -1098,6 +1113,8 @@ is t, hide the part initially and show the button."
(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)
@ -1126,6 +1143,8 @@ is t, hide the part initially and show the button."
"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))
@ -1143,6 +1162,8 @@ is t, hide the part initially and show the button."
"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
@ -1203,6 +1224,8 @@ buttons for a corresponding notmuch search."
'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.
@ -1325,6 +1348,8 @@ If no messages match the query return NIL."
;; Report back to the caller whether any messages matched.
forest))
;;; Refresh command
(defun notmuch-show-capture-state ()
"Capture the state of the current buffer.
@ -1399,6 +1424,8 @@ reset based on the original query."
(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)
@ -1479,6 +1506,8 @@ reset based on the original query."
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.
@ -1515,6 +1544,8 @@ All currently available key bindings:
(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)
@ -1529,17 +1560,14 @@ All currently available key bindings:
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.
@ -1583,8 +1611,7 @@ effects."
(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))
@ -1594,8 +1621,7 @@ effects."
(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
@ -1768,8 +1794,7 @@ Reshows the current thread with matches defined by the new query-string."
(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."
@ -1783,7 +1808,7 @@ Reshows the current thread with matches defined by the new query-string."
(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.
@ -1911,6 +1936,9 @@ any effects from previous calls to
(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.
@ -2381,7 +2409,7 @@ omit --in-reply-to=<Message-Id>."
(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."
@ -2528,6 +2556,8 @@ browsing."
(funcall fn (completing-read prompt urls nil nil nil nil (car urls)))
(message "No URLs found."))))
;;; _
(provide 'notmuch-show)
;;; notmuch-show.el ends here

View file

@ -37,6 +37,8 @@
(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"
@ -84,6 +86,8 @@ from TAGGING-OPERATIONS."
: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")
@ -217,6 +221,8 @@ See `notmuch-tag-formats' for full documentation."
:group 'notmuch-faces
:type 'notmuch-tag-format-type)
;;; Icons
(defun notmuch-tag-format-image-data (tag data)
"Replace TAG with image DATA, if available.
@ -270,6 +276,8 @@ This can be used with `notmuch-tag-format-image-data'."
</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'.")
@ -347,6 +355,8 @@ changed (the normal case) are shown using formats from
face
t)))
;;; Hooks
(defcustom notmuch-before-tag-hook nil
"Hooks that are run before tags of a message are modified.
@ -369,6 +379,8 @@ the messages that were tagged."
: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.")
@ -429,6 +441,8 @@ initial input in the minibuffer."
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.
@ -547,7 +561,7 @@ and vice versa."
(setq action-map (nreverse action-map))
(notmuch-jump action-map "Tag: ")))
;;
;;; _
(provide 'notmuch-tag)

View file

@ -54,6 +54,8 @@
(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)
@ -118,7 +120,9 @@ For example:
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"
@ -169,7 +173,8 @@ For example:
: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."
@ -206,6 +211,8 @@ For example:
: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.")
@ -238,6 +245,8 @@ This is used to try and make sure we don't close the message pane
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.
@ -305,6 +314,8 @@ then NAME behaves like CMD."
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)
@ -363,6 +374,8 @@ then NAME behaves like CMD."
map)
"Keymap for \"notmuch tree\" buffers.")
;;; Message properties
(defun notmuch-tree-get-message-properties ()
"Return the properties of the current message as a plist.
@ -414,6 +427,8 @@ Some useful entries are:
(interactive)
(notmuch-tree-get-prop :match))
;;; Update display
(defun notmuch-tree-refresh-result ()
"Redisplay the current message line.
@ -456,6 +471,8 @@ NOT change the database."
(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
@ -835,7 +852,7 @@ buffer."
(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
@ -1142,7 +1159,7 @@ The arguments are:
(interactive)
(notmuch-tree query query-context target buffer-name open-target t))
;;
;;; _
(provide 'notmuch-tree)

View file

@ -30,7 +30,7 @@
(msg part depth &optional hide))
(defvar notmuch-show-indent-messages-width)
;;
;;; Options
(defgroup notmuch-wash nil
"Cleaning up messages for display."
@ -130,6 +130,8 @@ or at the window width (whichever one is lower)."
(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
@ -143,6 +145,8 @@ message parts."
: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)))
@ -225,6 +229,8 @@ that PREFIX should not include a newline."
: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))
@ -270,8 +276,6 @@ that PREFIX should not include a newline."
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
@ -293,8 +297,6 @@ that PREFIX should not include a newline."
(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.
@ -319,8 +321,6 @@ Perform several transformations on the message body:
(while (re-search-forward "\\(^>[> ]*\n\\)\\(^$\\|^[^>].*\\)" nil t)
(replace-match "\\2")))
;;
(defun notmuch-wash-wrap-long-lines (msg depth)
"Wrap long lines in the message.
@ -342,7 +342,7 @@ the wrapped text are maintained."
2)))
(coolj-wrap-region (point-min) (point-max))))
;;
;;;; Convert Inline Patches
(require 'diff-mode)
@ -417,7 +417,7 @@ for error."
(delete-region (point-min) (point-max))
(notmuch-show-insert-bodypart nil part depth)))))
;;
;;; _
(provide 'notmuch-wash)

View file

@ -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)
@ -195,6 +205,8 @@ there will be called at other points of notmuch execution."
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)
@ -214,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)
@ -271,6 +287,8 @@ 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))
,@(and (>= emacs-major-version 27) '(:extend t))
@ -356,6 +374,8 @@ This face is the default value for the \"unread\" tag in
: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.
@ -400,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).
@ -558,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)))
@ -639,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.
@ -881,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.
@ -1132,7 +1160,7 @@ notmuch buffers exist, run `notmuch'."
(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.
@ -1149,6 +1177,8 @@ beginning of the line."
(author (notmuch-search-find-authors)))
(format "%s (%s)" subject author)))
;;; _
(setq mail-user-agent 'notmuch-user-agent)
(provide 'notmuch)

View file

@ -1,4 +1,4 @@
;; test-lib.el --- auxiliary stuff for Notmuch Emacs tests.
;;; test-lib.el --- auxiliary stuff for Notmuch Emacs tests
;;
;; Copyright © Carl Worth
;; Copyright © David Edmondson
@ -20,6 +20,8 @@
;;
;; Authors: Dmitry Kurochkin <dmitry.kurochkin@gmail.com>
;;; Code:
(require 'cl-lib)
;; Ensure that the dynamic variables that are defined by this library