Skip to content

Commit d6dcc14

Browse files
committed
[Fix #776, #773, #733] Rewrite bencode decoder
- nREPL dicts are now plists and accessor api is given by `nrepl-dict-p`, `nrepl-dict-get` and `nrepl-dict-put`. - nested stack is used for decoded messages to avoid re-parsing of incomplete messages - queues are used for raw strings from server and for decoded requests
1 parent 14ac115 commit d6dcc14

11 files changed

+679
-304
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ are used to translate filenames from/to the nREPL server (default Cygwin impleme
2020

2121
### Changes
2222

23+
* bencode decoder was rewriten:
24+
- nREPL dicts are now plists and accessor api is given by `nrepl-dict-p`,
25+
`nrepl-dict-get` and `nrepl-dict-put`.
26+
- nested stack is used for decoded messages to avoid re-parsing of incomplete messages
27+
- queues are used for incoming strings from the server and for the decoded responses
2328
* REPL buffers are now connection buffers for REPL client connections.
2429
* Server and client cranking were isolated into `nrepl-start-server-process` and
2530
`nrepl-start-client-process`.

cider-client.el

Lines changed: 11 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -169,34 +169,17 @@ loaded."
169169
(buffer-local-value 'nrepl-repl-buffer
170170
(get-buffer (nrepl-current-connection-buffer)))))
171171

