* [PATCH v2 0/7] emacs: show tag changes in buffer
@ 2014-02-19 20:20 Mark Walters
2014-02-19 20:20 ` [PATCH v2 1/7] Make keys of notmuch-tag-formats regexps and use caching Mark Walters
` (7 more replies)
0 siblings, 8 replies; 16+ messages in thread
From: Mark Walters @ 2014-02-19 20:20 UTC (permalink / raw)
To: notmuch
This is v2 of the patch set. Version 1 is at
id:1390087855-26194-1-git-send-email-markwalters1009@gmail.com.
The changes in this version are: use regexp tag-format matching (a
slightly tweaked version of Austin's patch
id:1392226351-31440-1-git-send-email-amdragon@mit.edu), make the
tag-deleted/added formats apply on top of the normal tag-formatting,
and fixup the way the :orig-tags field is added in notmuch-search.
I think this version fixes all outstanding review comments.
Best wishes
Mark
Austin Clements (1):
Make keys of notmuch-tag-formats regexps and use caching
Mark Walters (6):
emacs: tag split customise option for format-tags into a widget
emacs: tag: add customize for deleted/added tag formats
emacs: show: mark tags changed since buffer loaded
emacs: show: use orig-tags for tag display
emacs: search: use orig-tags in search
emacs: tree: use orig-tags in search
emacs/notmuch-show.el | 7 ++-
emacs/notmuch-tag.el | 179 +++++++++++++++++++++++++++++++++++++-----------
emacs/notmuch-tree.el | 10 ++-
emacs/notmuch.el | 41 +++++++-----
test/test-lib.el | 5 ++
5 files changed, 180 insertions(+), 62 deletions(-)
--
1.7.9.1
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v2 1/7] Make keys of notmuch-tag-formats regexps and use caching
2014-02-19 20:20 [PATCH v2 0/7] emacs: show tag changes in buffer Mark Walters
@ 2014-02-19 20:20 ` Mark Walters
2014-03-11 2:06 ` Austin Clements
2014-02-19 20:20 ` [PATCH v2 2/7] emacs: tag split customise option for format-tags into a widget Mark Walters
` (6 subsequent siblings)
7 siblings, 1 reply; 16+ messages in thread
From: Mark Walters @ 2014-02-19 20:20 UTC (permalink / raw)
To: notmuch
From: Austin Clements <amdragon@MIT.EDU>
This patch switches notmuch-tag-formats to use regexps with caching
for performance.
We have to clear the cache somehow on changes to notmuch-tag-formats.
This version takes the simplest approach: search/show/tree all clear
the cache whenever they start loading.
We cannot use assoc-default since there's no way to distinguish a
missing key from a present key with a null cdr: thus, we use assoc*
from cl instead.
Performance-wise, the caching of regexp lookup makes this at least as
fast as the previous code using assoc (see
id:1392226351-31440-1-git-send-email-amdragon@mit.edu for timing
details).
---
emacs/notmuch-show.el | 1 +
emacs/notmuch-tag.el | 70 +++++++++++++++++++++++++++++++++---------------
emacs/notmuch-tree.el | 1 +
emacs/notmuch.el | 1 +
4 files changed, 51 insertions(+), 22 deletions(-)
diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 1ac80ca..4bddf6c 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -1145,6 +1145,7 @@ function is used."
;; Don't track undo information for this buffer
(set 'buffer-undo-list t)
+ (notmuch-tag-clear-cache)
(erase-buffer)
(goto-char (point-min))
(save-excursion
diff --git a/emacs/notmuch-tag.el b/emacs/notmuch-tag.el
index 908e7ad..47e0205 100644
--- a/emacs/notmuch-tag.el
+++ b/emacs/notmuch-tag.el
@@ -28,23 +28,39 @@
(require 'crm)
(require 'notmuch-lib)
+;; (notmuch-tag-clear-cache will be called by the defcustom
+;; notmuch-tag-formats, so it has to be defined first.)
+
+(defvar notmuch-tag--format-cache (make-hash-table :test 'equal)
+ "Cache of tag format lookup. Internal to `notmuch-tag-format-tag'.")
+
+(defun notmuch-tag-clear-cache ()
+ "Clear the internal cache of tag formats.
+
+This must be called after changes to `notmuch-tag-formats'."
+ (clrhash notmuch-tag--format-cache))
+
(defcustom notmuch-tag-formats
'(("unread" (propertize tag 'face '(:foreground "red")))
("flagged" (propertize tag 'face '(:foreground "blue"))
(notmuch-tag-format-image-data tag (notmuch-tag-star-icon))))
"Custom formats for individual tags.
-This gives a list that maps from tag names to lists of formatting
-expressions. The car of each element gives a tag name and the
-cdr gives a list of Elisp expressions that modify the tag. If
-the list is empty, the tag will simply be hidden. Otherwise,
-each expression will be evaluated in order: for the first
-expression, the variable `tag' will be bound to the tag name; for
-each later expression, the variable `tag' will be bound to the
-result of the previous expression. In this way, each expression
-can build on the formatting performed by the previous expression.
-The result of the last expression will displayed in place of the
-tag.
+This is an association list that maps from tag name regexps to
+lists of formatting expressions. The first entry whose car
+regexp-matches a tag will be used to format that tag. The regexp
+is implicitly anchored, so to match a literal tag name, just use
+that tag name (if it contains special regexp characters like
+\".\" or \"*\", these have to be escaped). The cdr of the
+matching entry gives a list of Elisp expressions that modify the
+tag. If the list is empty, the tag will simply be hidden.
+Otherwise, each expression will be evaluated in order: for the
+first expression, the variable `tag' will be bound to the tag
+name; for each later expression, the variable `tag' will be bound
+to the result of the previous expression. In this way, each
+expression can build on the formatting performed by the previous
+expression. The result of the last expression will displayed in
+place of the tag.
For example, to replace a tag with another string, simply use
that string as a formatting expression. To change the foreground
@@ -56,7 +72,7 @@ with images."
:group 'notmuch-search
:group 'notmuch-show
- :type '(alist :key-type (string :tag "Tag")
+ :type '(alist :key-type (regexp :tag "Tag")
:extra-offset -3
:value-type
(radio :format "%v"
@@ -137,16 +153,26 @@ This can be used with `notmuch-tag-format-image-data'."
(defun notmuch-tag-format-tag (tag)
"Format TAG by looking into `notmuch-tag-formats'."
- (let ((formats (assoc tag notmuch-tag-formats)))
- (cond
- ((null formats) ;; - Tag not in `notmuch-tag-formats',
- tag) ;; the format is the tag itself.
- ((null (cdr formats)) ;; - Tag was deliberately hidden,
- nil) ;; no format must be returned
- (t ;; - Tag was found and has formats,
- (let ((tag tag)) ;; we must apply all the formats.
- (dolist (format (cdr formats) tag)
- (setq tag (eval format))))))))
+ (let ((formatted (gethash tag notmuch-tag--format-cache 'missing)))
+ (when (eq formatted 'missing)
+ (let* ((formats
+ (save-match-data
+ (assoc* tag notmuch-tag-formats
+ :test (lambda (tag key)
+ (and (eq (string-match key tag) 0)
+ (= (match-end 0) (length tag))))))))
+ (setq formatted
+ (cond
+ ((null formats) ;; - Tag not in `notmuch-tag-formats',
+ tag) ;; the format is the tag itself.
+ ((null (cdr formats)) ;; - Tag was deliberately hidden,
+ nil) ;; no format must be returned
+ (t ;; - Tag was found and has formats,
+ (let ((tag tag)) ;; we must apply all the formats.
+ (dolist (format (cdr formats) tag)
+ (setq tag (eval format)))))))
+ (puthash tag formatted notmuch-tag--format-cache)))
+ formatted))
(defun notmuch-tag-format-tags (tags &optional face)
"Return a string representing formatted TAGS."
diff --git a/emacs/notmuch-tree.el b/emacs/notmuch-tree.el
index 4f2ac02..a106e09 100644
--- a/emacs/notmuch-tree.el
+++ b/emacs/notmuch-tree.el
@@ -881,6 +881,7 @@ the same as for the function notmuch-tree."
(message-arg "--entire-thread"))
(if (equal (car (process-lines notmuch-command "count" search-args)) "0")
(setq search-args basic-query))
+ (notmuch-tag-clear-cache)
(let ((proc (notmuch-start-notmuch
"notmuch-tree" (current-buffer) #'notmuch-tree-process-sentinel
"show" "--body=false" "--format=sexp"
diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index 0471750..0c767f7 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -888,6 +888,7 @@ the configured default sort order."
(set 'notmuch-search-oldest-first oldest-first)
(set 'notmuch-search-target-thread target-thread)
(set 'notmuch-search-target-line target-line)
+ (notmuch-tag-clear-cache)
(let ((proc (get-buffer-process (current-buffer)))
(inhibit-read-only t))
(if proc
--
1.7.9.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v2 2/7] emacs: tag split customise option for format-tags into a widget
2014-02-19 20:20 [PATCH v2 0/7] emacs: show tag changes in buffer Mark Walters
2014-02-19 20:20 ` [PATCH v2 1/7] Make keys of notmuch-tag-formats regexps and use caching Mark Walters
@ 2014-02-19 20:20 ` Mark Walters
2014-02-19 20:20 ` [PATCH v2 3/7] emacs: tag: add customize for deleted/added tag formats Mark Walters
` (5 subsequent siblings)
7 siblings, 0 replies; 16+ messages in thread
From: Mark Walters @ 2014-02-19 20:20 UTC (permalink / raw)
To: notmuch
We will re-use the customize option for format-tags for formattting
deleted tags to added tags in the next patch so split it into a
widget. There should be no functional change.
---
emacs/notmuch-tag.el | 55 ++++++++++++++++++++++++++-----------------------
1 files changed, 29 insertions(+), 26 deletions(-)
diff --git a/emacs/notmuch-tag.el b/emacs/notmuch-tag.el
index 47e0205..878aaf7 100644
--- a/emacs/notmuch-tag.el
+++ b/emacs/notmuch-tag.el
@@ -40,6 +40,34 @@
This must be called after changes to `notmuch-tag-formats'."
(clrhash notmuch-tag--format-cache))
+(define-widget 'notmuch-tag-format-type 'lazy
+ "Customize widget for notmuch-tag-format and friends"
+ :type '(alist :key-type (regexp :tag "Tag")
+ :extra-offset -3
+ :value-type
+ (radio :format "%v"
+ (const :tag "Hidden" nil)
+ (set :tag "Modified"
+ (string :tag "Display as")
+ (list :tag "Face" :extra-offset -4
+ (const :format "" :inline t
+ (propertize tag 'face))
+ (list :format "%v"
+ (const :format "" quote)
+ custom-face-edit))
+ (list :format "%v" :extra-offset -4
+ (const :format "" :inline t
+ (notmuch-tag-format-image-data tag))
+ (choice :tag "Image"
+ (const :tag "Star"
+ (notmuch-tag-star-icon))
+ (const :tag "Empty star"
+ (notmuch-tag-star-empty-icon))
+ (const :tag "Tag"
+ (notmuch-tag-tag-icon))
+ (string :tag "Custom")))
+ (sexp :tag "Custom")))))
+
(defcustom notmuch-tag-formats
'(("unread" (propertize tag 'face '(:foreground "red")))
("flagged" (propertize tag 'face '(:foreground "blue"))
@@ -69,34 +97,9 @@ of a tag to red, use the expression
See also `notmuch-tag-format-image', which can help replace tags
with images."
-
:group 'notmuch-search
:group 'notmuch-show
- :type '(alist :key-type (regexp :tag "Tag")
- :extra-offset -3
- :value-type
- (radio :format "%v"
- (const :tag "Hidden" nil)
- (set :tag "Modified"
- (string :tag "Display as")
- (list :tag "Face" :extra-offset -4
- (const :format "" :inline t
- (propertize tag 'face))
- (list :format "%v"
- (const :format "" quote)
- custom-face-edit))
- (list :format "%v" :extra-offset -4
- (const :format "" :inline t
- (notmuch-tag-format-image-data tag))
- (choice :tag "Image"
- (const :tag "Star"
- (notmuch-tag-star-icon))
- (const :tag "Empty star"
- (notmuch-tag-star-empty-icon))
- (const :tag "Tag"
- (notmuch-tag-tag-icon))
- (string :tag "Custom")))
- (sexp :tag "Custom")))))
+ :type 'notmuch-tag-format-type)
(defun notmuch-tag-format-image-data (tag data)
"Replace TAG with image DATA, if available.
--
1.7.9.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v2 3/7] emacs: tag: add customize for deleted/added tag formats
2014-02-19 20:20 [PATCH v2 0/7] emacs: show tag changes in buffer Mark Walters
2014-02-19 20:20 ` [PATCH v2 1/7] Make keys of notmuch-tag-formats regexps and use caching Mark Walters
2014-02-19 20:20 ` [PATCH v2 2/7] emacs: tag split customise option for format-tags into a widget Mark Walters
@ 2014-02-19 20:20 ` Mark Walters
2014-03-11 2:09 ` Austin Clements
2014-03-11 2:37 ` Austin Clements
2014-02-19 20:20 ` [PATCH v2 4/7] emacs: show: mark tags changed since buffer loaded Mark Walters
` (4 subsequent siblings)
7 siblings, 2 replies; 16+ messages in thread
From: Mark Walters @ 2014-02-19 20:20 UTC (permalink / raw)
To: notmuch
Add customize options for deleted/added tag formats. These are not
used yet but will be later in the series.
---
emacs/notmuch-tag.el | 31 +++++++++++++++++++++++++++++++
1 files changed, 31 insertions(+), 0 deletions(-)
diff --git a/emacs/notmuch-tag.el b/emacs/notmuch-tag.el
index 878aaf7..064fbdb 100644
--- a/emacs/notmuch-tag.el
+++ b/emacs/notmuch-tag.el
@@ -101,6 +101,37 @@ with images."
:group 'notmuch-show
:type 'notmuch-tag-format-type)
+(defcustom notmuch-tag-deleted-formats
+ '((".*" (propertize tag 'face
+ (if (display-supports-face-attributes-p '(:strike-through "red"))
+ '(:strike-through "red")
+ '(:inverse-video t)))))
+ "Custom formats for tags when deleted.
+
+For deleted tags the formats in `notmuch-tag-formats` are applied
+first and then these formats are applied on top.
+
+By default this shows deleted tags with strike-through in red,
+unless strike-through is not available (e.g., emacs is running in
+a terminal) in which case it uses inverse video. To hide deleted
+tags completely set this to
+ '((\"\" nil))
+
+See `notmuch-tag-formats' for full documentation."
+ :group 'notmuch-show
+ :type 'notmuch-tag-format-type)
+
+(defcustom notmuch-tag-added-formats
+ '((".*" (propertize tag 'face '(:underline "green"))))
+ "Custom formats for tags when added.
+
+For added tags the formats in `notmuch-tag-formats` are applied
+first and then these formats are applied on top.
+
+See `notmuch-tag-formats' for full documentation."
+ :group 'notmuch-show
+ :type 'notmuch-tag-format-type)
+
(defun notmuch-tag-format-image-data (tag data)
"Replace TAG with image DATA, if available.
--
1.7.9.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v2 4/7] emacs: show: mark tags changed since buffer loaded
2014-02-19 20:20 [PATCH v2 0/7] emacs: show tag changes in buffer Mark Walters
` (2 preceding siblings ...)
2014-02-19 20:20 ` [PATCH v2 3/7] emacs: tag: add customize for deleted/added tag formats Mark Walters
@ 2014-02-19 20:20 ` Mark Walters
2014-03-11 2:29 ` Austin Clements
2014-02-19 20:20 ` [PATCH v2 5/7] emacs: show: use orig-tags for tag display Mark Walters
` (3 subsequent siblings)
7 siblings, 1 reply; 16+ messages in thread
From: Mark Walters @ 2014-02-19 20:20 UTC (permalink / raw)
To: notmuch
This allows (and requires) the original-tags to be passed along with
the current-tags to be passed to notmuch-tag-format-tags. This allows
the tag formatting to show added and deleted tags.By default a removed
tag is displayed with strike-through in red (if strike-through is not
available, eg on a terminal, inverse video is used instead) and an
added tag is displayed underlined in green.
If the caller does not wish to use the new feature it can pass
current-tags for both arguments and, at this point, we do exactly that
in the three callers of this function.
Note, we cannot tidily allow original-tags to be optional because we would
need to distinguish nil meaning "we are not specifying original-tags"
from nil meaning there were no original-tags (an empty list).
We use this in subsequent patches to make it clear when a message was
unread when you first loaded a show buffer (previously the unread tag
could be removed before a user realised that it had been unread).
The code adds into the existing tag formatting code. The user can
specify exactly how a tag should be displayed normally, when deleted,
or when added. For convenience an entry for the empty string in the
notmuch-tag-formats (and the corresponding notmuch-tag-deleted-formats
notmuch-tag-added-formats) is applied to all tags which do not have an
explicit match.
This means that a user can tell notmuch not to show deleted tags at
all by setting notmuch-tag-deleted-formats to
'(("" nil))
or not to show any deleted tags except "unread" by setting it to
'(("" nil)
("unread" (propertize tag 'face '(strike-through "red"))))
All the variables are customizable; however, more complicated cases
like changing the face depending on the type of display will require
custom lisp.
Currently this overrides notmuch-tag-deleted-formats for the tests
setting it to '(("" nil)) so that they get removed from the display
and, thus, all tests still pass.
---
emacs/notmuch-show.el | 4 +-
emacs/notmuch-tag.el | 65 ++++++++++++++++++++++++++++++++++++++----------
emacs/notmuch-tree.el | 2 +-
emacs/notmuch.el | 2 +-
test/test-lib.el | 5 ++++
5 files changed, 60 insertions(+), 18 deletions(-)
diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 4bddf6c..719e7d1 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -344,7 +344,7 @@ operation on the contents of the current buffer."
(if (re-search-forward "(\\([^()]*\\))$" (line-end-position) t)
(let ((inhibit-read-only t))
(replace-match (concat "("
- (notmuch-tag-format-tags tags)
+ (notmuch-tag-format-tags tags tags)
")"))))))
(defun notmuch-clean-address (address)
@@ -423,7 +423,7 @@ message at DEPTH in the current thread."
" ("
date
") ("
- (notmuch-tag-format-tags tags)
+ (notmuch-tag-format-tags tags tags)
")\n")
(overlay-put (make-overlay start (point)) 'face 'notmuch-message-summary-face)))
diff --git a/emacs/notmuch-tag.el b/emacs/notmuch-tag.el
index 064fbdb..869b97d 100644
--- a/emacs/notmuch-tag.el
+++ b/emacs/notmuch-tag.el
@@ -185,36 +185,73 @@ This can be used with `notmuch-tag-format-image-data'."
</g>
</svg>")
-(defun notmuch-tag-format-tag (tag)
- "Format TAG by looking into `notmuch-tag-formats'."
- (let ((formatted (gethash tag notmuch-tag--format-cache 'missing)))
+(defun notmuch-tag-format-tag-by-state (tag formatted-tag tag-state)
+ "Format TAG by looking into the appropriate `notmuch-tag-formats`.
+
+Applies formats for TAG from the appropriate one of
+`notmuch-tag-formats`, `notmuch-tag-deleted-formats` and
+`notmuch-tag-added-formats` based on TAG-STATE to the partially
+formatted tag FORMATTED-TAG."
+ (let ((formatted (gethash (cons tag tag-state) notmuch-tag--format-cache 'missing)))
(when (eq formatted 'missing)
- (let* ((formats
+ (let* ((tag-formats (cond ((null tag-state) notmuch-tag-formats)
+ ((eq 'deleted tag-state) notmuch-tag-deleted-formats)
+ ((eq 'added tag-state) notmuch-tag-added-formats)))
+ (formats
(save-match-data
- (assoc* tag notmuch-tag-formats
+ (assoc* tag tag-formats
:test (lambda (tag key)
(and (eq (string-match key tag) 0)
(= (match-end 0) (length tag))))))))
(setq formatted
(cond
- ((null formats) ;; - Tag not in `notmuch-tag-formats',
- tag) ;; the format is the tag itself.
+ ((null formats) ;; - Tag not in `tag-formats',
+ formatted-tag) ;; the format is the tag itself.
((null (cdr formats)) ;; - Tag was deliberately hidden,
nil) ;; no format must be returned
- (t ;; - Tag was found and has formats,
- (let ((tag tag)) ;; we must apply all the formats.
+ (t
+ ;; Tag was found and has formats, we must apply all
+ ;; the formats. FORMATTED-TAG may be null so treat
+ ;; that as a special case.
+ (let ((tag (or formatted-tag "")))
(dolist (format (cdr formats) tag)
- (setq tag (eval format)))))))
- (puthash tag formatted notmuch-tag--format-cache)))
+ (setq tag (eval format)))
+ (if (and (null formatted-tag)
+ (equal tag ""))
+ nil
+ tag)))))
+ (puthash (cons tag tag-state) formatted notmuch-tag--format-cache)))
formatted))
-(defun notmuch-tag-format-tags (tags &optional face)
+(defun notmuch-tag-format-tag (tags orig-tags tag)
+ "Format TAG by looking into `notmuch-tag-formats'.
+
+TAGS and ORIG-TAGS are lists of the current tags and the original
+tags; tags which have been deleted (i.e., are in ORIG-TAGS but
+are not in TAGS) are shown using formats from
+`notmuch-tag-deleted-formats'; tags which have been added (i.e.,
+are in TAGS but are not in ORIG-TAGS) are shown using formats
+from `notmuch-tag-added-formats' and tags which have not been
+changed (the normal case) are shown using formats from
+`notmuch-tag-formats'"
+ (let* ((formatted-tag (notmuch-tag-format-tag-by-state tag tag nil)))
+ (cond ((not (member tag tags))
+ (notmuch-tag-format-tag-by-state tag formatted-tag 'deleted))
+ ((not (member tag orig-tags))
+ (notmuch-tag-format-tag-by-state tag formatted-tag 'added))
+ (t
+ formatted-tag))))
+
+(defun notmuch-tag-format-tags (tags orig-tags &optional face)
"Return a string representing formatted TAGS."
- (let ((face (or face 'notmuch-tag-face)))
+ (let ((face (or face 'notmuch-tag-face))
+ (all-tags (sort (delete-dups (append tags orig-tags nil)) #'string<)))
(notmuch-combine-face-text-property-string
(mapconcat #'identity
;; nil indicated that the tag was deliberately hidden
- (delq nil (mapcar #'notmuch-tag-format-tag tags))
+ (delq nil (mapcar
+ (apply-partially #'notmuch-tag-format-tag tags orig-tags)
+ all-tags))
" ")
face
t)))
diff --git a/emacs/notmuch-tree.el b/emacs/notmuch-tree.el
index a106e09..7080e6f 100644
--- a/emacs/notmuch-tree.el
+++ b/emacs/notmuch-tree.el
@@ -704,7 +704,7 @@ unchanged ADDRESS if parsing fails."
(face (if match
'notmuch-tree-match-tag-face
'notmuch-tree-no-match-tag-face)))
- (format format-string (notmuch-tag-format-tags tags face)))))))
+ (format format-string (notmuch-tag-format-tags tags tags face)))))))
(defun notmuch-tree-format-field-list (field-list msg)
"Format fields of MSG according to FIELD-LIST and return string"
diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index 0c767f7..04587c0 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -754,7 +754,7 @@ non-authors is found, assume that all of the authors match."
((string-equal field "tags")
(let ((tags (plist-get result :tags)))
- (insert (format format-string (notmuch-tag-format-tags tags)))))))
+ (insert (format format-string (notmuch-tag-format-tags tags tags)))))))
(defun notmuch-search-show-result (result &optional pos)
"Insert RESULT at POS or the end of the buffer if POS is null."
diff --git a/test/test-lib.el b/test/test-lib.el
index 37fcb3d..437f83f 100644
--- a/test/test-lib.el
+++ b/test/test-lib.el
@@ -165,3 +165,8 @@ nothing."
(t
(notmuch-test-report-unexpected output expected)))))
+
+;; For historical reasons, we hide deleted tags by default in the test
+;; suite
+(setq notmuch-tag-deleted-formats
+ '((".*" nil)))
--
1.7.9.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v2 5/7] emacs: show: use orig-tags for tag display
2014-02-19 20:20 [PATCH v2 0/7] emacs: show tag changes in buffer Mark Walters
` (3 preceding siblings ...)
2014-02-19 20:20 ` [PATCH v2 4/7] emacs: show: mark tags changed since buffer loaded Mark Walters
@ 2014-02-19 20:20 ` Mark Walters
2014-02-19 20:20 ` [PATCH v2 6/7] emacs: search: use orig-tags in search Mark Walters
` (2 subsequent siblings)
7 siblings, 0 replies; 16+ messages in thread
From: Mark Walters @ 2014-02-19 20:20 UTC (permalink / raw)
To: notmuch
This uses the previous patch to show the tag changes that have occured
in the show buffer since it was last loaded/refreshed.
---
emacs/notmuch-show.el | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
index 719e7d1..145ddeb 100644
--- a/emacs/notmuch-show.el
+++ b/emacs/notmuch-show.el
@@ -344,7 +344,7 @@ operation on the contents of the current buffer."
(if (re-search-forward "(\\([^()]*\\))$" (line-end-position) t)
(let ((inhibit-read-only t))
(replace-match (concat "("
- (notmuch-tag-format-tags tags tags)
+ (notmuch-tag-format-tags tags (notmuch-show-get-prop :orig-tags))
")"))))))
(defun notmuch-clean-address (address)
@@ -1168,6 +1168,8 @@ function is used."
(jit-lock-register #'notmuch-show-buttonise-links)
+ (notmuch-show-mapc (lambda () (notmuch-show-set-prop :orig-tags (notmuch-show-get-tags))))
+
;; Set the header line to the subject of the first message.
(setq header-line-format (notmuch-sanitize (notmuch-show-strip-re (notmuch-show-get-subject))))
--
1.7.9.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v2 6/7] emacs: search: use orig-tags in search
2014-02-19 20:20 [PATCH v2 0/7] emacs: show tag changes in buffer Mark Walters
` (4 preceding siblings ...)
2014-02-19 20:20 ` [PATCH v2 5/7] emacs: show: use orig-tags for tag display Mark Walters
@ 2014-02-19 20:20 ` Mark Walters
2014-02-22 11:25 ` [PATCH v2.1 " Mark Walters
2014-02-19 20:20 ` [PATCH v2 7/7] emacs: tree: " Mark Walters
2014-03-06 6:37 ` [PATCH v2 0/7] emacs: show tag changes in buffer Jani Nikula
7 siblings, 1 reply; 16+ messages in thread
From: Mark Walters @ 2014-02-19 20:20 UTC (permalink / raw)
To: notmuch
This uses the recent functionality to show the tag changes in the
search buffer. Currently this is only used to show changes the search
buffer makes itself: i.e., it does not make display any changes
reflecting tagging done by other notmuch-buffers.
---
emacs/notmuch.el | 40 ++++++++++++++++++++++++----------------
1 files changed, 24 insertions(+), 16 deletions(-)
diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index 04587c0..d8aef27 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -753,24 +753,32 @@ non-authors is found, assume that all of the authors match."
format-string (notmuch-sanitize (plist-get result :authors))))
((string-equal field "tags")
- (let ((tags (plist-get result :tags)))
- (insert (format format-string (notmuch-tag-format-tags tags tags)))))))
+ (let ((tags (plist-get result :tags))
+ (orig-tags (plist-get result :orig-tags)))
+ (insert (format format-string (notmuch-tag-format-tags tags orig-tags)))))))
-(defun notmuch-search-show-result (result &optional pos)
- "Insert RESULT at POS or the end of the buffer if POS is null."
+(defun notmuch-search-show-result (result beg)
+ "Insert RESULT at BEG."
;; Ignore excluded matches
(unless (= (plist-get result :matched) 0)
- (let ((beg (or pos (point-max))))
- (save-excursion
- (goto-char beg)
- (dolist (spec notmuch-search-result-format)
- (notmuch-search-insert-field (car spec) (cdr spec) result))
- (insert "\n")
- (notmuch-search-color-line beg (point) (plist-get result :tags))
- (put-text-property beg (point) 'notmuch-search-result result))
- (when (string= (plist-get result :thread) notmuch-search-target-thread)
- (setq notmuch-search-target-thread "found")
- (goto-char beg)))))
+ (save-excursion
+ (goto-char beg)
+ (dolist (spec notmuch-search-result-format)
+ (notmuch-search-insert-field (car spec) (cdr spec) result))
+ (insert "\n")
+ (notmuch-search-color-line beg (point) (plist-get result :tags))
+ (put-text-property beg (point) 'notmuch-search-result result))
+ (when (string= (plist-get result :thread) notmuch-search-target-thread)
+ (setq notmuch-search-target-thread "found")
+ (goto-char beg))))
+
+(defun notmuch-search-append-result (result)
+ "Insert RESULT at the end of the buffer.
+
+This is only called when a result is first inserted so it also
+sets the :orig-tag property."
+ (let ((new-result (plist-put result :orig-tags (plist-get result :tags))))
+ (notmuch-search-show-result new-result (point-max))))
(defun notmuch-search-process-filter (proc string)
"Process and filter the output of \"notmuch search\""
@@ -784,7 +792,7 @@ non-authors is found, assume that all of the authors match."
(save-excursion
(goto-char (point-max))
(insert string))
- (notmuch-sexp-parse-partial-list 'notmuch-search-show-result
+ (notmuch-sexp-parse-partial-list 'notmuch-search-append-result
results-buf)))))
(defun notmuch-search-tag-all (tag-changes)
--
1.7.9.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v2 7/7] emacs: tree: use orig-tags in search
2014-02-19 20:20 [PATCH v2 0/7] emacs: show tag changes in buffer Mark Walters
` (5 preceding siblings ...)
2014-02-19 20:20 ` [PATCH v2 6/7] emacs: search: use orig-tags in search Mark Walters
@ 2014-02-19 20:20 ` Mark Walters
2014-03-06 6:37 ` [PATCH v2 0/7] emacs: show tag changes in buffer Jani Nikula
7 siblings, 0 replies; 16+ messages in thread
From: Mark Walters @ 2014-02-19 20:20 UTC (permalink / raw)
To: notmuch
This uses the recent functionality to show the tag changes in the tree
buffer. Currently this is only used to show changes the tree buffer
makes itself: i.e., it does not make display any changes reflecting
tagging done by other notmuch-buffers.
---
emacs/notmuch-tree.el | 9 ++++++---
1 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/emacs/notmuch-tree.el b/emacs/notmuch-tree.el
index 7080e6f..4de69c8 100644
--- a/emacs/notmuch-tree.el
+++ b/emacs/notmuch-tree.el
@@ -701,10 +701,11 @@ unchanged ADDRESS if parsing fails."
((string-equal field "tags")
(let ((tags (plist-get msg :tags))
+ (orig-tags (plist-get msg :orig-tags))
(face (if match
'notmuch-tree-match-tag-face
'notmuch-tree-no-match-tag-face)))
- (format format-string (notmuch-tag-format-tags tags tags face)))))))
+ (format format-string (notmuch-tag-format-tags tags orig-tags face)))))))
(defun notmuch-tree-format-field-list (field-list msg)
"Format fields of MSG according to FIELD-LIST and return string"
@@ -766,8 +767,10 @@ message together with all its descendents."
(push "├" tree-status)))
(push (concat (if replies "┬" "─") "►") tree-status)
- (plist-put msg :first (and first (eq 0 depth)))
- (notmuch-tree-goto-and-insert-msg (plist-put msg :tree-status tree-status))
+ (setq msg (plist-put msg :first (and first (eq 0 depth))))
+ (setq msg (plist-put msg :tree-status tree-status))
+ (setq msg (plist-put msg :orig-tags (plist-get msg :tags)))
+ (notmuch-tree-goto-and-insert-msg msg)
(pop tree-status)
(pop tree-status)
--
1.7.9.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v2.1 6/7] emacs: search: use orig-tags in search
2014-02-19 20:20 ` [PATCH v2 6/7] emacs: search: use orig-tags in search Mark Walters
@ 2014-02-22 11:25 ` Mark Walters
2014-03-11 2:41 ` Austin Clements
0 siblings, 1 reply; 16+ messages in thread
From: Mark Walters @ 2014-02-22 11:25 UTC (permalink / raw)
To: notmuch
This uses the recent functionality to show the tag changes in the
search buffer. Currently this is only used to show changes the search
buffer makes itself: i.e., it does not make display any changes
reflecting tagging done by other notmuch-buffers.
---
This is a rewrite of this single patch. When trying to rebase my
unread stuff on top of this series I realised that the previous
version split the notmuch-search-show-result in a a strange place. In
particular the code for "is this the target thread" so should only be
called when building the buffer not when redisplaying a thread. Of
course it works either way but I think this is cleaner.
Best wishes
Mark
emacs/notmuch.el | 41 +++++++++++++++++++++++++----------------
1 files changed, 25 insertions(+), 16 deletions(-)
diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index 04587c0..d1f1f0a 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -753,24 +753,33 @@ non-authors is found, assume that all of the authors match."
format-string (notmuch-sanitize (plist-get result :authors))))
((string-equal field "tags")
- (let ((tags (plist-get result :tags)))
- (insert (format format-string (notmuch-tag-format-tags tags tags)))))))
+ (let ((tags (plist-get result :tags))
+ (orig-tags (plist-get result :orig-tags)))
+ (insert (format format-string (notmuch-tag-format-tags tags orig-tags)))))))
-(defun notmuch-search-show-result (result &optional pos)
- "Insert RESULT at POS or the end of the buffer if POS is null."
+(defun notmuch-search-show-result (result pos)
+ "Insert RESULT at POS."
;; Ignore excluded matches
(unless (= (plist-get result :matched) 0)
- (let ((beg (or pos (point-max))))
- (save-excursion
- (goto-char beg)
- (dolist (spec notmuch-search-result-format)
- (notmuch-search-insert-field (car spec) (cdr spec) result))
- (insert "\n")
- (notmuch-search-color-line beg (point) (plist-get result :tags))
- (put-text-property beg (point) 'notmuch-search-result result))
- (when (string= (plist-get result :thread) notmuch-search-target-thread)
- (setq notmuch-search-target-thread "found")
- (goto-char beg)))))
+ (save-excursion
+ (goto-char pos)
+ (dolist (spec notmuch-search-result-format)
+ (notmuch-search-insert-field (car spec) (cdr spec) result))
+ (insert "\n")
+ (notmuch-search-color-line pos (point) (plist-get result :tags))
+ (put-text-property pos (point) 'notmuch-search-result result))))
+
+(defun notmuch-search-append-result (result)
+ "Insert RESULT at the end of the buffer.
+
+This is only called when a result is first inserted so it also
+sets the :orig-tag property."
+ (let ((new-result (plist-put result :orig-tags (plist-get result :tags)))
+ (pos (point-max)))
+ (notmuch-search-show-result new-result pos)
+ (when (string= (plist-get result :thread) notmuch-search-target-thread)
+ (setq notmuch-search-target-thread "found")
+ (goto-char pos))))
(defun notmuch-search-process-filter (proc string)
"Process and filter the output of \"notmuch search\""
@@ -784,7 +793,7 @@ non-authors is found, assume that all of the authors match."
(save-excursion
(goto-char (point-max))
(insert string))
- (notmuch-sexp-parse-partial-list 'notmuch-search-show-result
+ (notmuch-sexp-parse-partial-list 'notmuch-search-append-result
results-buf)))))
(defun notmuch-search-tag-all (tag-changes)
--
1.7.9.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH v2 0/7] emacs: show tag changes in buffer
2014-02-19 20:20 [PATCH v2 0/7] emacs: show tag changes in buffer Mark Walters
` (6 preceding siblings ...)
2014-02-19 20:20 ` [PATCH v2 7/7] emacs: tree: " Mark Walters
@ 2014-03-06 6:37 ` Jani Nikula
7 siblings, 0 replies; 16+ messages in thread
From: Jani Nikula @ 2014-03-06 6:37 UTC (permalink / raw)
To: Mark Walters, notmuch
On Wed, 19 Feb 2014, Mark Walters <markwalters1009@gmail.com> wrote:
> This is v2 of the patch set. Version 1 is at
> id:1390087855-26194-1-git-send-email-markwalters1009@gmail.com.
>
> The changes in this version are: use regexp tag-format matching (a
> slightly tweaked version of Austin's patch
> id:1392226351-31440-1-git-send-email-amdragon@mit.edu), make the
> tag-deleted/added formats apply on top of the normal tag-formatting,
> and fixup the way the :orig-tags field is added in notmuch-search.
>
> I think this version fixes all outstanding review comments.
Just for the record, I've been using this version for a while (and the
previous versions before that), and I still think it's one of the best
emacs UI improvements we've had lately. Would be great to have this
merged.
BR,
Jani.
>
> Best wishes
>
> Mark
>
>
>
> Austin Clements (1):
> Make keys of notmuch-tag-formats regexps and use caching
>
> Mark Walters (6):
> emacs: tag split customise option for format-tags into a widget
> emacs: tag: add customize for deleted/added tag formats
> emacs: show: mark tags changed since buffer loaded
> emacs: show: use orig-tags for tag display
> emacs: search: use orig-tags in search
> emacs: tree: use orig-tags in search
>
> emacs/notmuch-show.el | 7 ++-
> emacs/notmuch-tag.el | 179 +++++++++++++++++++++++++++++++++++++-----------
> emacs/notmuch-tree.el | 10 ++-
> emacs/notmuch.el | 41 +++++++-----
> test/test-lib.el | 5 ++
> 5 files changed, 180 insertions(+), 62 deletions(-)
>
> --
> 1.7.9.1
>
> _______________________________________________
> notmuch mailing list
> notmuch@notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2 1/7] Make keys of notmuch-tag-formats regexps and use caching
2014-02-19 20:20 ` [PATCH v2 1/7] Make keys of notmuch-tag-formats regexps and use caching Mark Walters
@ 2014-03-11 2:06 ` Austin Clements
0 siblings, 0 replies; 16+ messages in thread
From: Austin Clements @ 2014-03-11 2:06 UTC (permalink / raw)
To: Mark Walters, notmuch
On Wed, 19 Feb 2014, Mark Walters <markwalters1009@gmail.com> wrote:
> From: Austin Clements <amdragon@MIT.EDU>
>
> This patch switches notmuch-tag-formats to use regexps with caching
> for performance.
>
> We have to clear the cache somehow on changes to notmuch-tag-formats.
> This version takes the simplest approach: search/show/tree all clear
> the cache whenever they start loading.
>
> We cannot use assoc-default since there's no way to distinguish a
> missing key from a present key with a null cdr: thus, we use assoc*
> from cl instead.
>
> Performance-wise, the caching of regexp lookup makes this at least as
> fast as the previous code using assoc (see
> id:1392226351-31440-1-git-send-email-amdragon@mit.edu for timing
> details).
How about this for a commit message?
- 8< -
This modifies `notmuch-tag-format-tag' to treat the keys of
`notmuch-tag-formats' as (anchored) regexps, rather than literal
strings. This is clearly more flexible, as it allows for prefix
matching, defining a fallback format, etc. This may cause compatibility
problems if people have customized `notmuch-tag-formats' to match tags
that contain regexp specials, but this seems unlikely.
Regular expression matching has quite a performance hit over string
lookup, so this also introduces a simple cache from exact tags to
formatted strings. The number of unique tags is likely to be quite
small, so this cache should have a high hit rate. In addition to
eliminating the regexp lookup in the common case, this cache stores
fully formatted tags, eliminating the repeated evaluation of potentially
expensive, user-specified formatting code. This makes regexp lookup at
least as fast as assoc for unformatted tags (e.g., inbox) and *faster*
than the current code for formatted tags (e.g., unread):
inbox (usec) unread (usec)
assoc: 0.4 2.8
regexp: 3.2 7.2
regexp+caching: 0.4 0.4
(Though even at 7.2 usec, tag formatting is not our top bottleneck.)
This cache must be explicitly cleared to keep it coherent, so this adds
the appropriate clearing calls.
- >8 -
> ---
> emacs/notmuch-show.el | 1 +
> emacs/notmuch-tag.el | 70 +++++++++++++++++++++++++++++++++---------------
> emacs/notmuch-tree.el | 1 +
> emacs/notmuch.el | 1 +
> 4 files changed, 51 insertions(+), 22 deletions(-)
>
> diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
> index 1ac80ca..4bddf6c 100644
> --- a/emacs/notmuch-show.el
> +++ b/emacs/notmuch-show.el
> @@ -1145,6 +1145,7 @@ function is used."
> ;; Don't track undo information for this buffer
> (set 'buffer-undo-list t)
>
> + (notmuch-tag-clear-cache)
> (erase-buffer)
> (goto-char (point-min))
> (save-excursion
> diff --git a/emacs/notmuch-tag.el b/emacs/notmuch-tag.el
> index 908e7ad..47e0205 100644
> --- a/emacs/notmuch-tag.el
> +++ b/emacs/notmuch-tag.el
> @@ -28,23 +28,39 @@
> (require 'crm)
> (require 'notmuch-lib)
>
> +;; (notmuch-tag-clear-cache will be called by the defcustom
> +;; notmuch-tag-formats, so it has to be defined first.)
This is no longer true, so this comment can be removed and the following
two defs can be moved to a more natural location further down in the
file.
> +
> +(defvar notmuch-tag--format-cache (make-hash-table :test 'equal)
> + "Cache of tag format lookup. Internal to `notmuch-tag-format-tag'.")
> +
> +(defun notmuch-tag-clear-cache ()
> + "Clear the internal cache of tag formats.
> +
> +This must be called after changes to `notmuch-tag-formats'."
Likewise, this sentence is out of date. I would just omit it and add
the doc I suggest below.
> + (clrhash notmuch-tag--format-cache))
> +
> (defcustom notmuch-tag-formats
> '(("unread" (propertize tag 'face '(:foreground "red")))
> ("flagged" (propertize tag 'face '(:foreground "blue"))
> (notmuch-tag-format-image-data tag (notmuch-tag-star-icon))))
> "Custom formats for individual tags.
>
> -This gives a list that maps from tag names to lists of formatting
> -expressions. The car of each element gives a tag name and the
> -cdr gives a list of Elisp expressions that modify the tag. If
> -the list is empty, the tag will simply be hidden. Otherwise,
> -each expression will be evaluated in order: for the first
> -expression, the variable `tag' will be bound to the tag name; for
> -each later expression, the variable `tag' will be bound to the
> -result of the previous expression. In this way, each expression
> -can build on the formatting performed by the previous expression.
> -The result of the last expression will displayed in place of the
> -tag.
> +This is an association list that maps from tag name regexps to
> +lists of formatting expressions. The first entry whose car
> +regexp-matches a tag will be used to format that tag. The regexp
> +is implicitly anchored, so to match a literal tag name, just use
> +that tag name (if it contains special regexp characters like
> +\".\" or \"*\", these have to be escaped). The cdr of the
> +matching entry gives a list of Elisp expressions that modify the
> +tag. If the list is empty, the tag will simply be hidden.
> +Otherwise, each expression will be evaluated in order: for the
> +first expression, the variable `tag' will be bound to the tag
> +name; for each later expression, the variable `tag' will be bound
> +to the result of the previous expression. In this way, each
> +expression can build on the formatting performed by the previous
> +expression. The result of the last expression will displayed in
> +place of the tag.
>
> For example, to replace a tag with another string, simply use
> that string as a formatting expression. To change the foreground
> @@ -56,7 +72,7 @@ with images."
>
> :group 'notmuch-search
> :group 'notmuch-show
> - :type '(alist :key-type (string :tag "Tag")
> + :type '(alist :key-type (regexp :tag "Tag")
> :extra-offset -3
> :value-type
> (radio :format "%v"
> @@ -137,16 +153,26 @@ This can be used with `notmuch-tag-format-image-data'."
>
> (defun notmuch-tag-format-tag (tag)
> "Format TAG by looking into `notmuch-tag-formats'."
This would be a great place to mention that modes need to call
`notmuch-tag-clear-cache' if they intent to use formatted tags.
"Format TAG according to `notmuch-tag-formats'.
Callers must ensure that the tag format cache has been recently cleared
via `notmuch-tag-clear-cache' before using this function. For example,
it would be appropriate to clear the cache just prior to filling a
buffer that uses formatted tags."
> - (let ((formats (assoc tag notmuch-tag-formats)))
> - (cond
> - ((null formats) ;; - Tag not in `notmuch-tag-formats',
> - tag) ;; the format is the tag itself.
> - ((null (cdr formats)) ;; - Tag was deliberately hidden,
> - nil) ;; no format must be returned
> - (t ;; - Tag was found and has formats,
> - (let ((tag tag)) ;; we must apply all the formats.
> - (dolist (format (cdr formats) tag)
> - (setq tag (eval format))))))))
> + (let ((formatted (gethash tag notmuch-tag--format-cache 'missing)))
> + (when (eq formatted 'missing)
> + (let* ((formats
> + (save-match-data
This is a better place for the comment about assoc* that's currently in
the commit message.
;; Don't use assoc-default since there's no way to distinguish a missing
;; key from a present key with a null cdr:.
> + (assoc* tag notmuch-tag-formats
> + :test (lambda (tag key)
> + (and (eq (string-match key tag) 0)
> + (= (match-end 0) (length tag))))))))
> + (setq formatted
> + (cond
> + ((null formats) ;; - Tag not in `notmuch-tag-formats',
> + tag) ;; the format is the tag itself.
> + ((null (cdr formats)) ;; - Tag was deliberately hidden,
> + nil) ;; no format must be returned
> + (t ;; - Tag was found and has formats,
> + (let ((tag tag)) ;; we must apply all the formats.
> + (dolist (format (cdr formats) tag)
> + (setq tag (eval format)))))))
> + (puthash tag formatted notmuch-tag--format-cache)))
> + formatted))
>
> (defun notmuch-tag-format-tags (tags &optional face)
> "Return a string representing formatted TAGS."
> diff --git a/emacs/notmuch-tree.el b/emacs/notmuch-tree.el
> index 4f2ac02..a106e09 100644
> --- a/emacs/notmuch-tree.el
> +++ b/emacs/notmuch-tree.el
> @@ -881,6 +881,7 @@ the same as for the function notmuch-tree."
> (message-arg "--entire-thread"))
> (if (equal (car (process-lines notmuch-command "count" search-args)) "0")
> (setq search-args basic-query))
> + (notmuch-tag-clear-cache)
> (let ((proc (notmuch-start-notmuch
> "notmuch-tree" (current-buffer) #'notmuch-tree-process-sentinel
> "show" "--body=false" "--format=sexp"
> diff --git a/emacs/notmuch.el b/emacs/notmuch.el
> index 0471750..0c767f7 100644
> --- a/emacs/notmuch.el
> +++ b/emacs/notmuch.el
> @@ -888,6 +888,7 @@ the configured default sort order."
> (set 'notmuch-search-oldest-first oldest-first)
> (set 'notmuch-search-target-thread target-thread)
> (set 'notmuch-search-target-line target-line)
> + (notmuch-tag-clear-cache)
> (let ((proc (get-buffer-process (current-buffer)))
> (inhibit-read-only t))
> (if proc
> --
> 1.7.9.1
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2 3/7] emacs: tag: add customize for deleted/added tag formats
2014-02-19 20:20 ` [PATCH v2 3/7] emacs: tag: add customize for deleted/added tag formats Mark Walters
@ 2014-03-11 2:09 ` Austin Clements
2014-03-11 2:37 ` Austin Clements
1 sibling, 0 replies; 16+ messages in thread
From: Austin Clements @ 2014-03-11 2:09 UTC (permalink / raw)
To: Mark Walters, notmuch
On Wed, 19 Feb 2014, Mark Walters <markwalters1009@gmail.com> wrote:
> Add customize options for deleted/added tag formats. These are not
> used yet but will be later in the series.
> ---
> emacs/notmuch-tag.el | 31 +++++++++++++++++++++++++++++++
> 1 files changed, 31 insertions(+), 0 deletions(-)
>
> diff --git a/emacs/notmuch-tag.el b/emacs/notmuch-tag.el
> index 878aaf7..064fbdb 100644
> --- a/emacs/notmuch-tag.el
> +++ b/emacs/notmuch-tag.el
> @@ -101,6 +101,37 @@ with images."
> :group 'notmuch-show
> :type 'notmuch-tag-format-type)
>
> +(defcustom notmuch-tag-deleted-formats
> + '((".*" (propertize tag 'face
> + (if (display-supports-face-attributes-p '(:strike-through "red"))
> + '(:strike-through "red")
> + '(:inverse-video t)))))
> + "Custom formats for tags when deleted.
> +
> +For deleted tags the formats in `notmuch-tag-formats` are applied
> +first and then these formats are applied on top.
> +
> +By default this shows deleted tags with strike-through in red,
> +unless strike-through is not available (e.g., emacs is running in
> +a terminal) in which case it uses inverse video. To hide deleted
> +tags completely set this to
> + '((\"\" nil))
Should this be '((\".*\" nil))?
> +
> +See `notmuch-tag-formats' for full documentation."
> + :group 'notmuch-show
> + :type 'notmuch-tag-format-type)
> +
> +(defcustom notmuch-tag-added-formats
> + '((".*" (propertize tag 'face '(:underline "green"))))
> + "Custom formats for tags when added.
> +
> +For added tags the formats in `notmuch-tag-formats` are applied
> +first and then these formats are applied on top.
> +
> +See `notmuch-tag-formats' for full documentation."
> + :group 'notmuch-show
> + :type 'notmuch-tag-format-type)
> +
> (defun notmuch-tag-format-image-data (tag data)
> "Replace TAG with image DATA, if available.
>
> --
> 1.7.9.1
>
> _______________________________________________
> notmuch mailing list
> notmuch@notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2 4/7] emacs: show: mark tags changed since buffer loaded
2014-02-19 20:20 ` [PATCH v2 4/7] emacs: show: mark tags changed since buffer loaded Mark Walters
@ 2014-03-11 2:29 ` Austin Clements
0 siblings, 0 replies; 16+ messages in thread
From: Austin Clements @ 2014-03-11 2:29 UTC (permalink / raw)
To: Mark Walters, notmuch
On Wed, 19 Feb 2014, Mark Walters <markwalters1009@gmail.com> wrote:
> This allows (and requires) the original-tags to be passed along with
> the current-tags to be passed to notmuch-tag-format-tags. This allows
> the tag formatting to show added and deleted tags.By default a removed
> tag is displayed with strike-through in red (if strike-through is not
> available, eg on a terminal, inverse video is used instead) and an
> added tag is displayed underlined in green.
>
> If the caller does not wish to use the new feature it can pass
> current-tags for both arguments and, at this point, we do exactly that
> in the three callers of this function.
>
> Note, we cannot tidily allow original-tags to be optional because we would
> need to distinguish nil meaning "we are not specifying original-tags"
> from nil meaning there were no original-tags (an empty list).
>
> We use this in subsequent patches to make it clear when a message was
> unread when you first loaded a show buffer (previously the unread tag
> could be removed before a user realised that it had been unread).
>
> The code adds into the existing tag formatting code. The user can
> specify exactly how a tag should be displayed normally, when deleted,
> or when added. For convenience an entry for the empty string in the
> notmuch-tag-formats (and the corresponding notmuch-tag-deleted-formats
> notmuch-tag-added-formats) is applied to all tags which do not have an
> explicit match.
>
> This means that a user can tell notmuch not to show deleted tags at
> all by setting notmuch-tag-deleted-formats to
> '(("" nil))
> or not to show any deleted tags except "unread" by setting it to
> '(("" nil)
Same comment about ".*" on these two.
> ("unread" (propertize tag 'face '(strike-through "red"))))
>
> All the variables are customizable; however, more complicated cases
> like changing the face depending on the type of display will require
> custom lisp.
>
> Currently this overrides notmuch-tag-deleted-formats for the tests
> setting it to '(("" nil)) so that they get removed from the display
.. and here.
> and, thus, all tests still pass.
> ---
> emacs/notmuch-show.el | 4 +-
> emacs/notmuch-tag.el | 65 ++++++++++++++++++++++++++++++++++++++----------
> emacs/notmuch-tree.el | 2 +-
> emacs/notmuch.el | 2 +-
> test/test-lib.el | 5 ++++
> 5 files changed, 60 insertions(+), 18 deletions(-)
>
> diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el
> index 4bddf6c..719e7d1 100644
> --- a/emacs/notmuch-show.el
> +++ b/emacs/notmuch-show.el
> @@ -344,7 +344,7 @@ operation on the contents of the current buffer."
> (if (re-search-forward "(\\([^()]*\\))$" (line-end-position) t)
> (let ((inhibit-read-only t))
> (replace-match (concat "("
> - (notmuch-tag-format-tags tags)
> + (notmuch-tag-format-tags tags tags)
> ")"))))))
>
> (defun notmuch-clean-address (address)
> @@ -423,7 +423,7 @@ message at DEPTH in the current thread."
> " ("
> date
> ") ("
> - (notmuch-tag-format-tags tags)
> + (notmuch-tag-format-tags tags tags)
> ")\n")
> (overlay-put (make-overlay start (point)) 'face 'notmuch-message-summary-face)))
>
> diff --git a/emacs/notmuch-tag.el b/emacs/notmuch-tag.el
> index 064fbdb..869b97d 100644
> --- a/emacs/notmuch-tag.el
> +++ b/emacs/notmuch-tag.el
> @@ -185,36 +185,73 @@ This can be used with `notmuch-tag-format-image-data'."
> </g>
> </svg>")
>
> -(defun notmuch-tag-format-tag (tag)
> - "Format TAG by looking into `notmuch-tag-formats'."
> - (let ((formatted (gethash tag notmuch-tag--format-cache 'missing)))
> +(defun notmuch-tag-format-tag-by-state (tag formatted-tag tag-state)
> + "Format TAG by looking into the appropriate `notmuch-tag-formats`.
Since you're rewriting the docstrings, you might as well change "by
looking into" to "according to".
> +
> +Applies formats for TAG from the appropriate one of
> +`notmuch-tag-formats`, `notmuch-tag-deleted-formats` and
> +`notmuch-tag-added-formats` based on TAG-STATE to the partially
> +formatted tag FORMATTED-TAG."
> + (let ((formatted (gethash (cons tag tag-state) notmuch-tag--format-cache 'missing)))
> (when (eq formatted 'missing)
> - (let* ((formats
> + (let* ((tag-formats (cond ((null tag-state) notmuch-tag-formats)
> + ((eq 'deleted tag-state) notmuch-tag-deleted-formats)
> + ((eq 'added tag-state) notmuch-tag-added-formats)))
Use `case' instead of `cond'?
> + (formats
> (save-match-data
> - (assoc* tag notmuch-tag-formats
> + (assoc* tag tag-formats
> :test (lambda (tag key)
> (and (eq (string-match key tag) 0)
> (= (match-end 0) (length tag))))))))
> (setq formatted
> (cond
> - ((null formats) ;; - Tag not in `notmuch-tag-formats',
> - tag) ;; the format is the tag itself.
> + ((null formats) ;; - Tag not in `tag-formats',
> + formatted-tag) ;; the format is the tag itself.
> ((null (cdr formats)) ;; - Tag was deliberately hidden,
> nil) ;; no format must be returned
> - (t ;; - Tag was found and has formats,
> - (let ((tag tag)) ;; we must apply all the formats.
> + (t
> + ;; Tag was found and has formats, we must apply all
> + ;; the formats. FORMATTED-TAG may be null so treat
> + ;; that as a special case.
> + (let ((tag (or formatted-tag "")))
> (dolist (format (cdr formats) tag)
> - (setq tag (eval format)))))))
> - (puthash tag formatted notmuch-tag--format-cache)))
> + (setq tag (eval format)))
> + (if (and (null formatted-tag)
> + (equal tag ""))
> + nil
> + tag)))))
> + (puthash (cons tag tag-state) formatted notmuch-tag--format-cache)))
> formatted))
>
> -(defun notmuch-tag-format-tags (tags &optional face)
> +(defun notmuch-tag-format-tag (tags orig-tags tag)
> + "Format TAG by looking into `notmuch-tag-formats'.
s/by looking into/according to/ here, too.
> +
> +TAGS and ORIG-TAGS are lists of the current tags and the original
> +tags; tags which have been deleted (i.e., are in ORIG-TAGS but
> +are not in TAGS) are shown using formats from
> +`notmuch-tag-deleted-formats'; tags which have been added (i.e.,
> +are in TAGS but are not in ORIG-TAGS) are shown using formats
> +from `notmuch-tag-added-formats' and tags which have not been
> +changed (the normal case) are shown using formats from
> +`notmuch-tag-formats'"
> + (let* ((formatted-tag (notmuch-tag-format-tag-by-state tag tag nil)))
> + (cond ((not (member tag tags))
> + (notmuch-tag-format-tag-by-state tag formatted-tag 'deleted))
> + ((not (member tag orig-tags))
> + (notmuch-tag-format-tag-by-state tag formatted-tag 'added))
> + (t
> + formatted-tag))))
> +
> +(defun notmuch-tag-format-tags (tags orig-tags &optional face)
> "Return a string representing formatted TAGS."
> - (let ((face (or face 'notmuch-tag-face)))
> + (let ((face (or face 'notmuch-tag-face))
> + (all-tags (sort (delete-dups (append tags orig-tags nil)) #'string<)))
> (notmuch-combine-face-text-property-string
> (mapconcat #'identity
> ;; nil indicated that the tag was deliberately hidden
> - (delq nil (mapcar #'notmuch-tag-format-tag tags))
> + (delq nil (mapcar
> + (apply-partially #'notmuch-tag-format-tag tags orig-tags)
> + all-tags))
> " ")
> face
> t)))
> diff --git a/emacs/notmuch-tree.el b/emacs/notmuch-tree.el
> index a106e09..7080e6f 100644
> --- a/emacs/notmuch-tree.el
> +++ b/emacs/notmuch-tree.el
> @@ -704,7 +704,7 @@ unchanged ADDRESS if parsing fails."
> (face (if match
> 'notmuch-tree-match-tag-face
> 'notmuch-tree-no-match-tag-face)))
> - (format format-string (notmuch-tag-format-tags tags face)))))))
> + (format format-string (notmuch-tag-format-tags tags tags face)))))))
>
> (defun notmuch-tree-format-field-list (field-list msg)
> "Format fields of MSG according to FIELD-LIST and return string"
> diff --git a/emacs/notmuch.el b/emacs/notmuch.el
> index 0c767f7..04587c0 100644
> --- a/emacs/notmuch.el
> +++ b/emacs/notmuch.el
> @@ -754,7 +754,7 @@ non-authors is found, assume that all of the authors match."
>
> ((string-equal field "tags")
> (let ((tags (plist-get result :tags)))
> - (insert (format format-string (notmuch-tag-format-tags tags)))))))
> + (insert (format format-string (notmuch-tag-format-tags tags tags)))))))
>
> (defun notmuch-search-show-result (result &optional pos)
> "Insert RESULT at POS or the end of the buffer if POS is null."
> diff --git a/test/test-lib.el b/test/test-lib.el
> index 37fcb3d..437f83f 100644
> --- a/test/test-lib.el
> +++ b/test/test-lib.el
> @@ -165,3 +165,8 @@ nothing."
>
> (t
> (notmuch-test-report-unexpected output expected)))))
> +
> +;; For historical reasons, we hide deleted tags by default in the test
> +;; suite
> +(setq notmuch-tag-deleted-formats
> + '((".*" nil)))
> --
> 1.7.9.1
>
> _______________________________________________
> notmuch mailing list
> notmuch@notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2 3/7] emacs: tag: add customize for deleted/added tag formats
2014-02-19 20:20 ` [PATCH v2 3/7] emacs: tag: add customize for deleted/added tag formats Mark Walters
2014-03-11 2:09 ` Austin Clements
@ 2014-03-11 2:37 ` Austin Clements
2014-03-11 14:46 ` [PATCH] emacs: Combine notmuch-combine-face-text-property{,-string} Austin Clements
1 sibling, 1 reply; 16+ messages in thread
From: Austin Clements @ 2014-03-11 2:37 UTC (permalink / raw)
To: Mark Walters, notmuch
On Wed, 19 Feb 2014, Mark Walters <markwalters1009@gmail.com> wrote:
> Add customize options for deleted/added tag formats. These are not
> used yet but will be later in the series.
> ---
> emacs/notmuch-tag.el | 31 +++++++++++++++++++++++++++++++
> 1 files changed, 31 insertions(+), 0 deletions(-)
>
> diff --git a/emacs/notmuch-tag.el b/emacs/notmuch-tag.el
> index 878aaf7..064fbdb 100644
> --- a/emacs/notmuch-tag.el
> +++ b/emacs/notmuch-tag.el
> @@ -101,6 +101,37 @@ with images."
> :group 'notmuch-show
> :type 'notmuch-tag-format-type)
>
> +(defcustom notmuch-tag-deleted-formats
> + '((".*" (propertize tag 'face
It occurs to me that `propertize' is problematic here, since it replaces
the face property of the tag wholesale. If we really want this to apply
in addition to a face added by notmuch-tag-formats, I don't think
there's any way to massage things so that `propertize' works (short of
horrible hackery). `notmuch-combine-face-text-property-string' does
exactly what we need here, but maybe needs a shorter name?
`notmuch-apply-face'? Or maybe there's some solution I'm not thinking
of?
> + (if (display-supports-face-attributes-p '(:strike-through "red"))
> + '(:strike-through "red")
> + '(:inverse-video t)))))
> + "Custom formats for tags when deleted.
> +
> +For deleted tags the formats in `notmuch-tag-formats` are applied
> +first and then these formats are applied on top.
> +
> +By default this shows deleted tags with strike-through in red,
> +unless strike-through is not available (e.g., emacs is running in
> +a terminal) in which case it uses inverse video. To hide deleted
> +tags completely set this to
> + '((\"\" nil))
> +
> +See `notmuch-tag-formats' for full documentation."
> + :group 'notmuch-show
> + :type 'notmuch-tag-format-type)
> +
> +(defcustom notmuch-tag-added-formats
> + '((".*" (propertize tag 'face '(:underline "green"))))
> + "Custom formats for tags when added.
> +
> +For added tags the formats in `notmuch-tag-formats` are applied
> +first and then these formats are applied on top.
> +
> +See `notmuch-tag-formats' for full documentation."
> + :group 'notmuch-show
> + :type 'notmuch-tag-format-type)
> +
> (defun notmuch-tag-format-image-data (tag data)
> "Replace TAG with image DATA, if available.
>
> --
> 1.7.9.1
>
> _______________________________________________
> notmuch mailing list
> notmuch@notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2.1 6/7] emacs: search: use orig-tags in search
2014-02-22 11:25 ` [PATCH v2.1 " Mark Walters
@ 2014-03-11 2:41 ` Austin Clements
0 siblings, 0 replies; 16+ messages in thread
From: Austin Clements @ 2014-03-11 2:41 UTC (permalink / raw)
To: Mark Walters, notmuch
On Sat, 22 Feb 2014, Mark Walters <markwalters1009@gmail.com> wrote:
> This uses the recent functionality to show the tag changes in the
> search buffer. Currently this is only used to show changes the search
> buffer makes itself: i.e., it does not make display any changes
> reflecting tagging done by other notmuch-buffers.
> ---
> This is a rewrite of this single patch. When trying to rebase my
> unread stuff on top of this series I realised that the previous
> version split the notmuch-search-show-result in a a strange place. In
> particular the code for "is this the target thread" so should only be
> called when building the buffer not when redisplaying a thread. Of
> course it works either way but I think this is cleaner.
I like this better than v2 as well.
> Best wishes
>
> Mark
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH] emacs: Combine notmuch-combine-face-text-property{,-string}
2014-03-11 2:37 ` Austin Clements
@ 2014-03-11 14:46 ` Austin Clements
0 siblings, 0 replies; 16+ messages in thread
From: Austin Clements @ 2014-03-11 14:46 UTC (permalink / raw)
To: notmuch
This combines our two face combining functions into one, easy to use
function with a much shorter name: `notmuch-apply-face'. This
function takes the full set of arguments that
`notmuch-combine-face-text-property' took, but takes them in a more
convenient order and provides smarter defaults that make the function
easy to use on both strings and buffers.
---
Here's the combined, cleaned up face combiner interface I mentioned on
IRC. I think the new `notmuch-apply-face' function introduced here
would be ideal for use in notmuch-tag-formats to fix the problem with
propertize overriding the entire face.
emacs/notmuch-lib.el | 35 ++++++++++++++++++-----------------
emacs/notmuch-tag.el | 4 ++--
emacs/notmuch-tree.el | 2 +-
emacs/notmuch.el | 2 +-
4 files changed, 22 insertions(+), 21 deletions(-)
diff --git a/emacs/notmuch-lib.el b/emacs/notmuch-lib.el
index 2fefdad..05be5b8 100644
--- a/emacs/notmuch-lib.el
+++ b/emacs/notmuch-lib.el
@@ -578,23 +578,32 @@ single element face list."
face
(list face)))
-(defun notmuch-combine-face-text-property (start end face &optional below object)
- "Combine FACE into the 'face text property between START and END.
+(defun notmuch-apply-face (object face &optional start end below)
+ "Combine FACE into the 'face text property of OBJECT between START and END.
This function combines FACE with any existing faces between START
-and END in OBJECT (which defaults to the current buffer).
-Attributes specified by FACE take precedence over existing
-attributes unless BELOW is non-nil. FACE must be a face name (a
-symbol or string), a property list of face attributes, or a list
-of these. For convenience when applied to strings, this returns
-OBJECT."
+and END in OBJECT. Attributes specified by FACE take precedence
+over existing attributes unless BELOW is non-nil.
+
+OBJECT may be a string, a buffer, or nil (which means the current
+buffer). If object is a string, START and END are 0-based;
+otherwise they are buffer positions (integers or markers). FACE
+must be a face name (a symbol or string), a property list of face
+attributes, or a list of these. If START and/or END are omitted,
+they default to the beginning/end of OBJECT. For convenience
+when applied to strings, this returns OBJECT."
;; A face property can have three forms: a face name (a string or
;; symbol), a property list, or a list of these two forms. In the
;; list case, the faces will be combined, with the earlier faces
;; taking precedent. Here we canonicalize everything to list form
;; to make it easy to combine.
- (let ((pos start)
+ (let ((pos (cond (start start)
+ ((stringp object) 0)
+ (t 1)))
+ (end (cond (end end)
+ ((stringp object) (length object))
+ (t (1+ (buffer-size object)))))
(face-list (notmuch-face-ensure-list-form face)))
(while (< pos end)
(let* ((cur (get-text-property pos 'face object))
@@ -607,14 +616,6 @@ OBJECT."
(setq pos next))))
object)
-(defun notmuch-combine-face-text-property-string (string face &optional below)
- (notmuch-combine-face-text-property
- 0
- (length string)
- face
- below
- string))
-
(defun notmuch-map-text-property (start end prop func &optional object)
"Transform text property PROP using FUNC.
diff --git a/emacs/notmuch-tag.el b/emacs/notmuch-tag.el
index 908e7ad..d7deaf0 100644
--- a/emacs/notmuch-tag.el
+++ b/emacs/notmuch-tag.el
@@ -151,13 +151,13 @@ This can be used with `notmuch-tag-format-image-data'."
(defun notmuch-tag-format-tags (tags &optional face)
"Return a string representing formatted TAGS."
(let ((face (or face 'notmuch-tag-face)))
- (notmuch-combine-face-text-property-string
+ (notmuch-apply-face
(mapconcat #'identity
;; nil indicated that the tag was deliberately hidden
(delq nil (mapcar #'notmuch-tag-format-tag tags))
" ")
face
- t)))
+ nil nil t)))
(defcustom notmuch-before-tag-hook nil
"Hooks that are run before tags of a message are modified.
diff --git a/emacs/notmuch-tree.el b/emacs/notmuch-tree.el
index 4f2ac02..bc4c0b0 100644
--- a/emacs/notmuch-tree.el
+++ b/emacs/notmuch-tree.el
@@ -715,7 +715,7 @@ unchanged ADDRESS if parsing fails."
(dolist (spec field-list result-string)
(let ((field-string (notmuch-tree-format-field (car spec) (cdr spec) msg)))
(setq result-string (concat result-string field-string))))
- (notmuch-combine-face-text-property-string result-string face t)))
+ (notmuch-apply-face result-string face nil nil t)))
(defun notmuch-tree-insert-msg (msg)
"Insert the message MSG according to notmuch-tree-result-format"
diff --git a/emacs/notmuch.el b/emacs/notmuch.el
index 0471750..222d8b1 100644
--- a/emacs/notmuch.el
+++ b/emacs/notmuch.el
@@ -649,7 +649,7 @@ foreground and blue background."
(let ((tag (car elem))
(attributes (cdr elem)))
(when (member tag line-tag-list)
- (notmuch-combine-face-text-property start end attributes))))
+ (notmuch-apply-face nil attributes start end))))
;; Reverse the list so earlier entries take precedence
(reverse notmuch-search-line-faces)))
--
1.8.4.rc3
^ permalink raw reply related [flat|nested] 16+ messages in thread
end of thread, other threads:[~2014-03-11 14:47 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-02-19 20:20 [PATCH v2 0/7] emacs: show tag changes in buffer Mark Walters
2014-02-19 20:20 ` [PATCH v2 1/7] Make keys of notmuch-tag-formats regexps and use caching Mark Walters
2014-03-11 2:06 ` Austin Clements
2014-02-19 20:20 ` [PATCH v2 2/7] emacs: tag split customise option for format-tags into a widget Mark Walters
2014-02-19 20:20 ` [PATCH v2 3/7] emacs: tag: add customize for deleted/added tag formats Mark Walters
2014-03-11 2:09 ` Austin Clements
2014-03-11 2:37 ` Austin Clements
2014-03-11 14:46 ` [PATCH] emacs: Combine notmuch-combine-face-text-property{,-string} Austin Clements
2014-02-19 20:20 ` [PATCH v2 4/7] emacs: show: mark tags changed since buffer loaded Mark Walters
2014-03-11 2:29 ` Austin Clements
2014-02-19 20:20 ` [PATCH v2 5/7] emacs: show: use orig-tags for tag display Mark Walters
2014-02-19 20:20 ` [PATCH v2 6/7] emacs: search: use orig-tags in search Mark Walters
2014-02-22 11:25 ` [PATCH v2.1 " Mark Walters
2014-03-11 2:41 ` Austin Clements
2014-02-19 20:20 ` [PATCH v2 7/7] emacs: tree: " Mark Walters
2014-03-06 6:37 ` [PATCH v2 0/7] emacs: show tag changes in buffer Jani Nikula
Code repositories for project(s) associated with this public inbox
https://yhetil.org/notmuch.git/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).