Skip to content

Align threading macro args with the first arg - #153

Merged
bbatsov merged 1 commit into
clojure-emacs:mainfrom
jasonjckn:fix-threading-macro-arg-indentation
Oct 29, 2026
Merged

bbatsov merged 1 commit into
clojure-emacs:mainfrom
jasonjckn:fix-threading-macro-arg-indentation

Conversation

@jasonjckn

@jasonjckn jasonjckn commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

In semantic indentation, the arguments of ->, ->>, some-> and the other threading macros are lined up with the previous argument instead of the first one. That works only when every line holds exactly one form. After a line with several forms, a trailing comment, or a comment after the first argument, every following line jumps to the right.

This PR removes the special threading-macro rule. The ordinary function-call rule already aligns each argument with the first one, which gives the same result in the cases the threading rule was written for, and the right result in the cases above. The output now matches clojure-mode and cljfmt.

Examples

Each example shows the result of indent-region with default settings and alignment turned on (clojure-ts-align-forms-automatically / clojure-align-forms-automatically). Identical outputs are grouped under one heading.

A line with several threaded forms

clojure-mode, cljfmt 0.13.1, clojure-ts-mode with this PR:

(->> app
     (http/get-router)
     (first) (last) :interceptors
     (filter :enter)
     (mapv :name))

clojure-ts-mode main:

(->> app
     (http/get-router)
     (first) (last) :interceptors
                    (filter :enter)
                    (mapv :name))

A trailing comment

clojure-mode, cljfmt 0.13.1, clojure-ts-mode with this PR:

(->> tx-data
     (group-by :e) ; group by entity
     (map summarize)
     (into []))

clojure-ts-mode main:

(->> tx-data
     (group-by :e) ; group by entity
                   (map summarize)
                   (into []))

A comment after the first argument

clojure-mode, cljfmt 0.13.1, clojure-ts-mode with this PR:

(-> config ;; from the environment
    (merge defaults)
    (validate!))

clojure-ts-mode main:

(-> config ;; from the environment
           (merge defaults)
           (validate!))

Any symbol ending in -> or ->> (here some->)

clojure-mode, cljfmt 0.13.1, clojure-ts-mode with this PR:

(some-> request
        (assoc :user user) (assoc :roles roles)
        (handler))

clojure-ts-mode main:

(some-> request
        (assoc :user user) (assoc :roles roles)
                           (handler))

Tests

This PR adds a new spec, should align threading macro args with the first arg, covering several forms on one line, a trailing comment, some->, a multi-line argument, and ->> with its first argument on the next line. It fails on main and passes with this PR.

How it was checked locally:

  • make all (Eldev: compile with warnings as errors, lint, indent check, tests) passes on Emacs 30.1 (the nix-emacs-ci build CI uses) and on 31.1.50, the closest local build to CI's snapshot.

Notes

  • The rule came from 85871fd ("Match threading alignment of cljfmt, clojure-mode"). The examples above show that removing it matches both of those better.
  • clojure-ts--threading-macro is kept, because other code still uses it.
  • Corpus check: of 73 real-world Clojure files, 4 indent differently with this PR, and every change is a threading form like the ones above.

Part of a series

This is one of 7 small, independent PRs, each fixing one problem found while making clojure-ts-mode format like clojure-mode. Each one is based on main and none depends on another. Some touch neighbouring lines in CHANGELOG.md and the indentation tests, so once one is merged the others may need a quick rebase, which we're happy to do:

  1. Align threading macro args with the first arg #153: threading macro arguments (this PR)
  2. Don't count metadata and comments as block form arguments #154: metadata/comments in :block forms
  3. Indent a form on the line after its reader prefix #155: form on the line after a reader prefix
  4. Align clojure.test/are, not the nonexistent clojure.core/are #156: clojure.test/are alignment
  5. Compile the align query from the current align form options #157: align options changed after loading
  6. Run the two metadata indentation specs #158: two specs that checked nothing (test-only)
  7. Align the whole region in clojure-ts-indent-region #159: indent-region leaving the last forms unaligned

About this PR

The code, tests and this description were generated by an AI (Claude, by Anthropic), at @jasonjckn's request. Sorry for the PR spam: the fixes are split up so that each one can be accepted or rejected on its own instead of in one big change. If AI-generated contributions are a problem for this project, please feel free to close these PRs right away.


  • The commits are consistent with our contribution guidelines.
  • You've run M-x checkdoc and fixed any warnings in the code you've written.
  • You've updated the changelog (if adding/changing user-visible functionality).
  • You've updated the readme (if adding/changing user-visible functionality).

The threading macro rule anchored each argument on its previous
sibling. That only works when every line holds exactly one form: after
a line like `(first) (last) :interceptors` or a trailing comment, the
next argument lined up with that last form or the comment instead.

The function call rule already aligns arguments with the first one, and
it gives the same result for the cases the threading rule was written
for, so the threading rule is removed. This matches cljfmt and
clojure-mode.
@bbatsov
bbatsov force-pushed the fix-threading-macro-arg-indentation branch from 8453c30 to 04336e7 Compare October 29, 2026 06:02
@bbatsov
bbatsov merged commit 2060e69 into clojure-emacs:main Oct 29, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants