Fork me on GitHub
#lsp
<
2023-12-14
>
Nim Sadeh18:12:30

Hey - I set up lsp in emacs and I am getting some warnings for unresolved var that are incorrect (the var is definitely resolved), and my code still compiles and runs. How do I fix/debug that?

Nim Sadeh18:12:27

Here's an example piece of code:

(ns undl-sync.state.redis
  (:gen-class)
  (:require
   [taoensso.carmine :as carmine]))

(defn redis-key
  "Computes the key for a given task"
  [date [start end]]
  (str date ":"  start "-"  end))

(def statuses {:initialized "INITIALIZED"
               :assigned "ASSIGNED"
               :downloaded "DOWNLOADED"
               :failed-to-download "FAILED_TO_DOWNLOAD"
               :completed "COMPLETED"})

(defonce conn-pool (carmine/connection-pool {}))

(def conn-spec {:uri ""})

(def car-opts {:pool conn-pool :spec conn-spec})

(defmacro wcar* [& body] `(carmine/wcar ~car-opts ~@body))

(defn set-state
  "Sets the state of a work, defined by its date and range.
  Expects an object with { :status state } at least, and potentially other metadata"
  [date range  status]
  (let [work-status (:status status)
        body (if (= work-status :downloaded) (str work-status (:file-size status))
                 work-status)
        key (redis-key date range)]
    (wcar* (carmine/set key body))))
LSP throws a warning on the final line, for (carmine/set), but on no other line, carmine-related or otherwise. Compiling works fine.

seancorfield18:12:11

Which var is it claiming is unresolved?

seancorfield18:12:34

Specifically carmine/set?

Nim Sadeh18:12:21

Yes, specifically carmine/set

Nim Sadeh18:12:46

I also added a function with carmine/get which it claimed to be unresolved but I have been using in the REPL quite happily

seancorfield19:12:19

That should run when taoensso.carmine is required tho', right?

hiredman19:12:19

yeah, but kondo's static analysis won't know about anything it defines

seancorfield19:12:54

Oh, gotcha... FWIW, I setup a test project with Carmine and your code in VS Code/Calva/LSP and carmine/set is not flagged as unresolved...

seancorfield19:12:05

Hmm, interestingly, carmine/i-do-not-exist is also not flagged... Weird šŸ˜

Nim Sadeh19:12:07

My setup is prelude on emacs with LSP, I think Kondo is in there

Nim Sadeh19:12:17

Is that interfering somehow?

hiredman19:12:34

kondo is what powers clojure-lsp's analysis

Nim Sadeh19:12:36

Since I am always calling these insdie macros

hiredman19:12:58

it is multiple things

Nim Sadeh19:12:27

Great šŸ˜›

hiredman19:12:10

but I think at base level it is just the static analysis kondo does cannot tell that defcommands is introducing definitions into the carmine namespace, so as far as kondo is concerned those names don't exist

seancorfield19:12:55

On a separate note: it's not a good idea to have side-effecting stuff in def or defonce:

(defonce conn-pool (carmine/connection-pool {}))
That will run whenever the namespace is first loaded in a process which will include when you try to compile it to build an uberjar.

seancorfield19:12:08

(and since {} is provided, it will attempt to connect to the default localhost Redis instance when it is loaded -- I don't have Redis running locally on 6379 so your code will not load/compile for me)

seancorfield19:12:44

The same applies to car-opts since it depends on conn-pool having been evaluated.

seancorfield19:12:01

You also do not want ~car-opts inside your macro. car-opts is a resolvable symbol at that point, not something you can unquote. The following changes would address both of these issues:

(defonce conn-pool (delay (carmine/connection-pool {})))

(def conn-spec {:uri ""})

(def car-opts (delay {:pool @conn-pool :spec conn-spec}))

(defmacro wcar* [& body] `(carmine/wcar @car-opts ~@body))

Nim Sadeh19:12:14

Thanks - I need to extract some of that to .env files eventually for sure. I just started this project today as a first Clojure project

seancorfield19:12:56

With those two delay and @ (deref) added, it will load/compile for me. You probably need conn-spec first and (carmine/connection-pool conn-spec) for that to work correctly?

Nim Sadeh19:12:57

The macro, I copied from the Carmine quickstart page. It actually doesn't work, but that's not why the symbols don't resolve. I don't actually know how to write clojure macros yet šŸ™‚

Nim Sadeh19:12:40

