From 98c6bbd0534620901cf8d13cf0c843a4c888e947 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Fri, 8 Nov 2024 09:38:27 -0800 Subject: [PATCH] If a text block is outdented, outdent the opening `"""` too PiperOrigin-RevId: 694533649 --- .../googlejavaformat/java/JavaInputAstVisitor.java | 10 ++++++++++ .../google/googlejavaformat/java/StringWrapper.java | 6 +++--- .../googlejavaformat/java/StringWrapperTest.java | 2 +- .../googlejavaformat/java/testdata/B377585941.output | 4 ++-- .../google/googlejavaformat/java/testdata/RSLs.input | 7 +++++++ .../google/googlejavaformat/java/testdata/RSLs.output | 11 +++++++++-- 6 files changed, 32 insertions(+), 8 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 01f9a3e05..af9810114 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java +++ b/core/src/main/java/com/google/googlejavaformat/java/JavaInputAstVisitor.java @@ -70,6 +70,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; @@ -1667,6 +1668,15 @@ public Void visitMemberSelect(MemberSelectTree node, Void unused) { public Void visitLiteral(LiteralTree node, Void unused) { sync(node); String sourceForNode = getSourceForNode(node, getCurrentPath()); + if (sourceForNode.endsWith("\"\"\"") + && (Newlines.hasNewlineAt(sourceForNode, sourceForNode.length() - 4) != -1)) { + // If the closing delimiter of a text block starts at the margin, outdent the opening + // delimiter as well by adding a break with negative indentation. Outdenting for text blocks + // with wide contents is also handled by StringWrapper, but this means the behaviour for + // the opening delimiter is consistent if string wrapping is disabled, and also effectively + // preserves user choice about which text blocks stay de-indented. + builder.breakOp(Indent.Const.make(Integer.MIN_VALUE / indentMultiplier, indentMultiplier)); + } 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 c0b4dc1db..81ea800da 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/StringWrapper.java +++ b/core/src/main/java/com/google/googlejavaformat/java/StringWrapper.java @@ -190,9 +190,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 startColumn = CharMatcher.whitespace().negate().indexIn(text) + 1; // 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 @@ -203,13 +204,12 @@ private void indentTextBlocks( int deindent = initialLines.get(1).stripTrailing().length() - lines.get(0).stripTrailing().length(); - int startColumn = lineMap.getColumnNumber(startPosition); String prefix = (deindent == 0 || lines.stream().anyMatch(x -> x.length() + startColumn > columnLimit)) ? "" : " ".repeat(startColumn - 1); - StringBuilder output = new StringBuilder(TEXT_BLOCK_DELIMITER); + 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.stripLeading().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 7854126c4..bc1a93384 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/B377585941.output b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B377585941.output index 1dfc49503..bd3107be4 100644 --- a/core/src/test/resources/com/google/googlejavaformat/java/testdata/B377585941.output +++ b/core/src/test/resources/com/google/googlejavaformat/java/testdata/B377585941.output @@ -2,7 +2,7 @@ class T { { f( /* foo */ """ - hello - """); + hello + """); } } 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 22aa8f2b2..e557ea2ce 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 @@ -50,5 +50,12 @@ ipsum hello %s """ .formatted("world"); + f( + /* foo= */ """ + foo + """, + /* bar= */ """ + bar + """); } } 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 5f59bc5ea..7d291b15c 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 @@ -42,13 +42,13 @@ class RSLs { ipsum """; String j = - """ +""" 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 """; @@ -65,5 +65,12 @@ ipsum hello %s """ .formatted("world"); + f( + /* foo= */ """ + foo + """, + /* bar= */ """ + bar + """); } }