[PATCH] emacs: Function to query the list of labels from a thread-id
This patch adds `notmuch-query-thread-labels-from-id' and corresponding test. This function returns the labels of thread whose id is passed as argument. The thread labels are the union of the labels of emails in the thread. I need this function to integrate notmuch-labeler. Signed-off-by: Damien Cassou --- emacs/notmuch-query.el | 16 test/emacs | 23 +++ 2 files changed, 39 insertions(+) diff --git a/emacs/notmuch-query.el b/emacs/notmuch-query.el index d66baea..8b9a41d 100644 --- a/emacs/notmuch-query.el +++ b/emacs/notmuch-query.el @@ -81,4 +81,20 @@ See the function notmuch-query-get-threads for more information." (lambda (msg) (plist-get msg :id)) (notmuch-query-get-threads search-terms))) +(defun notmuch-query-thread-labels-from-id (thread-id) + "Return the labels of thread whose id is THREAD-ID. +The thread labels are the union of the labels of emails in the +thread." + (let ((label-lists +(notmuch-query-map-forest + (lambda (msg) (plist-get msg :tags)) + (car (notmuch-query-get-threads + (list (concat "thread:" thread-id))) +(case (length label-lists) + (0 nil) + (1 (car label-lists)) + (otherwise (reduce (lambda (l1 l2) + (union l1 l2 :test 'string=)) +label-lists) + (provide 'notmuch-query) diff --git a/test/emacs b/test/emacs index 44f641e..3e8bdb8 100755 --- a/test/emacs +++ b/test/emacs @@ -820,5 +820,28 @@ Date: Fri, 05 Jan 2001 15:43:57 + EOF test_expect_equal_file OUTPUT EXPECTED +test_begin_subtest "Extracting all labels from a thread" +add_message \ +'[subject]="Extracting all labels from a thread"' \ +'[body]="body 1"' +first=${gen_msg_cnt} +parent=${gen_msg_id} +add_message \ +'[subject]="Extracting all labels from a thread"' \ +'[body]="body 2"' \ +"[in-reply-to]=\<$parent\>" +add_message \ +'[subject]="Extracting all labels from a thread"' \ +'[body]="body 3"' \ +"[in-reply-to]=\<$parent\>" +latest=${gen_msg_id} +# Extract the thread-id from one of the emails +thread_id=$(notmuch search id:${latest} | sed -e "s/thread:\([a-f0-9]*\).*/\1/") +# Add tag "mytagfoo" to one of the emails +notmuch tag +mytagfoo id:${latest} +test_emacs_expect_t \ +"(let ((output (notmuch-query-thread-labels-from-id \"${thread_id}\")) + (expected '(\"inbox\" \"mytagfoo\" \"unread\"))) + (notmuch-test-expect-equal output expected))" test_done -- 1.7.10.4
[PATCH v5 2/9] parse-time-string: add a date/time parser to notmuch
Quoth Jani Nikula on Oct 29 at 12:30 am: > On Mon, 22 Oct 2012, Austin Clements wrote: > >> +/* > >> + * Accepted keywords. > >> + * > >> + * A keyword may optionally contain a '|' to indicate the minimum > >> + * match length. Without one, full match is required. It's advisable > >> + * to keep the minimum match parts unique across all keywords. > >> + * > >> + * If keyword begins with upper case letter, then the matching will be > >> + * case sensitive. Otherwise the matching is case insensitive. > >> + * > >> + * If setter is NULL, set_default will be used. > >> + * > >> + * Note: Order matters. Matching is greedy, longest match is used, but > >> + * of equal length matches the first one is used, unless there's an > >> + * equal length case sensitive match which trumps case insensitive > >> + * matches. > > > > If you do have a tokenizer (or disallow mashing keywords together), > > then all of complexity arising from longest match goes away because > > the keyword token either will or won't match a keyword. If you also > > eliminate the rule for case sensitivity and put case-sensitive things > > before conflicting case-insensitive things (so put "M" before > > "m|inutes"), then you can simply use the first match. > > At least one reason for going through the whole table is that if this > ever gets i18n support, the conflicting things might be different. While > order matters in principle, you should create the table so that it > really doesn't matter. While that's true, if the input keyword has to be syntactically delimited, there's still no such thing as a "longest match", since the length of any match will be the length of the input. You may still want to scan the whole table, but if you find multiple matches, it's a bug in the table indicating that |ed prefixes aren't unique. Hence, if you're not interested in finding bugs in the table, you can just find the first match. Or you could remove the |'s from the table, scan the whole table, and consider the input string ambiguous if it matches multiple table entries (being careful with case sensitivity), just like you do now if the input string is shorter than the |ed prefixes. That would simplify your table, your matching logic, and possibly your scanning logic. > > > >> + */ > >> +static struct keyword keywords[] = { > >> +/* Weekdays. */ > >> +{ N_("sun|day"), TM_ABS_WDAY,0, NULL }, > >> +{ N_("mon|day"), TM_ABS_WDAY,1, NULL }, > >> +{ N_("tue|sday"), TM_ABS_WDAY,2, NULL }, > >> +{ N_("wed|nesday"), TM_ABS_WDAY,3, NULL }, > >> +{ N_("thu|rsday"),TM_ABS_WDAY,4, NULL }, > >> +{ N_("fri|day"), TM_ABS_WDAY,5, NULL }, > >> +{ N_("sat|urday"),TM_ABS_WDAY,6, NULL }, > >> + > >> +/* Months. */ > >> +{ N_("jan|uary"), TM_ABS_MON, 1, kw_set_month }, > >> +{ N_("feb|ruary"),TM_ABS_MON, 2, kw_set_month }, > >> +{ N_("mar|ch"), TM_ABS_MON, 3, kw_set_month }, > >> +{ N_("apr|il"), TM_ABS_MON, 4, kw_set_month }, > >> +{ N_("may"), TM_ABS_MON, 5, kw_set_month }, > >> +{ N_("jun|e"),TM_ABS_MON, 6, kw_set_month }, > >> +{ N_("jul|y"),TM_ABS_MON, 7, kw_set_month }, > >> +{ N_("aug|ust"), TM_ABS_MON, 8, kw_set_month }, > >> +{ N_("sep|tember"), TM_ABS_MON, 9, kw_set_month }, > >> +{ N_("oct|ober"), TM_ABS_MON, 10, kw_set_month }, > >> +{ N_("nov|ember"),TM_ABS_MON, 11, kw_set_month }, > >> +{ N_("dec|ember"),TM_ABS_MON, 12, kw_set_month }, > >> + > >> +/* Durations. */ > >> +{ N_("y|ears"), TM_REL_YEAR,1, kw_set_rel }, > >> +{ N_("w|eeks"), TM_REL_WEEK,1, kw_set_rel }, > >> +{ N_("d|ays"),TM_REL_DAY, 1, kw_set_rel }, > >> +{ N_("h|ours"), TM_REL_HOUR,1, kw_set_rel }, > >> +{ N_("hr|s"), TM_REL_HOUR,1, kw_set_rel }, > >> +{ N_("m|inutes"), TM_REL_MIN, 1, kw_set_rel }, > >> +/* M=months, m=minutes */ > >> +{ N_("M"),TM_REL_MON, 1, kw_set_rel }, > >> +{ N_("mins"), TM_REL_MIN, 1, kw_set_rel }, > >> +{ N_("mo|nths"), TM_REL_MON, 1, kw_set_rel }, > >> +{ N_("s|econds"), TM_REL_SEC, 1, kw_set_rel }, > >> +{ N_("secs"), TM_REL_SEC, 1, kw_set_rel }, > >> + > >> +/* Numbers. */ > >> +{ N_("one"), TM_NONE,1, kw_set_number }, > >> +{ N_("two"), TM_NONE,2, kw_set_number }, > >> +{ N_("three"),TM_NONE,3, kw_set_number }, > >> +{ N_("four"), TM_NONE,4, kw_set_number }, > >> +{ N_("five"), TM_NONE,5, kw_set_number }, > >> +{ N_("six"), TM_NONE,6, kw_set_number }, > >> +{ N_("seven"),TM_NONE,7, kw_set_number
[PATCH 0/2] automatic tagging based on imap maildir
Quoth Andrei POPESCU on Oct 28 at 11:44 pm: > On Du, 28 oct 12, 11:31:38, Austin Clements wrote: > > > > Why does that cause you to not receive mailing lists? (Or did I > > misinterpret your statement?) > > Yes. The main deterrent in Gmail silently dropping my own postings > returning via the list, because it considers it identical to the sent > message. Ah. And I assume you want to see those in your inbox even if they're not a reply to some other message in your inbox? I do recall Gmail suppressing list reflections. Though I think that, by default, notmuch *will* put your own list postings in your inbox. Assuming the list sends the message back to you (not all do), and assuming your notmuch new.tags contains inbox, notmuch will simply see it as a new message and tag it inbox. If you have Fcc setup in your frontend of choice to save sent messages in a folder indexed by notmuch, then it should likewise tag the message inbox as soon as it indexes it.
bug related to ical
Olivier Berger writes: > Hi. > > Just in case, Tomi proposed an updated version in Message-ID: > <1349333712-18347-1-git-send-email-tomi.ollila at iki.fi> > > ... but it doesn't seem to fix the issue for me :-/ > Actually, this is not true, as I had forgotten to recompile the emacs lisp before testing. I do confirm that the patches in Message-ID: <1349333712-18347-1-git-send-email-tomi.ollila at iki.fi> (http://permalink.gmane.org/gmane.mail.notmuch.general/12518) and Message-ID: <1350826509-12119-1-git-send-email-tomi.ollila at iki.fi> (http://permalink.gmane.org/gmane.mail.notmuch.general/12631) seem to solve the issue. Hope this helps. Best regards, -- Olivier BERGER http://www-public.it-sudparis.eu/~berger_o/ - OpenPGP-Id: 2048R/5819D7E8 Ingenieur Recherche - Dept INF Institut Mines-Telecom, Telecom SudParis, Evry (France)
[PATCH] contrib: pick: use async parser from lib
This moves notmuch-pick to use the newly split out async json parser from notmuch-lib.el. --- I hadn't expected the split out json parser to go in so quickly: this moves notmuch-pick to use the new function. Best wishes Mark contrib/notmuch-pick/notmuch-pick.el | 52 +++-- 1 files changed, 5 insertions(+), 47 deletions(-) diff --git a/contrib/notmuch-pick/notmuch-pick.el b/contrib/notmuch-pick/notmuch-pick.el index be6a91a..15ac5e8 100644 --- a/contrib/notmuch-pick/notmuch-pick.el +++ b/contrib/notmuch-pick/notmuch-pick.el @@ -435,7 +435,7 @@ Does NOT change the database." (unless (notmuch-pick-get-match) (notmuch-pick-next-matching-message)) (while (and (not (notmuch-pick-get-match)) - (not (eq notmuch-pick-process-state 'end))) + (get-buffer-process (current-buffer))) (message "waiting for message") (sit-for 0.1) (goto-char (point-min)) @@ -733,9 +733,6 @@ Complete list of currently available key bindings: (insert "\n"))) -(defvar notmuch-pick-json-parser nil - "Incremental JSON parser for the search process filter.") - (defun notmuch-pick-process-filter (proc string) "Process and filter the output of \"notmuch show\" (for pick)" (let ((results-buf (process-buffer proc)) @@ -748,46 +745,10 @@ Complete list of currently available key bindings: ;; Insert new data (save-excursion (goto-char (point-max)) - (insert string))) - (with-current-buffer results-buf - (save-excursion - (goto-char (point-max)) - (while (not done) - (condition-case nil - (case notmuch-pick-process-state - ((begin) - ;; Enter the results list - (if (eq (notmuch-json-begin-compound - notmuch-pick-json-parser) 'retry) - (setq done t) -(setq notmuch-pick-process-state 'result))) - ((result) - ;; Parse a result - (let ((result (notmuch-json-read notmuch-pick-json-parser))) -(case result - ((retry) (setq done t)) - ((end) (setq notmuch-pick-process-state 'end)) - (otherwise (notmuch-pick-insert-forest-thread result) - ((end) - ;; Any trailing data is unexpected - (with-current-buffer parse-buf -(skip-chars-forward " \t\r\n") -(if (eobp) -(setq done t) - (signal 'json-error nil) - (json-error - ;; Do our best to resynchronize and ensure forward - ;; progress - (notmuch-pick-show-error - "%s" - (with-current-buffer parse-buf - (let ((bad (buffer-substring (line-beginning-position) - (line-end-position - (forward-line) - bad)) - ;; Clear out what we've parsed - (with-current-buffer parse-buf - (delete-region (point-min) (point + (insert string)) + (notmuch-json-parse-partial-list 'notmuch-pick-insert-forest-thread +'notmuch-pick-show-error +results-buf) (defun notmuch-pick-worker (basic-query query-context buffer) (interactive) @@ -815,9 +776,6 @@ Complete list of currently available key bindings: ;; This buffer will be killed by the sentinel, which ;; should be called no matter how the process dies. (parse-buf (generate-new-buffer " *notmuch pick parse*"))) - (set (make-local-variable 'notmuch-pick-process-state) 'begin) - (set (make-local-variable 'notmuch-pick-json-parser) - (notmuch-json-create-parser parse-buf)) (process-put proc 'parse-buf parse-buf) (set-process-sentinel proc 'notmuch-pick-process-sentinel) (set-process-filter proc 'notmuch-pick-process-filter) -- 1.7.9.1
[PATCH 0/3] Add notmuch-pick to contrib
Mark Walters writes: > This is a new version of notmuch-pick (previous version at > id:"1343164911-31589-1-git-send-email-markwalters1009 at gmail.com")following > suggestions of Tomi and David in that thread. The main change is that > it is now entirely self contained in contrib: all the user needs to do > is copy the notmuch-pick.el somewhere in the emacs load path and add > (require 'notmuch-pick nil t) to their .emacs file. I have pushed this to contrib. We do need tests before this goes mainline. What about (untested) having the tests in contrib/notmuch-pick for now, including as needed from ../../test. We should mention it in NEWS; at this point I think it is reasonable to expect to do at least one release with pick in contrib. As a vague feature request, what about forwarding unknown keys to the notmuch-show buffer? d
[PATCH 0/2] automatic tagging based on imap maildir
On Sb, 27 oct 12, 10:00:46, David Bremner wrote: > > As I said (or tried to say), in my opinion, duplication with an external > package is not the main issue; I think moving features into the core > when appropriate is a normal development process. On the other hand, I'm > not really a gmail user, so I don't know yet if these patches solve > enough of the problem to be interesting. They are interesting not only for Gmail[1], but also for other kinds of setups. As far as I understand (please correct me if I'm wrong), currently notmuch treats multiple copies of a message similar to Gmail (indexes one, but ignores the rest), which is why I'm *not* receiving any mailing lists on my Gmail account. Besides that consider also that I'm subscribed to about 40 mailing lists, each sorted to it's own folder by rules based on List-Id (which notmuch doesn't support yet as far as I know). This separation is very useful for my read-flow. However, there are messages crossposed to several lists. It would be great if notmuch or (more probably) a client using notmuch could mark all copies of a message as read in all folders, but still keep it there (otherwise the thread in the respective folder is incomplete). [1] yes, this is probably one missing feature that prevents me from putting my Gmail account in notmuch as well. Kind regards, Andrei -- If you can't explain it simply, you don't understand it well enough. (Albert Einstein) -- next part -- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 490 bytes Desc: Digital signature URL: <http://notmuchmail.org/pipermail/notmuch/attachments/20121028/9eac1aa3/attachment-0001.pgp>
[PATCH 0/2] automatic tagging based on imap maildir
Quoth Andrei POPESCU on Oct 28 at 12:03 pm: > On Sb, 27 oct 12, 10:00:46, David Bremner wrote: > > > > As I said (or tried to say), in my opinion, duplication with an external > > package is not the main issue; I think moving features into the core > > when appropriate is a normal development process. On the other hand, I'm > > not really a gmail user, so I don't know yet if these patches solve > > enough of the problem to be interesting. > > They are interesting not only for Gmail[1], but also for other kinds of What is preventing folder: searches from addressing this? > setups. As far as I understand (please correct me if I'm wrong), > currently notmuch treats multiple copies of a message similar to Gmail > (indexes one, but ignores the rest), which is why I'm *not* receiving > any mailing lists on my Gmail account. notmuch tracks all copies of a message, but its output generally shows messages, rather than files, so you see a message only once regardless of how many copies there are in the file system. Why does that cause you to not receive mailing lists? (Or did I misinterpret your statement?) > Besides that consider also that I'm subscribed to about 40 mailing > lists, each sorted to it's own folder by rules based on List-Id (which > notmuch doesn't support yet as far as I know). This separation is very > useful for my read-flow. > > However, there are messages crossposed to several lists. It would be > great if notmuch or (more probably) a client using notmuch could mark > all copies of a message as read in all folders, but still keep it there > (otherwise the thread in the respective folder is incomplete). If I understand what you're saying, this is exactly what notmuch does. When you remove the "unread" tag, notmuch will (should?) add the "seen" maildir flag to all copies of that message in the file system (barring some corner-cases that flag sync doesn't handle well; maybe you're encountering one of those?). And since notmuch never deletes files, they will remain in the folders they were filed in. > [1] yes, this is probably one missing feature that prevents me from > putting my Gmail account in notmuch as well. > > Kind regards, > Andrei
[PATCH (draft) 1/2] emacs: allow the user to toggle the visibility of multipart/alternative parts
Ethan Glasser-Camp writes: > Mark Walters writes: > >> This patch adds a keybinding to the buttons in the notmuch-show emacs >> buffer to allow the user to toggle the visibility of each part of a >> message in the show buffer. This is particularly useful for >> multipart/alternative parts where the parts are not really >> alternatives but contain different information. >> --- >> emacs/notmuch-show.el | 47 +++ >> 1 files changed, 39 insertions(+), 8 deletions(-) >> >> diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el >> index 0f54259..9157669 100644 >> --- a/emacs/notmuch-show.el >> +++ b/emacs/notmuch-show.el >> @@ -155,6 +155,10 @@ indentation." >> (make-variable-buffer-local 'notmuch-show-indent-content) >> (put 'notmuch-show-indent-content 'permanent-local t) >> >> +(defvar notmuch-show-message-multipart/alternative-display-parts nil) >> +(make-variable-buffer-local >> 'notmuch-show-message-multipart/alternative-display-parts) >> +(put 'notmuch-show-message-multipart/alternative-display-parts >> 'permanent-local t) >> + >> (defcustom notmuch-show-stash-mlarchive-link-alist >>'(("Gmane" . "http://mid.gmane.org/;) >> ("MARC" . "http://marc.info/?i=;) >> @@ -455,6 +459,7 @@ message at DEPTH in the current thread." >> (define-key map "v" 'notmuch-show-part-button-view) >> (define-key map "o" 'notmuch-show-part-button-interactively-view) >> (define-key map "|" 'notmuch-show-part-button-pipe) >> +(define-key map "t" 'notmuch-show-part-button-internally-show) >> map) >>"Submap for button commands") >> (fset 'notmuch-show-part-button-map notmuch-show-part-button-map) >> @@ -531,6 +536,16 @@ message at DEPTH in the current thread." >> (let ((handle (mm-make-handle (current-buffer) (list content-type >>(mm-pipe-part handle >> >> +(defun notmuch-show-internally-show-part (message-id nth filename >> content-type) >> + "Set a part to be displayed internally" >> + (let ((current-parts (lax-plist-get >> notmuch-show-message-multipart/alternative-display-parts message-id))) >> +(setq notmuch-show-message-multipart/alternative-display-parts >> + (lax-plist-put >> notmuch-show-message-multipart/alternative-display-parts message-id >> + (if (memq nth current-parts) >> + (delq nth current-parts) >> +(cons nth current-parts) >> + (notmuch-show-refresh-view)) >> + >> (defun notmuch-show-multipart/*-to-list (part) >>(mapcar (lambda (inner-part) (plist-get inner-part :content-type)) >> (plist-get part :content))) >> @@ -543,12 +558,15 @@ message at DEPTH in the current thread." >> ;; This inserts all parts of the chosen type rather than just one, >> ;; but it's not clear that this is the wrong thing to do - which >> ;; should be chosen if there are more than one that match? >> + >> +;; The variable user-parts says which parts should override the >> +;; default so we use xor (handcoded since lisp does not have it). > > I don't follow the comment. user-parts isn't used in this > function. Neither is xor. Sorry that is vestigial from when the logic was in this function. The "xor" now occurs in the other function. > >> (mapc (lambda (inner-part) >> (let ((inner-type (plist-get inner-part :content-type))) >> - (if (or notmuch-show-all-multipart/alternative-parts >> - (string= chosen-type inner-type)) >> - (notmuch-show-insert-bodypart msg inner-part depth) >> - (notmuch-show-insert-part-header (plist-get inner-part :id) >> inner-type inner-type nil " (not shown)" >> + (notmuch-show-insert-bodypart msg inner-part depth >> + (not (or >> notmuch-show-all-multipart/alternative-parts >> + (string= >> chosen-type inner-type)) > > For what it's worth, I found this not-shown logic very confusing, and > have had to think about it seven or eight different times to make sure I > understood what's going on. I'm not sure why exactly this is, though I > could offer hypotheses -- the fact that it's split across two functions, > or the fiddling with mime-types. I'm satisfied that it's correct, but I > wish it could be made clearer. I think the reason I went for the split is that I wanted all parts to be togglable: I think having some parts which can be collapsed and some which can't is a recipe for confusion (particularly as they might both be labelled "[text/html]" for example). I think this means the split is required: the first is "what does notmuch want to do with this part" and the second is "what does the user want to do" > This is just armchair hypothesizing, but here are some ideas that might > make it more obvious what's going on: bringing the user-parts logic into > this function; making user-parts,
[PATCH v5 2/9] parse-time-string: add a date/time parser to notmuch
On Thu, Oct 25 2012, Austin Clements wrote: > Quoth myself on Oct 22 at 4:14 am: >> Overall this looks pretty good to me, and I must say, this parser is >> amazingly flexible and copes well with a remarkably hostile grammar. >> >> A lot of little comments below (sorry if any of this ground has >> already been covered in the previous four versions). >> >> I do have one broad comment. While I'm all for ad hoc parsers for ad >> hoc grammars like dates, there is one piece of the literature I think >> this parser suffers for by ignoring: tokenizing. I think it would >> simplify a lot of this code if it did a tokenizing pass before the >> parsing pass. It doesn't have to be a serious tokenizer with >> streaming and keywords and token types and junk; just something that >> first splits the input into substrings, possibly just non-overlapping >> matches of [[:digit:]]+|[[:alpha:]]+|[-+:/.]. This would simplify the >> handling of postponed numbers because, with trivial lookahead in the >> token stream, you wouldn't have to postpone them. Likewise, it would >> eliminate last_field. It would simplify keyword matching because you >> wouldn't have to worry about matching substrings (I spent a long time >> staring at that code before I figured out what it would and wouldn't >> accept). Most important, I think it would make the parser more >> predictable for users; for example, the parser currently accepts >> things like "saturtoday" because it's aggressively single-pass. > > I should add that I am not at all opposed to this patch as it is > currently designed. We need a date parser. My comment about > separating tokenization is just a way that this code could probably be > simplified if someone were so inclined or if simplifying the code > would help it pass any hurdles. What if the current patch set, i.e. messages $ grep Message-Id: ~/patch | sed 's/Message-Id: /id:/; y/<>/""/' id:"e684cadbb5a01b6079ef344b0d6f97541847914a.1350854171.git.jani at nikula.org" id:"a90d3b687895a26f765539d6c0420038a74ee42f.1350854171.git.jani at nikula.org" id:"75a8f129d5e0d824b3e04ddfc1816c45fa0ec70d.1350854171.git.jani at nikula.org" id:"606a94d565e6b21abfc59d6ba9676a807d669127.1350854171.git.jani at nikula.org" id:"cbd383bfc4bf844bb0366f13f675d48956137c52.1350854171.git.jani at nikula.org" id:"f21b8702728457c087478b26700e9448bc16c61d.1350854171.git.jani at nikula.org" id:"37026480956679b12e82e4975f1837e93ef1c531.1350854171.git.jani at nikula.org" id:"cff9c1dd87b8bc11326dca0b3589c81656500f5e.1350854171.git.jani at nikula.org" (patches 1-8 / 9 -- NEWS patch is stale) would just be pushed: there are just few trivial things to be tuned and NEWS rebased -- which I think Jani will gladly do... It is just so much easier for him to continue and us others to review the new diffs than these whole patches again and again... At least I volunteer to track that these remaining issues (tokenizer not included :). Tomi
Re: [PATCH (draft) 1/2] emacs: allow the user to toggle the visibility of multipart/alternative parts
Ethan Glasser-Camp ethan.glasser.c...@gmail.com writes: Mark Walters markwalters1...@gmail.com writes: This patch adds a keybinding to the buttons in the notmuch-show emacs buffer to allow the user to toggle the visibility of each part of a message in the show buffer. This is particularly useful for multipart/alternative parts where the parts are not really alternatives but contain different information. --- emacs/notmuch-show.el | 47 +++ 1 files changed, 39 insertions(+), 8 deletions(-) diff --git a/emacs/notmuch-show.el b/emacs/notmuch-show.el index 0f54259..9157669 100644 --- a/emacs/notmuch-show.el +++ b/emacs/notmuch-show.el @@ -155,6 +155,10 @@ indentation. (make-variable-buffer-local 'notmuch-show-indent-content) (put 'notmuch-show-indent-content 'permanent-local t) +(defvar notmuch-show-message-multipart/alternative-display-parts nil) +(make-variable-buffer-local 'notmuch-show-message-multipart/alternative-display-parts) +(put 'notmuch-show-message-multipart/alternative-display-parts 'permanent-local t) + (defcustom notmuch-show-stash-mlarchive-link-alist '((Gmane . http://mid.gmane.org/;) (MARC . http://marc.info/?i=;) @@ -455,6 +459,7 @@ message at DEPTH in the current thread. (define-key map v 'notmuch-show-part-button-view) (define-key map o 'notmuch-show-part-button-interactively-view) (define-key map | 'notmuch-show-part-button-pipe) +(define-key map t 'notmuch-show-part-button-internally-show) map) Submap for button commands) (fset 'notmuch-show-part-button-map notmuch-show-part-button-map) @@ -531,6 +536,16 @@ message at DEPTH in the current thread. (let ((handle (mm-make-handle (current-buffer) (list content-type (mm-pipe-part handle +(defun notmuch-show-internally-show-part (message-id nth optional filename content-type) + Set a part to be displayed internally + (let ((current-parts (lax-plist-get notmuch-show-message-multipart/alternative-display-parts message-id))) +(setq notmuch-show-message-multipart/alternative-display-parts + (lax-plist-put notmuch-show-message-multipart/alternative-display-parts message-id + (if (memq nth current-parts) + (delq nth current-parts) +(cons nth current-parts) + (notmuch-show-refresh-view)) + (defun notmuch-show-multipart/*-to-list (part) (mapcar (lambda (inner-part) (plist-get inner-part :content-type)) (plist-get part :content))) @@ -543,12 +558,15 @@ message at DEPTH in the current thread. ;; This inserts all parts of the chosen type rather than just one, ;; but it's not clear that this is the wrong thing to do - which ;; should be chosen if there are more than one that match? + +;; The variable user-parts says which parts should override the +;; default so we use xor (handcoded since lisp does not have it). I don't follow the comment. user-parts isn't used in this function. Neither is xor. Sorry that is vestigial from when the logic was in this function. The xor now occurs in the other function. (mapc (lambda (inner-part) (let ((inner-type (plist-get inner-part :content-type))) - (if (or notmuch-show-all-multipart/alternative-parts - (string= chosen-type inner-type)) - (notmuch-show-insert-bodypart msg inner-part depth) - (notmuch-show-insert-part-header (plist-get inner-part :id) inner-type inner-type nil (not shown) + (notmuch-show-insert-bodypart msg inner-part depth + (not (or notmuch-show-all-multipart/alternative-parts + (string= chosen-type inner-type)) For what it's worth, I found this not-shown logic very confusing, and have had to think about it seven or eight different times to make sure I understood what's going on. I'm not sure why exactly this is, though I could offer hypotheses -- the fact that it's split across two functions, or the fiddling with mime-types. I'm satisfied that it's correct, but I wish it could be made clearer. I think the reason I went for the split is that I wanted all parts to be togglable: I think having some parts which can be collapsed and some which can't is a recipe for confusion (particularly as they might both be labelled [text/html] for example). I think this means the split is required: the first is what does notmuch want to do with this part and the second is what does the user want to do This is just armchair hypothesizing, but here are some ideas that might make it more obvious what's going on: bringing the user-parts logic into this function; making user-parts, instead of a t meaning user has toggled this, something like 'opened or 'closed and if user-parts for this message is absent,
Re: [PATCH 0/2] automatic tagging based on imap maildir
On Sb, 27 oct 12, 10:00:46, David Bremner wrote: As I said (or tried to say), in my opinion, duplication with an external package is not the main issue; I think moving features into the core when appropriate is a normal development process. On the other hand, I'm not really a gmail user, so I don't know yet if these patches solve enough of the problem to be interesting. They are interesting not only for Gmail[1], but also for other kinds of setups. As far as I understand (please correct me if I'm wrong), currently notmuch treats multiple copies of a message similar to Gmail (indexes one, but ignores the rest), which is why I'm *not* receiving any mailing lists on my Gmail account. Besides that consider also that I'm subscribed to about 40 mailing lists, each sorted to it's own folder by rules based on List-Id (which notmuch doesn't support yet as far as I know). This separation is very useful for my read-flow. However, there are messages crossposed to several lists. It would be great if notmuch or (more probably) a client using notmuch could mark all copies of a message as read in all folders, but still keep it there (otherwise the thread in the respective folder is incomplete). [1] yes, this is probably one missing feature that prevents me from putting my Gmail account in notmuch as well. Kind regards, Andrei -- If you can't explain it simply, you don't understand it well enough. (Albert Einstein) signature.asc Description: Digital signature ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH] contrib: pick: use async parser from lib
This moves notmuch-pick to use the newly split out async json parser from notmuch-lib.el. --- I hadn't expected the split out json parser to go in so quickly: this moves notmuch-pick to use the new function. Best wishes Mark contrib/notmuch-pick/notmuch-pick.el | 52 +++-- 1 files changed, 5 insertions(+), 47 deletions(-) diff --git a/contrib/notmuch-pick/notmuch-pick.el b/contrib/notmuch-pick/notmuch-pick.el index be6a91a..15ac5e8 100644 --- a/contrib/notmuch-pick/notmuch-pick.el +++ b/contrib/notmuch-pick/notmuch-pick.el @@ -435,7 +435,7 @@ Does NOT change the database. (unless (notmuch-pick-get-match) (notmuch-pick-next-matching-message)) (while (and (not (notmuch-pick-get-match)) - (not (eq notmuch-pick-process-state 'end))) + (get-buffer-process (current-buffer))) (message waiting for message) (sit-for 0.1) (goto-char (point-min)) @@ -733,9 +733,6 @@ Complete list of currently available key bindings: (insert \n))) -(defvar notmuch-pick-json-parser nil - Incremental JSON parser for the search process filter.) - (defun notmuch-pick-process-filter (proc string) Process and filter the output of \notmuch show\ (for pick) (let ((results-buf (process-buffer proc)) @@ -748,46 +745,10 @@ Complete list of currently available key bindings: ;; Insert new data (save-excursion (goto-char (point-max)) - (insert string))) - (with-current-buffer results-buf - (save-excursion - (goto-char (point-max)) - (while (not done) - (condition-case nil - (case notmuch-pick-process-state - ((begin) - ;; Enter the results list - (if (eq (notmuch-json-begin-compound - notmuch-pick-json-parser) 'retry) - (setq done t) -(setq notmuch-pick-process-state 'result))) - ((result) - ;; Parse a result - (let ((result (notmuch-json-read notmuch-pick-json-parser))) -(case result - ((retry) (setq done t)) - ((end) (setq notmuch-pick-process-state 'end)) - (otherwise (notmuch-pick-insert-forest-thread result) - ((end) - ;; Any trailing data is unexpected - (with-current-buffer parse-buf -(skip-chars-forward \t\r\n) -(if (eobp) -(setq done t) - (signal 'json-error nil) - (json-error - ;; Do our best to resynchronize and ensure forward - ;; progress - (notmuch-pick-show-error - %s - (with-current-buffer parse-buf - (let ((bad (buffer-substring (line-beginning-position) - (line-end-position - (forward-line) - bad)) - ;; Clear out what we've parsed - (with-current-buffer parse-buf - (delete-region (point-min) (point + (insert string)) + (notmuch-json-parse-partial-list 'notmuch-pick-insert-forest-thread +'notmuch-pick-show-error +results-buf) (defun notmuch-pick-worker (basic-query optional query-context buffer) (interactive) @@ -815,9 +776,6 @@ Complete list of currently available key bindings: ;; This buffer will be killed by the sentinel, which ;; should be called no matter how the process dies. (parse-buf (generate-new-buffer *notmuch pick parse*))) - (set (make-local-variable 'notmuch-pick-process-state) 'begin) - (set (make-local-variable 'notmuch-pick-json-parser) - (notmuch-json-create-parser parse-buf)) (process-put proc 'parse-buf parse-buf) (set-process-sentinel proc 'notmuch-pick-process-sentinel) (set-process-filter proc 'notmuch-pick-process-filter) -- 1.7.9.1 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: bug related to ical
Olivier Berger olivier.ber...@it-sudparis.eu writes: Hi. Just in case, Tomi proposed an updated version in Message-ID: 1349333712-18347-1-git-send-email-tomi.oll...@iki.fi ... but it doesn't seem to fix the issue for me :-/ Actually, this is not true, as I had forgotten to recompile the emacs lisp before testing. I do confirm that the patches in Message-ID: 1349333712-18347-1-git-send-email-tomi.oll...@iki.fi (http://permalink.gmane.org/gmane.mail.notmuch.general/12518) and Message-ID: 1350826509-12119-1-git-send-email-tomi.oll...@iki.fi (http://permalink.gmane.org/gmane.mail.notmuch.general/12631) seem to solve the issue. Hope this helps. Best regards, -- Olivier BERGER http://www-public.it-sudparis.eu/~berger_o/ - OpenPGP-Id: 2048R/5819D7E8 Ingenieur Recherche - Dept INF Institut Mines-Telecom, Telecom SudParis, Evry (France) ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH 0/3] Add notmuch-pick to contrib
Mark Walters markwalters1...@gmail.com writes: This is a new version of notmuch-pick (previous version at id:1343164911-31589-1-git-send-email-markwalters1...@gmail.com)following suggestions of Tomi and David in that thread. The main change is that it is now entirely self contained in contrib: all the user needs to do is copy the notmuch-pick.el somewhere in the emacs load path and add (require 'notmuch-pick nil t) to their .emacs file. I have pushed this to contrib. We do need tests before this goes mainline. What about (untested) having the tests in contrib/notmuch-pick for now, including as needed from ../../test. We should mention it in NEWS; at this point I think it is reasonable to expect to do at least one release with pick in contrib. As a vague feature request, what about forwarding unknown keys to the notmuch-show buffer? d ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH v4 0/3] split async json parser into utility function
Mark Walters markwalters1...@gmail.com writes: This is version 4 of this patch set (v3 is at id:1351037602-11157-1-git-send-email-markwalters1...@gmail.com). It splits the async json parser into its own function and moves it to lib. Series pushed, d ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH 0/2] automatic tagging based on imap maildir
Quoth Andrei POPESCU on Oct 28 at 12:03 pm: On Sb, 27 oct 12, 10:00:46, David Bremner wrote: As I said (or tried to say), in my opinion, duplication with an external package is not the main issue; I think moving features into the core when appropriate is a normal development process. On the other hand, I'm not really a gmail user, so I don't know yet if these patches solve enough of the problem to be interesting. They are interesting not only for Gmail[1], but also for other kinds of What is preventing folder: searches from addressing this? setups. As far as I understand (please correct me if I'm wrong), currently notmuch treats multiple copies of a message similar to Gmail (indexes one, but ignores the rest), which is why I'm *not* receiving any mailing lists on my Gmail account. notmuch tracks all copies of a message, but its output generally shows messages, rather than files, so you see a message only once regardless of how many copies there are in the file system. Why does that cause you to not receive mailing lists? (Or did I misinterpret your statement?) Besides that consider also that I'm subscribed to about 40 mailing lists, each sorted to it's own folder by rules based on List-Id (which notmuch doesn't support yet as far as I know). This separation is very useful for my read-flow. However, there are messages crossposed to several lists. It would be great if notmuch or (more probably) a client using notmuch could mark all copies of a message as read in all folders, but still keep it there (otherwise the thread in the respective folder is incomplete). If I understand what you're saying, this is exactly what notmuch does. When you remove the unread tag, notmuch will (should?) add the seen maildir flag to all copies of that message in the file system (barring some corner-cases that flag sync doesn't handle well; maybe you're encountering one of those?). And since notmuch never deletes files, they will remain in the folders they were filed in. [1] yes, this is probably one missing feature that prevents me from putting my Gmail account in notmuch as well. Kind regards, Andrei ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
[PATCH] emacs: Function to query the list of labels from a thread-id
This patch adds `notmuch-query-thread-labels-from-id' and corresponding test. This function returns the labels of thread whose id is passed as argument. The thread labels are the union of the labels of emails in the thread. I need this function to integrate notmuch-labeler. Signed-off-by: Damien Cassou damien.cas...@gmail.com --- emacs/notmuch-query.el | 16 test/emacs | 23 +++ 2 files changed, 39 insertions(+) diff --git a/emacs/notmuch-query.el b/emacs/notmuch-query.el index d66baea..8b9a41d 100644 --- a/emacs/notmuch-query.el +++ b/emacs/notmuch-query.el @@ -81,4 +81,20 @@ See the function notmuch-query-get-threads for more information. (lambda (msg) (plist-get msg :id)) (notmuch-query-get-threads search-terms))) +(defun notmuch-query-thread-labels-from-id (thread-id) + Return the labels of thread whose id is THREAD-ID. +The thread labels are the union of the labels of emails in the +thread. + (let ((label-lists +(notmuch-query-map-forest + (lambda (msg) (plist-get msg :tags)) + (car (notmuch-query-get-threads + (list (concat thread: thread-id))) +(case (length label-lists) + (0 nil) + (1 (car label-lists)) + (otherwise (reduce (lambda (l1 l2) + (union l1 l2 :test 'string=)) +label-lists) + (provide 'notmuch-query) diff --git a/test/emacs b/test/emacs index 44f641e..3e8bdb8 100755 --- a/test/emacs +++ b/test/emacs @@ -820,5 +820,28 @@ Date: Fri, 05 Jan 2001 15:43:57 + EOF test_expect_equal_file OUTPUT EXPECTED +test_begin_subtest Extracting all labels from a thread +add_message \ +'[subject]=Extracting all labels from a thread' \ +'[body]=body 1' +first=${gen_msg_cnt} +parent=${gen_msg_id} +add_message \ +'[subject]=Extracting all labels from a thread' \ +'[body]=body 2' \ +[in-reply-to]=\$parent\ +add_message \ +'[subject]=Extracting all labels from a thread' \ +'[body]=body 3' \ +[in-reply-to]=\$parent\ +latest=${gen_msg_id} +# Extract the thread-id from one of the emails +thread_id=$(notmuch search id:${latest} | sed -e s/thread:\([a-f0-9]*\).*/\1/) +# Add tag mytagfoo to one of the emails +notmuch tag +mytagfoo id:${latest} +test_emacs_expect_t \ +(let ((output (notmuch-query-thread-labels-from-id \${thread_id}\)) + (expected '(\inbox\ \mytagfoo\ \unread\))) + (notmuch-test-expect-equal output expected)) test_done -- 1.7.10.4 ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH 0/2] automatic tagging based on imap maildir
On Du, 28 oct 12, 11:31:38, Austin Clements wrote: Why does that cause you to not receive mailing lists? (Or did I misinterpret your statement?) Yes. The main deterrent in Gmail silently dropping my own postings returning via the list, because it considers it identical to the sent message. If I understand what you're saying, this is exactly what notmuch does. When you remove the unread tag, notmuch will (should?) add the seen maildir flag to all copies of that message in the file system (barring some corner-cases that flag sync doesn't handle well; maybe you're encountering one of those?). And since notmuch never deletes files, they will remain in the folders they were filed in. Great. Then I only need a client that suits me. I've wanted to have a look at mutt-kz, but keep postponing it. Kind regards, Andrei -- If you can't explain it simply, you don't understand it well enough. (Albert Einstein) signature.asc Description: Digital signature ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH 0/2] automatic tagging based on imap maildir
Quoth Andrei POPESCU on Oct 28 at 11:44 pm: On Du, 28 oct 12, 11:31:38, Austin Clements wrote: Why does that cause you to not receive mailing lists? (Or did I misinterpret your statement?) Yes. The main deterrent in Gmail silently dropping my own postings returning via the list, because it considers it identical to the sent message. Ah. And I assume you want to see those in your inbox even if they're not a reply to some other message in your inbox? I do recall Gmail suppressing list reflections. Though I think that, by default, notmuch *will* put your own list postings in your inbox. Assuming the list sends the message back to you (not all do), and assuming your notmuch new.tags contains inbox, notmuch will simply see it as a new message and tag it inbox. If you have Fcc setup in your frontend of choice to save sent messages in a folder indexed by notmuch, then it should likewise tag the message inbox as soon as it indexes it. ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH v5 4/9] test: add smoke tests for the date/time parser module
On Tue, 23 Oct 2012, Austin Clements amdra...@mit.edu wrote: Quoth Jani Nikula on Oct 22 at 12:22 am: Test the date/time parser module directly, independent of notmuch, using the parse-time test tool. Credits to Michal Sojka sojk...@fel.cvut.cz for writing most of the tests. --- test/notmuch-test |1 + test/parse-time-string | 71 2 files changed, 72 insertions(+) create mode 100755 test/parse-time-string diff --git a/test/notmuch-test b/test/notmuch-test index cc732c3..7eadfdf 100755 --- a/test/notmuch-test +++ b/test/notmuch-test @@ -60,6 +60,7 @@ TESTS= emacs-hello emacs-show missing-headers + parse-time-string TESTS=${NOTMUCH_TESTS:=$TESTS} diff --git a/test/parse-time-string b/test/parse-time-string new file mode 100755 index 000..862e701 --- /dev/null +++ b/test/parse-time-string @@ -0,0 +1,71 @@ +#!/usr/bin/env bash +test_description=date/time parser module +. ./test-lib.sh + +# Sanity/smoke tests for the date/time parser independent of notmuch + +_date () +{ +date -d $* +%s +} + +_parse_time () +{ +${TEST_DIRECTORY}/parse-time --format=%s $* +} + +test_begin_subtest date(1) default format without TZ code +test_expect_equal $(_parse_time Fri Aug 3 23:06:06 2012) $(_date Fri Aug 3 23:06:06 2012) + +test_begin_subtest date(1) --rfc-2822 format +test_expect_equal $(_parse_time Fri, 03 Aug 2012 23:07:46 +0100) $(_date Fri, 03 Aug 2012 23:07:46 +0100) + +test_begin_subtest date(1) --rfc=3339=seconds format +test_expect_equal $(_parse_time 2012-08-03 23:09:37+03:00) $(_date 2012-08-03 23:09:37+03:00) + +test_begin_subtest Date parser tests +REFERENCE=$(_date Tue Jan 11 11:11:00 + 2011) +cat EOF INPUT +now == Tue Jan 11 11:11:00 + 2011 +2010-1-1 == ERROR: 5 It would be nice if these errors were strings. I have no idea if 5 is the right error for this. Good idea. Will fix. +Jan 2== Sun Jan 02 11:11:00 + 2011 +Mon == Mon Jan 10 11:11:00 + 2011 +last Friday == ERROR: 4 +2 hours ago == ERROR: 1 I'll silently eat away ago too. +last month == Sat Dec 11 11:11:00 + 2010 +month ago== ERROR: 1 +8am == Tue Jan 11 08:00:00 + 2011 +9:15 == Tue Jan 11 09:15:00 + 2011 +12:34== Tue Jan 11 12:34:00 + 2011 +monday == Mon Jan 10 11:11:00 + 2011 +yesterday== Mon Jan 10 11:11:00 + 2011 +tomorrow == ERROR: 1 + == Tue Jan 11 11:11:00 + 2011 # empty string is reference time + +Aug 3 23:06:06 2012 == Fri Aug 03 23:06:06 + 2012 # date(1) default format without TZ code +Fri, 03 Aug 2012 23:07:46 +0100 == Fri Aug 03 22:07:46 + 2012 # rfc-2822 +2012-08-03 23:09:37+03:00 == Fri Aug 03 20:09:37 + 2012 # rfc-3339 seconds + +10s == Tue Jan 11 11:10:50 + 2011 +19701223s == Fri May 28 10:37:17 + 2010 +19701223 == Wed Dec 23 11:11:00 + 1970 + +19701223 +0100 == Wed Dec 23 11:11:00 + 1970 # Timezone is ignored without an error + +today ==^ Tue Jan 11 23:59:59 + 2011 +today ==_ Tue Jan 11 00:00:00 + 2011 + +thisweek ==^ Sat Jan 15 23:59:59 + 2011 +thisweek ==_ Sun Jan 09 00:00:00 + 2011 + +two months ago== ERROR: 1 # ago is not supported +two months == Thu Nov 11 11:11:00 + 2010 + +@1348569850 == Tue Sep 25 10:44:10 + 2012 +@10 == Thu Jan 01 00:00:10 + 1970 Very nice. The only thing that jumps out at me is that there are no ==^^ tests, though it would be interesting to run a code coverage tool to see how thorough these tests are. Again, most of the credit here goes to Michal Sojka. Will add some ==^^ tests too. BR, Jani. +EOF + +${TEST_DIRECTORY}/parse-time --ref=${REFERENCE} INPUT OUTPUT +test_expect_equal_file INPUT OUTPUT + +test_done ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch
Re: [PATCH v5 6/9] lib: add date range query support
On Tue, 23 Oct 2012, Austin Clements amdra...@mit.edu wrote: Quoth Jani Nikula on Oct 22 at 12:22 am: Add a custom value range processor to enable date and time searches of the form date:since..until, where since and until are expressions understood by the previously added date/time parser, to restrict the results to messages within a particular time range (based on the Date: header). If since or until describes date/time at an accuracy of days or less, the values are rounded according to the accuracy, towards past for since and towards future for until. For example, date:november..yesterday would match from the beginning of November until the end of yesterday. Expressions such as date:today..today means since the beginning of today until the end of today. Open-ended ranges are supported (since Xapian 1.2.1), i.e. you can specify date:..until or date:since.. to not limit the start or end date, respectively. CAVEATS: Xapian does not support spaces in range expressions. You can replace the spaces with '_', or (in most cases) '-', or (in some cases) leave the spaces out altogether. Entering date:expr without .. (for example date:yesterday) will not work as you might expect. You can achieve the expected result by duplicating the expr both sides of .. (for example date:yesterday..yesterday). Open-ended ranges won't work with pre-1.2.1 Xapian, but they don't produce an error either. Signed-off-by: Jani Nikula j...@nikula.org --- lib/Makefile.local |1 + lib/database-private.h |1 + lib/database.cc|5 + lib/parse-time-vrp.cc | 40 lib/parse-time-vrp.h | 19 +++ 5 files changed, 66 insertions(+) create mode 100644 lib/parse-time-vrp.cc create mode 100644 lib/parse-time-vrp.h diff --git a/lib/Makefile.local b/lib/Makefile.local index d1635cf..6c0f42f 100644 --- a/lib/Makefile.local +++ b/lib/Makefile.local @@ -58,6 +58,7 @@ libnotmuch_c_srcs =\ libnotmuch_cxx_srcs = \ $(dir)/database.cc \ +$(dir)/parse-time-vrp.cc\ $(dir)/directory.cc \ $(dir)/index.cc \ $(dir)/message.cc \ diff --git a/lib/database-private.h b/lib/database-private.h index 88532d5..d3e65fd 100644 --- a/lib/database-private.h +++ b/lib/database-private.h @@ -52,6 +52,7 @@ struct _notmuch_database { Xapian::QueryParser *query_parser; Xapian::TermGenerator *term_gen; Xapian::ValueRangeProcessor *value_range_processor; +Xapian::ValueRangeProcessor *date_range_processor; }; /* Return the list of terms from the given iterator matching a prefix. diff --git a/lib/database.cc b/lib/database.cc index 761dc1a..4df3217 100644 --- a/lib/database.cc +++ b/lib/database.cc @@ -19,6 +19,7 @@ */ #include database-private.h +#include parse-time-vrp.h #include iostream @@ -710,12 +711,14 @@ notmuch_database_open (const char *path, notmuch-term_gen = new Xapian::TermGenerator; notmuch-term_gen-set_stemmer (Xapian::Stem (english)); notmuch-value_range_processor = new Xapian::NumberValueRangeProcessor (NOTMUCH_VALUE_TIMESTAMP); +notmuch-date_range_processor = new ParseTimeValueRangeProcessor (NOTMUCH_VALUE_TIMESTAMP); notmuch-query_parser-set_default_op (Xapian::Query::OP_AND); notmuch-query_parser-set_database (*notmuch-xapian_db); notmuch-query_parser-set_stemmer (Xapian::Stem (english)); notmuch-query_parser-set_stemming_strategy (Xapian::QueryParser::STEM_SOME); notmuch-query_parser-add_valuerangeprocessor (notmuch-value_range_processor); +notmuch-query_parser-add_valuerangeprocessor (notmuch-date_range_processor); for (i = 0; i ARRAY_SIZE (BOOLEAN_PREFIX_EXTERNAL); i++) { prefix_t *prefix = BOOLEAN_PREFIX_EXTERNAL[i]; @@ -778,6 +781,8 @@ notmuch_database_close (notmuch_database_t *notmuch) notmuch-xapian_db = NULL; delete notmuch-value_range_processor; notmuch-value_range_processor = NULL; +delete notmuch-date_range_processor; +notmuch-date_range_processor = NULL; } void diff --git a/lib/parse-time-vrp.cc b/lib/parse-time-vrp.cc new file mode 100644 index 000..7e4eca4 --- /dev/null +++ b/lib/parse-time-vrp.cc @@ -0,0 +1,40 @@ Should this file have the usual preamble? Probably, yes. + +#include database-private.h +#include parse-time-vrp.h +#include parse-time-string.h + +#define PREFIX date: + +/* See *ValueRangeProcessor in xapian-core/api/valuerangeproc.cc */ +Xapian::valueno +ParseTimeValueRangeProcessor::operator() (std::string begin, std::string end) +{ +time_t t, now; + +/* Require date: prefix in start of the range... */ +if (STRNCMP_LITERAL (begin.c_str (), PREFIX)) Could be if (begin.rfind (PREFIX, 0) == string::npos) but that may not be clearer. Not to me at least; my C++ is rusty.
Re: [PATCH v5 8/9] man: document the date:since..until range queries
Many thanks, I'll incorporate most of your suggestions as-is. BR, Jani. On Thu, 25 Oct 2012, Austin Clements amdra...@mit.edu wrote: Quoth Jani Nikula on Oct 22 at 12:22 am: --- man/man7/notmuch-search-terms.7 | 147 +++ 1 file changed, 135 insertions(+), 12 deletions(-) diff --git a/man/man7/notmuch-search-terms.7 b/man/man7/notmuch-search-terms.7 index 17a109e..fbd3ee7 100644 --- a/man/man7/notmuch-search-terms.7 +++ b/man/man7/notmuch-search-terms.7 @@ -54,6 +54,8 @@ terms to match against specific portions of an email, (where folder:directory-path +date:since..until + The .B from: prefix is used to match the name or address of the sender of an email @@ -104,6 +106,26 @@ contained within particular directories within the mail store. Only the directory components below the top-level mail database path are available to be searched. +The +.B date: +prefix can be used to restrict the results to only messages within a +particular time range (based on the Date: header) with a range syntax +of: + +date:since..until + +See \fBDATE AND TIME SEARCH\fR below for details on the range +expression, and supported syntax for since and until date and time +expressions. + +The time range can also be specified using timestamps with a syntax +of: + +initial-timestamp..final-timestamp + +Each timestamp is a number representing the number of seconds since +1970\-01\-01 00:00:00 UTC. + In addition to individual terms, multiple terms can be combined with Boolean operators ( .BR and , or , not @@ -117,20 +139,121 @@ operators, but will have to be protected from interpretation by the shell, (such as by putting quotation marks around any parenthesized expression). -Finally, results can be restricted to only messages within a -particular time range, (based on the Date: header) with a syntax of: +.SH DATE AND TIME SEARCH -initial-timestamp..final-timestamp +This is a non-exhaustive description of the date and time search with +some pseudo notation. Most of the constructs can be mixed freely, and +in any order, but the same absolute date or time can't be expressed +twice. I'm not sure what the end of this sentence means, though I assume it's related to the restrictions on repeated absolute components. It would also be nice to give a broader view of the syntax here. Maybe, notmuch understands a variety of standard and natural ways of expressing dates and times, both in absolute terms (2012-10-24) and in relative terms (yesterday). Any number of relative terms can be combined (1 hour 25 minutes) and an absolute date/time can be combined with relative terms to further adjust it. A non-exhaustive description of the syntax supported for absolute and relative terms is given below. -Each timestamp is a number representing the number of seconds since -1970\-01\-01 00:00:00 UTC. This is not the most convenient means of -expressing date ranges, but until notmuch is fixed to accept a more -convenient form, one can use the date program to construct -timestamps. For example, with the bash shell the following syntax would -specify a date range to return messages from 2009\-10\-01 until the -current time: - -$(date +%s \-d 2009\-10\-01)..$(date +%s) +.RS 4 +.TP 4 +.B The range expression + +date:since..until + +The above expression restricts the results to only messages from +since to until, based on the Date: header. + +If since or until describes time at an accuracy of days or less, +the date/time is rounded, towards past for since and towards future +for until, to be inclusive. For example, date:january..february The accuracy doesn't seem to have have anything to do with days; if I say date:1hour..1hour I get a span of an hour. Describing it as rounding also seems like it could be confusing to someone who hasn't thought a lot about this (though, as someone who has though a lot about this, I could be wrong). What about something like, since and until can describe imprecise times, such as yesterday. In this case, since is taken as the earliest time it could describe (the beginning of yesterday) and until is taken as the latest time it could describe (the end of yesterday). Similarly, date:january..february matches from the beginning of January to the end of February. +matches from the beginning of January until the end of +February. Similarly, date:yesterday..yesterday matches from the +beginning of yesterday until the end of yesterday. + +Open-ended ranges are supported (since Xapian 1.2.1), i.e. it's +possible to specify date:..until or date:since.. to not limit the +start or end time, respectively. Unfortunately, pre-1.2.1 Xapian does No need for the Unfortunately. +not report an error on open ended ranges, but it does not work as +expected either. + +Xapian does not support spaces in range expressions. You can
Re: [PATCH v5 2/9] parse-time-string: add a date/time parser to notmuch
Quoth Jani Nikula on Oct 29 at 12:30 am: On Mon, 22 Oct 2012, Austin Clements amdra...@mit.edu wrote: +/* + * Accepted keywords. + * + * A keyword may optionally contain a '|' to indicate the minimum + * match length. Without one, full match is required. It's advisable + * to keep the minimum match parts unique across all keywords. + * + * If keyword begins with upper case letter, then the matching will be + * case sensitive. Otherwise the matching is case insensitive. + * + * If setter is NULL, set_default will be used. + * + * Note: Order matters. Matching is greedy, longest match is used, but + * of equal length matches the first one is used, unless there's an + * equal length case sensitive match which trumps case insensitive + * matches. If you do have a tokenizer (or disallow mashing keywords together), then all of complexity arising from longest match goes away because the keyword token either will or won't match a keyword. If you also eliminate the rule for case sensitivity and put case-sensitive things before conflicting case-insensitive things (so put M before m|inutes), then you can simply use the first match. At least one reason for going through the whole table is that if this ever gets i18n support, the conflicting things might be different. While order matters in principle, you should create the table so that it really doesn't matter. While that's true, if the input keyword has to be syntactically delimited, there's still no such thing as a longest match, since the length of any match will be the length of the input. You may still want to scan the whole table, but if you find multiple matches, it's a bug in the table indicating that |ed prefixes aren't unique. Hence, if you're not interested in finding bugs in the table, you can just find the first match. Or you could remove the |'s from the table, scan the whole table, and consider the input string ambiguous if it matches multiple table entries (being careful with case sensitivity), just like you do now if the input string is shorter than the |ed prefixes. That would simplify your table, your matching logic, and possibly your scanning logic. + */ +static struct keyword keywords[] = { +/* Weekdays. */ +{ N_(sun|day), TM_ABS_WDAY,0, NULL }, +{ N_(mon|day), TM_ABS_WDAY,1, NULL }, +{ N_(tue|sday), TM_ABS_WDAY,2, NULL }, +{ N_(wed|nesday), TM_ABS_WDAY,3, NULL }, +{ N_(thu|rsday),TM_ABS_WDAY,4, NULL }, +{ N_(fri|day), TM_ABS_WDAY,5, NULL }, +{ N_(sat|urday),TM_ABS_WDAY,6, NULL }, + +/* Months. */ +{ N_(jan|uary), TM_ABS_MON, 1, kw_set_month }, +{ N_(feb|ruary),TM_ABS_MON, 2, kw_set_month }, +{ N_(mar|ch), TM_ABS_MON, 3, kw_set_month }, +{ N_(apr|il), TM_ABS_MON, 4, kw_set_month }, +{ N_(may), TM_ABS_MON, 5, kw_set_month }, +{ N_(jun|e),TM_ABS_MON, 6, kw_set_month }, +{ N_(jul|y),TM_ABS_MON, 7, kw_set_month }, +{ N_(aug|ust), TM_ABS_MON, 8, kw_set_month }, +{ N_(sep|tember), TM_ABS_MON, 9, kw_set_month }, +{ N_(oct|ober), TM_ABS_MON, 10, kw_set_month }, +{ N_(nov|ember),TM_ABS_MON, 11, kw_set_month }, +{ N_(dec|ember),TM_ABS_MON, 12, kw_set_month }, + +/* Durations. */ +{ N_(y|ears), TM_REL_YEAR,1, kw_set_rel }, +{ N_(w|eeks), TM_REL_WEEK,1, kw_set_rel }, +{ N_(d|ays),TM_REL_DAY, 1, kw_set_rel }, +{ N_(h|ours), TM_REL_HOUR,1, kw_set_rel }, +{ N_(hr|s), TM_REL_HOUR,1, kw_set_rel }, +{ N_(m|inutes), TM_REL_MIN, 1, kw_set_rel }, +/* M=months, m=minutes */ +{ N_(M),TM_REL_MON, 1, kw_set_rel }, +{ N_(mins), TM_REL_MIN, 1, kw_set_rel }, +{ N_(mo|nths), TM_REL_MON, 1, kw_set_rel }, +{ N_(s|econds), TM_REL_SEC, 1, kw_set_rel }, +{ N_(secs), TM_REL_SEC, 1, kw_set_rel }, + +/* Numbers. */ +{ N_(one), TM_NONE,1, kw_set_number }, +{ N_(two), TM_NONE,2, kw_set_number }, +{ N_(three),TM_NONE,3, kw_set_number }, +{ N_(four), TM_NONE,4, kw_set_number }, +{ N_(five), TM_NONE,5, kw_set_number }, +{ N_(six), TM_NONE,6, kw_set_number }, +{ N_(seven),TM_NONE,7, kw_set_number }, +{ N_(eight),TM_NONE,8, kw_set_number }, +{ N_(nine), TM_NONE,9, kw_set_number }, +{ N_(ten), TM_NONE,10, kw_set_number }, +{ N_(dozen),TM_NONE,12, kw_set_number }, +{
Re: [PATCH 0/2] automatic tagging based on imap maildir
[Remembered to Reply-All, my fingers are trained to Reply-List only ;) ] On Du, 28 oct 12, 18:12:40, Austin Clements wrote: Ah. And I assume you want to see those in your inbox even if they're not a reply to some other message in your inbox? I do recall Gmail suppressing list reflections. Yes, except the Inbox part :p. As already mentioned, I sort all lists by List-Id and I want to have my own posts nicely in their place in the corresponding threads (cross-posts included). Most of the times I even read my posts again, to spot significant mistakes. Though I think that, by default, notmuch *will* put your own list postings in your inbox. Assuming the list sends the message back to you (not all do), and assuming your notmuch new.tags contains inbox, notmuch will simply see it as a new message and tag it inbox. If you have Fcc setup in your frontend of choice to save sent messages in a folder indexed by notmuch, then it should likewise tag the message inbox as soon as it indexes it. Mmm, can't comment on that until I have a full notmuch client. Right now I'm using mutt and notmuch-mutt only. Kind regards, Andrei -- If you can't explain it simply, you don't understand it well enough. (Albert Einstein) signature.asc Description: Digital signature ___ notmuch mailing list notmuch@notmuchmail.org http://notmuchmail.org/mailman/listinfo/notmuch