Re: [PATCH 01/15] util: add DEBUG_PRINTF, rename error_util.h -> debug_print.h
Tomi Ollila writes: > To me, YAGNI says that we could drop the whole _debug_printf() and > have > #include > #define DEBUG_PRINTF(format, ...) fprintf(stderr, format " (%s).\n", \ > ##__VA_ARGS__, __location__) > > (but if there is need, then perhaps the lib code inside #ifdef DEBUG_PRINT > ... hmm, but, outside of this context, would this also move > _internal_error() to debug_print ;O )? I guess that version could just go in notmuch-private.h, since it isn't (currently) used in the CLI. Or even directly in thread.cc, since that's the only place it's used currently. d ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH 04/15] lib/thread: sort sibling messages by date
Tomi Ollila writes: >> +static int >> +_cmpmsg (const void *pa, const void *pb) >> +{ >> +notmuch_message_t **a = (notmuch_message_t **) pa; >> +notmuch_message_t **b = (notmuch_message_t **) pb; >> +time_t time_a = notmuch_message_get_date (*a); >> +time_t time_b = notmuch_message_get_date (*b); >> + >> +return (int) difftime (time_a, time_b); > > time_t is often 64 bits now (and I suspect signed). int is often 32-bits > (gcc -dM -E -xc /dev/null | grep -i size to verify), perhaps time_t as > return value ? > The return type is defined as int by the qsort prototype. What we care about here is the sign. I think it's better to just avoid difftime -return (int) difftime (time_a, time_b); +if (time_a == time_b) + return 0; +else if (time_a < time_b) + return -1; +else + return 1; } ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
feature request: fetch missing keys in the background
Hi! Because I have a rather large keyring, fetching new keys or refreshing old ones takes a long time. When I click on the red red button saying "Unknown key ID [...] or unsupported algorithm", Emacs freezes for a good 90 seconds. Considering I use that editor^Wvirtual machine for nearly everything, it's quite annoying and sends me off browsing the web in Firefox forever. I end up having a horde of shaven yaks and then finally remember that I had that key update, by which time I had forgotten what I was doing reading email in the first place, let alone what I was doing *before* opening my inbox... So. It would be great if Notmuch would run those key updates asynchronously. I am not sure how that would work: as Bremner said on IRC, it might make it difficult to update the button automatically. But I don't mind that: I can refresh the page myself. He suggested running things in the background when clicking with a prefix (C-u?) but I would argue that freezing Emacs is just a no-no in general. I couldn't find directly what function was called behind that button: "C-h k" just says it's, obviously, `push-button'. Bremner says it might be `notmuch-crypto-sigstatus-good-callback' which looks reasonable. I'm only a junior elisp programmer, but it seems to me the `notmuch-show-refresh-view' call there could be an asynchronous callback to an async `make-process' call, as opposed to `call-process', which is synchronous. But I'd like others to chime in here: is this something that would be accepted? Would the above work? A. -- If quantum mechanics hasn't profoundly shocked you, you haven't understood it yet. - Niels Bohr ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
Re: feature request: fetch missing keys in the background
On Monday, 2018-09-03 at 11:49:09 -04, Antoine Beaupré wrote: > Hi! > > Because I have a rather large keyring, fetching new keys or refreshing > old ones takes a long time. When I click on the red red button saying > "Unknown key ID [...] or unsupported algorithm", Emacs freezes for a > good 90 seconds. Considering I use that editor^Wvirtual machine for > nearly everything, it's quite annoying and sends me off browsing the web > in Firefox forever. I end up having a horde of shaven yaks and then > finally remember that I had that key update, by which time I had > forgotten what I was doing reading email in the first place, let alone > what I was doing *before* opening my inbox... > > So. It would be great if Notmuch would run those key updates > asynchronously. I am not sure how that would work: as Bremner said on > IRC, it might make it difficult to update the button automatically. But > I don't mind that: I can refresh the page myself. He suggested running > things in the background when clicking with a prefix (C-u?) but I would > argue that freezing Emacs is just a no-no in general. > > I couldn't find directly what function was called behind that button: > "C-h k" just says it's, obviously, `push-button'. Bremner says it might > be `notmuch-crypto-sigstatus-good-callback' which looks reasonable. I'm > only a junior elisp programmer, but it seems to me the > `notmuch-show-refresh-view' call there could be an asynchronous callback > to an async `make-process' call, as opposed to `call-process', which is > synchronous. > > But I'd like others to chime in here: is this something that would be > accepted? Would the above work? I'm puzzled about the currently expected behaviour based on your question. I have “notmuch-crypto-process-mime” set to t. I *don't* have “keyserver-options auto-key-retrieve” set in my gpg.conf, so I don't expect to get any automatic retrieval of keys (it was annoyingly slow sometimes). When I read a message with a signature using a key that I don't have, I get the expected “Unknown key ID ...” button. If I click on that button a new window appears showing me the details of that key (with a slight delay). The referenced key is *not* imported into my keyring, so updating the view of the message does nothing to change the display of the button - it still says “Unknown key ID ...”. Enabling “auto-key-retrieve” changes this behaviour, as you would expect (I see a delay opening the message while the key is retrieved, and then the button shows it as good). (Caveat: I'm using “remote-notmuch”, so emacs and notmuch/gpg are on different machines, but I don't know that this changes any of the above.) dme. -- She's as sweet as Tupelo honey, she's an angel of the first degree. ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
Re: feature request: fetch missing keys in the background
On Monday, 2018-09-03 at 17:46:00 +01, David Edmondson wrote: > (Caveat: I'm using “remote-notmuch”, so emacs and notmuch/gpg are on > different machines, but I don't know that this changes any of the > above.) Ah, of course it does - “gpg --recv-keys ...” runs on the same machine as emacs, not on the server in this case. Ick. dme. -- But uh oh, I love her because, she moves in her own way. ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
Re: feature request: fetch missing keys in the background
On 2018-09-03 17:46:00, David Edmondson wrote: [...] > I'm puzzled about the currently expected behaviour based on your > question. [...] > Enabling “auto-key-retrieve” changes this behaviour, as you would expect > (I see a delay opening the message while the key is retrieved, and then > the button shows it as good). The current behavior is somewhat expected: I'm happy notmuch fetches the keys on click. The problem is it takes forever (that's GPG's fault) and that Emacs freezes while it happens (that's Notmuch's fault). > (Caveat: I'm using “remote-notmuch”, so emacs and notmuch/gpg are on > different machines, but I don't know that this changes any of the > above.) I'm not sure either. A. -- If I can't dance, I don't want to be part of your revolution. - Emma Goldman ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
Re: feature request: fetch missing keys in the background
How about this patch? You'll need to set “notmuch-crypto-get-keys-asynchronously” to “t” to see any benefit. diff --git a/emacs/notmuch-crypto.el b/emacs/notmuch-crypto.el index fc2b5301..97396ba0 100644 --- a/emacs/notmuch-crypto.el +++ b/emacs/notmuch-crypto.el @@ -43,6 +43,11 @@ mode." :package-version '(notmuch . "0.25") :group 'notmuch-crypto) +(defcustom notmuch-crypto-get-keys-asynchronously nil + "Retrieve gpg keys asynchronously." + :type 'boolean + :group 'notmuch-crypto) + (defface notmuch-crypto-part-header 'class color) (background dark)) @@ -145,6 +150,36 @@ mode." (call-process epg-gpg-program nil t t "--list-keys" fingerprint)) (recenter -1 +(defun notmuch-crypto--async-key-sentinel (process event) + (let ((status (process-status process)) + (exit-status (process-exit-status process))) +(when (memq status '(exit signal)) + (message "Asynchronous GPG key retrieval %s." + (if (= exit-status 0) + "completed" + "failed") + +(defun notmuch-crypto-sigstatus-error-callback (button) + (let* ((sigstatus (button-get button :notmuch-sigstatus)) + (keyid (concat "0x" (plist-get sigstatus :keyid))) + (buffer (get-buffer-create "*notmuch-crypto-gpg-out*"))) +(if notmuch-crypto-get-keys-asynchronously + (progn + (message "Getting the GPG key %s asynchronously..." keyid) + (make-process :name "notmuch GPG key retrieval" + :buffer buffer + :command (list epg-gpg-program "--recv-keys" keyid) + :sentinel #'notmuch-crypto--async-key-sentinel)) + (let ((window (display-buffer buffer t nil))) + (with-selected-window window + (with-current-buffer buffer + (goto-char (point-max)) + (call-process epg-gpg-program nil t t "--recv-keys" keyid) + (insert "\n") + (call-process epg-gpg-program nil t t "--list-keys" keyid)) + (recenter -1)) + (notmuch-show-refresh-view) + (defun notmuch-crypto-sigstatus-error-callback (button) (let* ((sigstatus (button-get button :notmuch-sigstatus)) (keyid (concat "0x" (plist-get sigstatus :keyid))) dme. -- For a long time I felt, without style and grace. ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
Re: feature request: fetch missing keys in the background
On Monday, 2018-09-03 at 18:21:32 +01, David Edmondson wrote: > How about this patch? > > You'll need to set “notmuch-crypto-get-keys-asynchronously” to “t” to > see any benefit. Oops, and delete the old version of “notmuch-crypto-sigstatus-error-callback” from just below the new one. > diff --git a/emacs/notmuch-crypto.el b/emacs/notmuch-crypto.el > index fc2b5301..97396ba0 100644 > --- a/emacs/notmuch-crypto.el > +++ b/emacs/notmuch-crypto.el > @@ -43,6 +43,11 @@ mode." >:package-version '(notmuch . "0.25") >:group 'notmuch-crypto) > > +(defcustom notmuch-crypto-get-keys-asynchronously nil > + "Retrieve gpg keys asynchronously." > + :type 'boolean > + :group 'notmuch-crypto) > + > (defface notmuch-crypto-part-header >'class color) >(background dark)) > @@ -145,6 +150,36 @@ mode." > (call-process epg-gpg-program nil t t "--list-keys" fingerprint)) >(recenter -1 > > +(defun notmuch-crypto--async-key-sentinel (process event) > + (let ((status (process-status process)) > + (exit-status (process-exit-status process))) > +(when (memq status '(exit signal)) > + (message "Asynchronous GPG key retrieval %s." > +(if (= exit-status 0) > +"completed" > + "failed") > + > +(defun notmuch-crypto-sigstatus-error-callback (button) > + (let* ((sigstatus (button-get button :notmuch-sigstatus)) > + (keyid (concat "0x" (plist-get sigstatus :keyid))) > + (buffer (get-buffer-create "*notmuch-crypto-gpg-out*"))) > +(if notmuch-crypto-get-keys-asynchronously > + (progn > + (message "Getting the GPG key %s asynchronously..." keyid) > + (make-process :name "notmuch GPG key retrieval" > +:buffer buffer > +:command (list epg-gpg-program "--recv-keys" keyid) > +:sentinel #'notmuch-crypto--async-key-sentinel)) > + (let ((window (display-buffer buffer t nil))) > + (with-selected-window window > + (with-current-buffer buffer > + (goto-char (point-max)) > + (call-process epg-gpg-program nil t t "--recv-keys" keyid) > + (insert "\n") > + (call-process epg-gpg-program nil t t "--list-keys" keyid)) > + (recenter -1)) > + (notmuch-show-refresh-view) > + > (defun notmuch-crypto-sigstatus-error-callback (button) >(let* ((sigstatus (button-get button :notmuch-sigstatus)) >(keyid (concat "0x" (plist-get sigstatus :keyid))) > > dme. > -- > For a long time I felt, without style and grace. dme. -- I'm not living in the real world, no more, no more. ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
PATCH: fetch missing keys in the background
On 2018-09-03 18:21:32, David Edmondson wrote: > How about this patch? > > You'll need to set “notmuch-crypto-get-keys-asynchronously” to “t” to > see any benefit. This is great! As you said on IRC, the patch is more likely: diff --git i/emacs/notmuch-crypto.el w/emacs/notmuch-crypto.el index fc2b5301..175dc5f2 100644 --- i/emacs/notmuch-crypto.el +++ w/emacs/notmuch-crypto.el @@ -43,6 +43,18 @@ mode." :package-version '(notmuch . "0.25") :group 'notmuch-crypto) +(defcustom notmuch-crypto-get-keys-asynchronously nil + "Retrieve gpg keys asynchronously. + +If this variable is non-nil, hitting the crypto button will +trigger network operations in the background. This will also have +the effect of disabling the automatic refresh on completion. Keep +this set to nil to make sure the button display is up to date, +but this will freeze everything until the crypto operation is +completed, which can take a long time for larger keyrings." + :type 'boolean + :group 'notmuch-crypto) + (defface notmuch-crypto-part-header 'class color) (background dark)) @@ -145,19 +157,35 @@ mode." (call-process epg-gpg-program nil t t "--list-keys" fingerprint)) (recenter -1 +(defun notmuch-crypto--async-key-sentinel (process event) + (let ((status (process-status process)) + (exit-status (process-exit-status process))) +(when (memq status '(exit signal)) + (message "Asynchronous GPG key retrieval %s." + (if (= exit-status 0) + "completed" + "failed") + (defun notmuch-crypto-sigstatus-error-callback (button) (let* ((sigstatus (button-get button :notmuch-sigstatus)) (keyid (concat "0x" (plist-get sigstatus :keyid))) - (buffer (get-buffer-create "*notmuch-crypto-gpg-out*")) - (window (display-buffer buffer t nil))) -(with-selected-window window - (with-current-buffer buffer - (goto-char (point-max)) - (call-process epg-gpg-program nil t t "--recv-keys" keyid) - (insert "\n") - (call-process epg-gpg-program nil t t "--list-keys" keyid)) - (recenter -1)) -(notmuch-show-refresh-view))) + (buffer (get-buffer-create "*notmuch-crypto-gpg-out*"))) +(if notmuch-crypto-get-keys-asynchronously + (progn + (message "Getting the GPG key %s asynchronously..." keyid) + (make-process :name "notmuch GPG key retrieval" + :buffer buffer + :command (list epg-gpg-program "--recv-keys" keyid) + :sentinel #'notmuch-crypto--async-key-sentinel)) + (let ((window (display-buffer buffer t nil))) + (with-selected-window window + (with-current-buffer buffer + (goto-char (point-max)) + (call-process epg-gpg-program nil t t "--recv-keys" keyid) + (insert "\n") + (call-process epg-gpg-program nil t t "--list-keys" keyid)) + (recenter -1)) + (notmuch-show-refresh-view) (defun notmuch-crypto-insert-encstatus-button (encstatus) (let* ((status (plist-get encstatus :status)) One thing that's missing is to refresh the view automatically. I understand this might be difficult to implement however. For example, I naively tried to add this at the end of the sentinel: (when (= exit-status 0) (notmuch-show-refresh-view)) Then switch to another buffer (back to the search view, FWIW). The sentinel then fails with: error in process sentinel: notmuch-escape-boolean-term: Wrong type argument: stringp, nil error in process sentinel: Wrong type argument: stringp, nil Not sure why exactly. But I would certainly take the async update over automatic refresh any time. It would also be useful to indicate that will be the effect of the variable in the customize help as well. I gave that a try in the above patch. Thanks for the ultra-fast response! A. -- The United States is a nation of laws: badly written and randomly enforced. - Frank Zappa ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 1/1] RFC: add attachment checks
This implements basic attachment checks like those present in other MUAs (e.g. Thunderbird, IIRC). A hook watches for keywords implemented using a customizable regex. The keywords are assume to indicate the user forgot to add an attachment. This currently checks for words in english and french and some care was taken to avoid false positive, but those are bound to happen and we embrace them with open arms: it's better to warn by mistake than forget an attachment ever again. New languages can be added through customization, which help string suggests contributing it back to the community. --- emacs/notmuch-message.el | 37 + 1 file changed, 37 insertions(+) diff --git a/emacs/notmuch-message.el b/emacs/notmuch-message.el index 55e4cfee..ccf0906c 100644 --- a/emacs/notmuch-message.el +++ b/emacs/notmuch-message.el @@ -47,6 +47,43 @@ the \"inbox\" and \"todo\" tags, you would set: (add-hook 'message-send-hook 'notmuch-message-mark-replied) +;; attachment checks +;; +;; should be sent upstream, but needs unit tests in test/T310-emacs.sh +(defcustom notmuch-message-attach-regex + "\\b\\(attache\?ment\\|attached\\|attach\\|pi[èe]ce\s+jointe?\\)\\b" + "Pattern of text announcing there should be an attachment. + +This is used by `notmuch-message-check-attach' to check email +bodies for words that might indicate the email should have an +attachement. If the pattern matches and there is no attachment (a +`<#part ...>' magic block), notmuch will show a confirmation +prompt before sending the email. + +The default regular expression is deliberately liberal: we prefer +false positive than forgotten attachments. This should be +customized for non-english languages and notmuch welcomes +additions to the pattern for your native language, unless it +conflicts with common words in other languages." + :type '(regexp) + :group 'notmuch-send) + +(defun notmuch-message-check-attach () + """Check for missing attachments. + +This is normally added to `message-send-hook' and is configured +through `notmuch-message-attach-regex'.""" + (save-excursion +(goto-char (point-min)) +(if (re-search-forward notmuch-message-attach-regex nil t) +(progn + (goto-char (point-min)) + (unless (re-search-forward "<#part [^>]*filename=[^>]*>" nil t) +(or (y-or-n-p "Email seem to refer to attachment, but nothing attached, send anyways?") +(error "No attachment found, aborting"))) + +(add-hook 'message-send-hook 'notmuch-message-check-attach) + (provide 'notmuch-message) ;;; notmuch-message.el ends here -- 2.18.0 ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH 0/1] RFC: add attachment checks
This is a re-issue of my "attachment checks" patch, which failed to raise comments or interest in its last round. I'm resubmitting it in the hope it will fare better this time around. This code is working: I use it daily and never worry about missing attachments anymore. It did catch a few occurences but also a few false positives, which I did not mind. There are still no unit tests: bremner suggested I add some in test/T310-emacs.sh and I looked there briefly, but couldn't figure out where to add a blurb. I would need help to complete this. I did some summary tests using `re-builder' to see the effect the regex has on random strings. I tested the possible false positive "a joint attaché presse" which doesn't match and "here is an attachment, attached in the pièce jointe or piece jointe" which does. I am not sure how to implement this in a unit test: should we try to send an email and check if it aborts like the "Sending a message via (fake) SMTP" test? Or should I just check that `notmuch-message-check-attach' works against a temporary buffer? Is there a harness that allows matching against messages like that already? I'd also welcome comments on the approach in general. Another user came up on IRC recently (impatkor) with the same need and used the following snippet instead: https://pastebin.com/N9ku3DBD It is a very similar implementation although it checks for `Content-Disposition: attachment` instead of `<#part>`: not sure which one is actually accurate. It also adds the word `bifoga` as a pattern, but I haven't verified that in swedish and would wait for feedback on the multilingual approach before adding new words here. Finally, note that an earlier version of this used `save-mark-and-excursion` but I had to revert back to `save-excursion` because the function was missing in some other version of Emacs I was testing. That part does not work anyways: something else is moving the mark around when sending, but I figured I would keep this hook well-behaving even if others screw that up. I did remove the "XXX" note there because there's nothing else to do on that front. Antoine Beaupré (1): RFC: add attachment checks emacs/notmuch-message.el | 37 + 1 file changed, 37 insertions(+) -- 2.18.0 ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
Re: PATCH: fetch missing keys in the background
On Monday, 2018-09-03 at 13:47:09 -0400, Antoine Beaupré wrote: > On 2018-09-03 18:21:32, David Edmondson wrote: >> How about this patch? >> >> You'll need to set “notmuch-crypto-get-keys-asynchronously” to “t” to >> see any benefit. > > This is great! > > As you said on IRC, the patch is more likely: Another version, which attempts to redisplay the buffer if it thinks that it's safe and sensible to do so. This version *defaults* to async behaviour, as I think that it's safe to do so. diff --git a/emacs/notmuch-crypto.el b/emacs/notmuch-crypto.el index fc2b5301..6e003f51 100644 --- a/emacs/notmuch-crypto.el +++ b/emacs/notmuch-crypto.el @@ -43,6 +43,11 @@ mode." :package-version '(notmuch . "0.25") :group 'notmuch-crypto) +(defcustom notmuch-crypto-get-keys-asynchronously t + "Retrieve gpg keys asynchronously." + :type 'boolean + :group 'notmuch-crypto) + (defface notmuch-crypto-part-header 'class color) (background dark)) @@ -145,19 +150,56 @@ mode." (call-process epg-gpg-program nil t t "--list-keys" fingerprint)) (recenter -1 +(defun notmuch-crypto--async-key-sentinel (process event) + (let ((status (process-status process)) + (exit-status (process-exit-status process)) + (keyid (process-get process :gpg-key-id))) +(when (memq status '(exit signal)) + (message "Getting the GPG key %s asynchronously...%s." + keyid + (if (= exit-status 0) + "completed" + "failed")) + ;; If retrieving the key was successful, the original buffer is + ;; still alive and point didn't move (i.e. the user didn't move + ;; on or away), refresh the buffer. + (when (= exit-status 0) + (let ((show-buffer (process-get process :notmuch-show-buffer)) + (show-point (process-get process :notmuch-show-point))) + (when (and (bufferp show-buffer) + (buffer-live-p show-buffer) + (with-current-buffer show-buffer + (= show-point (point + (with-current-buffer show-buffer + (notmuch-show-refresh-view + (defun notmuch-crypto-sigstatus-error-callback (button) (let* ((sigstatus (button-get button :notmuch-sigstatus)) (keyid (concat "0x" (plist-get sigstatus :keyid))) - (buffer (get-buffer-create "*notmuch-crypto-gpg-out*")) - (window (display-buffer buffer t nil))) -(with-selected-window window - (with-current-buffer buffer - (goto-char (point-max)) - (call-process epg-gpg-program nil t t "--recv-keys" keyid) - (insert "\n") - (call-process epg-gpg-program nil t t "--list-keys" keyid)) - (recenter -1)) -(notmuch-show-refresh-view))) + (buffer (get-buffer-create "*notmuch-crypto-gpg-out*"))) +(if notmuch-crypto-get-keys-asynchronously + (let ((p (make-process :name "notmuch GPG key retrieval" + :buffer buffer + :command (list epg-gpg-program "--recv-keys" keyid) + :sentinel #'notmuch-crypto--async-key-sentinel + ;; Create the process stopped so that + ;; we have time to store the key id on + ;; it. + :stop t))) + (process-put p :gpg-key-id keyid) + (process-put p :notmuch-show-buffer (current-buffer)) + (process-put p :notmuch-show-point (point)) + (message "Getting the GPG key %s asynchronously..." keyid) + (continue-process p)) + (let ((window (display-buffer buffer t nil))) + (with-selected-window window + (with-current-buffer buffer + (goto-char (point-max)) + (call-process epg-gpg-program nil t t "--recv-keys" keyid) + (insert "\n") + (call-process epg-gpg-program nil t t "--list-keys" keyid)) + (recenter -1)) + (notmuch-show-refresh-view) (defun notmuch-crypto-insert-encstatus-button (encstatus) (let* ((status (plist-get encstatus :status)) dme. -- Please don't stand so close to me. ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
Re: feature request: fetch missing keys in the background
That's great! It's basically what I was looking for, but unfortunately it does not work here. I am not sure why, but it never actually updates the widget, even if I do not move the point. A. -- Sous le projecteur, on ne voit pas les autres. - Félix Leclerc ___ notmuch mailing list notmuch@notmuchmail.org https://notmuchmail.org/mailman/listinfo/notmuch
[PATCH] cli: add --output=filesandtags to notmuch search
This commit adds a filesandtags output format, which outputs the filenames of all matching messages together with their tags. Files and tags are separated by newlines or null-bytes for --format=text or text0 respectively, so that filenames and tags are on alternating lines. The json and sexp output formats are a list of maps, with a "filename" and "tags" key each. The rationale for this output parameter is to have a way of searching messages with notmuch in a scenario where display of message info is taken care of by another application based on filenames (e.g. mblaze), but that also want to make use of related tags. This use case isn't covered with any other notmuch search output format, and very cumbersome with notmuch show. It's possible to cover this workflow with a trivial python script. However in a quick test, a query that returned 40 messages was about three times slower for me with a python script with a hot cache, and even worse with a cold cache. --- NEWS| 7 ++ doc/man1/notmuch-search.rst | 10 ++- notmuch-search.c| 58 +++- test/T090-search-output.sh | 171 4 files changed, 241 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index 240d594b..18e8a08d 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,10 @@ +Command Line Interface +-- + +Add the --output=filesandtags option to `notmuch search` + + This option outputs both the filenames and tags of relevant messages. + Notmuch 0.27 (2018-06-13) = diff --git a/doc/man1/notmuch-search.rst b/doc/man1/notmuch-search.rst index 654c5f2c..96593096 100644 --- a/doc/man1/notmuch-search.rst +++ b/doc/man1/notmuch-search.rst @@ -35,7 +35,7 @@ Supported options for **search** include intended for programs that invoke **notmuch(1)** internally. If omitted, the latest supported version will be used. -``--output=(summary|threads|messages|files|tags)`` +``--output=(summary|threads|messages|files|tags|filesandtags)`` **summary** Output a summary of each thread with any message matching the search terms. The summary includes the thread ID, date, the @@ -71,6 +71,14 @@ Supported options for **search** include in other directories that are included in the output, although these files alone would not match the search. +**filesandtags** +Output the filenames of all messages matching the search terms, together +with their corresponding tags. Filenames and tags are output as lines in +an alternating fashion so that filenames are on odd lines and their tags +on the following even line (``--format=text``), as a JSON arrray of +objects (``--format=text``), or as an S-Expression list +(``--format=sexp``). + **tags** Output all tags that appear on any message matching the search terms, either one per line (``--format=text``), separated by null diff --git a/notmuch-search.c b/notmuch-search.c index 8f467db4..65167afa 100644 --- a/notmuch-search.c +++ b/notmuch-search.c @@ -29,12 +29,13 @@ typedef enum { OUTPUT_MESSAGES= 1 << 2, OUTPUT_FILES = 1 << 3, OUTPUT_TAGS= 1 << 4, +OUTPUT_FILESANDTAGS = 1 << 5, /* Address command */ -OUTPUT_SENDER = 1 << 5, -OUTPUT_RECIPIENTS = 1 << 6, -OUTPUT_COUNT = 1 << 7, -OUTPUT_ADDRESS = 1 << 8, +OUTPUT_SENDER = 1 << 6, +OUTPUT_RECIPIENTS = 1 << 7, +OUTPUT_COUNT = 1 << 8, +OUTPUT_ADDRESS = 1 << 9, } output_t; typedef enum { @@ -537,6 +538,7 @@ do_search_messages (search_context_t *ctx) notmuch_message_t *message; notmuch_messages_t *messages; notmuch_filenames_t *filenames; +notmuch_tags_t *tags; sprinter_t *format = ctx->format; int i; notmuch_status_t status; @@ -583,6 +585,52 @@ do_search_messages (search_context_t *ctx) } notmuch_filenames_destroy( filenames ); + } else if (ctx->output == OUTPUT_FILESANDTAGS) { + int j; + filenames = notmuch_message_get_filenames (message); + + for (j = 1; + notmuch_filenames_valid (filenames); + notmuch_filenames_move_to_next (filenames), j++) + { + + if (ctx->dupe < 0 || ctx->dupe == j) { + format->begin_map (format); + format->map_key (format, "filename"); + + format->string (format, notmuch_filenames_get (filenames)); + if (format->is_text_printer) { + format->separator (format); + } + + format->map_key (format, "tags"); + format->begin_list (format); + + bool first_tag = true; + for (tags = notmuch_message_get_tags (message); + notmuch_tags_valid (tags)