Re: [PATCH] emacs: move async json parser to its own function
[notmuch-archives.git] / be / bfbcc42243f1dacc7f8cfb09abe7b243a123f8
1 Return-Path: <amdragon@mit.edu>\r
2 X-Original-To: notmuch@notmuchmail.org\r
3 Delivered-To: notmuch@notmuchmail.org\r
4 Received: from localhost (localhost [127.0.0.1])\r
5         by olra.theworths.org (Postfix) with ESMTP id 5A293431FAF\r
6         for <notmuch@notmuchmail.org>; Sun, 29 Jul 2012 18:35:16 -0700 (PDT)\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
8 X-Spam-Flag: NO\r
9 X-Spam-Score: -0.7\r
10 X-Spam-Level: \r
11 X-Spam-Status: No, score=-0.7 tagged_above=-999 required=5\r
12         tests=[RCVD_IN_DNSWL_LOW=-0.7] autolearn=disabled\r
13 Received: from olra.theworths.org ([127.0.0.1])\r
14         by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
15         with ESMTP id SSDr-+mrrIuW for <notmuch@notmuchmail.org>;\r
16         Sun, 29 Jul 2012 18:35:12 -0700 (PDT)\r
17 Received: from dmz-mailsec-scanner-6.mit.edu (DMZ-MAILSEC-SCANNER-6.MIT.EDU\r
18         [18.7.68.35])\r
19         by olra.theworths.org (Postfix) with ESMTP id 354A3431FAE\r
20         for <notmuch@notmuchmail.org>; Sun, 29 Jul 2012 18:35:12 -0700 (PDT)\r
21 X-AuditID: 12074423-b7f396d0000008f4-7a-5015e4cd8a59\r
22 Received: from mailhub-auth-3.mit.edu ( [18.9.21.43])\r
23         by dmz-mailsec-scanner-6.mit.edu (Symantec Messaging Gateway) with SMTP\r
24         id 07.13.02292.DC4E5105; Sun, 29 Jul 2012 21:35:09 -0400 (EDT)\r
25 Received: from outgoing.mit.edu (OUTGOING-AUTH.MIT.EDU [18.7.22.103])\r
26         by mailhub-auth-3.mit.edu (8.13.8/8.9.2) with ESMTP id q6U1Z8nq005853; \r
27         Sun, 29 Jul 2012 21:35:09 -0400\r
28 Received: from awakening.csail.mit.edu (awakening.csail.mit.edu [18.26.4.91])\r
29         (authenticated bits=0)\r
30         (User authenticated as amdragon@ATHENA.MIT.EDU)\r
31         by outgoing.mit.edu (8.13.6/8.12.4) with ESMTP id q6U1Z7C6029430\r
32         (version=TLSv1/SSLv3 cipher=AES256-SHA bits=256 verify=NOT);\r
33         Sun, 29 Jul 2012 21:35:08 -0400 (EDT)\r
34 Received: from amthrax by awakening.csail.mit.edu with local (Exim 4.77)\r
35         (envelope-from <amdragon@MIT.EDU>)\r
36         id 1Svet0-0000Gh-Vu; Sun, 29 Jul 2012 21:35:07 -0400\r
37 Date: Sun, 29 Jul 2012 21:35:06 -0400\r
38 From: Austin Clements <amdragon@MIT.EDU>\r
39 To: Mark Walters <markwalters1009@gmail.com>\r
40 Subject: Re: [PATCH] emacs: move async json parser to its own function\r
41 Message-ID: <20120730013506.GF8502@mit.edu>\r
42 References: <87k3xo85tv.fsf@qmul.ac.uk>\r
43 MIME-Version: 1.0\r
44 Content-Type: text/plain; charset=us-ascii\r
45 Content-Disposition: inline\r
46 In-Reply-To: <87k3xo85tv.fsf@qmul.ac.uk>\r
47 User-Agent: Mutt/1.5.21 (2010-09-15)\r
48 X-Brightmail-Tracker:\r
49  H4sIAAAAAAAAA+NgFmpkleLIzCtJLcpLzFFi42IR4hTV1j37RDTA4OEWYYvVc3ksrt+cyezA\r
50         5LFz1l12j2erbjEHMEVx2aSk5mSWpRbp2yVwZWzum8tW8FGnYs+8DcwNjHOVuxg5OCQETCSm\r
51         T/HtYuQEMsUkLtxbz9bFyMUhJLCPUeJv81RGCGcDo0Tj4fcsEM5JJolzNw9DOUsYJZ7OecMM\r
52         0s8ioCox90kHE4jNJqAhsW3/ckYQW0RAR+L2oQXsIDazgLTEt9/NTCCrhQXcJD4vDQYJ8wpo\r
53         S/x9dB6sREhAXeLTnFnsEHFBiZMzn7BAtGpJ3Pj3EqwVZMzyfxwgYU6gTfe+3WADsUUFVCSm\r
54         nNzGNoFRaBaS7llIumchdC9gZF7FKJuSW6Wbm5iZU5yarFucnJiXl1qka6aXm1mil5pSuokR\r
55         FNLsLso7GP8cVDrEKMDBqMTD23lVNECINbGsuDL3EKMkB5OSKG/LDaAQX1J+SmVGYnFGfFFp\r
56         TmrxIUYJDmYlEd5r54ByvCmJlVWpRfkwKWkOFiVx3mspN/2FBNITS1KzU1MLUotgsjIcHEoS\r
57         vAHA2BUSLEpNT61Iy8wpQUgzcXCCDOcBGm4CUsNbXJCYW5yZDpE/xagoJc775TFQQgAkkVGa\r
58         B9cLSzmvGMWBXhHm9QRp5wGmK7juV0CDmYAGW0QLgQwuSURISTUwbvp5dIty+TrXStuKb91v\r
59         zfZdiTv37OMhpQ3KX8uSI/x9Vj9QfV45VUu/90tC72bzlA0T3EJ/i91oEmFQmMIuH1eYaxn1\r
60         fWeRrLywQIrv/Pnh3x9vKj3wJGJjUN0Ub95VDzfuFdrivvzpem2dnX6tJ7nqDyz/Jr/jf7KA\r
61         mFXHnNufpH7VTwpdqsRSnJFoqMVcVJwIAHYDyncUAwAA\r
62 Cc: notmuch@notmuchmail.org\r
63 X-BeenThere: notmuch@notmuchmail.org\r
64 X-Mailman-Version: 2.1.13\r
65 Precedence: list\r
66 List-Id: "Use and development of the notmuch mail system."\r
67         <notmuch.notmuchmail.org>\r
68 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
69         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
70 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
71 List-Post: <mailto:notmuch@notmuchmail.org>\r
72 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
73 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
74         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
75 X-List-Received-Date: Mon, 30 Jul 2012 01:35:16 -0000\r
76 \r
77 This seems like a good idea, but as a generic interface, this seems\r
78 suboptimal.  In particular, it seems odd that a parsing function would\r
79 have to know about a process and require the caller to set up various\r
80 process properties and buffer-local variables.  What about something\r
81 dedicated to incrementally parsing lists, like the async parser but\r
82 more specialized?  Something along the lines of,\r
83 \r
84 (defun notmuch-json-parse-partial-list (result-function error-function \r
85                                         &optional buffer)\r
86   "Parse a partial JSON list from BUFFER (or the current buffer).\r
87 \r
88 This function consumes a JSON list from BUFFER, applying\r
89 RESULT-FUNCTION to each complete value in the list.  It operates\r
90 incrementally and should be called whenever the buffer has been\r
91 extended with additional data.\r
92 \r
93 If there is a syntax error, this will attempt to resynchronize with\r
94 the input and will apply ERROR-FUNCTION to any input that was\r
95 skipped.\r
96 \r
97 This calls RESULT-FUNCTION and ERROR-FUNCTION with the same current\r
98 buffer as this function is called with (that is, this function does\r
99 not visibly switch to BUFFER)."\r
100   ...)\r
101 \r
102 This could use buffer-local variables for tracking the async parser\r
103 state as well its own state.  It could even set these up automatically\r
104 when called for the first time in a buffer without them set, making it\r
105 very DWIM.  It would clearly require a little more help from the\r
106 caller for process management than your patch does (and a little less\r
107 for parser setup), but I think the genericity would be worth it.\r
108 \r
109 Quoth Mark Walters on Jul 28 at 12:48 pm:\r
110\r
111 > We separate out the json parser into its own function. \r
112 > ---\r
113\r
114 > Hi\r
115\r
116 > Notmuch pick uses the new asynchronous json parser and the code to do so\r
117 > is almost identical to that for the search mode. Thus separate out the\r
118 > parsing in search mode into a more general function that can easily be\r
119 > used by both pick and search.\r
120\r
121 > This saves nearly 50 lines of duplicated code in notmuch-pick.el.\r
122\r
123 > The function notmuch-json-async-parse should probably be move in\r
124 > notmuch-lib but that can be a follow on patch.\r
125\r
126 > Best wishes\r
127\r
128 > Mark\r
129\r
130 >  emacs/notmuch.el |   46 ++++++++++++++++++++++++++++++++++++----------\r
131 >  1 files changed, 36 insertions(+), 10 deletions(-)\r
132\r
133 > diff --git a/emacs/notmuch.el b/emacs/notmuch.el\r
134 > index fd1836f..ee01028 100644\r
135 > --- a/emacs/notmuch.el\r
136 > +++ b/emacs/notmuch.el\r
137 > @@ -816,7 +816,32 @@ non-authors is found, assume that all of the authors match."\r
138 >    "Incremental JSON parser for the search process filter.")\r
139 >  \r
140 >  (defun notmuch-search-process-filter (proc string)\r
141 > -  "Process and filter the output of \"notmuch search\""\r
142 > +  "Process and filter the output of  \"notmuch search\" using the asynchronous parser."\r
143 > +  (setq notmuch-search-process-state\r
144 > +     (notmuch-json-async-parse proc\r
145 > +                               string\r
146 > +                               notmuch-search-process-state\r
147 > +                               notmuch-search-json-parser\r
148 > +                               'notmuch-search-show-result\r
149 > +                               'notmuch-search-show-error)))\r
150 > +\r
151 > +(defun notmuch-json-async-parse (proc string process-state parser result-function error-function)\r
152 > +  "Process and filter the output using the asynchronous parser.\r
153 > +\r
154 > +This function steps into the first level of JSON nesting and then\r
155 > +applies RESULT-FUNCTION to each complete JSON object as it comes\r
156 > +in.\r
157 > +\r
158 > +PROC is the process: it should have a results buffer as\r
159 > +process-buffer and a 'parse-buf for the incoming json.\r
160 > +PROCESS-STATE the current state of filter process\r
161 > +STRING the incoming data\r
162 > +PARSER the parser\r
163 > +RESULT-FUNCTION a function to call on complete pieces of json\r
164 > +ERROR-FUNCTION the function to call on errors\r
165 > +\r
166 > +The function returns the new PROCESS-STATE"\r
167 > +\r
168 >    (let ((results-buf (process-buffer proc))\r
169 >       (parse-buf (process-get proc 'parse-buf))\r
170 >       (inhibit-read-only t)\r
171 > @@ -831,28 +856,28 @@ non-authors is found, assume that all of the authors match."\r
172 >        (with-current-buffer results-buf\r
173 >       (while (not done)\r
174 >         (condition-case nil\r
175 > -           (case notmuch-search-process-state\r
176 > +           (case process-state\r
177 >               ((begin)\r
178 >                ;; Enter the results list\r
179 >                (if (eq (notmuch-json-begin-compound\r
180 > -                       notmuch-search-json-parser) 'retry)\r
181 > +                       parser) 'retry)\r
182 >                    (setq done t)\r
183 > -                (setq notmuch-search-process-state 'result)))\r
184 > +                (setq process-state 'result)))\r
185 >               ((result)\r
186 >                ;; Parse a result\r
187 > -              (let ((result (notmuch-json-read notmuch-search-json-parser)))\r
188 > +              (let ((result (notmuch-json-read parser)))\r
189 >                  (case result\r
190 >                    ((retry) (setq done t))\r
191 > -                  ((end) (setq notmuch-search-process-state 'end))\r
192 > -                  (otherwise (notmuch-search-show-result result)))))\r
193 > +                  ((end) (setq process-state 'end))\r
194 > +                  (otherwise (funcall result-function result)))))\r
195 >               ((end)\r
196 >                ;; Any trailing data is unexpected\r
197 > -              (notmuch-json-eof notmuch-search-json-parser)\r
198 > +              (notmuch-json-eof parser)\r
199 >                (setq done t)))\r
200 >           (json-error\r
201 >            ;; Do our best to resynchronize and ensure forward\r
202 >            ;; progress\r
203 > -          (notmuch-search-show-error\r
204 > +          (funcall error-function\r
205 >             "%s"\r
206 >             (with-current-buffer parse-buf\r
207 >               (let ((bad (buffer-substring (line-beginning-position)\r
208 > @@ -861,7 +886,8 @@ non-authors is found, assume that all of the authors match."\r
209 >                 bad))))))\r
210 >       ;; Clear out what we've parsed\r
211 >       (with-current-buffer parse-buf\r
212 > -       (delete-region (point-min) (point)))))))\r
213 > +       (delete-region (point-min) (point))))\r
214 > +      process-state)))\r
215 >  \r
216 >  (defun notmuch-search-tag-all (&optional tag-changes)\r
217 >    "Add/remove tags from all messages in current search buffer.\r