mirror of
https://github.com/twigphp/Twig.git
synced 2026-08-17 08:50:50 +00:00
Fix markdown_to_html mangling content that starts with a blank line
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
* Fix nested `block()` calls to resolve against the overriding template when a block rendered through `block(name, template)` calls `parent()`
|
||||
* Stop reporting a skipped test in `IntegrationTestCase` when there is no legacy test to run
|
||||
* Fix `markdown_to_html` to strip the indentation shared by all lines instead of mangling content that starts with a blank line
|
||||
* Make the `IntegrationTestCase` and `NodeTestCase` test helpers compatible with PHPUnit 11
|
||||
* Cast printed expressions to string so values that cannot be converted to a string (arrays, non-`Stringable` objects, ...) report a usable stack trace at the print location
|
||||
* Make the `include()` function return a `Markup` object so an assigned result is not re-escaped when printed
|
||||
|
||||
@@ -22,11 +22,55 @@ class MarkdownRuntime
|
||||
|
||||
public function convert(string $body): string
|
||||
{
|
||||
// remove indentation
|
||||
if ($white = substr($body, 0, strspn($body, " \t\r\n\0\x0B"))) {
|
||||
$body = preg_replace("{^$white}m", '', $body);
|
||||
return $this->converter->convert(self::stripCommonIndentation($body));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the indentation shared by all non-blank lines.
|
||||
*
|
||||
* This lets authors indent a `{% apply markdown_to_html %}` block to match
|
||||
* the surrounding template without that indentation leaking into Markdown
|
||||
* (where leading whitespace is significant, e.g. code blocks).
|
||||
*/
|
||||
private static function stripCommonIndentation(string $body): string
|
||||
{
|
||||
$lines = explode("\n", $body);
|
||||
|
||||
$indent = null;
|
||||
foreach ($lines as $line) {
|
||||
if ('' === trim($line)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$lineIndent = substr($line, 0, strspn($line, " \t"));
|
||||
if (null === $indent) {
|
||||
$indent = $lineIndent;
|
||||
continue;
|
||||
}
|
||||
|
||||
$max = min(\strlen($indent), \strlen($lineIndent));
|
||||
$common = 0;
|
||||
while ($common < $max && $indent[$common] === $lineIndent[$common]) {
|
||||
++$common;
|
||||
}
|
||||
$indent = substr($indent, 0, $common);
|
||||
|
||||
if ('' === $indent) {
|
||||
return $body;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->converter->convert($body);
|
||||
if (null === $indent || '' === $indent) {
|
||||
return $body;
|
||||
}
|
||||
|
||||
$length = \strlen($indent);
|
||||
foreach ($lines as $i => $line) {
|
||||
if (str_starts_with($line, $indent)) {
|
||||
$lines[$i] = substr($line, $length);
|
||||
}
|
||||
}
|
||||
|
||||
return implode("\n", $lines);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ use Twig\Extra\Markdown\DefaultMarkdown;
|
||||
use Twig\Extra\Markdown\ErusevMarkdown;
|
||||
use Twig\Extra\Markdown\LeagueMarkdown;
|
||||
use Twig\Extra\Markdown\MarkdownExtension;
|
||||
use Twig\Extra\Markdown\MarkdownInterface;
|
||||
use Twig\Extra\Markdown\MarkdownRuntime;
|
||||
use Twig\Extra\Markdown\MichelfMarkdown;
|
||||
use Twig\Loader\ArrayLoader;
|
||||
@@ -77,6 +78,42 @@ EOF, "<h1>Hello</h1>\n+<p>Great!</p>"],
|
||||
{% endapply %}
|
||||
EOF, "<h1>Hello</h1>\n+<p>Great!</p>"],
|
||||
["{{ include('html')|markdown_to_html }}", "<h1>Hello</h1>\n+<p>Great!</p>"],
|
||||
[<<<EOF
|
||||
{% apply markdown_to_html %}
|
||||
|
||||
Paragraph 1
|
||||
|
||||
Paragraph 2
|
||||
{% endapply %}
|
||||
EOF, "<p>Paragraph 1</p>\n+<p>Paragraph 2</p>"],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getIndentationTests
|
||||
*/
|
||||
public function testStripsCommonIndentation(string $body, string $expected)
|
||||
{
|
||||
$runtime = new MarkdownRuntime(new class implements MarkdownInterface {
|
||||
public function convert(string $body): string
|
||||
{
|
||||
return $body;
|
||||
}
|
||||
});
|
||||
|
||||
$this->assertSame($expected, $runtime->convert($body));
|
||||
}
|
||||
|
||||
public static function getIndentationTests()
|
||||
{
|
||||
return [
|
||||
'leading blank line keeps blank lines' => ["\nParagraph 1\n\nParagraph 2", "\nParagraph 1\n\nParagraph 2"],
|
||||
'common indentation is removed' => ["\n Hello\n =====\n\n Great!\n", "\nHello\n=====\n\nGreat!\n"],
|
||||
'minimal common indentation is removed' => [" a\n b\n", "a\n b\n"],
|
||||
'indented code block before non-indented prose is preserved' => [" Code\n\nParagraph\n", " Code\n\nParagraph\n"],
|
||||
'tab indentation is removed' => ["\tHello\n\tGreat!\n", "Hello\nGreat!\n"],
|
||||
'mixed tabs and spaces are left untouched' => ["\ta\n b\n", "\ta\n b\n"],
|
||||
'blank lines are ignored when computing indentation' => [" a\n\n b\n", "a\n\nb\n"],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user