aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoão Távora2018-08-09 10:43:41 +0100
committerJoão Távora2018-08-09 10:43:41 +0100
commitcdafa8933d0b5a2261e1cdb959703951eae98f74 (patch)
tree7befac0678a0aad95fa5440bfc0fb0b4e0d71b71
parent63a8f4cfd78b6fbf6d56cdeeb5df1f6d0688435c (diff)
downloademacs-cdafa8933d0b5a2261e1cdb959703951eae98f74.tar.gz
emacs-cdafa8933d0b5a2261e1cdb959703951eae98f74.zip
Synchronous JSONRPC requests can be cancelled on user input
This allows building more responsive interfaces, such as a snappier completion backend. * lisp/jsonrpc.el (Version): Bump to 1.0.1 (jsonrpc-connection-receive): Don't warn when continuation isn't found. (jsonrpc-request): Add parameters CANCEL-ON-INPUT and CANCEL-ON-INPUT-RETVAL.
-rw-r--r--lisp/jsonrpc.el53
1 files changed, 36 insertions, 17 deletions
diff --git a/lisp/jsonrpc.el b/lisp/jsonrpc.el
index b2ccea5c143..8e1e2aba333 100644
--- a/lisp/jsonrpc.el
+++ b/lisp/jsonrpc.el
@@ -6,7 +6,7 @@
6;; Maintainer: João Távora <joaotavora@gmail.com> 6;; Maintainer: João Távora <joaotavora@gmail.com>
7;; Keywords: processes, languages, extensions 7;; Keywords: processes, languages, extensions
8;; Package-Requires: ((emacs "25.2")) 8;; Package-Requires: ((emacs "25.2"))
9;; Version: 1.0.0 9;; Version: 1.0.1
10 10
11;; This is an Elpa :core package. Don't use functionality that is not 11;; This is an Elpa :core package. Don't use functionality that is not
12;; compatible with Emacs 25.2. 12;; compatible with Emacs 25.2.
@@ -193,9 +193,7 @@ dispatcher in CONNECTION."
193 (when timer (cancel-timer timer))) 193 (when timer (cancel-timer timer)))
194 (remhash id (jsonrpc--request-continuations connection)) 194 (remhash id (jsonrpc--request-continuations connection))
195 (if error (funcall (nth 1 continuations) error) 195 (if error (funcall (nth 1 continuations) error)
196 (funcall (nth 0 continuations) result))) 196 (funcall (nth 0 continuations) result))))
197 (;; An abnormal situation
198 id (jsonrpc--warn "No continuation for id %s" id)))
199 (jsonrpc--call-deferred connection)))) 197 (jsonrpc--call-deferred connection))))
200 198
201 199
@@ -256,17 +254,30 @@ Returns nil."
256 (apply #'jsonrpc--async-request-1 connection method params args) 254 (apply #'jsonrpc--async-request-1 connection method params args)
257 nil) 255 nil)
258 256
259(cl-defun jsonrpc-request (connection method params &key deferred timeout) 257(cl-defun jsonrpc-request (connection
258 method params &key
259 deferred timeout
260 cancel-on-input
261 cancel-on-input-retval)
260 "Make a request to CONNECTION, wait for a reply. 262 "Make a request to CONNECTION, wait for a reply.
261Like `jsonrpc-async-request' for CONNECTION, METHOD and PARAMS, 263Like `jsonrpc-async-request' for CONNECTION, METHOD and PARAMS,
262but synchronous, i.e. this function doesn't exit until anything 264but synchronous.
263interesting (success, error or timeout) happens. Furthermore, it
264only exits locally (returning the JSONRPC result object) if the
265request is successful, otherwise exit non-locally with an error
266of type `jsonrpc-error'.
267 265
268DEFERRED is passed to `jsonrpc-async-request', which see." 266Except in the case of a non-nil CANCEL-ON-INPUT (explained
267below), this function doesn't exit until anything interesting
268happens (success reply, error reply, or timeout). Furthermore,
269it only exits locally (returning the JSONRPC result object) if
270the request is successful, otherwise it exits non-locally with an
271error of type `jsonrpc-error'.
272
273DEFERRED is passed to `jsonrpc-async-request', which see.
274
275If CANCEL-ON-INPUT is non-nil and the user inputs something while
276the functino is waiting, then it exits immediately, returning
277CANCEL-ON-INPUT-RETVAL. Any future replies (normal or error) are
278ignored."
269 (let* ((tag (cl-gensym "jsonrpc-request-catch-tag")) id-and-timer 279 (let* ((tag (cl-gensym "jsonrpc-request-catch-tag")) id-and-timer
280 cancelled
270 (retval 281 (retval
271 (unwind-protect ; protect against user-quit, for example 282 (unwind-protect ; protect against user-quit, for example
272 (catch tag 283 (catch tag
@@ -274,19 +285,27 @@ DEFERRED is passed to `jsonrpc-async-request', which see."
274 id-and-timer 285 id-and-timer
275 (jsonrpc--async-request-1 286 (jsonrpc--async-request-1
276 connection method params 287 connection method params
277 :success-fn (lambda (result) (throw tag `(done ,result))) 288 :success-fn (lambda (result)
289 (unless cancelled
290 (throw tag `(done ,result))))
278 :error-fn 291 :error-fn
279 (jsonrpc-lambda 292 (jsonrpc-lambda
280 (&key code message data) 293 (&key code message data)
281 (throw tag `(error (jsonrpc-error-code . ,code) 294 (unless cancelled
282 (jsonrpc-error-message . ,message) 295 (throw tag `(error (jsonrpc-error-code . ,code)
283 (jsonrpc-error-data . ,data)))) 296 (jsonrpc-error-message . ,message)
297 (jsonrpc-error-data . ,data)))))
284 :timeout-fn 298 :timeout-fn
285 (lambda () 299 (lambda ()
286 (throw tag '(error (jsonrpc-error-message . "Timed out")))) 300 (unless cancelled
301 (throw tag '(error (jsonrpc-error-message . "Timed out")))))
287 :deferred deferred 302 :deferred deferred
288 :timeout timeout)) 303 :timeout timeout))
289 (while t (accept-process-output nil 30))) 304 (cond (cancel-on-input
305 (while (sit-for 30))
306 (setq cancelled t)
307 `(cancelled ,cancel-on-input-retval))
308 (t (while t (accept-process-output nil 30)))))
290 (pcase-let* ((`(,id ,timer) id-and-timer)) 309 (pcase-let* ((`(,id ,timer) id-and-timer))
291 (remhash id (jsonrpc--request-continuations connection)) 310 (remhash id (jsonrpc--request-continuations connection))
292 (remhash (list deferred (current-buffer)) 311 (remhash (list deferred (current-buffer))