Skip to content

Docstring indentation, option A (pick one of #167/#168): leave docstring text alone, like cljfmt - #167

Closed
jasonjckn wants to merge 1 commit into
clojure-emacs:mainfrom
jasonjckn:docstring-indent-leave-alone
Closed

jasonjckn wants to merge 1 commit into
clojure-emacs:mainfrom
jasonjckn:docstring-indent-leave-alone

Conversation

@jasonjckn

@jasonjckn jasonjckn commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

This is one of two alternative PRs for the same problem: #167 leaves docstring text alone (like cljfmt), #168 indents docstrings like clojure-mode. Please merge at most one; we'll close the other.

indent-region changes the text of docstrings, and how it changes them depends on clojure-ts-use-markdown-inline and on whether the markdown-inline grammar is installed. With Markdown on, only the closing " moves. With Markdown off, every line moves to the opening quote's column + 1, which flattens indented code examples and undoes what M-q just did.

This PR removes the docstring indentation rule, so indent-region leaves every line inside a docstring as it is, in both settings. This is what cljfmt does.

Background

We found this by comparing clojure-mode's and clojure-ts-mode's indent-region over 73 real-world files (as-is, and with indentation stripped), using a formatter that runs indent-region in batch Emacs.

What each tool does to a line inside a top-level docstring:

Line cljfmt 0.16.6 clojure-mode 5.19, fontified buffer clojure-ts-mode main, markdown-inline on (default) clojure-ts-mode main, markdown-inline off
content at col 0 unchanged → col 2 unchanged → col 3
content at col 4 (code example) unchanged unchanged unchanged → col 3
closing " at col 0 unchanged → col 2 → col 2 (quote column) → col 2
line M-q just filled (col 2) unchanged unchanged unchanged → col 3
protocol-method docstring unchanged unchanged closing " → quote col content → quote col + 1, closing " → quote col
ordinary (non-doc) string unchanged unchanged unchanged unchanged
  • clojure-mode only indents docstring lines when clojure-in-docstring-p is true, and that checks for font-lock-doc-face. So in an unfontified (batch) buffer clojure-mode never touches docstrings and looks like cljfmt; in a normal fontified buffer it moves lines indented less than clojure-docstring-fill-prefix-width to that column and keeps deeper lines.
  • History: docstring indentation was added on purpose in 177ac05 ("Indent within docstrings - not working 100%"). The Markdown injection in Jank Support #23 (a16c6b4) moved docstring content into the markdown-inline parser, and the rule's comment now says it "only matches … when Markdown grammar is disabled".
  • Mechanism: with Markdown on, treesit-language-at a content line is markdown-inline, and treesit-simple-indent-rules has only a clojure entry, so those lines are left alone. The closing " belongs to the Clojure parser (parent str_lit), so clojure-ts--match-docstring fires and anchors it at the opening quote.
  • M-q: clojure-ts--fill-paragraph uses clojure-ts-docstring-fill-prefix-width (2) spaces from column 0, like clojure-mode. With Markdown off, indent-region then moves those lines to column 3.

This PR matches cljfmt, and clojure-mode in unfontified/batch use. #168 matches clojure-mode in normal fontified buffers instead.

Examples

Input:

(defn example
  "Summary.
content
    (code example)

"
  []
  :ok)

clojure-ts-mode main, markdown-inline on:

(defn example
  "Summary.
content
    (code example)

  "
  []
  :ok)

clojure-ts-mode main, markdown-inline off:

(defn example
  "Summary.
   content
   (code example)

  "
  []
  :ok)

With this PR (either setting), and cljfmt (same as the input):

(defn example
  "Summary.
content
    (code example)

"
  []
  :ok)

clojure-mode 5.19, fontified buffer:

(defn example
  "Summary.
  content
    (code example)

  "
  []
  :ok)

Tests

This PR adds a Docstring indentation group, run once with clojure-ts-use-markdown-inline nil and once with t (the t case is skipped with assume when the markdown-inline grammar isn't installed):

  • should preserve every docstring line: fails on main in both settings, passes with this PR.
  • should preserve protocol-method docstrings: fails on main in both settings, passes with this PR.
  • should preserve ordinary strings: a control; passes on main and with this PR.

How it was checked locally (Eldev isn't installed here, so these are the same steps run directly):

  • The full buttercup suite passes (0 failed) on Emacs 32.0.50 and 31.1.50. No Emacs 30.x was available locally, so it hasn't been run on CI's 30.1.
  • Byte-compiling with byte-compile-error-on-warn gives no warnings; checkdoc is clean; the changed .el files are indented as emacs-lisp-mode indents them.

Notes

  • This drops the feature added in 177ac05: docstrings are no longer indented at all. M-q still fills docstrings with clojure-ts-docstring-fill-prefix-width.
  • clojure-ts--match-docstring stays, since clojure-ts--fill-paragraph uses it. No other indent rule matches a line inside a docstring.
  • The removed rule was the one the code called the slowest.

About this PR

The code, tests and this description were generated by an AI (Claude, by Anthropic), at @jasonjckn's request. If AI-generated contributions are a problem for this project, please feel free to close this PR and #168 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).

@jasonjckn jasonjckn changed the title Docstring indentation, option A (pick one of #A/#B): leave docstring text alone, like cljfmt Docstring indentation, option A (pick one of #167/#168): leave docstring text alone, like cljfmt Oct 31, 2026
@bbatsov

bbatsov commented Nov 7, 2026

Copy link
Copy Markdown
Member

Closing in favor of #168, which indents docstrings the way clojure-mode does.

@bbatsov bbatsov closed this Nov 7, 2026
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