diff --git a/extra/markdown-extra/MarkdownRuntime.php b/extra/markdown-extra/MarkdownRuntime.php index 6a96a52756b..e1c4c0103e2 100644 --- a/extra/markdown-extra/MarkdownRuntime.php +++ b/extra/markdown-extra/MarkdownRuntime.php @@ -22,11 +22,37 @@ public function __construct(MarkdownInterface $converter) 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); - } + $body = $this->commonWhitespace($body); + $body = $this->removeIndentation($body); return $this->converter->convert($body); } + + protected function commonWhitespace(string $body): string + { + return str_replace(["\t", "\0", "\x0B"], [' ', '', ''], $body); + } + + protected function removeIndentation(string $body): string + { + $indent = $this->minIndentations($body); + if ($indent > 0) { + $body = preg_replace("{^ {{$indent}}}m", '', $body); + } + + return $body; + } + + protected function minIndentations(string $body): int + { + $non_empty_lines = preg_split('%(\r|\n)%', $body, -1, PREG_SPLIT_NO_EMPTY); + + $list = []; + foreach ($non_empty_lines as $line) + { + $list[] = strspn($line, " "); + } + + return min($list); + } } diff --git a/extra/markdown-extra/Tests/FunctionalTest.php b/extra/markdown-extra/Tests/FunctionalTest.php index 368a0467b3b..0c0c55f5c4d 100644 --- a/extra/markdown-extra/Tests/FunctionalTest.php +++ b/extra/markdown-extra/Tests/FunctionalTest.php @@ -27,35 +27,28 @@ class FunctionalTest extends TestCase /** * @dataProvider getMarkdownTests */ - public function testMarkdown(string $template, string $expected): void + public function testMarkdown(string $markdown, string $expected): void { foreach ([LeagueMarkdown::class, ErusevMarkdown::class, /*MichelfMarkdown::class,*/ DefaultMarkdown::class] as $class) { - $twig = new Environment(new ArrayLoader([ - 'index' => $template, - 'html' => <<getTwig($class, [ + 'apply' => "{% apply markdown_to_html %}\n{$markdown}\n{% endapply %}", + 'include' => "{{ include('md')|markdown_to_html }}", + 'indent' => "{{ include('indent_md')|markdown_to_html }}", + 'md' => $markdown, + 'indent_md' => ltrim(str_replace("\n", "\n\t", "\n$markdown"), "\n"), + ]); -Great! -EOF - ])); - $twig->addExtension(new MarkdownExtension()); - $twig->addRuntimeLoader(new class($class) implements RuntimeLoaderInterface { - private $class; + $twig_md = trim($twig->render('apply')); + $this->assertMatchesRegularExpression('{'.$expected.'}m', $twig_md); - public function __construct(string $class) - { - $this->class = $class; - } + $twig_md = trim($twig->render('include')); + $this->assertMatchesRegularExpression('{'.$expected.'}m', $twig_md); - public function load($c) - { - if (MarkdownRuntime::class === $c) { - return new $c(new $this->class()); - } - } - }); - $this->assertMatchesRegularExpression('{'.$expected.'}m', trim($twig->render('index'))); + $twig_md = trim($twig->render('indent')); + $this->assertMatchesRegularExpression('{'.$expected.'}m', $twig_md); + + $lib_md = trim((new $class)->convert($markdown)); + $this->assertEquals($lib_md, $twig_md, "Twig output versus {$class} output."); } } @@ -63,24 +56,50 @@ public function getMarkdownTests() { return [ [<<Hello\n+

Great!

"], + [<<Hello\n+

Great!

"], - ["{{ include('html')|markdown_to_html }}", "

Hello

\n+

Great!

"], + , "

Leading

\n+

Linebreak

"], + + [<<Code\n?\n+

Paragraph

"], ]; } + + private function getTwig(string $class, array $templates): Environment + { + $twig = new Environment(new ArrayLoader($templates)); + $twig->addExtension(new MarkdownExtension()); + $twig->addRuntimeLoader(new class($class) implements RuntimeLoaderInterface { + private $class; + + public function __construct(string $class) + { + $this->class = $class; + } + + public function load($c) + { + if (MarkdownRuntime::class === $c) + { + return new $c(new $this->class()); + } + } + }); + return $twig; + } }