Skip to content
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 @@ -388,6 +388,16 @@ private static ImmutableList<Token> joinAdjacentLiteralsAndAdjacentWhitespace(Li
continue;
}

if (seenWhitespace.indexOf("\n") >= 0
&& !hasMultipleNewlines(seenWhitespace.toString())
&& isHyphenatedWordEnd(accumulated)
&& tokens.peek().getType() == LITERAL
&& isWordStart(tokens.peek().getValue())
&& !isSuspendedHyphenConjunction(tokens.peek().getValue())) {
accumulated.append(tokens.next().getValue());
continue;
}

output.add(new Token(LITERAL, accumulated.toString()));
accumulated.setLength(0);

Expand All @@ -399,13 +409,26 @@ private static ImmutableList<Token> joinAdjacentLiteralsAndAdjacentWhitespace(Li
// We have another token coming, possibly of type OTHER. Leave it for the next iteration.
}

/*
* TODO(cpovirk): Another case where we could try to join tokens is if a line ends with
* /[^ -]-/, as in "non-\nblocking."
*/
return output.build();
}

private static boolean isHyphenatedWordEnd(CharSequence cs) {
int length = cs.length();
return length >= 2 && cs.charAt(length - 1) == '-' && isWordChar(cs.charAt(length - 2));
}

private static boolean isWordChar(char c) {
return Character.isLetterOrDigit(c) || c == '_';
}

private static boolean isWordStart(String s) {
return !s.isEmpty() && isWordChar(s.charAt(0));
}

private static boolean isSuspendedHyphenConjunction(String s) {
return s.equals("and") || s.equals("or");
}

/**
* Where the input has two consecutive line breaks between literals, insert a {@code <p>} tag between the literals.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,7 @@ void writeFooterJavadocTagStart(Token token) {
*/
postWriteModifiedContinuingListCount.reset();

if (!wroteAnythingSignificant) {
// Javadoc consists solely of tags. This is frowned upon in general but OK for @Overrides.
} else if (!continuingFooterTag) {
if (!continuingFooterTag) {
// First footer tag after a body tag.
requestBlankLine();
} else {
Expand Down Expand Up @@ -328,6 +326,12 @@ private void writeToken(Token token) {
requestNewline();
}

if (!wroteAnythingSignificant) {
// Nothing precedes the first token but the opening ∕✱✱ and its newline, so no requested
// whitespace (e.g., the blank line a <pre> or <ul> asks for) belongs before it.
requestedWhitespace = NONE;
}

if (requestedWhitespace == BLANK_LINE
&& (postWriteModifiedContinuingListCount.isPositive() || continuingFooterTag)) {
/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1625,4 +1625,90 @@ void preCodeMixedStarAndBareLinesKeepRelativeIndent() {
};
doFormatTest(input, expected);
}

@Test
void hyphenatedLineBreakJoined() {
String[] input = {
"/**", //
" * This calculation requires an infinite-",
" * precision number.",
" */",
"class Test {}",
};
String[] expected = {
"/** This calculation requires an infinite-precision number. */", //
"class Test {}",
};
doFormatTest(input, expected);
}

@Test
void suspendedHyphenPreserved() {
String[] input = {
"/**", //
" * Both pre-",
" * and post-processing steps.",
" */",
"class Test {}",
};
String[] expected = {
"/** Both pre- and post-processing steps. */", //
"class Test {}",
};
doFormatTest(input, expected);
}

@Test
void hyphenBeforeParagraphBreakNotJoined() {
String[] input = {
"/**", //
" * Ends with a non-",
" *",
" * blocking paragraph.",
" */",
"class Test {}",
};
String[] expected = {
"/**", //
" * Ends with a non-",
" *",
" * <p>blocking paragraph.",
" */",
"class Test {}",
};
doFormatTest(input, expected);
}

@Test
void preBlockAsFirstContentGetsNoBlankLines() {
String[] input = {
"/**", //
" * <pre>{@code",
" * class Demo {",
" * int x;",
" * }",
" * }</pre>",
" */",
"class Test {}",
};
doFormatTest(input, input);
}

@Test
void listAsFirstContentGetsNoBlankLines() {
String[] input = {
"/** <ul><li>one <li>two</ul> */", //
"class Test {}",
};
String[] expected = {
"/**", //
" * <ul>",
" * <li>one",
" * <li>two",
" * </ul>",
" */",
"class Test {}",
};
doFormatTest(input, expected);
}
}
Loading