Return-Path: X-Original-To: notmuch@notmuchmail.org Delivered-To: notmuch@notmuchmail.org Received: from localhost (localhost [127.0.0.1]) by olra.theworths.org (Postfix) with ESMTP id E2FAF431FB6 for ; Fri, 26 Nov 2010 05:13:31 -0800 (PST) X-Virus-Scanned: Debian amavisd-new at olra.theworths.org X-Spam-Flag: NO X-Spam-Score: 0 X-Spam-Level: X-Spam-Status: No, score=0 tagged_above=-999 required=5 tests=[RCVD_IN_DNSWL_NONE=-0.0001] autolearn=disabled Received: from olra.theworths.org ([127.0.0.1]) by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id gAKFKoxnirMU for ; Fri, 26 Nov 2010 05:13:31 -0800 (PST) Received: from mail-wy0-f181.google.com (mail-wy0-f181.google.com [74.125.82.181]) by olra.theworths.org (Postfix) with ESMTP id A0B26431FB5 for ; Fri, 26 Nov 2010 05:13:30 -0800 (PST) Received: by wyf22 with SMTP id 22so2113175wyf.26 for ; Fri, 26 Nov 2010 05:13:28 -0800 (PST) Received: by 10.216.15.10 with SMTP id e10mr152512wee.21.1290777208145; Fri, 26 Nov 2010 05:13:28 -0800 (PST) Received: from ut.hh.sledj.net (host81-149-164-25.in-addr.btopenworld.com [81.149.164.25]) by mx.google.com with ESMTPS id x3sm906001wes.22.2010.11.26.05.13.26 (version=TLSv1/SSLv3 cipher=RC4-MD5); Fri, 26 Nov 2010 05:13:27 -0800 (PST) Received: by ut.hh.sledj.net (Postfix, from userid 1000) id CF36B594058; Fri, 26 Nov 2010 13:13:23 +0000 (GMT) From: David Edmondson To: notmuch@notmuchmail.org Subject: [RFC] [PATCH] emacs: Use JSON output for search. Date: Fri, 26 Nov 2010 13:13:22 +0000 Message-Id: <1290777202-14040-1-git-send-email-dme@dme.org> X-Mailer: git-send-email 1.7.2.3 X-BeenThere: notmuch@notmuchmail.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: "Use and development of the notmuch mail system." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 26 Nov 2010 13:13:32 -0000 Modify the `notmuch search' JSON output to remove the outer list wrappers and item separators between elements. Add `date_relative' to the JSON search output. Replace the emacs use of the text based search output with the modified JSON output, including incremental parsing of the individual threads in the JSON. --- emacs/notmuch.el | 70 ++++++++++++++++++++++++++++++----------------------- notmuch-search.c | 8 ++++-- 2 files changed, 45 insertions(+), 33 deletions(-) Proper incremental parsing of the JSON output was hard, so I punted and got rid of the array wrappings around the search output. This may well break some other tools as a result (hence 'RFC'). Display of the thread can be a bit 'flashy' due to the incremental implementation, but it doesn't seem too off-putting on reasonable hardware - it may well be annoying on slower systems. diff --git a/emacs/notmuch.el b/emacs/notmuch.el index 5933747..0bbdf16 100644 --- a/emacs/notmuch.el +++ b/emacs/notmuch.el @@ -698,40 +698,50 @@ foreground and blue background." do (notmuch-search-insert-field field date count authors subject tags))) (insert "\n")) +(defvar notmuch-search-parse-start nil) +(make-variable-buffer-local 'notmuch-show-parse-start) + (defun notmuch-search-process-filter (proc string) - "Process and filter the output of \"notmuch search\"" + "Process and filter the output of `notmuch search'." + (let ((buffer (process-buffer proc)) - (found-target nil)) + object) (if (buffer-live-p buffer) (with-current-buffer buffer - (save-excursion - (let ((line 0) - (more t) - (inhibit-read-only t)) - (while more - (if (string-match "^\\(thread:[0-9A-Fa-f]*\\) \\([^][]*\\) \\(\\[[0-9/]*\\]\\) \\([^;]*\\); \\(.*\\) (\\([^()]*\\))$" string line) - (let* ((thread-id (match-string 1 string)) - (date (match-string 2 string)) - (count (match-string 3 string)) - (authors (match-string 4 string)) - (subject (match-string 5 string)) - (tags (match-string 6 string)) - (tag-list (if tags (save-match-data (split-string tags))))) - (goto-char (point-max)) - (let ((beg (point-marker))) + (let ((inhibit-read-only t) + (inhibit-redisplay t)) + (save-excursion + ;; Insert the text, advancing the process marker + (goto-char (point-max)) + (insert string) + (set-marker (process-mark proc) (point-max))) + + (save-excursion + (condition-case nil + (progn + (goto-char notmuch-search-parse-start) + (while (and (not (eobp)) + (setq object (json-read-object))) + (forward-char) + (delete-region notmuch-search-parse-start (point)) + + (let* ((thread-id (concat "thread:" (cdr (assoc 'thread object)))) + (date (format "%12s" (cdr (assoc 'date_relative object)))) + (count (format "[%d/%d]" + (cdr (assoc 'matched object)) + (cdr (assoc 'total object)))) + (authors (cdr (assoc 'authors object))) + (subject (cdr (assoc 'subject object))) + (tag-list (cdr (assoc 'tags object))) + (tags (mapconcat 'identity tag-list " ")) + (beg (point-marker))) (notmuch-search-show-result date count authors subject tags) (notmuch-search-color-line beg (point-marker) tag-list) (put-text-property beg (point-marker) 'notmuch-search-thread-id thread-id) (put-text-property beg (point-marker) 'notmuch-search-authors authors) - (put-text-property beg (point-marker) 'notmuch-search-subject subject) - (if (string= thread-id notmuch-search-target-thread) - (progn - (set 'found-target beg) - (set 'notmuch-search-target-thread "found")))) - (set 'line (match-end 0))) - (set 'more nil))))) - (if found-target - (goto-char found-target))) + (put-text-property beg (point-marker) 'notmuch-search-subject subject)) + (setq notmuch-search-parse-start (point)))) + (error nil))))) (delete-process proc)))) (defun notmuch-search-operate-all (action) @@ -806,15 +816,15 @@ The optional parameters are used as follows: (set 'notmuch-search-continuation continuation) (let ((proc (get-buffer-process (current-buffer))) (inhibit-read-only t)) - (if proc - (error "notmuch search process already running for query `%s'" query) - ) + (when proc + (error "notmuch search process already running for query `%s'" query)) (erase-buffer) - (goto-char (point-min)) + (setq notmuch-search-parse-start (point-min)) (save-excursion (let ((proc (start-process "notmuch-search" buffer notmuch-command "search" + "--format=json" (if oldest-first "--sort=oldest-first" "--sort=newest-first") diff --git a/notmuch-search.c b/notmuch-search.c index c628b36..1b07aa7 100644 --- a/notmuch-search.c +++ b/notmuch-search.c @@ -89,15 +89,15 @@ format_thread_json (const void *ctx, const char *authors, const char *subject); static const search_format_t format_json = { - "[", + "", "{", format_item_id_json, format_thread_json, "\"tags\": [", "\"%s\"", ", ", - "]", ",\n", + "]", "\n", "}", - "]\n", + "\n", }; static void @@ -152,12 +152,14 @@ format_thread_json (const void *ctx, printf ("\"thread\": %s,\n" "\"timestamp\": %ld,\n" + "\"date_relative\": %s,\n" "\"matched\": %d,\n" "\"total\": %d,\n" "\"authors\": %s,\n" "\"subject\": %s,\n", json_quote_str (ctx_quote, thread_id), date, + json_quote_str (ctx_quote, notmuch_time_relative_date (ctx, date)), matched, total, json_quote_str (ctx_quote, authors), -- 1.7.2.3