Skip to content

Add asciidoc formatter for AsciiDoc files#2955

Closed
dheid wants to merge 16 commits into
diffplug:mainfrom
dheid:main
Closed

Add asciidoc formatter for AsciiDoc files#2955
dheid wants to merge 16 commits into
diffplug:mainfrom
dheid:main

Conversation

@dheid
Copy link
Copy Markdown

@dheid dheid commented Jun 1, 2026

Adds a pure-Java AsciidocFormatterStep to lib (no external dependencies) and wires it into both the Gradle and Maven plugins as a first-class asciidoc format type.

What it does

The formatter applies a configurable pipeline of structural normalizations to .adoc files. Every option is a boolean flag; all default values are chosen to be safe on real-world documents.

Option Default Effect
normalizeSetextHeadings true Convert underline-style headings (Title\n=====) to ATX style (= Title)
removeTrailingHeaderEqualsSign true Remove symmetric trailing = signs (== Title ==== Title) and normalize whitespace after the leading = signs
ensureHeadingBlankLines true Insert blank lines before and after every section heading
normalizeBlockDelimiters true Shorten over-long delimiters (------------)
collapseConsecutiveBlankLines true Collapse multiple consecutive blank lines into one
removeTrailingWhitespace true Strip trailing whitespace from every line
oneSentencePerLine true Reflow paragraph text so each sentence starts on its own line
titleCase false Apply Chicago-style title case to section headings and block titles
normalizeListBullets false Convert dash bullets to asterisk style (- item* item)
normalizeOrderedListMarkers false Convert explicit numbers to AsciiDoc dot style (1. item. item)
ensureSourceDelimiters false Wrap bare [source,…] / [listing] blocks that have no ---- delimiter

All transformations respect delimited block boundaries — content inside ----,
====, ****, etc. is never modified.

Usage

Gradle:

spotless {
  asciidoc {
    target '**/*.adoc'
    asciidoc()
      // override any defaults here, e.g.:
      .titleCase(true)
      .normalizeListBullets(true)
  }
}

Maven:

<asciidoc>
  <includes><include>**/*.adoc</include></includes>
  <asciidocFormatting>
    <titleCase>true</titleCase>
    <normalizeListBullets>true</normalizeListBullets>
  </asciidocFormatting>
</asciidoc>

Tests

  • 122 unit tests in lib (AsciidocFormatterFuncTest) covering every option individually, including idempotency, block-boundary protection, and several bug-regression cases (setext detection inside code blocks, page-break / block-macro handling, tab-separated list markers).
  • AsciidocFormatterStepTest in testlib using StepHarness.testResource for an end-to-end before/after fixture, and SerializableEqualityTester to verify that every config field contributes to step identity.

Notes

  • The Maven plugin defaults are more conservative than the lib defaults (only removeTrailingWhitespace, collapseConsecutiveBlankLines, and ensureHeadingBlankLines are on) to avoid surprising users who opt in
    without reading the docs.
  • The oneSentencePerLine feature handles common AsciiDoc-specific structural lines (page breaks <<<, block macros include::, toc::, description-list terms, horizontal rules ''') so they are never accumulated into paragraph text.
  • All new files carry the standard Apache 2.0 / Copyright 2026 DiffPlug header. spotlessApply and spotbugsMain both pass.

@dheid
Copy link
Copy Markdown
Author

dheid commented Jun 2, 2026

@nedtwigg Could you review this pull request plz?

void removeTrailingHeaderEqualsSign() {
for (int i = 0; i < lines.size(); i++) {
String line = lines.get(i);
Matcher symmetric = SYMMETRIC_HEADING.matcher(line);
lines.set(i, symmetric.group(1) + ' ' + symmetric.group(2));
continue;
}
Matcher section = SECTION_HEADING.matcher(line);
continue;
}

if (SECTION_HEADING.matcher(line).matches()) {
}

private static String titleCaseLine(String line) {
Matcher matcher = AsciidocHeadingHandler.SECTION_HEADING.matcher(line);
@nedtwigg
Copy link
Copy Markdown
Member

nedtwigg commented Jun 2, 2026

@dheid This formatter looks big enough to warrant its own project.

Pros of that approach:

  • you won't be gated on Spotless when you want to fix or refactor something
  • you will be able to make breaking changes to the format (people can upgrade or downgrade Spotless while using older or newer versions of your formatting lib)

Cons: you'd have to setup your own mavenCentral publishing

Spotless is more of a switchboard than a formatter itself. We have added a few directly into lib (specifically DBeaver's sql formatting), but they have been:

  • existing mature codebases
  • which for one reason or another were never going to get published onto mavenCentral
  • and had high demand from the general Spotless userbase

Those three bulletpoints were the reason we decided to accept the code straight into lib, rather than requiring that it be published on its own and then incorporated into Spotless using our standard glue-code approach.

I think a lot of people will be eager to have AsciiDoc formatting, but the history in this PR makes me think this would be more appropriate at its own mavenCentral coordinate and integrated with glue code.

@nedtwigg nedtwigg closed this Jun 2, 2026
@dheid
Copy link
Copy Markdown
Author

dheid commented Jun 2, 2026

I'm super sad by this and won't publish an own lib. Can't understand the decision and feel super rejected by this. Demotivates me very much to contribute to open source again.

@nedtwigg
Copy link
Copy Markdown
Member

nedtwigg commented Jun 2, 2026

feel super rejected by this.

I think this is a great contribution and I want to merge it! But my preference is for you to publish the logic of the formatter in its own library, and then we merge the glue code into this. Maybe that was not clear? The logic (such as you put in lib) should be in dheid:asciidoc-formatter:123 (or wherever you like), and then Spotless (the changes you made in plugin-gradle and plugin-maven) would get merged into this Spotless pretty much as-is?

Let me know if that was not clear, or if there is a hurdle why that is not possible. The big advantage of it is that it decouples the formatter implementation from the formatter harness. Almost every FormatterStep in Spotless works this way, your contribution was not singled out.

I have given this exact feedback to other PRs in the past, #1649 comes to mind as an example of this, where someone wanted to add a new formatter, we asked them to put the impl into a separate jar, and then it got merged later on.

Demotivates me very much to contribute to open source again.

I hope you'll come back because I think it's good code. But I'm not responsible for motivating you. I apologize if my communication felt like a slammed door - you are always welcome to ask for further discussion or clarification. I am busy and I'm going to communicate simply and openly.

TL;DR: I would like to merge your code if you still want to contribute it, but the core logic needs to live in a separate jar.

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.

3 participants