clojure-emacs / cider

The Clojure Interactive Development Environment that Rocks for Emacs
https://cider.mx
GNU General Public License v3.0
3.54k stars 646 forks source link

clojuredocs lookup not working with CLI based project under spacemacs #2913

Open theophilusx opened 3 years ago

theophilusx commented 3 years ago

Expected behavior

After starting a repl, moving the cursor over a symbol in the clj file and hitting ', h d' (or SPC m h d) should open a cider docview buffer with the documentation for that symbol (assuming core symbols documented on clojuredocs).

Actual behavior

When entering ', h d' after moving the cursor over a symbol, you are prompted for the symbol to lookup (i.e. cider-try-symbol-at-point fails). You enter the symbol e.g. println and hit enter. You then get the following error

Wrong type argument: char-or-string-p, nil

The full backtrace is

Debugger entered--Lisp error: (wrong-type-argument char-or-string-p nil)
  cider-clojuredocs--content(nil)
  cider-clojuredocs-lookup("println")
  cider-try-symbol-at-point("ClojureDocs doc for" cider-clojuredocs-lookup)
  cider-clojuredocs(nil)
  funcall-interactively(cider-clojuredocs nil)
  call-interactively(cider-clojuredocs nil nil)
  command-execute(cider-clojuredocs)

Steps to reproduce the problem

Setup a simple CLI based project. I use Sean Corfield's deps.edn from his dot-clojure repository, which includes his clj-new library that allows you to setup a project using lein templates. I used the basic app template to create a test CLI project. The deps.edn is

{:paths ["src" "resources"]
 :deps  {org.clojure/clojure {:mvn/version "1.10.1"}}
 :aliases
 {:test    {:extra-paths ["test"]
            :extra-deps  {org.clojure/test.check {:mvn/version "1.0.0"}}}
  :runner
  {:extra-deps {com.cognitect/test-runner
                {:git/url "https://github.com/cognitect-labs/test-runner"
                 :sha     "f7ef16dc3b8332b0d77bc0274578ad5270fbfedd"}}
   :main-opts  ["-m" "cognitect.test-runner"
                "-d" "test"]}
  :uberjar {:extra-deps {seancorfield/depstar {:mvn/version "1.1.104"}}
            :main-opts  ["-m" "hf.depstar.uberjar" "core.jar"
                         "-C" "-m" "doctester.core"]}}}

I also have a .dir-locals.el file which has the following

((clojure-mode . ((cider-clojure-cli-global-options . "-A:test")
                  (cider-preferred-build-tool . clojure-cli))))

I open the core.clj file and move the cursor to the 'println' symbol

(ns doctester.core
  (:gen-class))

(defn -main
  "I don't do a whole lot ... yet."
  [& args]
  (println "Hello, World!"))

I then start a repl by entering ', '' (or SPC m , ') and selecting cider-jack-in-clj from the menu. This starts the cider repl. I then ener (with point over the 'println') ', h d' (or SPC m h d) and then am prompted for the symbol to lookup and enter println (this should not be necessary as spacemacs sets cider-prompt-for-symbol to nil, but as that fails, it then prompts to enter the symbol.

Environment & Version information

GNU/Linux (Ubunto 20.04) openjdk-11 spacemacs develop branch (HEAD)

CIDER version information

;; Connected to nREPL server - nrepl://localhost:37381
;; CIDER 1.0.0snapshot (package: 20201020.1058), nREPL 0.8.2
;; Clojure 1.10.1, Java 11.0.8

;; ======================================================================
;;  Startup: /usr/local/bin/clojure -A:test -Sdeps '{:deps {nrepl {:mvn/version "0.8.2"} cider/cider-nrepl {:mvn/version "0.25.4"}}}' -m nrepl.cmdline --middleware '["cider.nrepl/cider-middleware"]'
user> 

Lein/Boot version

tools.dep

clojure Version: 1.10.1.561

Emacs version

GNU Emacs 27.1 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.20, cairo version 1.16.0) of 2020-10-21

Operating system

GNU/Linux Ubuntu 20.04

Additional Info

NREPL messages log


(-->
  id         "9"
  op         "clojuredocs-lookup"
  session    "907886a7-d3e1-4780-9c1f-d02ec82f0dbb"
  time-stamp "2020-10-21 15:21:05.482030195"
  ns         #("doctester.core" 0 14 (fontified t help-echo cider--help-echo cider-locals nil cider-block-dynamic-font-lock t face font-lock-type-face))
  sym        "println"
)
(<--
  id         "9"
  session    "907886a7-d3e1-4780-9c1f-d02ec82f0dbb"
  time-stamp "2020-10-21 15:21:05.491460570"
  status     ("no-doc" "done")
)
(-->
  id         "10"
  op         "clojuredocs-lookup"
  session    "907886a7-d3e1-4780-9c1f-d02ec82f0dbb"
  time-stamp "2020-10-21 15:21:08.331321807"
  ns         #("doctester.core" 0 14 (fontified t help-echo cider--help-echo cider-locals nil cider-block-dynamic-font-lock t face font-lock-type-face))
  sym        "println"
)
(<--
  id         "10"
  session    "907886a7-d3e1-4780-9c1f-d02ec82f0dbb"
  time-stamp "2020-10-21 15:21:08.336404112"
  status     ("no-doc" "done")
)

