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 A2480431FB5 for ; Mon, 29 Nov 2010 02:30:44 -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 SgaAQyo4cs5B for ; Mon, 29 Nov 2010 02:30:43 -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 713B441A547 for ; Mon, 29 Nov 2010 02:30:43 -0800 (PST) Received: by wyf22 with SMTP id 22so4656184wyf.26 for ; Mon, 29 Nov 2010 02:30:41 -0800 (PST) Received: by 10.216.239.199 with SMTP id c49mr4762944wer.12.1291026641780; Mon, 29 Nov 2010 02:30:41 -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 o43sm2294205weq.47.2010.11.29.02.30.40 (version=TLSv1/SSLv3 cipher=RC4-MD5); Mon, 29 Nov 2010 02:30:40 -0800 (PST) Received: by ut.hh.sledj.net (Postfix, from userid 1000) id E5629594245; Mon, 29 Nov 2010 10:30:07 +0000 (GMT) From: David Edmondson To: notmuch@notmuchmail.org Subject: [PATCH 3/3] emacs: Use JSON output for search. Date: Mon, 29 Nov 2010 10:29:59 +0000 Message-Id: <1291026599-14795-4-git-send-email-dme@dme.org> X-Mailer: git-send-email 1.7.2.3 In-Reply-To: <1291026599-14795-1-git-send-email-dme@dme.org> References: <1291026599-14795-1-git-send-email-dme@dme.org> 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: Mon, 29 Nov 2010 10:30:44 -0000 Switch to using the JSON format output of `notmuch search' to avoid problems parsing the output text. In particular, a comma in the name of an author would confuse the previous implementation. --- emacs/notmuch.el | 114 +++++++++++++++++++++++++++++++++++++----------------- 1 files changed, 78 insertions(+), 36 deletions(-) diff --git a/emacs/notmuch.el b/emacs/notmuch.el index 5933747..bde8c47 100644 --- a/emacs/notmuch.el +++ b/emacs/notmuch.el @@ -50,6 +50,7 @@ (eval-when-compile (require 'cl)) (require 'mm-view) (require 'message) +(require 'json) (require 'notmuch-lib) (require 'notmuch-show) @@ -698,40 +699,81 @@ foreground and blue background." do (notmuch-search-insert-field field date count authors subject tags))) (insert "\n")) +(defun notmuch-search-process-insert-object (object) + (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))) + +(defvar notmuch-search-parse-start nil) +(make-variable-buffer-local 'notmuch-show-parse-start) + +(defun notmuch-search-process-insert (proc buffer string) + (with-current-buffer buffer + (let ((inhibit-read-only t) + (inhibit-redisplay t) + ;; Vectors are not as useful here. + (json-array-type 'list) + object) + (save-excursion + ;; Insert the text, advancing the process marker + (goto-char (point-max)) + (insert string) + (set-marker (process-mark proc) (point))) + + (save-excursion + (goto-char notmuch-search-parse-start) + (condition-case nil + (while + (cond + ;; Opening bracket or comma separator between + ;; objects. + ((or (char-equal (json-peek) ?\[) + (char-equal (json-peek) ?\,)) + (json-advance) + (delete-region notmuch-search-parse-start (point)) + t) + + ;; Closing array. + ((char-equal (json-peek) ?\]) + ;; Consume both the closing bracket and any trailing + ;; whitespace (typically a carriage return). + (json-advance) + (json-skip-whitespace) + (delete-region notmuch-search-parse-start (point)) + nil) + + ;; Single object. + ((setq object (json-read-object)) + ;; Delete the object that we consumed. + (delete-region notmuch-search-parse-start (point)) + ;; Insert the corresponding results. + (notmuch-search-process-insert-object object) + t)) + ;; Consume any white space between terms. + (let ((p (point))) + (json-skip-whitespace) + (delete-region p (point))) + ;; Remember where we got up to. + (setq notmuch-search-parse-start (point))) + (error nil)))))) + (defun notmuch-search-process-filter (proc string) - "Process and filter the output of \"notmuch search\"" - (let ((buffer (process-buffer proc)) - (found-target nil)) + "Process and filter the output of `notmuch search'." + (let ((buffer (process-buffer proc))) (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))) - (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))) + (notmuch-search-process-insert proc buffer string) (delete-process proc)))) (defun notmuch-search-operate-all (action) @@ -806,15 +848,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") -- 1.7.2.3