Hi I am not sure if I am just doing something wrong, but I can't get the output of clojure-lsp format to match a format lsp action from within my editor.
I have code which uses :style/indent metadata to inform formatting, and usages of this are formatted correctly when I run format from within my editor (so via a clojure-lsp action) but when I run clojure-lsp format it ignores the :style/indent metadata and indents it using default settings. I am using the same version of clojure-lsp (the latest release).
Trying to setup format lint rules in CI for a large project, and this makes it impossible. I can't find any known issues about it, am I doing something wrong or is this a bug? If it's a bug I am surprised I am the first to mention this - doesn't seem like an edge-case usage.
Example in thread ⬇️
Very easy to reproduce:
(ns io.julienvincent.definition
(:refer-clojure :exclude [reify]))
(defn do-thing
{:style/indent :defn}
[_varname _varbody])
(ns io.julienvincent.usages
(:require [io.julienvincent.definition :as d]))
(d/do-thing 1
2)
The above, formatted using my lsp format action.
Running clojure-lsp format in this project root:
❯ clojure-lsp format --dry
[ 99%] Project analyzed Formatting namespaces...
--- a/src/io/julienvincent/usages.clj
+++ b/src/io/julienvincent/usages.clj
@@ -2,4 +2,4 @@
(:require [io.julienvincent.definition :as d]))
(d/do-thing 1
- 2)
+ 2)❯ clojure-lsp --version
clojure-lsp 2025.11.28-12.47.43
clj-kondo 2025.10.24-SNAPSHOTlet me test it
I can repro, but I saw that in the past and I believe there is some trick/reason
both use same piece of code, but the problem seems that in https://github.com/clojure-lsp/clojure-lsp/blob/c2126582f633d78b9fa751028a21e359b6527ce6/lib/src/clojure_lsp/feature/format.clj#L83-L96 when we extract the style/indent it's comming empty for CLI
Good news, I found it https://github.com/clojure-lsp/clojure-lsp/blob/c2126582f633d78b9fa751028a21e359b6527ce6/lib/src/clojure_lsp/internal_api.clj#L375-L377
Hahaha
😅
Well, shit. I guess this could be put behind a flag or something
it took almost 2 years to someone complain :p
I guess
In the meantime I started mapping out all our functions which have this metadata to explicit cljfmt :extra-indent config in the project root. It's pretty sad having to do this, but it's a workable solution for me
yeah that would work
more context about the change https://github.com/clojure-lsp/clojure-lsp/issues/1723
but a flag should be possible, will take a look
the good thing is that I'm going do a change that would make possible use a existing flag that already works for all CLI commands, so would be:
clojure-lsp format --dry --analysis '{:type :project-only}'
the default is project-namespaces-only which doesn't work with style/indentjust pushed @m401, would be nice if you could test as well
Oh cool that's a nice solution. Just out for lunch, will test when I'm back!
sure, fixed your other style/indent issue as well
Can confirm, both issues fixed! Thanks :)
cool thank you!
Ok I did find an issue with the latest fixes. It now looks like I cannot define my own style/indent config for my own custom macros if those macros share names with clojure.core.
For example:
(ns io.julienvincent.definition
(:refer-clojure :exclude [reify]))
(defmacro reify
{:style/indent :defn}
[_varname])
(defmacro reify2
{:style/indent :defn}
[_varname])
(defmacro reify3
{:style/indent [1 [1]]}
[_varname])
(defmacro reify4
{:style/indent [1 [:defn]]}
[_varname])
(comment
(reify 1
(foo [x]
1))
(reify2 1
(foo [x]
1))
(reify3 1
(foo [x]
1))
(reify4 1
(foo [x]
1))
nil)
Notice how reify doesn't format like reify2 but it shouldAlso, side note, I had no idea I could do things like {:style/indent [1 [1]]}. Is the spec defined somewhere? I couldn't find it
not sure about the spec, but it comes from cljfmt logic
Well, no I don't think it's the same syntax as cljfmt. It is mapped to cljfmt indent syntax by clojure-lsp somehow
ah yes, it's done https://github.com/clojure-lsp/clojure-lsp/blob/70daed87e9858b13e3d878df183b16fda808d735/lib/src/clojure_lsp/feature/format.clj#L46-L81
sorry, I meant cider, not cljfmt
just tested your repro, but it's weird because we are mapping correctly to cljfmt indents:
{:indents {clojure-sample.foo/reify [[:inner 0]], clojure-sample.foo/reify2 [[:inner 0]], clojure-sample.foo/reify3 [[:block 1] [:inner 1]], clojure-sample.foo/reify4 [[:block 1] [:inner 1]], nrepl.misc/returning [[:block 1]]}}right?
That looks correct to me, yea
maybe :indents doesn't override
hum, maybe a cljfmt bug
yeah
I wonder if it should be extra-indents
I can play with it in a bit - just going into a meeting now
Ok, can confirm I think this is a bug in cljfmt. If I use just cljfmt with some indents config it completely ignores reify.
{:extra-indents {io.julienvincent.definition/reify [[:inner 1]]
io.julienvincent.definition/reify2 [[:inner 1]]}}
The above, reify is ignored.
{:extra-indents {reify [[:inner 1]]
io.julienvincent.definition/reify2 [[:inner 1]]}}
however overriding the definition for un-namespaced reify does apply (to everything)yeah, maybe @weavejester can help here
The more specific namespaced reify probably should override the unnamespaced one. Feel free to open an issue.
cljfmt also doesn't currently support looking for metadata, but it is functionality that's planned.
Surprisingly, this issue seems only to happen with reify (well, maybe others too?). I was playing with defrecord and it doesn't get overwritten - so I can attach definition specific indents - just not to reify. Weird!
I'll open an issue in a bit