lsp 2026-01-06

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-SNAPSHOT

let 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

Hahaha

Well, shit. I guess this could be put behind a flag or something

it took almost 2 years to someone complain :p

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

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/indent

just 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 should

Also, 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

sorry, I meant cider, not cljfmt

👍 1

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]]}}

That looks correct to me, yea

maybe :indents doesn't override

hum, maybe a cljfmt bug

I wonder if it should be extra-indents

I can play with it in a bit - just going into a meeting now

👍 1

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.

2

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