diff options
| author | João Távora | 2018-08-09 10:43:41 +0100 |
|---|---|---|
| committer | João Távora | 2018-08-09 10:43:41 +0100 |
| commit | cdafa8933d0b5a2261e1cdb959703951eae98f74 (patch) | |
| tree | 7befac0678a0aad95fa5440bfc0fb0b4e0d71b71 | |
| parent | 63a8f4cfd78b6fbf6d56cdeeb5df1f6d0688435c (diff) | |
| download | emacs-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.el | 53 |
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. |
| 261 | Like `jsonrpc-async-request' for CONNECTION, METHOD and PARAMS, | 263 | Like `jsonrpc-async-request' for CONNECTION, METHOD and PARAMS, |
| 262 | but synchronous, i.e. this function doesn't exit until anything | 264 | but synchronous. |
| 263 | interesting (success, error or timeout) happens. Furthermore, it | ||
| 264 | only exits locally (returning the JSONRPC result object) if the | ||
| 265 | request is successful, otherwise exit non-locally with an error | ||
| 266 | of type `jsonrpc-error'. | ||
| 267 | 265 | ||
| 268 | DEFERRED is passed to `jsonrpc-async-request', which see." | 266 | Except in the case of a non-nil CANCEL-ON-INPUT (explained |
| 267 | below), this function doesn't exit until anything interesting | ||
| 268 | happens (success reply, error reply, or timeout). Furthermore, | ||
| 269 | it only exits locally (returning the JSONRPC result object) if | ||
| 270 | the request is successful, otherwise it exits non-locally with an | ||
| 271 | error of type `jsonrpc-error'. | ||
| 272 | |||
| 273 | DEFERRED is passed to `jsonrpc-async-request', which see. | ||
| 274 | |||
| 275 | If CANCEL-ON-INPUT is non-nil and the user inputs something while | ||
| 276 | the functino is waiting, then it exits immediately, returning | ||
| 277 | CANCEL-ON-INPUT-RETVAL. Any future replies (normal or error) are | ||
| 278 | ignored." | ||
| 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)) |