172-
(defun cider--dict-to-alist (val)
173-
"Transforms a nREPL bdecoded dict VAL into an alist.
174-
Simply returns it if it's not a dict."
175-
(if (and (listp val)
176-
(eq (car val) 'dict))
177-
(-map '-cons-to-list (cdr val))
178-
val))
179-
180-
(defun cider--dict-to-plist (val)
181-
"Transforms a nREPL bdecoded dict VAL into a plist with symbol keys.
182-
Simply returns it if it's not a dict."
183-
(if (and (listp val)
184-
(eq (car val) 'dict))
185-
(-interleave (-map 'intern (-map 'car (cdr val)))
186-
(-map 'cdr (cdr val)))
187-
val))
188-
189172
(defun cider--var-choice (var-info)
190173
"Prompt to choose from among multiple VAR-INFO candidates, if required.
191174
This is needed only when the symbol queried is an unqualified host platform
192175
method, and multiple classes have a so-named member. If VAR-INFO does not
193176
contain a `candidates' key, it is returned as is."
194-
(let ((candidates (cdadr (assoc "candidates" var-info))))
177+
(let ((candidates (nrepl-dict-get var-info "candidates")))
195178
(if candidates
196-
(let* ((classes (mapcar (lambda (x) (cdr (assoc "class" x))) candidates))
179+
(let* ((classes (nrepl-dict-keys candidates))
197180
(choice (completing-read "Member in class: " classes nil t))
198-
(info (cdr (assoc choice candidates))))
199-
(cider--dict-to-alist info))
181+
(info (nrepl-dict-get candidates choice)))
182+
info)
200183
var-info)))
201184

202185
(defun cider-var-info (var &optional all)
@@ -211,25 +194,17 @@ unless ALL is truthy."
211194
"ns" (cider-current-ns)
212195
"symbol" var))
213196
:value)))
214-
(if all
215-
(cider--dict-to-alist val)
216-
(cider--var-choice
217-
(cider--dict-to-alist val))))))
197+
(if all val (cider--var-choice val)))))
218198

219199
(defun cider-member-info (class member)
220200
"Return the CLASS MEMBER's info as an alist with list cdrs."
221201
(when (and class member)
222-
(let ((val (plist-get (nrepl-send-sync-request
223-
(list "op" "info"
224-
"session" (nrepl-current-session)
225-
"class" class
226-
"member" member))
227-
:value)))
228-
(cider--dict-to-alist val))))
229-
230-
(defun cider-get-var-attr (var-info attr)
231-
"Return VAR-INFO's ATTR."
232-
(cadr (assoc attr var-info)))
202+
(plist-get (nrepl-send-sync-request
203+
(list "op" "info"
204+
"session" (nrepl-current-session)
205+
"class" class
206+
"member" member))
207+
:value)))
233208

234209
(provide 'cider-client)
235210

cider-doc.el

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -285,21 +285,21 @@ Tables are marked to be ignored by line wrap."
285285

286286
(defun cider-docview-render-info (buffer info)
287287
"Emit into BUFFER formatted INFO for the Clojure or Java symbol."
288-
(let* ((ns (cadr (assoc "ns" info)))
289-
(name (cadr (assoc "name" info)))
290-
(added (cadr (assoc "added" info)))
291-
(depr (cadr (assoc "deprecated" info)))
292-
(macro (cadr (assoc "macro" info)))
293-
(special (cadr (assoc "special-form" info)))
294-
(forms (cadr (assoc "forms-str" info)))
295-
(args (cadr (assoc "arglists-str" info)))
296-
(doc (cadr (assoc "doc" info)))
297-
(url (cadr (assoc "url" info)))
298-
(class (cadr (assoc "class" info)))
299-
(member (cadr (assoc "member" info)))
300-
(javadoc (cadr (assoc "javadoc" info)))
301-
(super (cadr (assoc "super" info)))
302-
(ifaces (cadr (assoc "interfaces" info)))
288+
(let* ((ns (nrepl-dict-get info "ns"))
289+
(name (nrepl-dict-get info "name"))
290+
(added (nrepl-dict-get info "added"))
291+
(depr (nrepl-dict-get info "deprecated"))
292+
(macro (nrepl-dict-get info "macro"))
293+
(special (nrepl-dict-get info "special-form"))
294+
(forms (nrepl-dict-get info "forms-str"))
295+
(args (nrepl-dict-get info "arglists-str"))
296+
(doc (nrepl-dict-get info "doc"))
297+
(url (nrepl-dict-get info "url"))
298+
(class (nrepl-dict-get info "class"))
299+
(member (nrepl-dict-get info "member"))
300+
(javadoc (nrepl-dict-get info "javadoc"))
301+
(super (nrepl-dict-get info "super"))
302+
(ifaces (nrepl-dict-get info "interfaces"))
303303
(clj-name (if ns (concat ns "/" name) name))
304304
(java-name (if member (concat class "/" member) class)))
305305
(with-current-buffer buffer
@@ -351,14 +351,14 @@ Tables are marked to be ignored by line wrap."
351351
(newline))
352352
(let ((beg (point-min))
353353
(end (point-max)))
354-
(dolist (x info)
355-
(put-text-property beg end (car x) (cadr x)))))
354+
(cl-loop for x on info by #'cddr
355+
do (put-text-property beg end (car x) (cadr x)))))
356356
(current-buffer))))
357357

358358
(defun cider-docview-render (buffer symbol info)
359359
"Emit into BUFFER formatted documentation for SYMBOL's INFO."
360360
(with-current-buffer buffer
361-
(let ((javadoc (cadr (assoc "javadoc" info)))
361+
(let ((javadoc (nrepl-dict-get info "javadoc"))
362362
(inhibit-read-only t))
363363
(cider-docview-mode)
364364

cider-eldoc.el

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,14 +96,14 @@ POS is the index of current argument."
9696
"Return the arglist for THING."
9797
(when (nrepl-op-supported-p "info")
9898
(let* ((var-info (cider-var-info thing t))
99-
(candidates (cdadr (assoc "candidates" var-info))))
99+
(candidates (cdr (nrepl-dict-get var-info "candidates"))))
100100
(if candidates
101101
(->> candidates
102-
(-map (lambda (x) (cdr (assoc "arglists-str" x))))
102+
(-map (lambda (x) (nrepl-dict-get "arglists-str" x)))
103103
(-map 'read)
104104
-flatten
105105
-distinct)
106-
(let ((arglists (cider-get-var-attr var-info "arglists-str")))
106+
(let ((arglists (nrepl-dict-get var-info "arglists-str")))
107107
(when arglists
108108
(read arglists)))))))
109109

cider-interaction.el

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -176,24 +176,27 @@ Signal an error if it is not supported."
176176
"Retrieve the underlying connection's Java version."
177177
(with-current-buffer (nrepl-current-connection-buffer)
178178
(when nrepl-versions
179-
(cdr (assoc "version-string" (assoc "java" nrepl-versions))))))
179+
(-> nrepl-versions
180+
(nrepl-dict-get "java")
181+
(nrepl-dict-get "version-string")))))
180182

181183
(defun cider--clojure-version ()
182184
"Retrieve the underlying connection's Clojure version."
183185
(with-current-buffer (nrepl-current-connection-buffer)
184186
(when nrepl-versions
185-
(let* ((version-dict (assoc "clojure" nrepl-versions))
186-
(major (cdr (assoc "major" version-dict)))
187-
(minor (cdr (assoc "minor" version-dict)))
188-
(incremental (cdr (assoc "incremental" version-dict))))
187+
(let* ((version-dict (nrepl-dict-get nrepl-versions "clojure"))
188+
(major (nrepl-dict-get version-dict "major"))
189+
(minor (nrepl-dict-get version-dict "minor"))
190+
(incremental (nrepl-dict-get version-dict "incremental")))
189191
(format "%s.%s.%s" major minor incremental)))))
190192

191193
(defun cider--nrepl-version ()
192194
"Retrieve the underlying connection's nREPL version."
193195
(with-current-buffer (nrepl-current-connection-buffer)
194196
(when nrepl-versions
195-
(cdr (assoc "version-string" (assoc "nrepl" nrepl-versions))))))
196-
197+
(-> nrepl-versions
198+
(nrepl-dict-get "nrepl")
199+
(nrepl-dict-get "version-string")))))
197200

198201
(defun cider--check-middleware-compatibility-callback (buffer)
199202
"A callback to check if the middleware used is compatible with CIDER."
@@ -670,7 +673,7 @@ existing file ending with URL has been found."
670673
not found."
671674
(cider-ensure-op-supported "info")
672675
(-when-let* ((info (cider-var-info var))
673-
(file (cadr (assoc "file" info))))
676+
(file (nrepl-dict-get info "file")))
674677
(cider-find-file file)))
675678

676679
(defun cider-jump-to (buffer &optional pos other-buffer)
@@ -710,20 +713,20 @@ When called interactively, this operates on point."
710713
"Jump to location give by INFO.
711714
INFO object is returned by `cider-var-info' or `cider-member-info'.
712715
OTHER-BUFFER is passed to `cider-jamp-to'."
713-
(-if-let* ((line (cadr (assoc "line" info)))
714-
(file (cadr (assoc "file" info)))
716+
(-if-let* ((line (nrepl-dict-get info "line"))
717+
(file (nrepl-dict-get info "file"))
715718
(buffer (unless (cider--tooling-file-p file)
716719
(cider-find-file file))))
717720
(cider-jump-to buffer (cons line nil) other-buffer)
718721
;; var was created interactively and has no file info
719-
(-if-let* ((ns (cadr (assoc "ns" info)))
720-
(name (cadr (assoc "name" info)))
721-
(buffer (cider-find-buffer ns))
722-
(pos (cider-locate-def name buffer line)))
723-
(cider-jump-to buffer pos other-buffer)
724-
(-if-let (name (cadr (assoc "name" info)))
725-
(message "No location found for %s" name)
726-
(message "No source info")))))
722+
(-if-let* ((ns (nrepl-dict-get info "ns"))
723+
(name (nrepl-dict-get info "name"))
724+
(buffer (cider-find-buffer ns))
725+
(pos (cider-locate-def name buffer line)))
726+
(cider-jump-to buffer pos other-buffer)
727+
(-if-let (name (nrepl-dict-get info "name"))
728+
(message "No location found for %s" name)
729+
(message "No source info")))))
727730

728731
(defun cider-jump-to-var (&optional var line)
729732
"Jump to the definition of VAR, optionally at a specific LINE.
@@ -803,9 +806,9 @@ Currently we annotate macros, special-forms and functions,
803806
as it's not obvious from their names alone which is which."
804807
(if cider-annotate-completion-candidates
805808
(-when-let (info (cider-var-info symbol))
806-
(let ((macro (cadr (assoc "macro" info)))
807-
(special (cadr (assoc "special-form" info)))
808-
(args (cadr (assoc "arglists-str" info))))
809+
(let ((macro (nrepl-dict-get info "macro"))
810+
(special (nrepl-dict-get info "special-form"))
811+
(args (nrepl-dict-get info "arglists-str")))
809812
(cond
810813
(macro " <m>")
811814
(special " <s>")
@@ -830,8 +833,8 @@ as it's not obvious from their names alone which is which."
830833
Returns the cons of the buffer itself and the location of VAR's definition
831834
in the buffer."
832835
(-when-let* ((info (cider-var-info var))
833-
(file (cadr (assoc "file" info)))
834-
(line (cadr (assoc "line" info)))
836+
(file (nrepl-dict-get info "file"))
837+
(line (nrepl-dict-get info "line"))
835838
(buffer (cider-find-file file)))
836839
(with-current-buffer buffer
837840
(save-excursion
@@ -852,7 +855,7 @@ in the buffer."
852855
(when symbol-name
853856
(cider-ensure-op-supported "info")
854857
(let* ((info (cider-var-info symbol-name))
855-
(url (cadr (assoc "javadoc" info))))
858+
(url (nrepl-dict-get info "javadoc")))
856859
(if url
857860
(browse-url url)
858861
(error "No Javadoc available for %s" symbol-name)))))
@@ -1620,8 +1623,8 @@ under point, prompts for a var."
16201623
(defun cider-grimoire-web-lookup (symbol)
16211624
"Look up the grimoire documentation for SYMBOL."
16221625
(-if-let (var-info (cider-var-info symbol))
1623-
(let ((name (cider-get-var-attr var-info "name"))
1624-
(ns (cider-get-var-attr var-info "ns")))
1626+
(let ((name (nrepl-dict-get var-info "name"))
1627+
(ns (nrepl-dict-get var-info "ns")))
16251628
;; TODO: add a whitelist of supported namespaces
16261629
(browse-url (cider-grimoire-url name ns (cider--clojure-version))))
16271630
(message "Symbol %s not resolved" symbol)))
@@ -1643,8 +1646,8 @@ under point, prompts for a var."
16431646
(defun cider-grimoire-lookup (symbol)
16441647
"Look up the grimoire documentation for SYMBOL."
16451648
(-if-let (var-info (cider-var-info symbol))
1646-
(let ((name (cider-get-var-attr var-info "name"))
1647-
(ns (cider-get-var-attr var-info "ns"))
1649+
(let ((name (nrepl-dict-get var-info "name"))
1650+
(ns (nrepl-dict-get var-info "ns"))
16481651
(url-request-method "GET")
16491652
(url-request-extra-headers `(("Content-Type" . "text/plain"))))
16501653
;; TODO: add a whitelist of supported namespaces

cider-stacktrace.el

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -403,10 +403,9 @@ it wraps to 0."
403403
(method (button-get button 'method))
404404
(info (or (and var (cider-var-info var))
405405
(and class method (cider-member-info class method))
406-
`(("file" ,(button-get button 'file)))))
406+
`(dict "file" ,(button-get button 'file))))
407407
;; stacktrace returns more accurate line numbers
408-
(info (cons `("line" ,(button-get button 'line))
409-
info)))
408+
(info (nrepl-dict-put info "line" (button-get button 'line))))
410409
(cider--jump-to-loc-from-info info t)))
411410

412411
(defun cider-stacktrace-jump ()

cider-test.el

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ With the actual value, the outermost '(not ...)' s-expression is removed."
267267
"Emit into BUFFER report detail for the TEST assertion."
268268
(with-current-buffer buffer
269269
(nrepl-dbind-response test (var context type message expected actual error)
270-
(cider-propertize-region (cider--dict-to-plist test)
270+
(cider-propertize-region (cdr test)
271271
(cider-insert (capitalize type) (cider-test-type-face type) nil " in ")
272272
(cider-insert var 'font-lock-function-name-face t)
273273
(when context (cider-insert context 'font-lock-doc-face t))

cider.el

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
;; Steve Purcell <[email protected]>
1111
;; URL: http://www.github.com/clojure-emacs/cider
1212
;; Version: 0.8.0-cvs
13-
;; Package-Requires: ((clojure-mode "2.0.0") (cl-lib "0.3") (dash "2.4.1") (pkg-info "0.4") (emacs "24"))
13+
;; Package-Requires: ((clojure-mode "2.0.0") (cl-lib "0.3") (dash "2.4.1") (pkg-info "0.4") (emacs "24") (queue "0.1.1"))
1414
;; Keywords: languages, clojure, cider
1515

1616
;; This program is free software: you can redistribute it and/or modify

0 commit comments

Comments
 (0)