emacs

Samuel Ludwig 2025-10-15T18:35:35.405039Z

Tree-sitter users, I've been experiencing some odd editing-behavior the last month or so (when I switched to using tree-sitter), which I think is a result of conflicting indentation/formatting mechanisms/configs, and I'm having trouble tracking it down. (I am using DOOM personally, but I haven't been able to prove/disprove explicit relation) My only clojure-related config is as follows:

;; CIDER Configs ;;
(setq clojure-ts-toplevel-inside-comment-form t)
(setq clojure-ts-indent-style 'fixed) ; 'tonsky style'

;; HACK: fix keybindings for new clojure tree-sitter mode (possibly no longer necessary? my localleader and other binds were disappearing without this)
(after! cider
  (set-keymap-parent clojure-ts-mode-map clojure-mode-map)
  (set-keymap-parent clojure-ts-clojurescript-mode-map clojurescript-mode-map)
  (set-keymap-parent clojure-ts-clojurec-mode-map clojurec-mode-map))
An example of the behavior I'm experiencing is below, where $ is my cursor, and I hit to begin writing a form on new line. I would expect for my cursor to be placed in line with the other elements of the list, but its instead indented an extra space:
;; INITIAL FORM
(ns my-ns
  (:require
   [clojure.string :as str]
   [malli.core :as m]$
   [malli.transform :as mt]))

;; ---

;; AFTER 
(ns my-ns
  (:require
   [clojure.string :as str]
   [malli.core :as m
    $]
   [malli.transform :as mt]))
So it seems like my editor is fighting between "semantic" indents (which would indent 2 spaces from the first element in thelist) and https://tonsky.me/blog/clojurefmt/ indents (which would indent in-line with the first element, because it isn't a symbol) (the moved square-bracket is my parinfer doing its best), but I'm not sure what other config I could add/alter to assure that my editor uses tonsky-style indents. (I've disabled electric-indent-mode to no discernible effect, and I've confirmed that clojure-ts-mode is active, and clojure-mode is not) I do see a var called lisp-body-indent which has a value of 2, but I can't tell if that's being used by any active mode or not (`lisp-mode` is not an active minor mode).

Roma 2025-10-15T19:01:30.041969Z

The only one well tested indentation style is semantic. Other styles might be broken due to switching to a modified grammar. I would suggest to report the issue on GitHub. lisp-body-indent shouldn't have any effect in clojure-ts-mode.

Roma 2025-10-15T19:05:49.835769Z

Although, I've just quickly tested your scenario and I cannot reproduce it. I noticed that in your snippet vectors in the (:require list have wrong indentation (1 space instead of 2), so when I end up with the following results:

(ns my-ns
  (:require
   [clojure.string :as str]
    [malli.core :as m]
    |
   [malli.transform :as mt]))
if the initial indentation is correct, then everything works as expected:
(ns my-ns
  (:require
    [clojure.string :as str]
    [malli.core :as m]
    |
    [malli.transform :as mt]))

Samuel Ludwig 2025-10-15T19:09:15.715169Z

For fixed (tonsky-style) indentation, the 1-space indentation is 'correct', according to the (entirety of the) rules below > • Multi-line lists that start with a symbol are always indented with two spaces, > • Other multi-line lists, vectors, maps and sets are aligned with the first element (1 or 2 spaces).

Roma 2025-10-15T19:10:22.757839Z

Maybe 🙂 But that's not how it's defined in clojure-ts-mode. Fixed style just indents everything with 2 spaces

Roma 2025-10-15T19:12:53.849639Z

mm, actually not exactly. If the first item is a symbol or a keyword, then children are indented with 2 spaces

Roma 2025-10-15T19:13:20.334409Z

(defvar clojure-ts--fixed-indent-rules
  ;; This is in contrast to semantic
  ;; fixed-indent-rules come from 
  `((clojure
     ((parent-is "source") parent-bol 0)
     ;; ((query "(list_lit . [(sym_lit) (kwd_lit)] _* @node)") parent 2)
     ;; Using the above `query' rule here doesn't always work because sometimes `node' is nil.
     ;; `query' requires `node' to be matched.
     ;; We really only care about the parent node being a function-call like list.
     ;; with it's first named child being a symbol
     ((lambda (node parent _)
        (and (clojure-ts--list-node-p parent)
             ;; Should we also check for keyword first child, as in (:k map) calls?
             (let ((first-child (treesit-node-child parent 0 t)))
               (or (clojure-ts--symbol-node-p first-child)
                   (clojure-ts--keyword-node-p first-child)))))
      parent 2)
     ((parent-is "vec_lit") parent 1)
     ((parent-is "map_lit") parent 1)
     ((parent-is "list_lit") parent 1)
     ((parent-is "set_lit") parent 2))))

