diff --git a/changelog/@unreleased/pr-70.v2.yml b/changelog/@unreleased/pr-70.v2.yml new file mode 100644 index 000000000..83a95de3b --- /dev/null +++ b/changelog/@unreleased/pr-70.v2.yml @@ -0,0 +1,8 @@ +type: improvement +improvement: + description: |- + Limit how far dots may appear in long method chains to 80 chars. + + Note that this doesn't currently apply to prefixes (such as `foo.bar().baz().stream()`) because prefixes are also used to group together fully qualified class names and it's a bit trickier to handle that case. + links: + - https://github.com/palantir/palantir-java-format/pull/70 diff --git a/palantir-java-format/src/main/java/com/palantir/javaformat/OpenOp.java b/palantir-java-format/src/main/java/com/palantir/javaformat/OpenOp.java index 98e829563..dca74ab35 100644 --- a/palantir-java-format/src/main/java/com/palantir/javaformat/OpenOp.java +++ b/palantir-java-format/src/main/java/com/palantir/javaformat/OpenOp.java @@ -18,6 +18,7 @@ import com.palantir.javaformat.doc.DocBuilder; import com.palantir.javaformat.doc.Level; import java.util.Optional; +import java.util.OptionalInt; import org.immutables.value.Value; import org.immutables.value.Value.Default; @@ -28,13 +29,19 @@ */ @Value.Immutable public abstract class OpenOp implements Op { + /** The extra indent inside this level. */ public abstract Indent plusIndent(); + /** + * When this level doesn't fit on one line, controls whether this level is to be broken (its breaks taken) or + * partially inlined onto the current line. + */ @Default public BreakBehaviour breakBehaviour() { return BreakBehaviours.breakThisLevel(); } + /** If it's the last level of its parent, when to inline this level rather than break the parent. */ @Default public LastLevelBreakability breakabilityIfLastLevel() { return LastLevelBreakability.ABORT; @@ -42,6 +49,9 @@ public LastLevelBreakability breakabilityIfLastLevel() { public abstract Optional debugName(); + /** Custom max column limit that contents of this level before the last break may not exceed. */ + public abstract OptionalInt columnLimitBeforeLastBreak(); + /** * Make an ordinary {@code OpenOp}. * @@ -69,7 +79,7 @@ public static Op make( @Override public void add(DocBuilder builder) { - builder.open(plusIndent(), breakBehaviour(), breakabilityIfLastLevel(), debugName()); + builder.open(this); } public static Builder builder() { diff --git a/palantir-java-format/src/main/java/com/palantir/javaformat/doc/Break.java b/palantir-java-format/src/main/java/com/palantir/javaformat/doc/Break.java index 7ab501adf..e352860cf 100644 --- a/palantir-java-format/src/main/java/com/palantir/javaformat/doc/Break.java +++ b/palantir-java-format/src/main/java/com/palantir/javaformat/doc/Break.java @@ -16,7 +16,6 @@ package com.palantir.javaformat.doc; -import com.google.common.base.MoreObjects; import com.google.common.collect.Range; import com.google.errorprone.annotations.Immutable; import com.palantir.javaformat.CommentsHelper; @@ -25,25 +24,19 @@ import com.palantir.javaformat.Output; import com.palantir.javaformat.doc.State.BreakState; import java.util.Optional; +import org.immutables.value.Value; /** A leaf node in a {@link Doc} for an optional break. */ @Immutable -public final class Break extends Doc implements Op { - private final FillMode fillMode; - private final String flat; - private final Indent plusIndent; - private final Optional optTag; - - private Break(FillMode fillMode, String flat, Indent plusIndent, Optional optTag) { - this.fillMode = fillMode; - this.flat = flat; - this.plusIndent = plusIndent; - this.optTag = optTag; - } +@Value.Immutable +public abstract class Break extends Doc implements Op { + public abstract FillMode fillMode(); - public FillMode getFillMode() { - return fillMode; - } + public abstract String flat(); + + public abstract Indent plusIndent(); + + public abstract Optional optTag(); /** * Make a {@code Break}. @@ -54,7 +47,7 @@ public FillMode getFillMode() { * @return the new {@code Break} */ public static Break make(FillMode fillMode, String flat, Indent plusIndent) { - return new Break(fillMode, flat, plusIndent, /* optTag= */ Optional.empty()); + return builder().fillMode(fillMode).flat(flat).plusIndent(plusIndent).build(); } /** @@ -67,7 +60,7 @@ public static Break make(FillMode fillMode, String flat, Indent plusIndent) { * @return the new {@code Break} */ public static Break make(FillMode fillMode, String flat, Indent plusIndent, Optional optTag) { - return new Break(fillMode, flat, plusIndent, optTag); + return builder().fillMode(fillMode).flat(flat).plusIndent(plusIndent).optTag(optTag).build(); } /** @@ -76,21 +69,16 @@ public static Break make(FillMode fillMode, String flat, Indent plusIndent, Opti * @return the new forced {@code Break} */ public static Break makeForced() { - return make(FillMode.FORCED, "", Indent.Const.ZERO); + return builder().fillMode(FillMode.FORCED).flat("").plusIndent(Indent.Const.ZERO).build(); } /** * Return the {@code Break}'s extra indent. * * @return the extra indent - * @param state */ public int evalPlusIndent(State state) { - return plusIndent.eval(state); - } - - Indent getPlusIndent() { - return plusIndent; + return plusIndent().eval(state); } /** @@ -99,7 +87,7 @@ Indent getPlusIndent() { * @return whether the {@code Break} is forced */ public boolean isForced() { - return fillMode == FillMode.FORCED; + return fillMode() == FillMode.FORCED; } @Override @@ -108,22 +96,22 @@ public void add(DocBuilder builder) { } @Override - float computeWidth() { - return isForced() ? Float.POSITIVE_INFINITY : (float) flat.length(); + protected float computeWidth() { + return isForced() ? Float.POSITIVE_INFINITY : (float) flat().length(); } @Override - String computeFlat() { - return flat; + protected String computeFlat() { + return flat(); } @Override - Range computeRange() { + protected Range computeRange() { return EMPTY_RANGE; } public State computeBreaks(State stateIn, boolean broken) { - State state = optTag.map(breakTag -> stateIn.breakTaken(breakTag, broken)).orElse(stateIn); + State state = optTag().map(breakTag -> stateIn.breakTaken(breakTag, broken)).orElse(stateIn); return state.withBreak(this, broken); } @@ -143,17 +131,13 @@ public void write(State state, Output output) { output.append(state, "\n", EMPTY_RANGE); output.indent(breakState.newIndent()); } else { - output.append(state, flat, range()); + output.append(state, flat(), range()); } } - @Override - public String toString() { - return MoreObjects.toStringHelper(this) - .add("fillMode", fillMode) - .add("flat", flat) - .add("plusIndent", plusIndent) - .add("optTag", optTag) - .toString(); + public static class Builder extends ImmutableBreak.Builder {} + + public static Builder builder() { + return new Builder(); } } diff --git a/palantir-java-format/src/main/java/com/palantir/javaformat/doc/Doc.java b/palantir-java-format/src/main/java/com/palantir/javaformat/doc/Doc.java index 138d7bfa5..49ac1b0f8 100644 --- a/palantir-java-format/src/main/java/com/palantir/javaformat/doc/Doc.java +++ b/palantir-java-format/src/main/java/com/palantir/javaformat/doc/Doc.java @@ -69,21 +69,21 @@ final Range range() { * * @return the width, or {@code Float.POSITIVE_INFINITY} if it must be broken */ - abstract float computeWidth(); + protected abstract float computeWidth(); /** * Compute the {@code Doc}'s flat value. Not defined (and never called) if contains forced breaks. * * @return the flat value */ - abstract String computeFlat(); + protected abstract String computeFlat(); /** * Compute the {@code Doc}'s {@link Range} of {@link Input.Token}s. * * @return the {@link Range} */ - abstract Range computeRange(); + protected abstract Range computeRange(); /** * Make breaking decisions for a {@code Doc}. diff --git a/palantir-java-format/src/main/java/com/palantir/javaformat/doc/DocBuilder.java b/palantir-java-format/src/main/java/com/palantir/javaformat/doc/DocBuilder.java index cd8de9410..f3f823616 100644 --- a/palantir-java-format/src/main/java/com/palantir/javaformat/doc/DocBuilder.java +++ b/palantir-java-format/src/main/java/com/palantir/javaformat/doc/DocBuilder.java @@ -17,20 +17,16 @@ package com.palantir.javaformat.doc; import com.google.common.base.MoreObjects; -import com.palantir.javaformat.BreakBehaviour; -import com.palantir.javaformat.BreakBehaviours; import com.palantir.javaformat.Indent; -import com.palantir.javaformat.LastLevelBreakability; import com.palantir.javaformat.Op; +import com.palantir.javaformat.OpenOp; import com.palantir.javaformat.OpsBuilder; import java.util.ArrayDeque; import java.util.List; -import java.util.Optional; /** A {@code DocBuilder} converts a sequence of {@link Op}s into a {@link Doc}. */ public final class DocBuilder { - private final Level base = Level.make( - Indent.Const.ZERO, BreakBehaviours.breakThisLevel(), LastLevelBreakability.ABORT, Optional.of("root")); + private final Level base = Level.make(OpenOp.builder().plusIndent(Indent.Const.ZERO).debugName("root").build()); private final ArrayDeque stack = new ArrayDeque<>(); /** @@ -68,20 +64,9 @@ public DocBuilder withOps(List ops) { return this; } - /** - * Open a new {@link Level}. - * - * @param plusIndent the extra indent for the {@link Level} - * @param breakBehaviour how to decide whether to break this level or not - * @param breakabilityIfLastLevel if last level, when to break this rather than parent - * @param debugName - */ - public void open( - Indent plusIndent, - BreakBehaviour breakBehaviour, - LastLevelBreakability breakabilityIfLastLevel, - Optional debugName) { - Level level = Level.make(plusIndent, breakBehaviour, breakabilityIfLastLevel, debugName); + /** Open a new {@link Level}. */ + public void open(OpenOp openOp) { + Level level = Level.make(openOp); stack.addLast(level); } diff --git a/palantir-java-format/src/main/java/com/palantir/javaformat/doc/Level.java b/palantir-java-format/src/main/java/com/palantir/javaformat/doc/Level.java index d5b008026..18c151aac 100644 --- a/palantir-java-format/src/main/java/com/palantir/javaformat/doc/Level.java +++ b/palantir-java-format/src/main/java/com/palantir/javaformat/doc/Level.java @@ -28,11 +28,13 @@ import com.palantir.javaformat.CommentsHelper; import com.palantir.javaformat.Indent; import com.palantir.javaformat.LastLevelBreakability; +import com.palantir.javaformat.OpenOp; import com.palantir.javaformat.Output; import com.palantir.javaformat.doc.StartsWithBreakVisitor.Result; import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.OptionalInt; import java.util.stream.Collector; import java.util.stream.Collectors; import org.immutables.value.Value; @@ -47,41 +49,19 @@ public final class Level extends Doc { private static final Collector> GET_LAST_COLLECTOR = Collectors.reducing((u, v) -> v); - private final Indent plusIndent; // The extra indent following breaks. - private final BreakBehaviour breakBehaviour; // Where to break when we can't fit on one line. - private final LastLevelBreakability breakabilityIfLastLevel; - // If last level, when to break this rather than parent. - private final Optional debugName; private final List docs = new ArrayList<>(); // The elements of the level. private final ImmutableSupplier memoizedSplitsBreaks = Suppliers.memoize(() -> splitByBreaks(docs))::get; + /** The immutable characteristics of this level determined before the level contents are available. */ + private final OpenOp openOp; - private Level( - Indent plusIndent, - BreakBehaviour breakBehaviour, - LastLevelBreakability breakabilityIfLastLevel, - Optional debugName) { - this.plusIndent = plusIndent; - this.breakBehaviour = breakBehaviour; - this.breakabilityIfLastLevel = breakabilityIfLastLevel; - this.debugName = debugName; + private Level(OpenOp openOp) { + this.openOp = openOp; } - /** - * Factory method for {@code Level}s. - * - * @param plusIndent the extra indent inside the {@code Level} - * @param breakBehaviour whether to attempt breaking only the last inner level first, instead of this level - * @param breakabilityIfLastLevel if last level, when to break this rather than parent - * @param debugName - * @return the new {@code Level} - */ - static Level make( - Indent plusIndent, - BreakBehaviour breakBehaviour, - LastLevelBreakability breakabilityIfLastLevel, - Optional debugName) { - return new Level(plusIndent, breakBehaviour, breakabilityIfLastLevel, debugName); + /** Factory method for {@code Level}s. */ + static Level make(OpenOp openOp) { + return new Level(openOp); } /** @@ -94,7 +74,7 @@ void add(Doc doc) { } @Override - float computeWidth() { + protected float computeWidth() { float thisWidth = 0.0F; for (Doc doc : docs) { thisWidth += doc.getWidth(); @@ -103,7 +83,7 @@ float computeWidth() { } @Override - String computeFlat() { + protected String computeFlat() { StringBuilder builder = new StringBuilder(); for (Doc doc : docs) { builder.append(doc.getFlat()); @@ -112,7 +92,7 @@ String computeFlat() { } @Override - Range computeRange() { + protected Range computeRange() { Range docRange = EMPTY_RANGE; for (Doc doc : docs) { docRange = union(docRange, doc.range()); @@ -122,15 +102,40 @@ Range computeRange() { @Override public State computeBreaks(CommentsHelper commentsHelper, int maxWidth, State state) { + return tryToFitOnOneLine(maxWidth, state).orElseGet(() -> { + State newState = getBreakBehaviour().match(new BreakImpl(commentsHelper, maxWidth, state)); + return state.updateAfterLevel(newState); + }); + } + + /** + * Try to fit this level onto one line. If this returns empty, then the level will be broken in some way that is + * dictated by the {@link #getBreakBehaviour()}. + */ + private Optional tryToFitOnOneLine(int maxWidth, State state) { + if (getColumnLimitBeforeLastBreak().isPresent()) { + float width = 0.0f; + float widthBeforeLastBreak = 0.0f; + for (Doc doc : docs) { + if (doc instanceof Break) { + widthBeforeLastBreak = width; + } + width += doc.getWidth(); + } + // Make an additional check that widthBeforeLastBreak fits in the column limit + if (state.column() + widthBeforeLastBreak > getColumnLimitBeforeLastBreak().getAsInt()) { + return Optional.empty(); + } + } + + // Check that the entirety of this level fits on the current line. float thisWidth = getWidth(); if (state.column() + thisWidth <= maxWidth) { - return state.withColumn(state.column() + (int) thisWidth) - .withLevelState(this, ImmutableLevelState.of(true)); + return Optional.of( + state.withColumn(state.column() + (int) thisWidth) + .withLevelState(this, ImmutableLevelState.of(true))); } - - State newState = breakBehaviour.match(new BreakImpl(commentsHelper, maxWidth, state)); - - return state.updateAfterLevel(newState); + return Optional.empty(); } class BreakImpl implements BreakBehaviour.Cases { @@ -145,7 +150,7 @@ public BreakImpl(CommentsHelper commentsHelper, int maxWidth, State state) { } private State breakNormally(State state) { - return computeBroken(commentsHelper, maxWidth, state.withIndentIncrementedBy(plusIndent)); + return computeBroken(commentsHelper, maxWidth, state.withIndentIncrementedBy(getPlusIndent())); } @Override @@ -227,7 +232,7 @@ private Optional handleBreakOnlyIfInnerLevelsThenFitOnOneLine( if (prefixFits) { State newState = state.withNoIndent(); if (keepIndent) { - newState = newState.withIndentIncrementedBy(plusIndent); + newState = newState.withIndentIncrementedBy(getPlusIndent()); } return Optional.of( tryToLayOutLevelOnOneLine(commentsHelper, maxWidth, newState, memoizedSplitsBreaks.get())); @@ -242,7 +247,7 @@ private Optional tryBreakLastLevel( } Level lastLevel = ((Level) getLast(docs)); // Only split levels that have declared they want to be split in this way. - if (lastLevel.breakabilityIfLastLevel == LastLevelBreakability.ABORT) { + if (lastLevel.getBreakabilityIfLastLevel() == LastLevelBreakability.ABORT) { return Optional.empty(); } // See if we can fill in everything but the lastDoc. @@ -269,9 +274,9 @@ private Optional tryBreakLastLevel( // * the lastLevel wants to be split, i.e. has Breakability.BREAK_HERE, then we continue // * the lastLevel indicates we should check inside it for a potential split candidate. // In this case, recurse rather than go into computeBreaks. - if (lastLevel.breakabilityIfLastLevel == LastLevelBreakability.CHECK_INNER) { + if (lastLevel.getBreakabilityIfLastLevel() == LastLevelBreakability.CHECK_INNER) { // Try to fit the entire inner prefix if it's that kind of level. - return BreakBehaviours.caseOf(lastLevel.breakBehaviour) + return BreakBehaviours.caseOf(lastLevel.getBreakBehaviour()) .preferBreakingLastInnerLevel(keepIndentWhenInlined -> { State state2 = state1; if (keepIndentWhenInlined) { @@ -282,7 +287,7 @@ private Optional tryBreakLastLevel( // We don't know how to fit the inner level on the same line, so bail out. .otherwise_(Optional.empty()); - } else if (lastLevel.breakabilityIfLastLevel == LastLevelBreakability.ONLY_IF_FIRST_LEVEL_FITS) { + } else if (lastLevel.getBreakabilityIfLastLevel() == LastLevelBreakability.ONLY_IF_FIRST_LEVEL_FITS) { // Otherwise, we may be able to check if the first inner level of the lastLevel fits. // This is safe because we assume (and check) that a newline comes after it, even though // it might be nested somewhere deep in the 2nd level. @@ -382,7 +387,7 @@ private static State computeBreakAndSplit( CommentsHelper commentsHelper, int maxWidth, State state, Optional optBreakDoc, List split) { float breakWidth = optBreakDoc.isPresent() ? optBreakDoc.get().getWidth() : 0.0F; float splitWidth = getWidth(split); - boolean shouldBreak = (optBreakDoc.isPresent() && optBreakDoc.get().getFillMode() == FillMode.UNIFIED) + boolean shouldBreak = (optBreakDoc.isPresent() && optBreakDoc.get().fillMode() == FillMode.UNIFIED) || state.mustBreak() || state.column() + breakWidth + splitWidth > maxWidth; @@ -429,11 +434,11 @@ private void writeFilled(State state, Output output) { } Indent getPlusIndent() { - return plusIndent; + return openOp.plusIndent(); } BreakBehaviour getBreakBehaviour() { - return breakBehaviour; + return openOp.breakBehaviour(); } List getDocs() { @@ -441,11 +446,15 @@ List getDocs() { } LastLevelBreakability getBreakabilityIfLastLevel() { - return breakabilityIfLastLevel; + return openOp.breakabilityIfLastLevel(); } public Optional getDebugName() { - return debugName; + return openOp.debugName(); + } + + public OptionalInt getColumnLimitBeforeLastBreak() { + return openOp.columnLimitBeforeLastBreak(); } /** An indented representation of this level and all nested levels inside it. */ @@ -474,10 +483,10 @@ private static Range union(Range x, Range y) { @Override public String toString() { return MoreObjects.toStringHelper(this) - .add("debugName", debugName) - .add("plusIndent", plusIndent) - .add("breakBehaviour", breakBehaviour) - .add("breakabilityIfLastLevel", breakabilityIfLastLevel) + .add("debugName", getDebugName()) + .add("plusIndent", getPlusIndent()) + .add("breakBehaviour", getBreakBehaviour()) + .add("breakabilityIfLastLevel", getBreakabilityIfLastLevel()) .add("docs", docs) .toString(); } diff --git a/palantir-java-format/src/main/java/com/palantir/javaformat/doc/LevelDelimitedFlatValueDocVisitor.java b/palantir-java-format/src/main/java/com/palantir/javaformat/doc/LevelDelimitedFlatValueDocVisitor.java index f6ec41941..3e0469b1a 100644 --- a/palantir-java-format/src/main/java/com/palantir/javaformat/doc/LevelDelimitedFlatValueDocVisitor.java +++ b/palantir-java-format/src/main/java/com/palantir/javaformat/doc/LevelDelimitedFlatValueDocVisitor.java @@ -48,7 +48,7 @@ public String visitToken(Token doc) { public String visitBreak(Break doc) { StringBuilder sb = new StringBuilder().append("⏎").append(doc.getFlat().isEmpty() ? "" : "(" + doc.getFlat() + ")"); - if (!doc.getPlusIndent().equals(Indent.Const.ZERO)) { + if (!doc.plusIndent().equals(Indent.Const.ZERO)) { sb.append(" +" + doc.evalPlusIndent(state)); } return sb.toString(); diff --git a/palantir-java-format/src/main/java/com/palantir/javaformat/doc/Space.java b/palantir-java-format/src/main/java/com/palantir/javaformat/doc/Space.java index 772437654..b496cfdd9 100644 --- a/palantir-java-format/src/main/java/com/palantir/javaformat/doc/Space.java +++ b/palantir-java-format/src/main/java/com/palantir/javaformat/doc/Space.java @@ -45,17 +45,17 @@ public void add(DocBuilder builder) { } @Override - float computeWidth() { + protected float computeWidth() { return 1.0F; } @Override - String computeFlat() { + protected String computeFlat() { return " "; } @Override - Range computeRange() { + protected Range computeRange() { return Doc.EMPTY_RANGE; } diff --git a/palantir-java-format/src/main/java/com/palantir/javaformat/doc/Tok.java b/palantir-java-format/src/main/java/com/palantir/javaformat/doc/Tok.java index 7b26ee29e..280fed435 100644 --- a/palantir-java-format/src/main/java/com/palantir/javaformat/doc/Tok.java +++ b/palantir-java-format/src/main/java/com/palantir/javaformat/doc/Tok.java @@ -51,7 +51,7 @@ public void add(DocBuilder builder) { } @Override - float computeWidth() { + protected float computeWidth() { int idx = Newlines.firstBreak(tok.getOriginalText()); // only count the first line of multi-line block comments if (tok.isComment()) { @@ -68,7 +68,7 @@ float computeWidth() { } @Override - String computeFlat() { + protected String computeFlat() { // TODO(cushon): commentsHelper.rewrite doesn't get called for spans that fit in a single // line. That's fine for multi-line comment reflowing, but problematic for adding missing // spaces in line comments. @@ -79,7 +79,7 @@ String computeFlat() { } @Override - Range computeRange() { + protected Range computeRange() { return Range.singleton(tok.getIndex()).canonical(INTEGERS); } diff --git a/palantir-java-format/src/main/java/com/palantir/javaformat/doc/Token.java b/palantir-java-format/src/main/java/com/palantir/javaformat/doc/Token.java index dcd68bb90..389d315fd 100644 --- a/palantir-java-format/src/main/java/com/palantir/javaformat/doc/Token.java +++ b/palantir-java-format/src/main/java/com/palantir/javaformat/doc/Token.java @@ -105,17 +105,17 @@ public void add(DocBuilder builder) { } @Override - float computeWidth() { + protected float computeWidth() { return token.getTok().length(); } @Override - String computeFlat() { + protected String computeFlat() { return token.getTok().getOriginalText(); } @Override - Range computeRange() { + protected Range computeRange() { return Range.singleton(token.getTok().getIndex()).canonical(INTEGERS); } diff --git a/palantir-java-format/src/main/java/com/palantir/javaformat/java/JavaInputAstVisitor.java b/palantir-java-format/src/main/java/com/palantir/javaformat/java/JavaInputAstVisitor.java index 78cae3a39..e58f7e264 100644 --- a/palantir-java-format/src/main/java/com/palantir/javaformat/java/JavaInputAstVisitor.java +++ b/palantir-java-format/src/main/java/com/palantir/javaformat/java/JavaInputAstVisitor.java @@ -157,6 +157,13 @@ /** An AST visitor that builds a stream of {@link Op}s to format from the given {@link CompilationUnitTree}. */ public final class JavaInputAstVisitor extends TreePathScanner { + /** + * Maximum column at which the last dot of a method chain may start. This exists in particular to improve + * readability of builder chains, but also in general to prevent hard to spot extra actions at the end of a method + * chain. + */ + private static final int METHOD_CHAIN_COLUMN_LIMIT = 80; + /** Direction for Annotations (usually VERTICAL). */ enum Direction { VERTICAL, @@ -2693,6 +2700,7 @@ private void visitRegularDot(List items, boolean needDot) { .plusIndent(plusFour) .breakBehaviour(BreakBehaviours.preferBreakingLastInnerLevel(false)) .breakabilityIfLastLevel(LastLevelBreakability.CHECK_INNER) + .columnLimitBeforeLastBreak(METHOD_CHAIN_COLUMN_LIMIT) .build()); } // don't break after the first element if it is every small, unless the @@ -2780,6 +2788,7 @@ private void visitDotWithPrefix( ? BreakBehaviours.preferBreakingLastInnerLevel(true) : BreakBehaviours.breakThisLevel()) .breakabilityIfLastLevel(LastLevelBreakability.ONLY_IF_FIRST_LEVEL_FITS) + .columnLimitBeforeLastBreak(METHOD_CHAIN_COLUMN_LIMIT) .build()); for (int times = 0; times < prefixes.size(); times++) { diff --git a/palantir-java-format/src/test/resources/com/palantir/javaformat/java/testdata/B21954779.output b/palantir-java-format/src/test/resources/com/palantir/javaformat/java/testdata/B21954779.output index 242a85b54..a69612618 100644 --- a/palantir-java-format/src/test/resources/com/palantir/javaformat/java/testdata/B21954779.output +++ b/palantir-java-format/src/test/resources/com/palantir/javaformat/java/testdata/B21954779.output @@ -29,6 +29,7 @@ class B21954779 { bind(new Key>() {}); // this isn't a feature; we'd prefer to keep `new Key...` as one unit - bind(new Key>() {}).then(); + bind(new Key>() {}) + .then(); } } diff --git a/palantir-java-format/src/test/resources/com/palantir/javaformat/java/testdata/B32114928.output b/palantir-java-format/src/test/resources/com/palantir/javaformat/java/testdata/B32114928.output index 35d176d63..8e1d35e75 100644 --- a/palantir-java-format/src/test/resources/com/palantir/javaformat/java/testdata/B32114928.output +++ b/palantir-java-format/src/test/resources/com/palantir/javaformat/java/testdata/B32114928.output @@ -1,6 +1,7 @@ class B32114928 { { Class tClass = (Class) - verifyNotNull((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; + verifyNotNull((ParameterizedType) getClass().getGenericSuperclass()) + .getActualTypeArguments()[0]; } } diff --git a/palantir-java-format/src/test/resources/com/palantir/javaformat/java/testdata/B35644813.output b/palantir-java-format/src/test/resources/com/palantir/javaformat/java/testdata/B35644813.output index 24d368030..6f3f019b3 100644 --- a/palantir-java-format/src/test/resources/com/palantir/javaformat/java/testdata/B35644813.output +++ b/palantir-java-format/src/test/resources/com/palantir/javaformat/java/testdata/B35644813.output @@ -1,6 +1,8 @@ class B35644813 { { - return foo____________.bar__________().baz____________().stream().map(Baz::getId).collect(toList()); + return foo____________.bar__________().baz____________().stream() + .map(Baz::getId) + .collect(toList()); } private static final ImmutableSet SCANDINAVIA = ImmutableSet.of( diff --git a/palantir-java-format/src/test/resources/com/palantir/javaformat/java/testdata/I365.output b/palantir-java-format/src/test/resources/com/palantir/javaformat/java/testdata/I365.output index b0d6fae9c..90a57f975 100644 --- a/palantir-java-format/src/test/resources/com/palantir/javaformat/java/testdata/I365.output +++ b/palantir-java-format/src/test/resources/com/palantir/javaformat/java/testdata/I365.output @@ -1,5 +1,7 @@ class I365 { { - return foo____________.bar__________().baz____________().parallelStream().map(Baz::getId).collect(toList()); + return foo____________.bar__________().baz____________().parallelStream() + .map(Baz::getId) + .collect(toList()); } } diff --git a/palantir-java-format/src/test/resources/com/palantir/javaformat/java/testdata/M.output b/palantir-java-format/src/test/resources/com/palantir/javaformat/java/testdata/M.output index b8188eb31..7f49c30d4 100644 --- a/palantir-java-format/src/test/resources/com/palantir/javaformat/java/testdata/M.output +++ b/palantir-java-format/src/test/resources/com/palantir/javaformat/java/testdata/M.output @@ -932,13 +932,16 @@ class M { 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0); Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.ffffffffff(0); - Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.fff(0).fff(0); - Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.fff(0 + 0).fff(0); + Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.fff(0) + .fff(0); + Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.fff(0 + 0) + .fff(0); Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.fff( 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0) .fff(0); - Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.ffffffffff(0).fff(0); + Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.ffffffffff(0) + .fff(0); return this; } @@ -951,9 +954,14 @@ class M { ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff(0); ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff(0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0); - ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff(0).f(0); - ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff(0).fff(0).fff(0).f(0); - ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff(0).ffffffffff(0); + ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff(0) + .f(0); + ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff(0) + .fff(0) + .fff(0) + .f(0); + ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff(0) + .ffffffffff(0); return this; }