Skip to content

Commit c0e7f25

Browse files
alexander-yakushevbbatsov
authored andcommitted
[info] Add support for sources JAR downloading on `info' events
1 parent 3c89404 commit c0e7f25

File tree

4 files changed

+68
-21
lines changed

4 files changed

+68
-21
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
### New features
66

7+
- Automatic downloading of third-party Java sources for better Java documentation and jump-to-definition functionality. See [Obtaining source JARs](https://docs.cider.mx/cider/usage/working_with_documentation.html#obtaining-source-jars).
78
- CIDER [History](https://docs.cider.mx/cider/repl/history.html): Add a command to delete history item at point.
89

910
### Changes

cider-client.el

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -189,16 +189,20 @@ the current connection. Return the id of the sent message.
189189
If TOOLING is truthy then the tooling session is used."
190190
(nrepl-send-request request callback (or connection (cider-current-repl 'any 'ensure)) tooling))
191191

192-
(defun cider-nrepl-send-sync-request (request &optional connection abort-on-input)
192+
(defun cider-nrepl-send-sync-request (request &optional connection
193+
abort-on-input callback)
193194
"Send REQUEST to the nREPL server synchronously using CONNECTION.
194195
Hold till final \"done\" message has arrived and join all response messages
195196
of the same \"op\" that came along and return the accumulated response.
196197
If ABORT-ON-INPUT is non-nil, the function will return nil
197198
at the first sign of user input, so as not to hang the
198-
interface."
199+
interface.
200+
if CALLBACK is non-nil, it will additionally be called on all received messages."
199201
(nrepl-send-sync-request request
200202
(or connection (cider-current-repl 'any 'ensure))
201-
abort-on-input))
203+
abort-on-input
204+
nil
205+
callback))
202206

203207
(defun cider-nrepl-send-unhandled-request (request &optional connection)
204208
"Send REQUEST to the nREPL CONNECTION and ignore any responses.
@@ -342,6 +346,17 @@ The default value in nREPL is 1024."
342346
:group 'cider
343347
:package-version '(cider . "0.25.0"))
344348

349+
(defcustom cider-download-java-sources nil
350+
"Whether to automatically download source artifacts for 3rd-party Java classes.
351+
352+
When enabled, CIDER will attempt to download source JARs from Maven for
353+
Java classes if the source file is not found locally. This downloading only
354+
happens once per artifact, and only when the user jumps to definition or
355+
requests `cider-doc' on a Java class or a member of the class."
356+
:type 'boolean
357+
:group 'cider
358+
:package-version '(cider . "1.17.0"))
359+
345360
(defun cider--print-fn ()
346361
"Return the value to send in the nrepl.middleware.print/print slot."
347362
(pcase cider-print-fn
@@ -681,13 +696,25 @@ CONTEXT represents a completion context for compliment."
681696

682697
(defun cider-sync-request:info (symbol &optional class member context)
683698
"Send \"info\" op with parameters SYMBOL or CLASS and MEMBER, honor CONTEXT."
684-
(let ((var-info (thread-first `("op" "info"
685-
"ns" ,(cider-current-ns)
686-
,@(when symbol `("sym" ,symbol))
687-
,@(when class `("class" ,class))
688-
,@(when member `("member" ,member))
689-
,@(when context `("context" ,context)))
690-
(cider-nrepl-send-sync-request (cider-current-repl)))))
699+
(let* ((req
700+
`("op" "info"
701+
"ns" ,(cider-current-ns)
702+
,@(when symbol `("sym" ,symbol))
703+
,@(when class `("class" ,class))
704+
,@(when member `("member" ,member))
705+
,@(when context `("context" ,context))
706+
,@(when cider-download-java-sources `("download-sources-jar" "1"))))
707+
(callback
708+
(lambda (resp)
709+
(let ((status (nrepl-dict-get resp "status"))
710+
(coords (nrepl-dict-get resp "coords")))
711+
(when (member "download-sources-jar" status)
712+
(message "Local source not found, downloading Java sources for artifact %s/%s %s..."
713+
(nrepl-dict-get coords "group")
714+
(nrepl-dict-get coords "artifact")
715+
(nrepl-dict-get coords "version"))))))
716+
(var-info
717+
(cider-nrepl-send-sync-request req (cider-current-repl) nil callback)))
691718
(if (member "no-info" (nrepl-dict-get var-info "status"))
692719
nil
693720
var-info)))

doc/modules/ROOT/pages/usage/working_with_documentation.adoc

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,21 @@ as some people prefer to keep holding `Control` and some don't.
1717

1818
Normally the command operates on the symbol at point. If invoked with a prefix argument, or no symbol is found at point, it will prompt for a symbol.
1919

20-
NOTE: If using `enrich-classpath`, Java doc comments are available and rendered in the same way that Clojure docstrings are.
21-
They're often much more handy than opening Javadoc in a browser. Starting from CIDER 1.8.0,
22-
the HTML-like language that they use is nicely rendered into syntax-colored strings, well-aligned tables, etc
20+
== Local JavaDoc
2321

24-
== JavaDoc
22+
Most JDK distributions ship with a `src.zip` file (an archive with all base Java source files). If you have such archive present in your JDK, CIDER will automatically parse the source file when you query the documentation for a Java class (e.g. `java.lang.Thread`) or a method (e.g. `java.lang.Thread/currentThread`) and will display the properly formatted JavaDoc in the documentation buffer. You will also see better Eldoc documentation (minibuffer hints) for Java methods. If the source file are present, you are able to jump to class or method definition by pressing kbd:[M-.] on the class name or method name.
23+
24+
Furthermore, CIDER is able to parse JavaDoc source files and jump to definitions for third-party Java libraries if you have downloaded the special `-sources.jar` file for that library. See the next section on how to download source JARs.
25+
26+
== Obtaining source JARs
27+
28+
Since version 1.17, CIDER is able to download the necessary source JAR file automatically when you either request the documentation for a Java class/method or when you jump to the definition of a Java class/method. In order for the sources to be downloaded, you need to enable custom variable `cider-download-java-sources`. When the download triggers, CIDER displays a minibuffer message about that. Fetching a single source JAR usually takes a few seconds. CIDER will make only one attempt to download the source JAR for a particular dependency per process — if it failed to download (usually, because the dependency doesn't have a source JAR published to Maven), CIDER will not retry that until the next restart.
29+
30+
NOTE: While Eldoc functionality benefits from having Java sources, the eldoc itself will not trigger the downloading of Java source JARs. You will have to lookup the documentation once manually or jump to the definition in order for the JAR is downloaded. After that, Eldoc will pick up the Java sources and display better hints.
31+
32+
Alternatively, you can use https://github.com/clojure-emacs/enrich-classpath[`enrich-classpath`] to download all source JARs used by your current project at once. This will incur longer startup time, but will not trigger individual JARs fetching at the runtime.
33+
34+
== Online JavaDoc
2535

2636
CIDER provides a quick access to the online Javadoc documentation
2737
via the command `cider-javadoc` (kbd:[C-c C-d j] or kbd:[C-c C-d C-j]), using your default browser.

nrepl-client.el

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -939,21 +939,30 @@ the standard session."
939939
(declare-function cider-repl-emit-interactive-stderr "cider-repl")
940940
(declare-function cider--render-stacktrace-causes "cider-eval")
941941

942-
(defun nrepl-send-sync-request (request connection &optional abort-on-input tooling)
942+
(defun nrepl-send-sync-request (request connection &optional abort-on-input
943+
tooling callback)
943944
"Send REQUEST to the nREPL server synchronously using CONNECTION.
944945
Hold till final \"done\" message has arrived and join all response messages
945946
of the same \"op\" that came along.
946947
If ABORT-ON-INPUT is non-nil, the function will return nil at the first
947948
sign of user input, so as not to hang the interface.
948-
If TOOLING, use the tooling session rather than the standard session."
949+
If TOOLING, use the tooling session rather than the standard session.
950+
951+
If CALLBACK is non-nil, it will additionally be called on all received
952+
messages. This shouldn't be used this for any control logic — use the
953+
asynchronous `nrepl-send-request' directly for that. CALLBACK here should
954+
be used to react to some intermediate events in an otherwise synchronous
955+
command and e.g. notify the user about them."
949956
(let* ((time0 (current-time))
950957
(response (cons 'dict nil))
951958
(nrepl-ongoing-sync-request t)
959+
(cb (lambda (resp)
960+
;; If caller has provided `callback', call it on the response.
961+
(when callback
962+
(funcall callback resp))
963+
(nrepl--merge response resp)))
952964
status)
953-
(nrepl-send-request request
954-
(lambda (resp) (nrepl--merge response resp))
955-
connection
956-
tooling)
965+
(nrepl-send-request request cb connection tooling)
957966
(while (and (not (member "done" status))
958967
(not (and abort-on-input
959968
(input-pending-p))))
@@ -962,7 +971,7 @@ If TOOLING, use the tooling session rather than the standard session."
962971
;; anywhere, and we'll just timeout. So we forward it to the user.
963972
(if (member "need-input" status)
964973
(progn (cider-need-input (current-buffer))
965-
;; If the used took a few seconds to respond, we might
974+
;; If the user took a few seconds to respond, we might
966975
;; unnecessarily timeout, so let's reset the timer.
967976
(setq time0 (current-time)))
968977
;; break out in case we don't receive a response for a while

0 commit comments

Comments
 (0)