Samuel Ludwig 2025-10-15T19:13:59.746399Z

ok good i thought my dementia had progressed further than i originally thought

😅 1
Roma 2025-10-15T19:14:45.452549Z

it can be easily fixed if this is wrong

Roma 2025-10-15T19:16:09.656399Z

I don't see any explanation regarding keywords in the git history

Roma 2025-10-15T19:16:26.570639Z

so maybe it was just a wrong assumption

Roma 2025-10-15T19:25:56.966739Z

I guess if the first element is a keyword it is also can be considered as a function call

Samuel Ludwig 2025-10-15T19:28:30.028949Z

Ah, yea I think, according to the rules-as-written, it shouldn't be indented for keyword-lead-lists, but I guess it would only come up for stuff like :require forms, and "`(:k map)`" calls as mentioned in the comment. I apologize though, as I may have then picked a bad example to illustrate my experiences, as my behavior is not limited to this name-space-indentation-fight (I was just hoping it was the same root cause). Another example, indicating some possible conflict between indentation/alignment systems: $ is once again my cursor

;; INITIAL FORM

(defn kill-file [path]
  (io/delete-file (io/file path))$)
When I hit enter (to add some other form below), this is what my emacs deems to be a suitable update/placement (all added whitespace appears to be real, and is not merely a display issue)
;; AFTER ``

(defn kill-file [path]
      (io/delete-file (io/file path))
$     )
And when I type (, to write the new form, it auto-indents reasonably for that form, but its no longer aligned with the one above
;; AFTER `(`

(defn kill-file [path]
      (io/delete-file (io/file path))
  ($))

Roma 2025-10-15T19:30:42.067499Z

Is it also happening with fixed style?

Samuel Ludwig 2025-10-15T19:30:51.413549Z

indeed

Roma 2025-10-15T19:31:02.416069Z

I cannot reproduce it

Roma 2025-10-15T19:31:25.906839Z

probably some other package causes it

Samuel Ludwig 2025-10-15T19:32:09.351279Z

mm, I do suspect I have some config hidden somewhere, I've been searching variables to track it down but nothing particularly suspicious has come up

Roma 2025-10-15T19:32:27.548039Z

To track it down, you can try to start with emacs -q and just enable clojure-ts-mode without any other packages

Roma 2025-10-15T19:35:26.775319Z

Roma 2025-10-15T19:35:59.093919Z

You can evaluate the following in the *scratch* buffer:

(require 'package)
(package-initialize)

(require 'clojure-ts-mode)
(setopt clojure-ts-indent-style 'fixed)

Roma 2025-10-15T19:36:19.833419Z

and then open any .clj file and try to reproduce your problems

Roma 2025-10-15T19:37:00.363519Z

you can also try enabling your extra packages one by one

Samuel Ludwig 2025-10-15T19:44:06.581549Z

ah this might be an artifact of using straight.el for managing my packages perhaps, as I get a No such file or directory, clojure-ts-mode error, i will need to... experiment. I will at least file an issue regarding the keyword-lead-list indentation (where the final verdict can be decided on wrt if its desired or not)

Roma 2025-10-15T19:45:15.099939Z

Sounds good. I can't help with straight.el unfortunately. If you know where the clojure-ts-mode.el is located, you can just add this directory to the load-path as I have done on the screenshot.

Samuel Ludwig 2025-10-15T19:54:44.133679Z

(got it working, turning things off and on again, much appreciate the guidance @rrudakov)

Roma 2025-10-15T19:57:43.568979Z

Happy to help. If you find any bugs in clojure-ts-mode, please report it on GH, so they won't get lost.

Samuel Ludwig 2025-10-16T14:06:21.186919Z

(I've been DMing mr tonsky himself to confirm, before I make an uneducated PR) I think I've pinned down the cause to something inside the lispy-mode package, which unfortunately seems to bundle quite a bit of functionality/other minor modes, but making headway thanks to you

👍 1