Skip to content

Indent a form on the line after its reader prefix - #155

Merged
bbatsov merged 1 commit into
clojure-emacs:mainfrom
jasonjckn:fix-indent-after-reader-prefix
Oct 29, 2026
Merged

bbatsov merged 1 commit into
clojure-emacs:mainfrom
jasonjckn:fix-indent-after-reader-prefix

Conversation

@jasonjckn

@jasonjckn jasonjckn commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

When a reader prefix (@, ', `, ~, ~@, #', #=) is at the end of a line and the form it applies to starts on the next line, no indentation rule matches that line. indent-region then leaves the line exactly where it was typed. The main outputs below are just the input, untouched.

This PR adds a rule for that case, in both the semantic and the fixed style. The line is indented as if the prefixed form started there, which is what clojure-mode does.

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.

Deref of a form on the next line

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

(swap! state assoc :n @
       (:counter state))

clojure-ts-mode main:

(swap! state assoc :n @
    (:counter state))

A quoted vector on the next line

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

(def table
  ['
   [identity int? pos-int?]
   [0 true false]])

clojure-ts-mode main:

(def table
  ['
           [identity int? pos-int?]
   [0 true false]])

Unquote inside syntax-quote

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

`(let [y# ~
       x]
   y#)

clojure-ts-mode main:

`(let [y# ~
x]
   y#)

Var quote as a map value

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

(def handlers {:get #'
               handle-get})

clojure-ts-mode main:

(def handlers {:get #'
                         handle-get})

Tests

This PR adds two new specs, should indent a form on the line after its reader prefix (semantic) and ... in fixed style. They start from unindented text, because when-indenting-it starts from correctly indented text and so can't catch a line that is left alone. Both fail on main and pass 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 calls treesit-simple-indent on the prefix node to find the anchor and offset, so it gives the same result as any other rule would for that node. A function offset like this works in Emacs 30.1 (checked in its treesit.el).
  • #_ is left out on purpose: clojure-ts-mode already treats it the way cljfmt does.
  • cljfmt joins the two lines instead of indenting them, so it isn't shown here.
  • Corpus check: 1 of 146 inputs changes (73 files as-is plus the same files with indentation stripped), the quoted-vector case 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
  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 (this PR)
  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).

No indentation rule matched a form that starts on the line after its
reader prefix, as in

    (swap! state assoc :n @
           (:counter state))

so `indent-region' left such lines wherever they were.  Indent the
form the way the prefixed form would be indented if it started the
line, in both the semantic and the fixed style.  This is what
clojure-mode does.
@bbatsov
bbatsov force-pushed the fix-indent-after-reader-prefix branch from 0cf4eae to 4c32370 Compare October 29, 2026 06:09
@bbatsov
bbatsov merged commit 8011de4 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