[PATCH 3/3] emacs: Use JSON output for search.
David Edmondson
dme at dme.org
Mon Nov 29 02:29:59 PST 2010
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
More information about the notmuch
mailing list