From 4e0eb5ae736b42c12ae667ec2a05b668704f9b89 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Mon, 24 Mar 2025 09:25:53 -0700 Subject: [PATCH] Text block formatting refinements * Don't automatically deindent long text blocks to start at column 0. For text blocks that are already deindented the existing choice will be preserved, but it won't happen automatically. * For deindented text blocks, put the opening `"""` at column 0 instead of indenting it PiperOrigin-RevId: 739966701 --- .../java/JavaInputAstVisitor.java | 19 +++++++++++++++++ .../googlejavaformat/java/StringWrapper.java | 21 ++++++------------- .../java/StringWrapperTest.java | 2 +- .../java/testdata/B361077825.output | 4 ++-- .../googlejavaformat/java/testdata/RSLs.input | 5 +++++ .../java/testdata/RSLs.output | 21 ++++++++++++------- 6 files changed, 47 insertions(+), 25 deletions(-) diff --git a/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java b/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java index dcaa930e4..f21f86a5c 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java +++ b/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java @@ -42,6 +42,7 @@ import static com.sun.source.tree.Tree.Kind.STRING_LITERAL; import static com.sun.source.tree.Tree.Kind.UNION_TYPE; import static com.sun.source.tree.Tree.Kind.VARIABLE; +import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.toList; import com.google.auto.value.AutoOneOf; @@ -71,6 +72,7 @@ import com.google.googlejavaformat.FormattingError; import com.google.googlejavaformat.Indent; import com.google.googlejavaformat.Input; +import com.google.googlejavaformat.Newlines; import com.google.googlejavaformat.Op; import com.google.googlejavaformat.OpenOp; import com.google.googlejavaformat.OpsBuilder; @@ -1753,6 +1755,23 @@ public Void visitMemberSelect(MemberSelectTree node, Void unused) { public Void visitLiteral(LiteralTree node, Void unused) { sync(node); String sourceForNode = getSourceForNode(node, getCurrentPath()); + if (sourceForNode.startsWith("\"\"\"")) { + String separator = Newlines.guessLineSeparator(sourceForNode); + ImmutableList initialLines = sourceForNode.lines().collect(toImmutableList()); + String stripped = initialLines.stream().skip(1).collect(joining(separator)).stripIndent(); + // Use the last line of the text block to determine if it is deindented to column 0, by + // comparing the length of the line in the input source with the length after processing + // the text block contents with stripIndent(). + boolean deindent = + getLast(initialLines).stripTrailing().length() + == Streams.findLast(stripped.lines()).orElseThrow().stripTrailing().length(); + if (deindent) { + Indent indent = Indent.Const.make(Integer.MIN_VALUE / indentMultiplier, indentMultiplier); + builder.breakOp(indent); + } + token(sourceForNode); + return null; + } if (isUnaryMinusLiteral(sourceForNode)) { token("-"); sourceForNode = sourceForNode.substring(1).trim(); diff --git a/core/src/main/java/com/google/googlejavaformat/java/StringWrapper.java b/core/src/main/java/com/google/googlejavaformat/java/StringWrapper.java index 5d10da388..27450d82f 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/StringWrapper.java +++ b/core/src/main/java/com/google/googlejavaformat/java/StringWrapper.java @@ -188,15 +188,10 @@ public Void visitLiteral(LiteralTree literalTree, Void aVoid) { private void indentTextBlocks( TreeRangeMap replacements, List textBlocks) { for (Tree tree : textBlocks) { - int startPosition = getStartPosition(tree); + int startPosition = lineMap.getStartPosition(lineMap.getLineNumber(getStartPosition(tree))); int endPosition = getEndPosition(unit, tree); String text = input.substring(startPosition, endPosition); - int lineStartPosition = lineMap.getStartPosition(lineMap.getLineNumber(startPosition)); - int startColumn = - CharMatcher.whitespace() - .negate() - .indexIn(input.substring(lineStartPosition, endPosition)) - + 1; + int leadingWhitespace = CharMatcher.whitespace().negate().indexIn(text); // Find the source code of the text block with incidental whitespace removed. // The first line of the text block is always """, and it does not affect incidental @@ -204,17 +199,13 @@ private void indentTextBlocks( ImmutableList initialLines = text.lines().collect(toImmutableList()); String stripped = initialLines.stream().skip(1).collect(joining(separator)).stripIndent(); ImmutableList lines = stripped.lines().collect(toImmutableList()); - int deindent = + boolean deindent = getLast(initialLines).stripTrailing().length() - - getLast(lines).stripTrailing().length(); + == getLast(lines).stripTrailing().length(); - String prefix = - (deindent == 0 - || lines.stream().anyMatch(x -> x.length() + startColumn - 1 > columnLimit)) - ? "" - : " ".repeat(startColumn - 1); + String prefix = deindent ? "" : " ".repeat(leadingWhitespace); - StringBuilder output = new StringBuilder(initialLines.get(0).stripLeading()); + StringBuilder output = new StringBuilder(prefix).append(initialLines.get(0).stripLeading()); for (int i = 0; i < lines.size(); i++) { String line = lines.get(i); String trimmed = line.stripTrailing(); diff --git a/core/src/test/java/com/google/googlejavaformat/java/StringWrapperTest.java b/core/src/test/java/com/google/googlejavaformat/java/StringWrapperTest.java index 339ed1340..a9ceeacb6 100644 --- a/core/src/test/java/com/google/googlejavaformat/java/StringWrapperTest.java +++ b/core/src/test/java/com/google/googlejavaformat/java/StringWrapperTest.java @@ -63,7 +63,7 @@ public void textBlock() throws Exception { " private String myString;", " private ReproBug() {", " String str =", - " \"\"\"", + "\"\"\"", "{\"sourceEndpoint\":\"ri.something.1-1.object-internal.1\",\"targetEndpoint" + "\":\"ri.something.1-1.object-internal.2\",\"typeId\":\"typeId\"}\\", "\"\"\";", diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B361077825.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B361077825.output index 62344bd54..c93942a5d 100644 --- a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B361077825.output +++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B361077825.output @@ -10,6 +10,6 @@ class T { """; String c = """ - # No implicit input file, because they can only be created outside a symbolic macro, -"""; + # No implicit input file, because they can only be created outside a symbolic macro, + """; } diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/RSLs.input b/core/src/test/resources/com/google/googlejavaformat/java/testdata/RSLs.input index 6eaa28558..002b3653a 100644 --- a/core/src/test/resources/com/google/googlejavaformat/java/testdata/RSLs.input +++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/RSLs.input @@ -40,6 +40,11 @@ class RSLs { lorem ipsum """; + String l = + """ + foo +bar + baz"""; { f(""" lorem diff --git a/core/src/test/resources/com/google/googlejavaformat/java/testdata/RSLs.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/RSLs.output index 6e9a3ae5b..af4a8a6fc 100644 --- a/core/src/test/resources/com/google/googlejavaformat/java/testdata/RSLs.output +++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/RSLs.output @@ -43,14 +43,20 @@ class RSLs { """; String j = """ -lorem -one long incredibly unbroken sentence moving from topic to topic so that no one had a chance to interrupt -ipsum -"""; + lorem + one long incredibly unbroken sentence moving from topic to topic so that no one had a chance to interrupt + ipsum + """; String k = - """ +""" lorem ipsum +"""; + String l = +""" + foo +bar + baz\ """; { @@ -85,10 +91,11 @@ ipsum bar """; String t = - """ +""" foo """ - + """ + + +""" bar """; String u =