Skip to content

Stop splitting a chained invocation that would fit on one line - #153

Merged
ctgnz merged 1 commit into
masterfrom
chore/152-chained-invocations
Sep 30, 2026
Merged

ctgnz merged 1 commit into
masterfrom
chore/152-chained-invocations

Conversation

@ctgnz

@ctgnz ctgnz commented Sep 30, 2026

Copy link
Copy Markdown
Owner

Closes #152.

// before                                          // after
this.entityTypes.addAll(entity.getEntityTypes()    this.entityTypes.addAll(entity.getEntityTypes().stream().map(this::adaptEntityType).toList());
    .stream()
    .map(this::adaptEntityType)
    .toList());

Two settings, and neither works alone

alignment_for_selector_in_method_invocation = 85
    = 80 (M_NEXT_PER_LINE_SPLIT) + 4 (M_INDENT_BY_ONE) + 1 (M_FORCE)

M_FORCE splits regardless of fit, so it drops to 84. On its own that changes nothing, because join_wrapped_lines was false and the Eclipse formatter then only ever adds a wrap, never removes one already present — so that moves to true as well. lineSplit stays at 200.

That interaction is the whole reason this looked like a formatter-choice problem rather than a two-line config problem.

Measured

files reformatted 175
net change 1,316 insertions, 2,676 deletions — ~1,360 lines shorter
clean verify green on -Pstandard, -Phistorical, -Pbattleorder
generator templates unaffected — raw regeneration then one spotless:apply lands exactly on the committed sources

That last row was the thing worth checking, and it is why this is cheap: the zero-diff property CLAUDE.md describes still holds, so no template needed retuning.

Quality rather than just height — of 147 newly joined lines in hand-written code, 138 are ≤90 characters and the longest is 114, against a limit of 200:

Files.walk(packageRoot).map(Path::toFile).sorted(Comparator.reverseOrder()).forEach(File::delete);
library.getHqtfDummys().stream().filter(status -> status.isSupported(symbolSet)).forEach(hqtfDummy -> {

The 21,000-character lines in the generated libraries are injected SVG string literals, byte-identical before and after. A string constant cannot be wrapped, and this does not make them worse.

It stays the Eclipse formatter, deliberately

Re-import the profile and the IDE's Source → Format agrees with the build again. A switch to palantir-java-format or google-java-format would have given that up, reformatted every generated file, and needed the templates retuned — for a chain style this already achieves.

The trade-off

join_wrapped_lines = true means the formatter now rejoins lines that were wrapped on purpose, which is presumably why it was false. Where a hand layout genuinely matters, // @formatter:off / // @formatter:on still work.

Worth reviewing the diff for any place where a deliberate layout was worth keeping — it is mechanical, so anything that reads worse is a candidate for a @formatter:off rather than a reason to drop the change.

🤖 Generated with Claude Code

The formatter put every selector in a chain on its own line whether or not the
whole thing fitted, so ordinary stream and builder code was several times taller
than it needed to be:

    this.entityTypes.addAll(entity.getEntityTypes()
        .stream()
        .map(this::adaptEntityType)
        .toList());

becomes

    this.entityTypes.addAll(entity.getEntityTypes().stream().map(this::adaptEntityType).toList());

Two settings, and they only work together. alignment_for_selector_in_method_invocation
was 85 - M_NEXT_PER_LINE_SPLIT plus M_INDENT_BY_ONE plus M_FORCE - and M_FORCE is
what splits regardless of fit, so it drops to 84. On its own that changes nothing,
because join_wrapped_lines was false and the Eclipse formatter then only ever adds
a wrap, never removes one already there. So that moves to true as well. lineSplit
stays at 200.

175 files, about 1,360 lines shorter. Clean verify on all three profiles.

The generator templates are unaffected, which was the thing worth checking: a raw
regeneration followed by one spotless:apply still lands exactly on the committed
sources, so the zero-diff property CLAUDE.md describes survives. The
21,000-character lines in the generated libraries are injected SVG string
literals, byte-identical before and after - a string constant cannot be wrapped.

Quality rather than just height: of 147 newly joined lines in hand-written code,
138 are 90 characters or shorter and the longest is 114, against a limit of 200.

This stays the Eclipse formatter deliberately. Re-importing the profile leaves the
IDE's Source > Format agreeing with the build, which a switch to
palantir-java-format or google-java-format would have given up - along with
reformatting every generated file and retuning the templates.

The trade-off: join_wrapped_lines now rejoins lines that were wrapped on purpose,
which is presumably why it was false. Where a hand layout matters,
// @Formatter:off and // @Formatter:on still work.

Closes #152.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ctgnz
ctgnz merged commit cc1103b into master Sep 30, 2026
1 check 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.

Chained invocations are split one call per line even when they fit

1 participant