Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid mangling {@snippet ...}. #1141

Merged
merged 1 commit into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ private static String render(List<Token> input, int blockIndent) {
case FOOTER_JAVADOC_TAG_START:
output.writeFooterJavadocTagStart(token);
break;
case SNIPPET_BEGIN:
output.writeSnippetBegin(token);
break;
case SNIPPET_END:
output.writeSnippetEnd(token);
break;
case LIST_OPEN_TAG:
output.writeListOpen(token);
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
import static com.google.googlejavaformat.java.javadoc.Token.Type.PARAGRAPH_OPEN_TAG;
import static com.google.googlejavaformat.java.javadoc.Token.Type.PRE_CLOSE_TAG;
import static com.google.googlejavaformat.java.javadoc.Token.Type.PRE_OPEN_TAG;
import static com.google.googlejavaformat.java.javadoc.Token.Type.SNIPPET_BEGIN;
import static com.google.googlejavaformat.java.javadoc.Token.Type.SNIPPET_END;
import static com.google.googlejavaformat.java.javadoc.Token.Type.TABLE_CLOSE_TAG;
import static com.google.googlejavaformat.java.javadoc.Token.Type.TABLE_OPEN_TAG;
import static com.google.googlejavaformat.java.javadoc.Token.Type.WHITESPACE;
Expand Down Expand Up @@ -97,6 +99,7 @@ private static String stripJavadocBeginAndEnd(String input) {
private final NestingCounter preDepth = new NestingCounter();
private final NestingCounter codeDepth = new NestingCounter();
private final NestingCounter tableDepth = new NestingCounter();
private boolean outerInlineTagIsSnippet;
private boolean somethingSinceNewline;

private JavadocLexer(CharStream input) {
Expand Down Expand Up @@ -158,13 +161,26 @@ private Type consumeToken() throws LexException {
}
somethingSinceNewline = true;

if (input.tryConsumeRegex(INLINE_TAG_OPEN_PATTERN)) {
if (input.tryConsumeRegex(SNIPPET_TAG_OPEN_PATTERN)) {
if (braceDepth.value() == 0) {
braceDepth.increment();
outerInlineTagIsSnippet = true;
return SNIPPET_BEGIN;
}
braceDepth.increment();
return LITERAL;
} else if (input.tryConsumeRegex(INLINE_TAG_OPEN_PATTERN)) {
braceDepth.increment();
return LITERAL;
} else if (input.tryConsume("{")) {
braceDepth.incrementIfPositive();
return LITERAL;
} else if (input.tryConsume("}")) {
if (outerInlineTagIsSnippet && braceDepth.value() == 1) {
braceDepth.decrementIfPositive();
outerInlineTagIsSnippet = false;
return SNIPPET_END;
}
braceDepth.decrementIfPositive();
return LITERAL;
}
Expand Down Expand Up @@ -239,7 +255,10 @@ private Type consumeToken() throws LexException {
}

private boolean preserveExistingFormatting() {
return preDepth.isPositive() || tableDepth.isPositive() || codeDepth.isPositive();
return preDepth.isPositive()
|| tableDepth.isPositive()
|| codeDepth.isPositive()
|| outerInlineTagIsSnippet;
}

private void checkMatchingTags() throws LexException {
Expand Down Expand Up @@ -400,6 +419,7 @@ private static ImmutableList<Token> optionalizeSpacesAfterLinks(List<Token> inpu
* <p>Also trim leading and trailing blank lines, and move the trailing `}` to its own line.
*/
private static ImmutableList<Token> deindentPreCodeBlocks(List<Token> input) {
// TODO: b/323389829 - De-indent {@snippet ...} blocks, too.
ImmutableList.Builder<Token> output = ImmutableList.builder();
for (PeekingIterator<Token> tokens = peekingIterator(input.iterator()); tokens.hasNext(); ) {
if (tokens.peek().getType() != PRE_OPEN_TAG) {
Expand Down Expand Up @@ -528,6 +548,7 @@ private static boolean hasMultipleNewlines(String s) {
private static final Pattern BLOCKQUOTE_OPEN_PATTERN = openTagPattern("blockquote");
private static final Pattern BLOCKQUOTE_CLOSE_PATTERN = closeTagPattern("blockquote");
private static final Pattern BR_PATTERN = openTagPattern("br");
private static final Pattern SNIPPET_TAG_OPEN_PATTERN = compile("^[{]@snippet\\b");
private static final Pattern INLINE_TAG_OPEN_PATTERN = compile("^[{]@\\w*");
/*
* We exclude < so that we don't swallow following HTML tags. This lets us fix up "foo<p>" (~400
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,38 @@ void writeFooterJavadocTagStart(Token token) {
continuingFooterTag = true;
}

void writeSnippetBegin(Token token) {
requestBlankLine();
writeToken(token);
/*
* We don't request a newline here because we should have at least a colon following on this
* line, and we may have attributes after that.
*
* (If we find it convenient, we could instead consume the entire rest of the line as part of
* the same token as `{@snippet` itself. But we already would never split the rest of the line
* across lines (because we preserve whitespace), so that might not accomplish anything. Plus,
* we'd probably want to be careful not to swallow an expectedly early closing `}`.)
*/
}

void writeSnippetEnd(Token token) {
/*
* We don't request a newline here because we have preserved all newlines that existed in the
* input. TODO: b/323389829 - Improve upon that. Specifically:
*
* - If there is not yet a newline, we should add one.
*
* - If there are multiple newlines, we should probably collapse them.
*
* - If the closing brace isn't indented as we'd want (as in the link below, in which the whole
* @apiNote isn't indented), we should indent it.
*
* https://github.com/openjdk/jdk/blob/1ebf2cf639300728ffc024784f5dc1704317b0b3/src/java.base/share/classes/java/util/Collections.java#L5993-L6006
*/
writeToken(token);
requestBlankLine();
}

void writeListOpen(Token token) {
requestBlankLine();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ enum Type {
END_JAVADOC,
/** The {@code @foo} that begins a block Javadoc tag like {@code @throws}. */
FOOTER_JAVADOC_TAG_START,
/** The opening {@code {@snippet} of a code snippet. */
SNIPPET_BEGIN,
/** The closing {@code }} of a code snippet. */
SNIPPET_END,
LIST_OPEN_TAG,
LIST_CLOSE_TAG,
LIST_ITEM_OPEN_TAG,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -906,6 +906,48 @@ public void unicodeCharacterCountArguableBug() {
doFormatTest(input, expected);
}

@Test
public void blankLinesAroundSnippetAndNoMangling() {
String[] input = {
"/**", //
" * hello world",
" * {@snippet :",
" * public class Foo {",
" * private String s;",
" * }",
" * }",
" * hello again",
" */",
"class Test {}",
};
String[] expected = {
"/**", //
" * hello world",
" *",
" * {@snippet :",
" * public class Foo {",
" * private String s;",
" * }",
" * }",
" *",
" * hello again",
" */",
"class Test {}",
};
doFormatTest(input, expected);
}

@Test
public void notASnippetUnlessOuterTag() {
String[] input = {
"/** I would like to tell you about the {@code {@snippet ...}} tag. */", "class Test {}",
};
String[] expected = {
"/** I would like to tell you about the {@code {@snippet ...}} tag. */", "class Test {}",
};
doFormatTest(input, expected);
}

@Test
public void blankLineBeforeParams() {
String[] input = {
Expand Down
Loading