[RFC] [PATCH] emacs: Use JSON output for search.

David Edmondson dme at dme.org
Fri Nov 26 05:13:22 PST 2010


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



More information about the notmuch mailing list