branch: elpa/cider
commit 9950962788e76b4f38cf5629da254391e9e73734
Author: Bozhidar Batsov <[email protected]>
Commit: Bozhidar Batsov <[email protected]>
Retire the async eldoc request when it completes
`cider-eldoc--request-async' accumulated responses and called back on the
`done' status but never marked the request id completed, so every eldoc
lookup left an entry in `nrepl-pending-requests'. Eldoc fires on nearly
every cursor move, so the table grew unbounded for the whole session and
a late/duplicate response could re-invoke the callback. Mark the id
completed on `done', matching every other async handler.
---
lisp/cider-eldoc.el | 15 ++++++++++-----
test/cider-eldoc-tests.el | 22 ++++++++++++++++++++++
2 files changed, 32 insertions(+), 5 deletions(-)
diff --git a/lisp/cider-eldoc.el b/lisp/cider-eldoc.el
index 18ce199b6e..d51925dde9 100644
--- a/lisp/cider-eldoc.el
+++ b/lisp/cider-eldoc.el
@@ -505,11 +505,16 @@ Unlike the synchronous path this never blocks Emacs, so
it needs no
"sym" ,thing
"context" ,(cider-completion-get-context t))
(lambda (response)
- (setq accumulated (if accumulated
- (nrepl-dict-merge accumulated response)
- response))
- (when (member "done" (nrepl-dict-get response "status"))
- (funcall k accumulated)))
+ (nrepl-dbind-response response (status id)
+ (setq accumulated (if accumulated
+ (nrepl-dict-merge accumulated response)
+ response))
+ (when (member "done" status)
+ ;; Eldoc fires on nearly every cursor move, so the request must
+ ;; be retired from `nrepl-pending-requests' once done -
otherwise
+ ;; the table grows unbounded for the whole session.
+ (nrepl--mark-id-completed id)
+ (funcall k accumulated))))
connection))
(funcall k nil)))
diff --git a/test/cider-eldoc-tests.el b/test/cider-eldoc-tests.el
index 27cee22d6a..1ca10729c7 100644
--- a/test/cider-eldoc-tests.el
+++ b/test/cider-eldoc-tests.el
@@ -388,3 +388,25 @@ Relies on the spied `cider-eldoc-info-async' invoking its
callback synchronously
:and-return-value '(dict "inputs" (("$" "?first-name"))))
(expect (cider--eldoc-add-datomic-query-inputs-to-arglists '(("query" "&"
"inputs")))
:to-equal '(("query" "$" "?first-name")))))
+
+(describe "cider-eldoc--request-async"
+ (it "retires the request id and calls back once done"
+ (spy-on 'cider-current-repl :and-return-value 'conn)
+ (spy-on 'cider-current-ns :and-return-value "user")
+ (spy-on 'cider-completion-get-context :and-return-value "nil")
+ (spy-on 'nrepl--mark-id-completed)
+ (spy-on 'cider-nrepl-send-request :and-call-fake
+ (lambda (_request callback &rest _)
+ (funcall callback '(dict "status" ("done") "id" "7" "eldoc"
(("x"))))))
+ (let (result)
+ (cider-eldoc--request-async "foo" (lambda (r) (setq result r)))
+ ;; the pending request is retired so the table doesn't grow every lookup
+ (expect 'nrepl--mark-id-completed :to-have-been-called-with "7")
+ ;; and the accumulated dict is handed to the continuation
+ (expect (nrepl-dict-get result "eldoc") :to-equal '(("x")))))
+
+ (it "calls back with nil when there is no connection"
+ (spy-on 'cider-current-repl :and-return-value nil)
+ (let ((called 'unset))
+ (cider-eldoc--request-async "foo" (lambda (r) (setq called r)))
+ (expect called :to-be nil))))