Skip to content

Commit 7135f3d

Browse files
author
Markus Paulsen
committed
Count the text a code span makes visible again
A backtick-delimited comment marker is not a comment. GitHub renders `<!--`, whatever follows it and `-->` in full, so a limit that skipped the text between them measured nothing a reader would see, and the same misreading could swallow a heading between a marker shown in prose and the next genuine comment. Inline code spans therefore join the constructs recognised in the same left-to-right scan, with both delimiter runs guarded on both sides so a run of two cannot close on the tail of a run of three, and with the search for the close stopping where the block does, at a blank line or at a heading. The opening run is possessive, because the body is untrusted input on a fork pull request and a run that never closes must cost one scan.
1 parent 3f057c6 commit 7135f3d

1 file changed

Lines changed: 24 additions & 10 deletions

File tree

.github/scripts/CheckPullRequestTemplate.java

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,16 @@ public class CheckPullRequestTemplate {
3232
private static final Pattern HEADING = Pattern.compile("^## .+$", Pattern.MULTILINE);
3333

3434
/**
35-
* The two constructs whose contents are not ordinary prose: an HTML comment, and a fenced code
36-
* block. Both alternatives run to the end of the text when they are never closed, which is what
37-
* Markdown renders and therefore what a reader sees.
35+
* The constructs whose contents are not ordinary prose: an HTML comment, a fenced code block,
36+
* and an inline code span. The comment and fence alternatives run to the end of the text when
37+
* they are never closed, which is what Markdown renders and therefore what a reader sees.
3838
*
39-
* <p>They are matched by one pattern rather than one after the other, because either can contain
40-
* the other's opening marker and only the one that starts first is real. Matching comments first
41-
* would let a {@code <!--} shown inside a code block swallow everything up to the next genuine
42-
* {@code -->}; matching fences first would let a fence quoted inside a comment do the same. A
43-
* single left-to-right scan asks the only question that has an answer: which one starts here?
39+
* <p>They are matched by one pattern rather than one after the other, because each can contain
40+
* another's opening marker and only the one that starts first is real. Matching comments first
41+
* would let a {@code <!--} shown in code swallow everything up to the next genuine {@code -->},
42+
* and the text in between would then be counted by nobody although a reader sees all of it;
43+
* matching code first would let a fence quoted inside a comment do the same. A single
44+
* left-to-right scan asks the only question that has an answer: which one starts here?
4445
*
4546
* <p>The fence alternatives follow CommonMark: up to three spaces of indent, at least three
4647
* backticks or tildes, closed by a run of the same character at least as long as the opening
@@ -49,11 +50,23 @@ public class CheckPullRequestTemplate {
4950
* run is matched possessively so that it cannot be given back to let an inner, shorter run pass
5051
* as the close, and a backtick fence's info string may not contain a backtick, as CommonMark
5152
* requires.
53+
*
54+
* <p>The inline alternative is a code span: a whole run of backticks, closed by a whole run of
55+
* the same length. Both ends are guarded on both sides, because a run of two that opens nothing
56+
* would otherwise close on the last two backticks of a run of three further down, and swallow
57+
* the heading in between. It comes last, so a fence opening a line is
58+
* read as a fence. A span may wrap onto the next line, but the search for its close stops
59+
* where the block it sits in does: at a blank line, and at a heading, which needs no blank line
60+
* to interrupt a paragraph. A stray backtick above a heading must not swallow it. Both the
61+
* opening run and the search for the close are written
62+
* so that neither can be given back. A body is untrusted input on a fork pull request, and a
63+
* run of backticks that never closes must cost one scan rather than an exponential one.
5264
*/
5365
private static final Pattern NOT_PROSE = Pattern.compile(
5466
"<!--.*?(?:-->|\\z)"
5567
+ "|^ {0,3}(?<backticks>`{3,}+)[^`\\n]*\\n.*?(?:^ {0,3}\\k<backticks>`*[ \\t]*$|\\z)"
56-
+ "|^ {0,3}(?<tildes>~{3,}+)[^\\n]*\\n.*?(?:^ {0,3}\\k<tildes>~*[ \\t]*$|\\z)",
68+
+ "|^ {0,3}(?<tildes>~{3,}+)[^\\n]*\\n.*?(?:^ {0,3}\\k<tildes>~*[ \\t]*$|\\z)"
69+
+ "|(?<!`)(?<span>`++)(?:(?!\\n(?:[ \\t]*\\n| {0,3}#{1,6}(?:[ \\t]|$))).)+?(?<!`)\\k<span>(?!`)",
5770
Pattern.DOTALL | Pattern.MULTILINE);
5871

5972
/** The opening of the comment alternative of {@link #NOT_PROSE}, to tell the two apart. */
@@ -291,7 +304,8 @@ private static List<String> outOfOrder(List<String> required, List<String> found
291304
}
292305

293306
/**
294-
* The text with every comment and every fenced block replaced by spaces of its own length,
307+
* The text with every comment, fenced block and inline code span replaced by spaces of its own
308+
* length,
295309
* newlines kept. Headings are located in this copy and sections are then cut out of the
296310
* original at the same offsets, which the equal length guarantees stays exact.
297311
*

0 commit comments

Comments
 (0)