clj-kondo 2024-10-15

Hi, wondering a kind of annoying issue regarding linting in VS Code / Calva. I noticed that my Problems -tab shows close to 200 warnings and they all stem from Clojure source code copied to the projects .clj-kondo -directory apparently because a certain dependency is found from my ~/.m2 directory (specifically cnuernber/dtype-next) which is not a dependency of this project. Checking my projects classpath clojure -A:test:dev -Spath shows that it is not a dependency. I assume that clj-kondo copies the dtype-next config and certain sources because it sees the library for some reason (maybe due my kondo/lsp configs šŸ¤·šŸ» )? Any pointers how I cold get rid of those linting warnings? .lsp/config.edn

{:paths-ignore-regex ["tmp.*" "\.clj-kondo.*" "target.*"]
 :source-paths-ignore-regex ["tmp.*" ".clj-kondo.*" "target.*"]
 :clean {:automatically-after-ns-refactor false}}
.clj-kondo/config.edn
{:linters {:unsorted-required-namespaces {:level :warning}
           :not-empty? {:level :off}}
 :output {:exclude-files ["^.clj-kondo"]}}

So, one must reroute this once more šŸ˜…

This is probably more a Calva or clojure-lsp problem than a clj-kondo problem. clj-kondo never automatically lints something you don't tell it to

Thank you, will reroute this to a more correct channel then. šŸ™

It’s not Calva creating those files. I also thought it was clj-kondo, but then I think it must be clojure-lsp.

clj-kondo does create those files, but the way they are integrated into your project is done by clojure-lsp

@borkdude is running macros like suggested in https://hey.hagelb.org/@technomancy/statuses/01JA8EY2EXVGMMKYHJYC7CVD5P something you ever considered for clj-kondo?

I think static analysis adds a lot on top of the repl.

There's a lot of linting that's about the code itself, and not the runtime. And for completion, it's nice to always be in-sync with the code, even if you forgot to re-eval. The REPL's primary job is evaluation, debugging and inspection. And we get all that as well. I'd be curious what Plexus think we lose, but I haven't seen anything lost. I've only seen tooling for both static and REPL get better over time. Now we have Portal, Reveal, Flow Storm, we have REPL debugging in Emacs and VSCode. Cursive recently added inline eval. And we have great static analysis, completion, linting, etc.

In my opinion, the only thing hurting the REPL is Java itself, but that's a trade off that has so many upsides, I can't imagine abandoning it. Plus the dynamism Java does support also happens to bring with it some of the best in class performance.

About macroexpanding though... Why not let everything load and fully macroexpand? I don't the think sandboxing matters. For example compile in Clojure can send the missiles as well. Starting the REPL can send the missiles as well. I feel just don't pull down a project you don't trust on your computer. I believe the challenge is the slow startup time of Clojure. Using sci means you can expand the macro super fast. But sci doesn't have the full context, so it'll fail to expand some macros. And I wrong @borkdude?

šŸ‘ 1

I do worry that the editor talking to the live runtime is pushed more and more to the edges. I find it worrying that e.g. Cursive is relying purely on static analysis to get completions. Not sure if the same is true for Calva but it seems to be a trend for more modern editors to integrate LSP and be done.

the R community knows how useful completions driven by the runtime can be. They’ve recently https://github.com/posit-dev/positron because it couldn’t give them what they needed otherwise.

I think the completion (and everything) works much better with LSP (using clj-kondo cache). Some part is probably just that at least for Vim the completion lib integration with LSP is probably much better than the integration with REPL libs.

this depends on what you want to complete. There’s stuff that just won’t work with static analysis. When analysing a new dataset, context specific completions can be very valuable and not everything exists in code. Keywords that just exist at runtime but not in the code being one example.

so we are painting ourselves in the corner and will get stuck in a local maxima if we move away from completions being able to talk to the runtime.

I do agree that the REPL is great and should be used primarily, but people often paint a picture where static analysis threatens the REPL which isn't based on any evidence imo. I see static analysis as just another way to get leverage from code as data in addition to the REPL. In my emacs I've set up completions to fall back on CIDER if lsp can't find anything. Plexus is known to rant every so often about linters (and other stuff) but I don't find such a rant very constructive.

Rich Hickey has said something about Cursive in his A History of Clojure talk, that even though Clojure is very dynamic, it can still be used for static analysis. He didn't say that was a terrible thing to do

I don't think the LSP protocol necessitates static analysis only btw. There's no reason why you couldn't peek into the runtime to get information. I've done this myself in an LSP implementation once (not for Clojure but a custom language).

Emacs isn't limited to the LSP protocol, but if your editor only supports LSP and no REPL, that would certainly be very bad.

@borkdude you’ve built such a thing already?

LSP is just a protocol. You can get completions from wherever you want, it doesn’t dictate anything about the how

I've built this thing a while ago for a custom language. It's a configuration language but uses the exact same code as when you would normally work with that library: https://github.com/zen-lang/zen-lsp/blob/main/server/src/zen_lang/lsp_server/impl/autocomplete.clj About the lifecycle comment on Mastodon: you can totally fake this. If there's an already running nREPL server, you could just say: ok, connect to this one, this is where I'm getting info from.

šŸ™ 1

But the question is: what does this buy you, if you already have CIDER

You can just run both things side by side

> Could be a graal binary using sci I don't know what you're thinking of here, but an LSP process doesn't have to be a binary. I'm running clojure-lsp (with clj-kondo) from source using clojure

it even spins up an nREPL so I can develop clj-kondo and immediately see changes

but the process has to be launched by the editor?

sure but you can do whatever you want in that process

could just be a thin proxy to nREPL

The macroexpand hook is already somewhat similar to "just sandbox the macros": https://github.com/clj-kondo/clj-kondo/blob/master/doc/hooks.md#macroexpand

You still need to enable it per macro and you usually (maybe?) need to write a simplified version which works on SCI (I guess in some cases you could use the original macro)

I see, so this feature already exists, cool. Wondering if it could also be applied automatically if the macro can be run in sci and is considered safe (whitelist of vars used?)

I guess (so I don't really know) that using the original macro could be problematic often, not because of the macro code itself, but if the ns where macro is originally defined requires some Java or Clojure namespaces that aren't available in the SCI env

but maybe if you read the clj file with analyzer and then just picked the defmacro form...

for the whole namespace, yes. But I suspect there’s a lot of macros out there that sci could run.

āž• 1

> is running macros like suggested in https://hey.hagelb.org/@technomancy/statuses/01JA8EY2EXVGMMKYHJYC7CVD5P something you ever considered for clj-kondo? yes, this is called the :macroexpand hook which has been available for a few years now

technomancy says: > basically, all compile-time code is run in a safe sandbox since the point of macros is to return data structures, not to perform arbitrary side-effects this is basically what clj-kondo also does, macros run in SCI, sandboxed

> Wondering if it could also be applied automatically Not currently, you'll have to copy paste your macro for now to an exported configuration

Too many issues, like @juhoteperi describes, like dependencies on namespace aliases, other functions that run inside the macro, etc. Better to vet the macro

I bet it’s hard to implement, not sure it’s better for the users.

yes, it would be awesome but if something doesn't work reliably it becomes a liability. I've been persuaded to add awesome stuff before which I then later regretted, like the inline config stuff

I don't agree with what plexus says: that static analysis tools are dumbing down clojure