diff --git a/src/Rules/PreRule.php b/src/Rules/PreRule.php index 15b3113..7c8cc8d 100644 --- a/src/Rules/PreRule.php +++ b/src/Rules/PreRule.php @@ -10,16 +10,18 @@ final class PreRule implements Rule, ProvidesFirstChar { - public string $firstChar = '`'; + public string $firstChar = '`~'; public function shouldParse(Parser $parser): bool { - return $parser->comesNext('```', 3); + return $parser->comesNext('```', 3) || $parser->comesNext('~~~', 3); } public function parse(Parser $parser): Token { - $parser->consumeIncluding('```'); + // A fence is a run of at least three backticks or tildes, and is + // closed by a run of the same character. + $fence = $parser->consumeWhile($parser->current ?? '`'); $language = $parser->consumeUntil(Parser::WHITESPACE); @@ -27,9 +29,9 @@ public function parse(Parser $parser): Token $parser->consumeWhile(Parser::NEW_LINE); - $content = $parser->consumeUntilString('```'); + $content = $parser->consumeUntilString($fence); - $parser->consumeIncluding('```'); + $parser->consumeIncluding($fence); $parser->consumeWhile(Parser::NEW_LINE); // Remove trailing newline. diff --git a/tests/Rules/PreRuleTest.php b/tests/Rules/PreRuleTest.php index d3c036d..0e613cf 100644 --- a/tests/Rules/PreRuleTest.php +++ b/tests/Rules/PreRuleTest.php @@ -5,6 +5,8 @@ use PHPUnit\Framework\Attributes\Test; use Tempest\Markdown\Parser; use Tempest\Markdown\Rules\PreRule; +use Tempest\Markdown\Rules\StrikethroughRule; +use Tempest\Markdown\Rules\TextRule; use Tempest\Markdown\Tests\ParserTestCase; class PreRuleTest extends ParserTestCase @@ -88,4 +90,54 @@ public function test_lex_with_backtick_in_content(): void $html, ); } + + #[Test] + public function lex_tilde_fence(): void + { + $html = + (string) new Parser(highlighter: null, rules: [new PreRule()])->parse( + "~~~\ncode\n~~~", + ); + + $this->assertSame('
code', $html); + } + + #[Test] + public function lex_tilde_fence_with_language(): void + { + $html = + (string) new Parser(highlighter: null, rules: [new PreRule()])->parse( + "~~~php\n\$a = 1;\n~~~", + ); + + $this->assertSame('
$a = 1;', $html); + } + + #[Test] + public function lex_longer_fence_may_contain_a_shorter_one(): void + { + $parser = new Parser(highlighter: null, rules: [new PreRule()]); + + $this->assertSame( + '
a ``` b', + (string) $parser->parse("````\na ``` b\n````"), + ); + + $this->assertSame( + '
a ~~~ b', + (string) $parser->parse("~~~~\na ~~~ b\n~~~~"), + ); + } + + #[Test] + public function lex_does_not_take_over_strikethrough(): void + { + $html = (string) new Parser(highlighter: null, rules: [ + new PreRule(), + new StrikethroughRule(), + new TextRule(), + ])->parse('a ~~b~~ c'); + + $this->assertSame('a