[PATCH] emacs: Function to query the list of labels from a thread-id

2012-10-28 Thread Damien Cassou
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

2012-10-28 Thread Austin Clements
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

2012-10-28 Thread Austin Clements
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

2012-10-28 Thread Olivier Berger
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

2012-10-28 Thread Mark Walters
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

2012-10-28 Thread David Bremner
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

2012-10-28 Thread Andrei POPESCU
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

2012-10-28 Thread Austin Clements
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

2012-10-28 Thread Mark Walters

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

2012-10-28 Thread Tomi Ollila
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

2012-10-28 Thread Mark Walters

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

2012-10-28 Thread Andrei POPESCU
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

2012-10-28 Thread Mark Walters
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

2012-10-28 Thread Olivier Berger
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

2012-10-28 Thread David Bremner
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

2012-10-28 Thread David Bremner
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

2012-10-28 Thread Austin Clements
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

2012-10-28 Thread Damien Cassou
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

2012-10-28 Thread Andrei POPESCU
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

2012-10-28 Thread Austin Clements
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

2012-10-28 Thread Jani Nikula
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

2012-10-28 Thread Jani Nikula
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

2012-10-28 Thread Jani Nikula

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

2012-10-28 Thread Austin Clements
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

2012-10-28 Thread Andrei POPESCU
[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