@U0NCTKEV8 is that specific to this package then, or is there a general Kondo misconfiguration?

seancorfield19:12:41

We used to use Carmine at work but we switched to just using the Jedis library via interop from Clojure.

seancorfield19:12:27

clj-kondo cannot know about anything defined by code-at-runtime like that -- unless the library also provides all the definitions to clj-kondo via exports.

šŸ‘€ 1
seancorfield19:12:41

Carmine has no clj-kondo exports configuration.

Nim Sadeh19:12:52

Sounds like it's too sophisticated for its own good

seancorfield19:12:52

Now that I have a working REPL (after those code changes), I do get the carmine/set warning BTW:

seancorfield19:12:01

(so you can see Calva is able to retrieve the docstring just fine via the REPL but clj-kondo cannot do static analysis because taoensso.carmine does not contain a (statically detectable) set function).

Nim Sadeh19:12:19

Got it, thanks. Off topic - I noticed that you use VSCode over Emacs and that you're very experienced in Clojure. I learned Emacs over the past couple of days partially because I thought it's the "OG" way of working with Clojure and wanted to dive into the deep end. Is that not the case, at the higher levels of Clojure experience?

seancorfield19:12:10

I started with Emacs back in the 17.x days and used it through 19.x (for C mostly) then switched out to other IDEs while I did C++ and Java etc. When I started with Clojure (2010), I came back to Emacs and tried a lot of different configurations over the years (including Prelude) but ultimately just found Emacs a) a bit too clunky after using a bunch of "modern" editors and b) required too much "care & feeding" in terms of trying to maintain a stable, productive setup... so I switched initially to Atom and ProtoREPL, then to Atom and Chlorine, then to VS Code and Clover, and finally to VS Code and Calva (and Joyride and LSP/clj-kondo). VS Code is modern, well-supported, has a lot of useful extensions that I've come to rely on. Calva is an awesome Clojure integration. And Joyride means I can script VS Code with ClojureScript just like I used to script Emacs with elisp (only nicer, because it's cljs!).

seancorfield19:12:33

(17.x-19.x was mid-'80s to mid-'90s)

Nim Sadeh19:12:16

Thanks! I like the overall Emacs experience so far but it does feel like a lot of things are not working out of the box/need a lot of IDE tinkering to work. I may stick around or may switch to VSCode.

ericdallo20:12:01

so you didn't test Emacs with LSP yet @U04V70XH6 šŸ˜›

ericdallo20:12:18

I think VsCode nowadays (after clojure-lsp integration in Calva especifically) is a good "work nice out of the box", but when you need to do lots of customizations, Emacs is better IMO

Nim Sadeh20:12:26

Somehow Emacs just overwrote a file I was working on with a stack trace, so I am not too happy with it right now

seancorfield21:12:10

@UKFSJSM38 I'm curious what sort of customizations you feel can be done with Emacs but not VS Code? (i.e., am I missing something cool/useful?)

ericdallo21:12:18

ā€¢ Sometimes I feel some vscode plugins are a little bit opinated, calva for example took some time to have options to prioritize LSP features over repl ā€¢ I think vscode shortcuts sucks.. doom-emacs keybindings are so good IMO, that I hardly need to add custom keybindings ā€¢ The programatic way of configuring things via emacs like ifs makes me have more extensible configs ā€¢ I can work entirely on emacs without a mouse, I'm not sure I have that on vscode

ericdallo21:12:49

But overall, vscode is the only editor I'd recommend if there was no emacs, it's pretty close in most things

Nim Sadeh21:12:08

@UKFSJSM38 do you use shortcuts for most things or M-x

ericdallo21:12:20

95% shortcuts

seancorfield21:12:28

I can use VS Code entirely without a mouse -- but I've added a number of extra key bindings to make that possible (and I have a lot of custom REPL snippets šŸ™‚ and several Joyride scripts that I use heavily).

borkdude22:12:09

I can't even discover how that carmine/set var is created by reading the source code, is that a good thing? ;)

hiredman22:12:14

yeah, I found it by loading the code in the repl and looking at the metadata on the var which lead me to the defcommands line

borkdude22:12:33

One solution to suppress warnings about this namespace could be:

:linters {:unresolved-var {:exclude [taoensso.carmine]}}

Nim Sadeh22:12:57

Is that added to project.clj?

borkdude22:12:22

@U05D3EAA6FM No, in .clj-kondo/config.edn

šŸ‘€ 1