The above indicates the issue may lie somewhere around the call to nrepl-send-sync-request. When running a lein based project, this call returns valid documentation and the message buffer shows valid dict structures in the clojuredocs key of the response message. 

Note that lein projects work perfectly and no errors occur when looking up documentation. Exact same spacemacs configuration. I have also tried minimising the spacemacs clojure layer and turning off everything (ie. said, clj-refactor, etc). 

Also note that the same projects (both lein and CLI) work fine when running plain emacs and loading packages using use-package (no spacemacs). All other aspects seem to be working fine - I can evaluate forms in the repl, send forms/buffers to the repl and run tests. 

I also note that other documentation options, like cider-doc return failure saying Symbol println not resolved as does cider-coljuredocs-web. Running clojuredocs-refresh-cache completes successfully, but has no impact on the resulting failures.

I have also tried a minimal spacemacs configuration - basically, the default .spacemacs with only the clojure layer added and see the same results. 
rakyi commented 3 years ago

After some debugging it looks like clojuredocs-lookup returns "no-doc" status if the form containing the symbol to look up is not evaluated first by the user in a deps.end based project. In a lein project it appears to work even without user evaluating the form explicitly first.

theophilusx mentioned that this problem isn't present in vanilla emacs, so I assume spacemacs must be doing something to cause the deps.edn project to not be evaluated at start of the session or something like that.

theophilusx commented 3 years ago

Confirming that Martin's analysis is correct.

Under spacemacs (and BTW it seems Doom Emacs as well), after starting the repl, you need to load (evaluate) the namespace at least once before any of the documentation help lookup functions work correctly. If you don't, cider-clojuredocs will throw the wrong type argument and cider-doc will fail with a message stating the symbol could not be qualitifed (regardless of whether it is a core lib symbol).

Once you have evaluated the buffer at least once, all works fine. This requirement does not exist when running under an emacs configuration which does not use spacemacs and just loads the same packages from ELPA. Under this configuration, there is no need to first evaluate the buffer before trying to do documentation lookup.

bbatsov commented 3 years ago

Can't imagine how this would work, as CIDER relies on the runtime state to do the lookup, meaning you have to have loaded the things you're trying to resolve/lookup. Might be that in the Lein project some namespaces got required automatically or someting like this.

theophilusx commented 3 years ago

It has to be something specific to spacemacs (and doom emacs it seems). I don't see this behaviour with Emacs using basic init.el file which just loads the packages from MELPA. Under such a 'vanilla' configuration, once you have started the repl, cider-clojuredocs and cider-doc work fine.

With lein, the core (main) namespace must be loaded automatically as lein leaves the repl in the core namespace. Under CLI, the repl is left in the 'user' namespace.

theophilusx commented 3 years ago

As this is a spacemacs specific issue, I'm fine for this to be closed.

bbatsov commented 3 years ago

With lein, the core (main) namespace must be loaded automatically as lein leaves the repl in the core namespace.

Only if :init-ns is specified. But really - it's not possible for this functionality to work with a namespace that's not loaded. It's just how CIDER and nREPl work.

practicalli-johnny commented 3 years ago

@theophilusx The way cider works, only special forms are available from the cider help commands until a namespace (any namspace in the project) is evaluated. So until a namespace is evaluated, the docs for if can be found, but not functions defined in clojure.core as they have not loaded yet.

Configuration in the external tool used to run the REPL might trigger some namespace evaluate, e.g setting :init-ns specifically for Leiningen, but if that happens its outside of cider and it sounds like its not something to rely upon.

Both docs.cider.mx and https://practicalli.github.io/spacemacs/documentation/cider-doc.html say that a namespace should be evaluated as the first step to using CIDER.

vemv commented 2 years ago

The issue itelf is clear as summarized by @practicalli-john.

It's almost a non-issue and more of a matter of getting used to CIDER's approach.

However, the failure is fairly opaque. Showing a stacktrace is not so good. We should at least handle these nils more gracefully and echo Not found! or such.

bbatsov commented 2 years ago

Yeah, that'd be reasonable. Might be even better to let people know that they are looking up stuff in a namespace that hasn't be evaluated (we just have to check that the namespace is missing).