[PATCH] emacs: Allow the display of absolute dates in the header line.
On Wed, 19 May 2010 07:44:18 +0100, David Edmondson wrote: > Add `notmuch-show-relative-dates' to control whether the summary line > in `notmuch-show' mode displays relative dates (e.g. '26 mins. ago') or > the full date string from the message. Default to `t' for > compatibility with the previous behaviour. Excellent - thanks for providing this (and all I did was mention it briefly on IRC... I love this project) /D -- Dirk Hohndel Intel Open Source Technology Center
[PATCH 13/13] emacs: Allow the display of absolute dates in the header line.
Add `notmuch-show-relative-dates' to control whether the summary line in `notmuch-show' mode displays relative dates (e.g. '26 mins ago') or the full date string from the message. Default to `t' for compatibility with the previous behaviour. --- emacs/notmuch-show.el |9 - 1 files changed, 8 insertions(+), 1 deletions(-) diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el index 7601857..cbc3012 100644 --- a/emacs/notmuch-show.el +++ b/emacs/notmuch-show.el @@ -58,6 +58,11 @@ any given message." :group 'notmuch :type 'boolean) +(defcustom notmuch-show-relative-dates t + "Display relative dates in the message summary line." + :group 'notmuch + :type 'boolean) + (defvar notmuch-show-markup-headers-hook '(notmuch-show-colour-headers) "A list of functions called to decorate the headers listed in `notmuch-message-headers'.") @@ -407,7 +412,9 @@ current buffer, if possible." (setq message-start (point-marker)) (notmuch-show-insert-headerline headers - (or (plist-get msg :date_relative) + (or (if notmuch-show-relative-dates + (plist-get msg :date_relative) + nil) (plist-get headers :Date)) (plist-get msg :tags) depth) -- 1.7.1
[PATCH 12/13] emacs: Tags should be shown with `notmuch-tag-face'.
Use the same face for tags in `notmuch-show' mode as that used in `notmuch-search' mode. --- emacs/notmuch-show.el |6 -- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el index ff1a7a7..7601857 100644 --- a/emacs/notmuch-show.el +++ b/emacs/notmuch-show.el @@ -189,7 +189,8 @@ any given message." (if (re-search-forward "(\\([^()]*\\))$" (line-end-position) t) (let ((inhibit-read-only t)) (replace-match (concat "(" -(mapconcat 'identity tags " ") +(propertize (mapconcat 'identity tags " ") +'face 'notmuch-tag-face) ")")) (defun notmuch-show-insert-headerline (headers date tags depth) @@ -201,7 +202,8 @@ message at DEPTH in the current thread." " (" date ") (" - (mapconcat 'identity tags " ") + (propertize (mapconcat 'identity tags " ") + 'face 'notmuch-tag-face) ")\n") (overlay-put (make-overlay start (point)) 'face 'notmuch-message-summary-face))) -- 1.7.1
[PATCH 11/13] emacs: Pretty print the numbers of matching messages.
Insert a separator every three digits when outputting numbers. Allow the user to choose the separator by customizing `notmuch-decimal-separator'. Widen the space allocated for message counts accordingly. --- emacs/notmuch-hello.el | 38 +++--- 1 files changed, 31 insertions(+), 7 deletions(-) diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el index 538785f..7ade0eb 100644 --- a/emacs/notmuch-hello.el +++ b/emacs/notmuch-hello.el @@ -91,6 +91,13 @@ So: (integer :tag "Number of characters") (float :tag "Fraction of window"))) +(defcustom notmuch-decimal-separator "," + "The string used as a decimal separator. + +Typically \",\" in the US and UK and \".\" in Europe." + :group 'notmuch + :type 'string) + (defvar notmuch-hello-url "http://notmuchmail.org"; "The `notmuch' web site.") @@ -103,6 +110,17 @@ So: notmuch-recent-searches-max) (setq notmuch-hello-recent-searches (butlast notmuch-hello-recent-searches +(defun notmuch-hello-nice-number (n) + (let (result) +(while (> n 0) + (push (% n 1000) result) + (setq n (/ n 1000))) +(apply #'concat + (number-to-string (car result)) + (mapcar (lambda (elem) + (format "%s%03d" notmuch-decimal-separator elem)) +(cdr result) + (defun notmuch-hello-trim (search) "Trim whitespace." (if (string-match "^[[:space:]]*\\(.*[^[:space:]]\\)[[:space:]]*$" search) @@ -180,9 +198,9 @@ should be. Returns a cons cell `(tags-per-line width)'." ((integerp notmuch-column-control) (max 1 (/ (- (window-width) notmuch-hello-indent) - ;; Count is 7 wide (6 digits plus space), 1 for the space + ;; Count is 9 wide (8 digits plus space), 1 for the space ;; after the name. - (+ 7 1 (max notmuch-column-control widest) + (+ 9 1 (max notmuch-column-control widest) ((floatp notmuch-column-control) (let* ((available-width (- (window-width) notmuch-hello-indent)) @@ -192,12 +210,15 @@ should be. Returns a cons cell `(tags-per-line width)'." (t (max 1 (/ (- (window-width) notmuch-hello-indent) - ;; Count is 7 wide (6 digits plus space), 1 for the space + ;; Count is 9 wide (8 digits plus space), 1 for the space ;; after the name. - (+ 7 1 widest))) + (+ 9 1 widest))) (cons tags-per-line (/ (- (window-width) notmuch-hello-indent - (* tags-per-line (+ 7 1))) + ;; Count is 9 wide (8 digits plus + ;; space), 1 for the space after the + ;; name. + (* tags-per-line (+ 9 1))) tags-per-line (defun notmuch-hello-insert-tags (tag-alist widest target) @@ -218,7 +239,9 @@ should be. Returns a cons cell `(tags-per-line width)'." (let* ((name (car elem)) (query (cdr elem)) (formatted-name (format "%s " name))) - (widget-insert (format "%6s " (notmuch-saved-search-count query))) + (widget-insert (format "%8s " + (notmuch-hello-nice-number + (string-to-number (notmuch-saved-search-count query) (if (string= formatted-name target) (setq found-target-pos (point-marker))) (widget-create 'push-button @@ -323,7 +346,8 @@ should be. Returns a cons cell `(tags-per-line width)'." :notify (lambda (&rest ignore) (notmuch-hello-update)) :help-echo "Refresh" -(car (process-lines notmuch-command "count"))) +(notmuch-hello-nice-number + (string-to-number (car (process-lines notmuch-command "count") (widget-insert " messages (that's not much mail).\n")) (let ((found-target-pos nil) -- 1.7.1
[PATCH 10/13] emacs: In search mode, truncate authors using invisible text.
Rather than discarding authors when truncated to fit the defined column width, mark the text beyond the end of the column as invisible and allow `isearch' to be used over the text so hidden. This allows us to retain the compact display whilst enabling a user to find the elided text. --- emacs/notmuch.el | 61 +++-- 1 files changed, 45 insertions(+), 16 deletions(-) diff --git a/emacs/notmuch.el b/emacs/notmuch.el index c2fefe5..10babe4 100644 --- a/emacs/notmuch.el +++ b/emacs/notmuch.el @@ -608,23 +608,52 @@ matching will be applied." (t (setq tags-faces (cdr tags-faces) +(defun notmuch-search-isearch-authors-show (overlay) + (remove-from-invisibility-spec (cons (overlay-get overlay 'invisible) t))) + (defun notmuch-search-insert-authors (format-string authors) - (insert (let* ((formatted-sample (format format-string "")) -(formatted-authors (format format-string authors)) -(truncated-string - (if (> (length formatted-authors) -(length formatted-sample)) - (concat (substring authors 0 (- (length formatted-sample) 4)) "... ") - formatted-authors))) - ;; Need to save the match data to avoid interfering with - ;; `notmuch-search-process-filter'. - (save-match-data - (if (string-match "\\(.*\\)|\\(..*\\)" truncated-string) - (concat (propertize (concat (match-string 1 truncated-string) ",") - 'face 'notmuch-search-matching-authors) - (propertize (match-string 2 truncated-string) - 'face 'notmuch-search-non-matching-authors)) - (propertize truncated-string 'face 'notmuch-search-matching-authors)) + (let* ((propertized-authors + ;; Need to save the match data to avoid interfering with + ;; `notmuch-search-process-filter'. + (save-match-data + ;; Authors that don't match the search query are shown in a + ;; different font. + (if (string-match "\\(.*\\)|\\(..*\\)" authors) + (concat (propertize (concat (match-string 1 authors) ",") + 'face 'notmuch-search-matching-authors) + (propertize (match-string 2 authors) + 'face 'notmuch-search-non-matching-authors)) + (propertize authors 'face 'notmuch-search-matching-authors + +(formatted-sample (format format-string "")) +(formatted-authors (format format-string propertized-authors)) +visible-string invisible-string) + +;; Determine the part of the authors that will be visible by +;; default. +(if (> (length formatted-authors) + (length formatted-sample)) + ;; 4 is `(length "... ")'. + (let ((visible-length (- (length formatted-sample) 4))) + (setq visible-string (substring propertized-authors 0 visible-length) + invisible-string (substring propertized-authors visible-length))) + (setq visible-string formatted-authors + invisible-string nil)) + +;; Insert both the visible and invisible author strings. +(insert visible-string) +(when invisible-string + (let ((start (point)) + (invis-spec (make-symbol "notmuch-search-authors")) + overlay) + (insert invisible-string) + ;; Using a cons-cell here causes an ellipsis to be inserted + ;; instead of the invisible text. + (add-to-invisibility-spec (cons invis-spec t)) + (setq overlay (make-overlay start (point))) + (overlay-put overlay 'invisible invis-spec) + (overlay-put overlay 'isearch-open-invisible #'notmuch-search-isearch-authors-show) + (insert " ") (defun notmuch-search-insert-field (field date count authors subject tags) (cond -- 1.7.1
[PATCH 09/13] emacs: Avoid runtime use of `cl'.
The GNU Emacs Lisp Reference Manual section D.1 says: > * Please don't require the cl package of Common Lisp extensions at >run time. Use of this package is optional, and it is not part of >the standard Emacs namespace. If your package loads cl at run time, >that could cause name clashes for users who don't use that package. > >However, there is no problem with using the cl package at compile >time, with (eval-when-compile (require 'cl)). That's sufficient for >using the macros in the cl package, because the compiler expands >them before generating the byte-code. Follow this advice, requiring the following changes where `cl' was used at runtime: - replace `rassoc-if' in `notmuch-search-buffer-title' with the `loop' macro and inline code. At the same time find the longest prefix which matches the query rather than simply the last, - replace `union', `intersection' and `set-difference' in `notmuch-show-add-tag' and `notmuch-show-remove-tag' with local code to calculate the result of adding and removing a list of tags from another list of tags. --- emacs/notmuch-hello.el |2 +- emacs/notmuch-show.el | 54 +++ emacs/notmuch.el | 16 + 3 files changed, 52 insertions(+), 20 deletions(-) diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el index acf40bc..538785f 100644 --- a/emacs/notmuch-hello.el +++ b/emacs/notmuch-hello.el @@ -19,9 +19,9 @@ ;; ;; Authors: David Edmondson +(eval-when-compile (require 'cl)) (require 'widget) (require 'wid-edit) ; For `widget-forward'. -(require 'cl) (require 'notmuch-lib) (require 'notmuch-mua) diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el index 4b1baf3..ff1a7a7 100644 --- a/emacs/notmuch-show.el +++ b/emacs/notmuch-show.el @@ -21,7 +21,7 @@ ;; Authors: Carl Worth ;; David Edmondson -(require 'cl) +(eval-when-compile (require 'cl)) (require 'mm-view) (require 'message) (require 'mm-decode) @@ -908,29 +908,55 @@ to stdout or stderr will appear in the *Messages* buffer." (list command " < " (shell-quote-argument (notmuch-show-get-filename) +(defun notmuch-show-add-tags-worker (current-tags add-tags) + "Add to `current-tags' with any tags from `add-tags' not +currently present and return the result." + (let ((result-tags (copy-seq current-tags))) +(mapc (lambda (add-tag) + (unless (member add-tag current-tags) + (setq result-tags (push add-tag result-tags + add-tags) +(sort result-tags 'string<))) + +(defun notmuch-show-del-tags-worker (current-tags del-tags) + "Remove any tags in `del-tags' from `current-tags' and return +the result." + (let ((result-tags (copy-seq current-tags))) +(mapc (lambda (del-tag) + (setq result-tags (delete del-tag result-tags))) + del-tags) +result-tags)) + (defun notmuch-show-add-tag (&rest toadd) "Add a tag to the current message." (interactive (list (notmuch-select-tag-with-completion "Tag to add: "))) - (apply 'notmuch-call-notmuch-process -(append (cons "tag" - (mapcar (lambda (s) (concat "+" s)) toadd)) -(cons (notmuch-show-get-message-id) nil))) - (notmuch-show-set-tags (sort (union toadd (notmuch-show-get-tags) :test 'string=) 'string<))) + + (let* ((current-tags (notmuch-show-get-tags)) +(new-tags (notmuch-show-add-tags-worker current-tags toadd))) + +(unless (equal current-tags new-tags) + (apply 'notmuch-call-notmuch-process +(append (cons "tag" + (mapcar (lambda (s) (concat "+" s)) toadd)) +(cons (notmuch-show-get-message-id) nil))) + (notmuch-show-set-tags new-tags (defun notmuch-show-remove-tag (&rest toremove) "Remove a tag from the current message." (interactive (list (notmuch-select-tag-with-completion "Tag to remove: " (notmuch-show-get-message-id - (let ((tags (notmuch-show-get-tags))) -(if (intersection tags toremove :test 'string=) - (progn - (apply 'notmuch-call-notmuch-process -(append (cons "tag" - (mapcar (lambda (s) (concat "-" s)) toremove)) -(cons (notmuch-show-get-message-id) nil))) - (notmuch-show-set-tags (sort (set-difference tags toremove :test 'string=) 'string<)) + + (let* ((current-tags (notmuch-show-get-tags)) +(new-tags (notmuch-show-del-tags-worker current-tags toremove))) + +(unless (equal current-tags new-tags) + (apply 'notmuch-call-notmuch-process +(append (cons "tag" + (mapcar (lambda (s) (concat "-" s)) toremove)) +(cons (notmuch-show-get-message-id) nil))) + (notmuch-show-set-tags new-tags (defun notmuch-show-toggle-headers () "Toggle the visibility of the current message headers." diff --git a/em
[PATCH 08/13] emacs: Reuse rather than reinvent message header filtering
From: Sebastian Spaeth In notmuch-mua-reply we were filtering out the Subject and To headers manually in a loop, but message mode offers a nice function for exactly that. Simplify the code by using that. Also, as notmuch-mua-mail already sorts and hides headers that we want sorted and hidden, we can safely remove those 2 functions from here as well. Signed-off-by: Sebastian Spaeth --- emacs/notmuch-mua.el |7 +-- 1 files changed, 1 insertions(+), 6 deletions(-) diff --git a/emacs/notmuch-mua.el b/emacs/notmuch-mua.el index bd06e3c..6318c15 100644 --- a/emacs/notmuch-mua.el +++ b/emacs/notmuch-mua.el @@ -92,12 +92,7 @@ list." ((same-window-regexps '("\\*mail .*"))) (notmuch-mua-mail (mail-header 'to headers) (mail-header 'subject headers) - (loop for header in headers - if (not (or (eq 'to (car header)) - (eq 'subject (car header - collect header))) -(message-sort-headers) -(message-hide-headers) + (message-headers-to-generate headers t '(to subject ;; insert the message body - but put it in front of the signature ;; if one is present (goto-char (point-max)) -- 1.7.1
[PATCH 07/13] emacs: Allow tuning of the tag/saved search layout.
Add `notmuch-column-control', which has three potential sets of values: - t: automatically calculate the number of columns per line based on the tags to be shown and the window width, - an integer: a lower bound on the number of characters that will be used to display each column, - a float: a fraction of the window width that is the lower bound on the number of characters that should be used for each column. So: - if you would like two columns of tags, set this to 0.5. - if you would like a single column of tags, set this to 1.0. - if you would like tags to be 30 characters wide, set this to 30. - if you don't want to worry about all of this nonsense, leave this set to `t'. --- emacs/notmuch-hello.el | 63 +++ 1 files changed, 57 insertions(+), 6 deletions(-) diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el index 1358387..acf40bc 100644 --- a/emacs/notmuch-hello.el +++ b/emacs/notmuch-hello.el @@ -65,6 +65,32 @@ "Background colour for the notmuch logo." :group 'notmuch) +(defcustom notmuch-column-control t + "Controls the number of columns for saved searches/tags in notmuch view. + +This variable has three potential sets of values: + +- t: automatically calculate the number of columns possible based + on the tags to be shown and the window width, +- an integer: a lower bound on the number of characters that will + be used to display each column, +- a float: a fraction of the window width that is the lower bound + on the number of characters that should be used for each + column. + +So: +- if you would like two columns of tags, set this to 0.5. +- if you would like a single column of tags, set this to 1.0. +- if you would like tags to be 30 characters wide, set this to + 30. +- if you don't want to worry about all of this nonsense, leave + this set to `t'." + :group 'notmuch + :type '(choice + (const :tag "Automatically calculated" t) + (integer :tag "Number of characters") + (float :tag "Fraction of window"))) + (defvar notmuch-hello-url "http://notmuchmail.org"; "The `notmuch' web site.") @@ -146,13 +172,38 @@ diagonal." (defun notmuch-saved-search-count (search) (car (process-lines notmuch-command "count" search))) +(defun notmuch-hello-tags-per-line (widest) + "Determine how many tags to show per line and how wide they +should be. Returns a cons cell `(tags-per-line width)'." + (let ((tags-per-line +(cond + ((integerp notmuch-column-control) + (max 1 + (/ (- (window-width) notmuch-hello-indent) + ;; Count is 7 wide (6 digits plus space), 1 for the space + ;; after the name. + (+ 7 1 (max notmuch-column-control widest) + + ((floatp notmuch-column-control) + (let* ((available-width (- (window-width) notmuch-hello-indent)) + (proposed-width (max (* available-width notmuch-column-control) widest))) +(floor available-width proposed-width))) + + (t + (max 1 + (/ (- (window-width) notmuch-hello-indent) + ;; Count is 7 wide (6 digits plus space), 1 for the space + ;; after the name. + (+ 7 1 widest))) + +(cons tags-per-line (/ (- (window-width) notmuch-hello-indent + (* tags-per-line (+ 7 1))) + tags-per-line + (defun notmuch-hello-insert-tags (tag-alist widest target) - (let* ((tags-per-line (max 1 -(/ (- (window-width) notmuch-hello-indent) - ;; Count is 7 wide (6 digits plus - ;; space), 1 for the space after the - ;; name. - (+ 7 1 widest + (let* ((tags-and-width (notmuch-hello-tags-per-line widest)) +(tags-per-line (car tags-and-width)) +(widest (cdr tags-and-width)) (count 0) (reordered-list (notmuch-hello-reflect tag-alist tags-per-line)) ;; Hack the display of the buttons used. -- 1.7.1
[PATCH 06/13] emacs: Allow control over faces for search mode columns.
Add face declarations for the date, count, matching author and subject columns in search mode and apply those faces when building the search mode display. --- emacs/notmuch.el | 59 +++-- 1 files changed, 43 insertions(+), 16 deletions(-) diff --git a/emacs/notmuch.el b/emacs/notmuch.el index d36a92d..7c9c028 100644 --- a/emacs/notmuch.el +++ b/emacs/notmuch.el @@ -285,27 +285,48 @@ For a mouse binding, return nil." "Face for the single-line message summary in notmuch-show-mode." :group 'notmuch) -(defface notmuch-tag-face +(defface notmuch-search-date + '((t :inherit default)) + "Face used in search mode for dates." + :group 'notmuch) + +(defface notmuch-search-count + '((t :inherit default)) + "Face used in search mode for the count matching the query." + :group 'notmuch) + +(defface notmuch-search-subject + '((t :inherit default)) + "Face used in search mode for subjects." + :group 'notmuch) + +(defface notmuch-search-matching-authors + '((t :inherit default)) + "Face used in search mode for authors matching the query." + :group 'notmuch) + +(defface notmuch-search-non-matching-authors 'class color) (background dark)) - (:foreground "OliveDrab1")) + (:foreground "grey30")) (((class color) (background light)) - (:foreground "navy blue" :bold t)) + (:foreground "grey60")) (t - (:bold t))) - "Notmuch search mode face used to highligh tags." + (:italic t))) + "Face used in search mode for authors not matching the query." :group 'notmuch) -(defface notmuch-search-non-matching-authors +(defface notmuch-tag-face 'class color) (background dark)) - (:foreground "grey30")) + (:foreground "OliveDrab1")) (((class color) (background light)) - (:foreground "grey60")) -(t (:italic t))) - "Face used in search mode for authors not matching the query." + (:foreground "navy blue" :bold t)) +(t + (:bold t))) + "Face used in search mode face for tags." :group 'notmuch) ;;;###autoload @@ -599,21 +620,27 @@ matching will be applied." ;; `notmuch-search-process-filter'. (save-match-data (if (string-match "\\(.*\\)|\\(..*\\)" truncated-string) - (concat (match-string 1 truncated-string) "," + (concat (propertize (concat (match-string 1 truncated-string) ",") + 'face 'notmuch-search-matching-authors) (propertize (match-string 2 truncated-string) 'face 'notmuch-search-non-matching-authors)) - truncated-string) + (propertize truncated-string 'face 'notmuch-search-matching-authors)) (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))) +(insert (propertize (format (cdr (assoc field notmuch-search-result-format)) date) + 'face 'notmuch-search-date))) ((string-equal field "count") -(insert (format (cdr (assoc field notmuch-search-result-format)) count))) +(insert (propertize (format (cdr (assoc field notmuch-search-result-format)) count) + 'face 'notmuch-search-count))) + ((string-equal field "subject") +(insert (propertize (format (cdr (assoc field notmuch-search-result-format)) subject) + 'face 'notmuch-search-subject))) + ((string-equal field "authors") (notmuch-search-insert-authors (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) ")") -- 1.7.1
[PATCH 05/13] emacs: Set the `face' property rather than `font-lock-face'.
Avoid using face properties reserved for the font-lock package. --- emacs/notmuch.el |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/emacs/notmuch.el b/emacs/notmuch.el index 60c0ee5..d36a92d 100644 --- a/emacs/notmuch.el +++ b/emacs/notmuch.el @@ -438,7 +438,7 @@ and will also appear in a buffer named \"*Notmuch errors*\"." (let ((end (point))) (delete-region beg end) (insert (propertize (mapconcat 'identity tags " ") - 'font-lock-face 'notmuch-tag-face)) + 'face 'notmuch-tag-face)) (defun notmuch-search-get-tags () (save-excursion -- 1.7.1
[PATCH 04/13] emacs: Display non-matching authors with a different face.
In search mode some messages don't match the search criteria. Show their authors names with a different face - generally darker than those that do match. --- emacs/notmuch.el | 36 +--- 1 files changed, 29 insertions(+), 7 deletions(-) diff --git a/emacs/notmuch.el b/emacs/notmuch.el index 7457da9..60c0ee5 100644 --- a/emacs/notmuch.el +++ b/emacs/notmuch.el @@ -297,6 +297,17 @@ For a mouse binding, return nil." "Notmuch search mode face used to highligh tags." :group 'notmuch) +(defface notmuch-search-non-matching-authors + 'class color) + (background dark)) + (:foreground "grey30")) +(((class color) + (background light)) + (:foreground "grey60")) +(t (:italic t))) + "Face used in search mode for authors not matching the query." + :group 'notmuch) + ;;;###autoload (defun notmuch-search-mode () "Major mode displaying results of a notmuch search. @@ -576,6 +587,23 @@ matching will be applied." (t (setq tags-faces (cdr tags-faces) +(defun notmuch-search-insert-authors (format-string authors) + (insert (let* ((formatted-sample (format format-string "")) +(formatted-authors (format format-string authors)) +(truncated-string + (if (> (length formatted-authors) +(length formatted-sample)) + (concat (substring authors 0 (- (length formatted-sample) 4)) "... ") + formatted-authors))) + ;; Need to save the match data to avoid interfering with + ;; `notmuch-search-process-filter'. + (save-match-data + (if (string-match "\\(.*\\)|\\(..*\\)" truncated-string) + (concat (match-string 1 truncated-string) "," + (propertize (match-string 2 truncated-string) + 'face 'notmuch-search-non-matching-authors)) + truncated-string) + (defun notmuch-search-insert-field (field date count authors subject tags) (cond ((string-equal field "date") @@ -583,13 +611,7 @@ matching will be applied." ((string-equal field "count") (insert (format (cdr (assoc field notmuch-search-result-format)) count))) ((string-equal field "authors") -(insert (let* ((format-string (cdr (assoc field notmuch-search-result-format))) - (formatted-sample (format format-string "")) - (formatted-authors (format format-string authors))) - (if (> (length formatted-authors) -(length formatted-sample)) - (concat (substring authors 0 (- (length formatted-sample) 4)) "... ") - formatted-authors +(notmuch-search-insert-authors (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") -- 1.7.1
[PATCH 03/13] emacs: Adjust comment to avoid confusing font-lock.
Comments with an open bracket in the first column confuse `font-lock' mode, so avoid them. --- emacs/notmuch.el |6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/emacs/notmuch.el b/emacs/notmuch.el index 57e1140..7457da9 100644 --- a/emacs/notmuch.el +++ b/emacs/notmuch.el @@ -551,10 +551,10 @@ This function advances the next thread when finished." "Tag/face mapping for line highlighting in notmuch-search. Here is an example of how to color search results based on tags. -(the following text would be placed in your ~/.emacs file): + (the following text would be placed in your ~/.emacs file): -(setq notmuch-search-line-faces '((\"delete\" . '(:foreground \"red\")) - (\"unread\" . '(:foreground \"green\" + (setq notmuch-search-line-faces '((\"delete\" . '(:foreground \"red\")) + (\"unread\" . '(:foreground \"green\" Order matters: for lines with multiple tags, the the first matching will be applied." -- 1.7.1
[PATCH 02/13] notmuch: Fix off-by-one errors if a header is >200 characters long.
If a single header is more than 200 characters long a set of 'off by one' errors cause memory corruption. When allocating memory with: a = malloc (len); the last usable byte of the memory is 'a + len - 1' rather than 'a + len'. Fix the same bug when calculating the current offset should the buffer used for collecting the output header need to be reallocated. --- gmime-filter-headers.c |6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gmime-filter-headers.c b/gmime-filter-headers.c index 2f3df80..7db3779 100644 --- a/gmime-filter-headers.c +++ b/gmime-filter-headers.c @@ -169,7 +169,7 @@ filter_filter (GMimeFilter *filter, char *inbuf, size_t inlen, size_t prespace, headers->lineptr = headers->line = malloc (headers->line_size); } lineptr = headers->lineptr; - lineend = headers->line + headers->line_size; + lineend = headers->line + headers->line_size - 1; if (lineptr == NULL) return; outptr = filter->outbuf; @@ -185,8 +185,8 @@ filter_filter (GMimeFilter *filter, char *inbuf, size_t inlen, size_t prespace, if (lineptr == lineend) { headers->line_size *= 2; headers->line = xrealloc (headers->line, headers->line_size); - lineptr = headers->line + headers->line_size / 2; - lineend = headers->line + headers->line_size; + lineptr = headers->line + (headers->line_size / 2) - 1; + lineend = headers->line + headers->line_size - 1; } if (headers->saw_nl && *inptr != ' ' && *inptr != '\t') { -- 1.7.1
[PATCH 01/13] emacs: Usability improvements for `notmuch-hello'.
- If no saved searches exist or are displayed, don't signal an error, - If no saved searches exist or are displayed, leave the cursor in the search bar, - Minor layout improvements. --- emacs/notmuch-hello.el | 36 +++- 1 files changed, 19 insertions(+), 17 deletions(-) diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el index 6a1c56e..1358387 100644 --- a/emacs/notmuch-hello.el +++ b/emacs/notmuch-hello.el @@ -273,7 +273,7 @@ diagonal." (notmuch-hello-update)) :help-echo "Refresh" (car (process-lines notmuch-command "count"))) - (widget-insert " messages (that's not much mail).\n\n")) + (widget-insert " messages (that's not much mail).\n")) (let ((found-target-pos nil) (final-target-pos nil)) @@ -292,7 +292,7 @@ diagonal." (widest (max saved-widest alltags-widest))) (when saved-alist - (widget-insert "Saved searches: ") + (widget-insert "\nSaved searches: ") (widget-create 'push-button :notify (lambda (&rest ignore) (customize-variable 'notmuch-saved-searches)) @@ -305,18 +305,16 @@ diagonal." (setq final-target-pos found-target-pos)) (indent-rigidly start (point) notmuch-hello-indent))) - (let ((start (point))) - (widget-insert "\nSearch: ") - (setq notmuch-hello-search-bar-marker (point-marker)) - (widget-create 'editable-field -;; Leave some space at the start and end of the -;; search boxes. -:size (max 8 (- (window-width) (* 2 notmuch-hello-indent) -(length "Search: "))) -:action (lambda (widget &rest ignore) - (notmuch-hello-search (widget-value widget - (widget-insert "\n") - (indent-rigidly start (point) notmuch-hello-indent)) + (widget-insert "\nSearch: ") + (setq notmuch-hello-search-bar-marker (point-marker)) + (widget-create 'editable-field + ;; Leave some space at the start and end of the + ;; search boxes. + :size (max 8 (- (window-width) notmuch-hello-indent + (length "Search: "))) + :action (lambda (widget &rest ignore) +(notmuch-hello-search (widget-value widget + (widget-insert "\n") (when notmuch-hello-recent-searches (widget-insert "\nRecent searches: ") @@ -408,9 +406,13 @@ diagonal." (widget-setup) - (goto-char final-target-pos) - (if (not (widget-at)) - (widget-forward 1) + (when final-target-pos + (goto-char final-target-pos) + (unless (widget-at) + (widget-forward 1))) + + (unless (widget-at) + (notmuch-hello-goto-search) ;;;###autoload (defun notmuch-folder () -- 1.7.1
patches for 0.4
This is a set of small feature and cleanup patches. The only particularly significant one is patch 2, as it fixes a memory corruption bug in notmuch. dme. [PATCH 01/13] emacs: Usability improvements for `notmuch-hello'. [PATCH 02/13] notmuch: Fix off-by-one errors if a header is >200 characters long. [PATCH 03/13] emacs: Adjust comment to avoid confusing font-lock. [PATCH 04/13] emacs: Display non-matching authors with a different face. [PATCH 05/13] emacs: Set the `face' property rather than `font-lock-face'. [PATCH 06/13] emacs: Allow control over faces for search mode columns. [PATCH 07/13] emacs: Allow tuning of the tag/saved search layout. [PATCH 08/13] emacs: Reuse rather than reinvent message header filtering [PATCH 09/13] emacs: Avoid runtime use of `cl'. [PATCH 10/13] emacs: In search mode, truncate authors using invisible text. [PATCH 11/13] emacs: Pretty print the numbers of matching messages. [PATCH 12/13] emacs: Tags should be shown with `notmuch-tag-face'. [PATCH 13/13] emacs: Allow the display of absolute dates in the header line.
[PATCH] emacs: Allow the display of absolute dates in the header line.
Add `notmuch-show-relative-dates' to control whether the summary line in `notmuch-show' mode displays relative dates (e.g. '26 mins. ago') or the full date string from the message. Default to `t' for compatibility with the previous behaviour. --- Re: > one thing I'd love for 0.4 (and haven't seen a patch for) is the > ability to disable the "xxmins. ago" and simply have it always > display the time a message arrived emacs/notmuch-show.el |9 - 1 files changed, 8 insertions(+), 1 deletions(-) diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el index 5b0050a..2a95e62 100644 --- a/emacs/notmuch-show.el +++ b/emacs/notmuch-show.el @@ -64,6 +64,11 @@ any given message." :group 'notmuch :type 'boolean) +(defcustom notmuch-show-relative-dates t + "Display relative dates in the message summary line." + :group 'notmuch + :type 'boolean) + (defvar notmuch-show-markup-headers-hook '(notmuch-show-colour-headers) "A list of functions called to decorate the headers listed in `notmuch-message-headers'.") @@ -592,7 +597,9 @@ current buffer, if possible." (setq message-start (point-marker)) (notmuch-show-insert-headerline headers - (or (plist-get msg :date_relative) + (or (if notmuch-show-relative-dates + (plist-get msg :date_relative) + nil) (plist-get headers :Date)) (plist-get msg :tags) depth) -- 1.7.1
[PATCH 03/13] emacs: Adjust comment to avoid confusing font-lock.
Comments with an open bracket in the first column confuse `font-lock' mode, so avoid them. --- emacs/notmuch.el |6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/emacs/notmuch.el b/emacs/notmuch.el index 57e1140..7457da9 100644 --- a/emacs/notmuch.el +++ b/emacs/notmuch.el @@ -551,10 +551,10 @@ This function advances the next thread when finished." "Tag/face mapping for line highlighting in notmuch-search. Here is an example of how to color search results based on tags. -(the following text would be placed in your ~/.emacs file): + (the following text would be placed in your ~/.emacs file): -(setq notmuch-search-line-faces '((\"delete\" . '(:foreground \"red\")) - (\"unread\" . '(:foreground \"green\" + (setq notmuch-search-line-faces '((\"delete\" . '(:foreground \"red\")) + (\"unread\" . '(:foreground \"green\" Order matters: for lines with multiple tags, the the first matching will be applied." -- 1.7.1 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 07/13] emacs: Allow tuning of the tag/saved search layout.
Add `notmuch-column-control', which has three potential sets of values: - t: automatically calculate the number of columns per line based on the tags to be shown and the window width, - an integer: a lower bound on the number of characters that will be used to display each column, - a float: a fraction of the window width that is the lower bound on the number of characters that should be used for each column. So: - if you would like two columns of tags, set this to 0.5. - if you would like a single column of tags, set this to 1.0. - if you would like tags to be 30 characters wide, set this to 30. - if you don't want to worry about all of this nonsense, leave this set to `t'. --- emacs/notmuch-hello.el | 63 +++ 1 files changed, 57 insertions(+), 6 deletions(-) diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el index 1358387..acf40bc 100644 --- a/emacs/notmuch-hello.el +++ b/emacs/notmuch-hello.el @@ -65,6 +65,32 @@ "Background colour for the notmuch logo." :group 'notmuch) +(defcustom notmuch-column-control t + "Controls the number of columns for saved searches/tags in notmuch view. + +This variable has three potential sets of values: + +- t: automatically calculate the number of columns possible based + on the tags to be shown and the window width, +- an integer: a lower bound on the number of characters that will + be used to display each column, +- a float: a fraction of the window width that is the lower bound + on the number of characters that should be used for each + column. + +So: +- if you would like two columns of tags, set this to 0.5. +- if you would like a single column of tags, set this to 1.0. +- if you would like tags to be 30 characters wide, set this to + 30. +- if you don't want to worry about all of this nonsense, leave + this set to `t'." + :group 'notmuch + :type '(choice + (const :tag "Automatically calculated" t) + (integer :tag "Number of characters") + (float :tag "Fraction of window"))) + (defvar notmuch-hello-url "http://notmuchmail.org"; "The `notmuch' web site.") @@ -146,13 +172,38 @@ diagonal." (defun notmuch-saved-search-count (search) (car (process-lines notmuch-command "count" search))) +(defun notmuch-hello-tags-per-line (widest) + "Determine how many tags to show per line and how wide they +should be. Returns a cons cell `(tags-per-line width)'." + (let ((tags-per-line +(cond + ((integerp notmuch-column-control) + (max 1 + (/ (- (window-width) notmuch-hello-indent) + ;; Count is 7 wide (6 digits plus space), 1 for the space + ;; after the name. + (+ 7 1 (max notmuch-column-control widest) + + ((floatp notmuch-column-control) + (let* ((available-width (- (window-width) notmuch-hello-indent)) + (proposed-width (max (* available-width notmuch-column-control) widest))) +(floor available-width proposed-width))) + + (t + (max 1 + (/ (- (window-width) notmuch-hello-indent) + ;; Count is 7 wide (6 digits plus space), 1 for the space + ;; after the name. + (+ 7 1 widest))) + +(cons tags-per-line (/ (- (window-width) notmuch-hello-indent + (* tags-per-line (+ 7 1))) + tags-per-line + (defun notmuch-hello-insert-tags (tag-alist widest target) - (let* ((tags-per-line (max 1 -(/ (- (window-width) notmuch-hello-indent) - ;; Count is 7 wide (6 digits plus - ;; space), 1 for the space after the - ;; name. - (+ 7 1 widest + (let* ((tags-and-width (notmuch-hello-tags-per-line widest)) +(tags-per-line (car tags-and-width)) +(widest (cdr tags-and-width)) (count 0) (reordered-list (notmuch-hello-reflect tag-alist tags-per-line)) ;; Hack the display of the buttons used. -- 1.7.1 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 02/13] notmuch: Fix off-by-one errors if a header is >200 characters long.
If a single header is more than 200 characters long a set of 'off by one' errors cause memory corruption. When allocating memory with: a = malloc (len); the last usable byte of the memory is 'a + len - 1' rather than 'a + len'. Fix the same bug when calculating the current offset should the buffer used for collecting the output header need to be reallocated. --- gmime-filter-headers.c |6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gmime-filter-headers.c b/gmime-filter-headers.c index 2f3df80..7db3779 100644 --- a/gmime-filter-headers.c +++ b/gmime-filter-headers.c @@ -169,7 +169,7 @@ filter_filter (GMimeFilter *filter, char *inbuf, size_t inlen, size_t prespace, headers->lineptr = headers->line = malloc (headers->line_size); } lineptr = headers->lineptr; - lineend = headers->line + headers->line_size; + lineend = headers->line + headers->line_size - 1; if (lineptr == NULL) return; outptr = filter->outbuf; @@ -185,8 +185,8 @@ filter_filter (GMimeFilter *filter, char *inbuf, size_t inlen, size_t prespace, if (lineptr == lineend) { headers->line_size *= 2; headers->line = xrealloc (headers->line, headers->line_size); - lineptr = headers->line + headers->line_size / 2; - lineend = headers->line + headers->line_size; + lineptr = headers->line + (headers->line_size / 2) - 1; + lineend = headers->line + headers->line_size - 1; } if (headers->saw_nl && *inptr != ' ' && *inptr != '\t') { -- 1.7.1 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 06/13] emacs: Allow control over faces for search mode columns.
Add face declarations for the date, count, matching author and subject columns in search mode and apply those faces when building the search mode display. --- emacs/notmuch.el | 59 +++-- 1 files changed, 43 insertions(+), 16 deletions(-) diff --git a/emacs/notmuch.el b/emacs/notmuch.el index d36a92d..7c9c028 100644 --- a/emacs/notmuch.el +++ b/emacs/notmuch.el @@ -285,27 +285,48 @@ For a mouse binding, return nil." "Face for the single-line message summary in notmuch-show-mode." :group 'notmuch) -(defface notmuch-tag-face +(defface notmuch-search-date + '((t :inherit default)) + "Face used in search mode for dates." + :group 'notmuch) + +(defface notmuch-search-count + '((t :inherit default)) + "Face used in search mode for the count matching the query." + :group 'notmuch) + +(defface notmuch-search-subject + '((t :inherit default)) + "Face used in search mode for subjects." + :group 'notmuch) + +(defface notmuch-search-matching-authors + '((t :inherit default)) + "Face used in search mode for authors matching the query." + :group 'notmuch) + +(defface notmuch-search-non-matching-authors 'class color) (background dark)) - (:foreground "OliveDrab1")) + (:foreground "grey30")) (((class color) (background light)) - (:foreground "navy blue" :bold t)) + (:foreground "grey60")) (t - (:bold t))) - "Notmuch search mode face used to highligh tags." + (:italic t))) + "Face used in search mode for authors not matching the query." :group 'notmuch) -(defface notmuch-search-non-matching-authors +(defface notmuch-tag-face 'class color) (background dark)) - (:foreground "grey30")) + (:foreground "OliveDrab1")) (((class color) (background light)) - (:foreground "grey60")) -(t (:italic t))) - "Face used in search mode for authors not matching the query." + (:foreground "navy blue" :bold t)) +(t + (:bold t))) + "Face used in search mode face for tags." :group 'notmuch) ;;;###autoload @@ -599,21 +620,27 @@ matching will be applied." ;; `notmuch-search-process-filter'. (save-match-data (if (string-match "\\(.*\\)|\\(..*\\)" truncated-string) - (concat (match-string 1 truncated-string) "," + (concat (propertize (concat (match-string 1 truncated-string) ",") + 'face 'notmuch-search-matching-authors) (propertize (match-string 2 truncated-string) 'face 'notmuch-search-non-matching-authors)) - truncated-string) + (propertize truncated-string 'face 'notmuch-search-matching-authors)) (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))) +(insert (propertize (format (cdr (assoc field notmuch-search-result-format)) date) + 'face 'notmuch-search-date))) ((string-equal field "count") -(insert (format (cdr (assoc field notmuch-search-result-format)) count))) +(insert (propertize (format (cdr (assoc field notmuch-search-result-format)) count) + 'face 'notmuch-search-count))) + ((string-equal field "subject") +(insert (propertize (format (cdr (assoc field notmuch-search-result-format)) subject) + 'face 'notmuch-search-subject))) + ((string-equal field "authors") (notmuch-search-insert-authors (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) ")") -- 1.7.1 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 08/13] emacs: Reuse rather than reinvent message header filtering
From: Sebastian Spaeth In notmuch-mua-reply we were filtering out the Subject and To headers manually in a loop, but message mode offers a nice function for exactly that. Simplify the code by using that. Also, as notmuch-mua-mail already sorts and hides headers that we want sorted and hidden, we can safely remove those 2 functions from here as well. Signed-off-by: Sebastian Spaeth --- emacs/notmuch-mua.el |7 +-- 1 files changed, 1 insertions(+), 6 deletions(-) diff --git a/emacs/notmuch-mua.el b/emacs/notmuch-mua.el index bd06e3c..6318c15 100644 --- a/emacs/notmuch-mua.el +++ b/emacs/notmuch-mua.el @@ -92,12 +92,7 @@ list." ((same-window-regexps '("\\*mail .*"))) (notmuch-mua-mail (mail-header 'to headers) (mail-header 'subject headers) - (loop for header in headers - if (not (or (eq 'to (car header)) - (eq 'subject (car header - collect header))) -(message-sort-headers) -(message-hide-headers) + (message-headers-to-generate headers t '(to subject ;; insert the message body - but put it in front of the signature ;; if one is present (goto-char (point-max)) -- 1.7.1 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 05/13] emacs: Set the `face' property rather than `font-lock-face'.
Avoid using face properties reserved for the font-lock package. --- emacs/notmuch.el |2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/emacs/notmuch.el b/emacs/notmuch.el index 60c0ee5..d36a92d 100644 --- a/emacs/notmuch.el +++ b/emacs/notmuch.el @@ -438,7 +438,7 @@ and will also appear in a buffer named \"*Notmuch errors*\"." (let ((end (point))) (delete-region beg end) (insert (propertize (mapconcat 'identity tags " ") - 'font-lock-face 'notmuch-tag-face)) + 'face 'notmuch-tag-face)) (defun notmuch-search-get-tags () (save-excursion -- 1.7.1 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 09/13] emacs: Avoid runtime use of `cl'.
The GNU Emacs Lisp Reference Manual section D.1 says: > * Please don't require the cl package of Common Lisp extensions at >run time. Use of this package is optional, and it is not part of >the standard Emacs namespace. If your package loads cl at run time, >that could cause name clashes for users who don't use that package. > >However, there is no problem with using the cl package at compile >time, with (eval-when-compile (require 'cl)). That's sufficient for >using the macros in the cl package, because the compiler expands >them before generating the byte-code. Follow this advice, requiring the following changes where `cl' was used at runtime: - replace `rassoc-if' in `notmuch-search-buffer-title' with the `loop' macro and inline code. At the same time find the longest prefix which matches the query rather than simply the last, - replace `union', `intersection' and `set-difference' in `notmuch-show-add-tag' and `notmuch-show-remove-tag' with local code to calculate the result of adding and removing a list of tags from another list of tags. --- emacs/notmuch-hello.el |2 +- emacs/notmuch-show.el | 54 +++ emacs/notmuch.el | 16 + 3 files changed, 52 insertions(+), 20 deletions(-) diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el index acf40bc..538785f 100644 --- a/emacs/notmuch-hello.el +++ b/emacs/notmuch-hello.el @@ -19,9 +19,9 @@ ;; ;; Authors: David Edmondson +(eval-when-compile (require 'cl)) (require 'widget) (require 'wid-edit) ; For `widget-forward'. -(require 'cl) (require 'notmuch-lib) (require 'notmuch-mua) diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el index 4b1baf3..ff1a7a7 100644 --- a/emacs/notmuch-show.el +++ b/emacs/notmuch-show.el @@ -21,7 +21,7 @@ ;; Authors: Carl Worth ;; David Edmondson -(require 'cl) +(eval-when-compile (require 'cl)) (require 'mm-view) (require 'message) (require 'mm-decode) @@ -908,29 +908,55 @@ to stdout or stderr will appear in the *Messages* buffer." (list command " < " (shell-quote-argument (notmuch-show-get-filename) +(defun notmuch-show-add-tags-worker (current-tags add-tags) + "Add to `current-tags' with any tags from `add-tags' not +currently present and return the result." + (let ((result-tags (copy-seq current-tags))) +(mapc (lambda (add-tag) + (unless (member add-tag current-tags) + (setq result-tags (push add-tag result-tags + add-tags) +(sort result-tags 'string<))) + +(defun notmuch-show-del-tags-worker (current-tags del-tags) + "Remove any tags in `del-tags' from `current-tags' and return +the result." + (let ((result-tags (copy-seq current-tags))) +(mapc (lambda (del-tag) + (setq result-tags (delete del-tag result-tags))) + del-tags) +result-tags)) + (defun notmuch-show-add-tag (&rest toadd) "Add a tag to the current message." (interactive (list (notmuch-select-tag-with-completion "Tag to add: "))) - (apply 'notmuch-call-notmuch-process -(append (cons "tag" - (mapcar (lambda (s) (concat "+" s)) toadd)) -(cons (notmuch-show-get-message-id) nil))) - (notmuch-show-set-tags (sort (union toadd (notmuch-show-get-tags) :test 'string=) 'string<))) + + (let* ((current-tags (notmuch-show-get-tags)) +(new-tags (notmuch-show-add-tags-worker current-tags toadd))) + +(unless (equal current-tags new-tags) + (apply 'notmuch-call-notmuch-process +(append (cons "tag" + (mapcar (lambda (s) (concat "+" s)) toadd)) +(cons (notmuch-show-get-message-id) nil))) + (notmuch-show-set-tags new-tags (defun notmuch-show-remove-tag (&rest toremove) "Remove a tag from the current message." (interactive (list (notmuch-select-tag-with-completion "Tag to remove: " (notmuch-show-get-message-id - (let ((tags (notmuch-show-get-tags))) -(if (intersection tags toremove :test 'string=) - (progn - (apply 'notmuch-call-notmuch-process -(append (cons "tag" - (mapcar (lambda (s) (concat "-" s)) toremove)) -(cons (notmuch-show-get-message-id) nil))) - (notmuch-show-set-tags (sort (set-difference tags toremove :test 'string=) 'string<)) + + (let* ((current-tags (notmuch-show-get-tags)) +(new-tags (notmuch-show-del-tags-worker current-tags toremove))) + +(unless (equal current-tags new-tags) + (apply 'notmuch-call-notmuch-process +(append (cons "tag" + (mapcar (lambda (s) (concat "-" s)) toremove)) +(cons (notmuch-show-get-message-id) nil))) + (notmuch-show-set-tags new-tags (defun notmuch-show-toggle-headers () "Toggle the visibility of the current message headers." diff --gi
[PATCH 10/13] emacs: In search mode, truncate authors using invisible text.
Rather than discarding authors when truncated to fit the defined column width, mark the text beyond the end of the column as invisible and allow `isearch' to be used over the text so hidden. This allows us to retain the compact display whilst enabling a user to find the elided text. --- emacs/notmuch.el | 61 +++-- 1 files changed, 45 insertions(+), 16 deletions(-) diff --git a/emacs/notmuch.el b/emacs/notmuch.el index c2fefe5..10babe4 100644 --- a/emacs/notmuch.el +++ b/emacs/notmuch.el @@ -608,23 +608,52 @@ matching will be applied." (t (setq tags-faces (cdr tags-faces) +(defun notmuch-search-isearch-authors-show (overlay) + (remove-from-invisibility-spec (cons (overlay-get overlay 'invisible) t))) + (defun notmuch-search-insert-authors (format-string authors) - (insert (let* ((formatted-sample (format format-string "")) -(formatted-authors (format format-string authors)) -(truncated-string - (if (> (length formatted-authors) -(length formatted-sample)) - (concat (substring authors 0 (- (length formatted-sample) 4)) "... ") - formatted-authors))) - ;; Need to save the match data to avoid interfering with - ;; `notmuch-search-process-filter'. - (save-match-data - (if (string-match "\\(.*\\)|\\(..*\\)" truncated-string) - (concat (propertize (concat (match-string 1 truncated-string) ",") - 'face 'notmuch-search-matching-authors) - (propertize (match-string 2 truncated-string) - 'face 'notmuch-search-non-matching-authors)) - (propertize truncated-string 'face 'notmuch-search-matching-authors)) + (let* ((propertized-authors + ;; Need to save the match data to avoid interfering with + ;; `notmuch-search-process-filter'. + (save-match-data + ;; Authors that don't match the search query are shown in a + ;; different font. + (if (string-match "\\(.*\\)|\\(..*\\)" authors) + (concat (propertize (concat (match-string 1 authors) ",") + 'face 'notmuch-search-matching-authors) + (propertize (match-string 2 authors) + 'face 'notmuch-search-non-matching-authors)) + (propertize authors 'face 'notmuch-search-matching-authors + +(formatted-sample (format format-string "")) +(formatted-authors (format format-string propertized-authors)) +visible-string invisible-string) + +;; Determine the part of the authors that will be visible by +;; default. +(if (> (length formatted-authors) + (length formatted-sample)) + ;; 4 is `(length "... ")'. + (let ((visible-length (- (length formatted-sample) 4))) + (setq visible-string (substring propertized-authors 0 visible-length) + invisible-string (substring propertized-authors visible-length))) + (setq visible-string formatted-authors + invisible-string nil)) + +;; Insert both the visible and invisible author strings. +(insert visible-string) +(when invisible-string + (let ((start (point)) + (invis-spec (make-symbol "notmuch-search-authors")) + overlay) + (insert invisible-string) + ;; Using a cons-cell here causes an ellipsis to be inserted + ;; instead of the invisible text. + (add-to-invisibility-spec (cons invis-spec t)) + (setq overlay (make-overlay start (point))) + (overlay-put overlay 'invisible invis-spec) + (overlay-put overlay 'isearch-open-invisible #'notmuch-search-isearch-authors-show) + (insert " ") (defun notmuch-search-insert-field (field date count authors subject tags) (cond -- 1.7.1 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
patches for 0.4
This is a set of small feature and cleanup patches. The only particularly significant one is patch 2, as it fixes a memory corruption bug in notmuch. dme. [PATCH 01/13] emacs: Usability improvements for `notmuch-hello'. [PATCH 02/13] notmuch: Fix off-by-one errors if a header is >200 characters long. [PATCH 03/13] emacs: Adjust comment to avoid confusing font-lock. [PATCH 04/13] emacs: Display non-matching authors with a different face. [PATCH 05/13] emacs: Set the `face' property rather than `font-lock-face'. [PATCH 06/13] emacs: Allow control over faces for search mode columns. [PATCH 07/13] emacs: Allow tuning of the tag/saved search layout. [PATCH 08/13] emacs: Reuse rather than reinvent message header filtering [PATCH 09/13] emacs: Avoid runtime use of `cl'. [PATCH 10/13] emacs: In search mode, truncate authors using invisible text. [PATCH 11/13] emacs: Pretty print the numbers of matching messages. [PATCH 12/13] emacs: Tags should be shown with `notmuch-tag-face'. [PATCH 13/13] emacs: Allow the display of absolute dates in the header line. ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 04/13] emacs: Display non-matching authors with a different face.
In search mode some messages don't match the search criteria. Show their authors names with a different face - generally darker than those that do match. --- emacs/notmuch.el | 36 +--- 1 files changed, 29 insertions(+), 7 deletions(-) diff --git a/emacs/notmuch.el b/emacs/notmuch.el index 7457da9..60c0ee5 100644 --- a/emacs/notmuch.el +++ b/emacs/notmuch.el @@ -297,6 +297,17 @@ For a mouse binding, return nil." "Notmuch search mode face used to highligh tags." :group 'notmuch) +(defface notmuch-search-non-matching-authors + 'class color) + (background dark)) + (:foreground "grey30")) +(((class color) + (background light)) + (:foreground "grey60")) +(t (:italic t))) + "Face used in search mode for authors not matching the query." + :group 'notmuch) + ;;;###autoload (defun notmuch-search-mode () "Major mode displaying results of a notmuch search. @@ -576,6 +587,23 @@ matching will be applied." (t (setq tags-faces (cdr tags-faces) +(defun notmuch-search-insert-authors (format-string authors) + (insert (let* ((formatted-sample (format format-string "")) +(formatted-authors (format format-string authors)) +(truncated-string + (if (> (length formatted-authors) +(length formatted-sample)) + (concat (substring authors 0 (- (length formatted-sample) 4)) "... ") + formatted-authors))) + ;; Need to save the match data to avoid interfering with + ;; `notmuch-search-process-filter'. + (save-match-data + (if (string-match "\\(.*\\)|\\(..*\\)" truncated-string) + (concat (match-string 1 truncated-string) "," + (propertize (match-string 2 truncated-string) + 'face 'notmuch-search-non-matching-authors)) + truncated-string) + (defun notmuch-search-insert-field (field date count authors subject tags) (cond ((string-equal field "date") @@ -583,13 +611,7 @@ matching will be applied." ((string-equal field "count") (insert (format (cdr (assoc field notmuch-search-result-format)) count))) ((string-equal field "authors") -(insert (let* ((format-string (cdr (assoc field notmuch-search-result-format))) - (formatted-sample (format format-string "")) - (formatted-authors (format format-string authors))) - (if (> (length formatted-authors) -(length formatted-sample)) - (concat (substring authors 0 (- (length formatted-sample) 4)) "... ") - formatted-authors +(notmuch-search-insert-authors (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") -- 1.7.1 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 11/13] emacs: Pretty print the numbers of matching messages.
Insert a separator every three digits when outputting numbers. Allow the user to choose the separator by customizing `notmuch-decimal-separator'. Widen the space allocated for message counts accordingly. --- emacs/notmuch-hello.el | 38 +++--- 1 files changed, 31 insertions(+), 7 deletions(-) diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el index 538785f..7ade0eb 100644 --- a/emacs/notmuch-hello.el +++ b/emacs/notmuch-hello.el @@ -91,6 +91,13 @@ So: (integer :tag "Number of characters") (float :tag "Fraction of window"))) +(defcustom notmuch-decimal-separator "," + "The string used as a decimal separator. + +Typically \",\" in the US and UK and \".\" in Europe." + :group 'notmuch + :type 'string) + (defvar notmuch-hello-url "http://notmuchmail.org"; "The `notmuch' web site.") @@ -103,6 +110,17 @@ So: notmuch-recent-searches-max) (setq notmuch-hello-recent-searches (butlast notmuch-hello-recent-searches +(defun notmuch-hello-nice-number (n) + (let (result) +(while (> n 0) + (push (% n 1000) result) + (setq n (/ n 1000))) +(apply #'concat + (number-to-string (car result)) + (mapcar (lambda (elem) + (format "%s%03d" notmuch-decimal-separator elem)) +(cdr result) + (defun notmuch-hello-trim (search) "Trim whitespace." (if (string-match "^[[:space:]]*\\(.*[^[:space:]]\\)[[:space:]]*$" search) @@ -180,9 +198,9 @@ should be. Returns a cons cell `(tags-per-line width)'." ((integerp notmuch-column-control) (max 1 (/ (- (window-width) notmuch-hello-indent) - ;; Count is 7 wide (6 digits plus space), 1 for the space + ;; Count is 9 wide (8 digits plus space), 1 for the space ;; after the name. - (+ 7 1 (max notmuch-column-control widest) + (+ 9 1 (max notmuch-column-control widest) ((floatp notmuch-column-control) (let* ((available-width (- (window-width) notmuch-hello-indent)) @@ -192,12 +210,15 @@ should be. Returns a cons cell `(tags-per-line width)'." (t (max 1 (/ (- (window-width) notmuch-hello-indent) - ;; Count is 7 wide (6 digits plus space), 1 for the space + ;; Count is 9 wide (8 digits plus space), 1 for the space ;; after the name. - (+ 7 1 widest))) + (+ 9 1 widest))) (cons tags-per-line (/ (- (window-width) notmuch-hello-indent - (* tags-per-line (+ 7 1))) + ;; Count is 9 wide (8 digits plus + ;; space), 1 for the space after the + ;; name. + (* tags-per-line (+ 9 1))) tags-per-line (defun notmuch-hello-insert-tags (tag-alist widest target) @@ -218,7 +239,9 @@ should be. Returns a cons cell `(tags-per-line width)'." (let* ((name (car elem)) (query (cdr elem)) (formatted-name (format "%s " name))) - (widget-insert (format "%6s " (notmuch-saved-search-count query))) + (widget-insert (format "%8s " + (notmuch-hello-nice-number + (string-to-number (notmuch-saved-search-count query) (if (string= formatted-name target) (setq found-target-pos (point-marker))) (widget-create 'push-button @@ -323,7 +346,8 @@ should be. Returns a cons cell `(tags-per-line width)'." :notify (lambda (&rest ignore) (notmuch-hello-update)) :help-echo "Refresh" -(car (process-lines notmuch-command "count"))) +(notmuch-hello-nice-number + (string-to-number (car (process-lines notmuch-command "count") (widget-insert " messages (that's not much mail).\n")) (let ((found-target-pos nil) -- 1.7.1 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH] emacs: Allow the display of absolute dates in the header line.
Add `notmuch-show-relative-dates' to control whether the summary line in `notmuch-show' mode displays relative dates (e.g. '26 mins. ago') or the full date string from the message. Default to `t' for compatibility with the previous behaviour. --- Re: > one thing I'd love for 0.4 (and haven't seen a patch for) is the > ability to disable the "xxmins. ago" and simply have it always > display the time a message arrived emacs/notmuch-show.el |9 - 1 files changed, 8 insertions(+), 1 deletions(-) diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el index 5b0050a..2a95e62 100644 --- a/emacs/notmuch-show.el +++ b/emacs/notmuch-show.el @@ -64,6 +64,11 @@ any given message." :group 'notmuch :type 'boolean) +(defcustom notmuch-show-relative-dates t + "Display relative dates in the message summary line." + :group 'notmuch + :type 'boolean) + (defvar notmuch-show-markup-headers-hook '(notmuch-show-colour-headers) "A list of functions called to decorate the headers listed in `notmuch-message-headers'.") @@ -592,7 +597,9 @@ current buffer, if possible." (setq message-start (point-marker)) (notmuch-show-insert-headerline headers - (or (plist-get msg :date_relative) + (or (if notmuch-show-relative-dates + (plist-get msg :date_relative) + nil) (plist-get headers :Date)) (plist-get msg :tags) depth) -- 1.7.1 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 12/13] emacs: Tags should be shown with `notmuch-tag-face'.
Use the same face for tags in `notmuch-show' mode as that used in `notmuch-search' mode. --- emacs/notmuch-show.el |6 -- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el index ff1a7a7..7601857 100644 --- a/emacs/notmuch-show.el +++ b/emacs/notmuch-show.el @@ -189,7 +189,8 @@ any given message." (if (re-search-forward "(\\([^()]*\\))$" (line-end-position) t) (let ((inhibit-read-only t)) (replace-match (concat "(" -(mapconcat 'identity tags " ") +(propertize (mapconcat 'identity tags " ") +'face 'notmuch-tag-face) ")")) (defun notmuch-show-insert-headerline (headers date tags depth) @@ -201,7 +202,8 @@ message at DEPTH in the current thread." " (" date ") (" - (mapconcat 'identity tags " ") + (propertize (mapconcat 'identity tags " ") + 'face 'notmuch-tag-face) ")\n") (overlay-put (make-overlay start (point)) 'face 'notmuch-message-summary-face))) -- 1.7.1 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 13/13] emacs: Allow the display of absolute dates in the header line.
Add `notmuch-show-relative-dates' to control whether the summary line in `notmuch-show' mode displays relative dates (e.g. '26 mins ago') or the full date string from the message. Default to `t' for compatibility with the previous behaviour. --- emacs/notmuch-show.el |9 - 1 files changed, 8 insertions(+), 1 deletions(-) diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el index 7601857..cbc3012 100644 --- a/emacs/notmuch-show.el +++ b/emacs/notmuch-show.el @@ -58,6 +58,11 @@ any given message." :group 'notmuch :type 'boolean) +(defcustom notmuch-show-relative-dates t + "Display relative dates in the message summary line." + :group 'notmuch + :type 'boolean) + (defvar notmuch-show-markup-headers-hook '(notmuch-show-colour-headers) "A list of functions called to decorate the headers listed in `notmuch-message-headers'.") @@ -407,7 +412,9 @@ current buffer, if possible." (setq message-start (point-marker)) (notmuch-show-insert-headerline headers - (or (plist-get msg :date_relative) + (or (if notmuch-show-relative-dates + (plist-get msg :date_relative) + nil) (plist-get headers :Date)) (plist-get msg :tags) depth) -- 1.7.1 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 01/13] emacs: Usability improvements for `notmuch-hello'.
- If no saved searches exist or are displayed, don't signal an error, - If no saved searches exist or are displayed, leave the cursor in the search bar, - Minor layout improvements. --- emacs/notmuch-hello.el | 36 +++- 1 files changed, 19 insertions(+), 17 deletions(-) diff --git a/emacs/notmuch-hello.el b/emacs/notmuch-hello.el index 6a1c56e..1358387 100644 --- a/emacs/notmuch-hello.el +++ b/emacs/notmuch-hello.el @@ -273,7 +273,7 @@ diagonal." (notmuch-hello-update)) :help-echo "Refresh" (car (process-lines notmuch-command "count"))) - (widget-insert " messages (that's not much mail).\n\n")) + (widget-insert " messages (that's not much mail).\n")) (let ((found-target-pos nil) (final-target-pos nil)) @@ -292,7 +292,7 @@ diagonal." (widest (max saved-widest alltags-widest))) (when saved-alist - (widget-insert "Saved searches: ") + (widget-insert "\nSaved searches: ") (widget-create 'push-button :notify (lambda (&rest ignore) (customize-variable 'notmuch-saved-searches)) @@ -305,18 +305,16 @@ diagonal." (setq final-target-pos found-target-pos)) (indent-rigidly start (point) notmuch-hello-indent))) - (let ((start (point))) - (widget-insert "\nSearch: ") - (setq notmuch-hello-search-bar-marker (point-marker)) - (widget-create 'editable-field -;; Leave some space at the start and end of the -;; search boxes. -:size (max 8 (- (window-width) (* 2 notmuch-hello-indent) -(length "Search: "))) -:action (lambda (widget &rest ignore) - (notmuch-hello-search (widget-value widget - (widget-insert "\n") - (indent-rigidly start (point) notmuch-hello-indent)) + (widget-insert "\nSearch: ") + (setq notmuch-hello-search-bar-marker (point-marker)) + (widget-create 'editable-field + ;; Leave some space at the start and end of the + ;; search boxes. + :size (max 8 (- (window-width) notmuch-hello-indent + (length "Search: "))) + :action (lambda (widget &rest ignore) +(notmuch-hello-search (widget-value widget + (widget-insert "\n") (when notmuch-hello-recent-searches (widget-insert "\nRecent searches: ") @@ -408,9 +406,13 @@ diagonal." (widget-setup) - (goto-char final-target-pos) - (if (not (widget-at)) - (widget-forward 1) + (when final-target-pos + (goto-char final-target-pos) + (unless (widget-at) + (widget-forward 1))) + + (unless (widget-at) + (notmuch-hello-goto-search) ;;;###autoload (defun notmuch-folder () -- 1.7.1 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch