Fork me on GitHub
#lsp
<
2022-02-15
>
jacob.maine01:02:52

A question for Emacs users... When you connect to CIDER it puts itself at the front of completion-at-point-functions. If CIDER returns any completions, then LSP will never be asked for completions. This gives inconsistent completion behavior based on whether the REPL is running. I don’t see any tools in either CIDER or LSP that would let me configure the completion-at-point priority. I prefer the clojure-lsp completions, so to work around it, I disable CIDER completions like so:

(defun disable-cider-completion ()
  (remove-hook 'completion-at-point-functions #'cider-complete-at-point))
(add-hook 'cider-mode-hook 'disable-cider-completion)
Are there any other approaches? Is it documented anywhere?

jacob.maine01:02:07

It makes it particularly hard to hack on the completion code, because when you jack-in to the LSP nREPL, the completions mostly stop being invoked. That one took awhile to figure out! I was thinking about adding this tip to development.md , but it might be too hidden there.

ericdallo01:02:05

Yeah, this is a common question and IMO we should add a simple way to configure that either on lsp-mode or cider... Meanwhile the recommend way is to do exactly what you are doing. I have the same config here: https://github.com/ericdallo/dotfiles/blob/master/.doom.d/config.el#L57

ericdallo01:02:01

Actually I need to update this guide to match that as well: https://emacs-lsp.github.io/lsp-mode/tutorials/clojure-guide/

anonimitoraf09:02:43

Do your LSP completions work fine even with large-ish projects? (> 10k LOC)? It feels so laggy and intermittently unreliable for me

anonimitoraf09:02:05

Btw, I've noticed the same thing with Typescript LSP. I wonder if it's my PC/OS/etc

ericdallo11:02:11

We merged a PR from @U07M2C8TT which improved performance a lot on completion @UR37CBF8D, maybe you can give it a try, check #clojure-lsp-builds

jacob.maine17:02:35

@ericdallo thanks, that’s good to know you’re doing the same thing

jacob.maine17:02:05

@UR37CBF8D I use clojure-lsp completion when working on clojure-lsp itself, which has almost 20K LOC. It’s fast enough for me. A lot can depend on how aggressive your completion settings are. If you have it set to try completion with only 1 character it may get laggy, although the recent changes Eric mentioned may improve that.

anonimitoraf23:02:04

Oh right, cool. @ericdallo mind linking the PR from @U07M2C8TT?

borkdude10:02:05

@ericdallo it seems the :copy-kondo-configs? false option isn't documented, perhaps that can be added?

ericdallo11:02:01

I'll add it

gratitude 1
borkdude12:02:42

thanks!

👍 1
jacob.maine17:02:35

When I run make lint-clean locally in clojure-lsp it reports several namespaces that need to be cleaned. But on CI, that lint test hasn’t been failing. Am I missing a config that would make the behavior match?

ericdallo17:02:48

not really :thinking_face: lint-clean just uses clojure-lsp itself calling clean-ns

ericdallo17:02:08

@U07M2C8TT try rm .lsp/.cache

jacob.maine17:02:50

No change. It feels like the problem is on CI, not on my machine. The require blocks in those namespaces all include an unused alias to [taoensso.timbre :as log]

ericdallo17:02:28

we have a custom config to ignore that log

jacob.maine17:02:07

Ahhh! OK, where can I find that config?

ericdallo17:02:12

check .clj-kondo/config.edn

ericdallo17:02:57

since log is a ns we use all the time, clojure-lsp/kondo doesn't complain about it with that config

jacob.maine17:02:13

In that case, I’m confused — why doesn’t my make lint-clean use that config? FWIW, Emacs also reports those extra aliases as errors.

ericdallo17:02:28

that's odd, that config is on project root config, clj-kondo should always bring it

ericdallo17:02:51

does that happens on master?

jacob.maine17:02:32

Yes. Could I have a global config file that’s overriding the local one?

ericdallo17:02:42

check ~/.lsp/config.edn (deprecated) and ~/.config/clojure-lsp/config.edn

jacob.maine17:02:47

I have a ~/.lsp/config.edn, but if I rename it, I still get the lint errors

ericdallo17:02:17

yeah, maybe it's not related indeed

ericdallo17:02:42

try rm -rf .lsp/.cache && rm -rf .clj-kondo/.cache

jacob.maine17:02:26

Same problem. I’ll try a clean checkout of clojure-lsp

👍 1
ericdallo17:02:03

also, you are seeing that on latest master right?

jacob.maine17:02:44

Ah, that got rid of the errors. So it must be something cached locally

thinking-face 1
jacob.maine18:02:58

Figured it out. rm -rf lib/.clj-kondo. I’m not sure what I had in there, but it must have been causing problems.

jacob.maine18:02:26

diff -qr bad-dir good-dir FTW

jacob.maine18:02:29

Thanks for your help

ericdallo18:02:28

hum, interesting, since the project-root is not lib, not sure why that config was being considered

jacob.maine18:02:23

Kinda weird, right? Here’s a minimal reproduction:

❯ mkdir lib/.clj-kondo
❯ make lint-clean

ericdallo18:02:48

I think this could explain some bugs some users complain from time to time

ericdallo18:02:04

@U04V15CAJ maybe you can help here, we have this arch:

clojure-lsp (project-root)
- .clj-kondo/config.edn
- lib 
    src
    test
    ...
- cli
    src
    test
    ...
if we create a lib/.clj-kondo folder it mess up the kondo config from .clj-kondo/config.edn , any clues?

borkdude18:02:13

define "mess up"

borkdude18:02:00

I'm afk for a few hours

borkdude18:02:42

it depends in which directory you lint.

borkdude18:02:51

and also what clojure-lsp itself does.

borkdude18:02:08

afk now

👍 1
ericdallo18:02:52

@U07M2C8TT we need to debug the config clojure-lsp is passing to kondo, probably something https://github.com/clojure-lsp/clojure-lsp/blob/master/lib/src/clojure_lsp/kondo.clj#L164

jacob.maine18:02:29

@ericdallo sounds good. I’ll look at that

👍 1
jacob.maine19:02:56

Here’s the config that’s passed to clj-kondo.core/run! . It’s generated by https://github.com/clojure-lsp/clojure-lsp/blob/ca1621ba7f8475095f2bf74d895411372debf4f4/lib/src/clojure_lsp/kondo.clj#L146 . I’ll see what I can learn about these settings and do some experimenting.

{:cache true
   :parallel true
   :copy-configs true
   :lint ["/Users/jmaine/workspace/opensource/clojure-lsp/cli/lib/src:/Users/jmaine/workspace/opensource/clojure-lsp/cli/cli/src:/Users/jmaine/workspace/opensource/clojure-lsp/cli/common-test/src:/Users/jmaine/workspace/opensource/clojure-lsp/cli/lib/test:/Users/jmaine/workspace/opensource/clojure-lsp/cli/cli/test:/Users/jmaine/workspace/opensource/clojure-lsp/cli/src:/Users/jmaine/workspace/opensource/clojure-lsp/cli/resources:/Users/jmaine/workspace/opensource/clojure-lsp/cli/target/lsp-classes:/Users/jmaine/workspace/opensource/clojure-lsp/lib/src:/Users/jmaine/workspace/opensource/clojure-lsp/lib/resources:/Users/jmaine/workspace/opensource/clojure-lsp/cli/scripts"]
   :config {:output {:analysis {:arglists true
                                :locals false
                                :keywords true
                                :protocol-impls true}
                     :canonical-paths true}
            :linters {:unresolved-symbol {:report-duplicates true}
                      :unresolved-namespace {:report-duplicates true}
                      :unresolved-var {:report-duplicates true}}}
   :custom-lint-fn #object[clojure.core$partial$fn__5859 0xabd801f "clojure.core$partial$fn__5859@abd801f"]}

ericdallo19:02:21

yes, looks correct to me, @U07M2C8TT maybe try to repro with clj-kondo CLI, it's easier for @U04V15CAJ debug later

ericdallo19:02:31

something like this, example:

clj-kondo --config '{:output {:format :json :analysis {:arglists true :locals false :keywords true}}}' --cache --copy-configs --parallel --lint src test

👍 1
borkdude21:02:01

Yes, please provide a clj-kondo only repro and try to prove that clj-kondo is doing something incorrectly, then I will look into it.

jacob.maine23:02:02

Wow... I spent a long time down the wrong path, but I finally understand. When clojure-lsp runs clean-ns from the command line, it first analyzes the full project, using something like this:

(kondo/run! {:lint [project-classpath]})
This part works as expected... there are no :findings of interest, because several linters have been turned off in .clj-kondo/config.edn. This is where I got stuck. I couldn’t figure out why there weren’t any :findings here, but the CLI suggested several namespaces to clean. What I didn’t realize was that after analyzing the full project, clojure-lsp loops through each file individually, analyzing each one more like this:
(with-in-str file-text
  (kondo/run! {:lint ["-"]
               :filename "lib/some/filename.clj"}))
When invoked this way, clj-kondo will pick lib/.clj-kondo as its config directory, because of https://github.com/clj-kondo/clj-kondo/blob/919478cdfc58b47dd48a7383c9b3a6de2b507b1f/src/clj_kondo/core.clj#L107. And since that config directory is empty, all the linters are on by default, and so we get :findings. @ericdallo, this isn’t just a cli problem. Both did-open and did-change follow the same path, linting via stdin with an explicit :filename. That means that users within an editor will also see unexpected lint findings if they have an extra .clj-kondo directory. The only fix I’ve thought of is to force kondo to use the project root config dir:
(with-in-str file-text
  (kondo/run! {:lint ["-"]
               :filename "lib/some/filename.clj"
               :config-dir (str
                            (io/file (shared/uri->filename (:project-root-uri @db/db))
                                     ".clj-kondo"))}))
That wouldn’t work for users who store their kondo config somewhere non-standard. Is that a problem?

ericdallo23:02:49

Amazing finding! Yeah, that is what I meant with users that already complained strange linting on editors, that explains everything now. > That wouldn’t work for users who store their kondo config somewhere non-standard. Is that a problem? Good question, actually until now, I thought that the lint only worked if config was on root, that's why we were always recommending having kondo config on project root when using LSP. It's good to know it works with nested kondo configs, so I see 2 options: • Merge the configs from root until file/folder being linted, not sure if there is a easy way to get that from kondo or we should that manually. • Just ignore nested configs and use root config as we were recommending

jacob.maine00:02:41

Looking at it more, I think #2 is better. Kondo itself doesn’t merge configs. Instead, it picks them according to this priority: 1. If you provide a :config-dir, use it. 2. If you provide a :filename, walk up the directory tree from the file, looking for a .clj-kondo directory. (The name of that directory is not configurable.) 3. Otherwise, start at the directory where the script was invoked (System/getProperty "user.dir"), and follow the same algorithm, walking up looking for .clj-kondo. In all three cases, it uses the first directory it finds. Most of the time the clj-kondo command line will ignore nested .clj-kondo directories, because it takes a lot of extra work to end up in the 2nd case. So, I think that nested .clj-kondo directories are usually a mistake on the user’s part, and they should be advised to move all their config to one root config dir.

ericdallo00:02:17

makes sense to me

ericdallo00:02:35

I'm ok with follwoing on ignoring nested and considering only the project root config

ericdallo00:02:49

BTW we have lsp-clojure-server-info which helps debug what config was chosen

jacob.maine00:02:51

So the correct kondo config dir is stored somewhere in the app db already?

ericdallo00:02:59

it's the same as project-root, we have a function which brings that on kondo.clj or config.clj I think

jacob.maine00:02:32

Those look pretty good, but they don’t do the “walk up looking for .clj-kondo” algorithm, https://github.com/clj-kondo/clj-kondo/blob/44fa20c186fa3f038b8777a8c2456678d08d25f9/src/clj_kondo/impl/core.clj#L179-L198 by clj-kondo.impl.core/config-dir. That might help users who save their kondo config in a parent directory but have their clojure-lsp project root as a subdirectory. Is that a common thing? (I think that kondo handles home/xdg config separately so I’m not as worried about that.) @U04V15CAJ perhaps clj-kondo.impl.core/config-dir could be added to the public API?

ericdallo01:02:05

Not a common thing @U07M2C8TT, IMO we should get the config from root, if not found we use no config, we can't infer user configured a wrong project root and try to get a correct config, there are multiple cases

jacob.maine01:02:55

OK, that makes sense. I’ll work on a PR. My first attempt, which worked great for my problem, breaks almost all of the tests. 😅

jacob.maine01:02:35

I bet they don’t all set a project root

ericdallo02:02:28

Yes, not all