|
27 | 27 | use App\Utils\Utils; |
28 | 28 | use Doctrine\Common\Collections\Collection; |
29 | 29 | use Doctrine\ORM\EntityManagerInterface; |
| 30 | +use Ramsey\Uuid\Uuid; |
30 | 31 | use Symfony\Component\DependencyInjection\Attribute\Autowire; |
31 | 32 | use Symfony\Component\Intl\Countries; |
32 | 33 | use Symfony\Component\Intl\Exception\MissingResourceException; |
|
38 | 39 | use Twig\Environment; |
39 | 40 | use Twig\Extension\AbstractExtension; |
40 | 41 | use Twig\Extension\GlobalsInterface; |
| 42 | +use Twig\Extra\Markdown\MarkdownRuntime; |
41 | 43 | use Twig\Runtime\EscaperRuntime; |
42 | 44 | use Twig\TwigFilter; |
43 | 45 | use Twig\TwigFunction; |
44 | 46 |
|
45 | 47 | class TwigExtension extends AbstractExtension implements GlobalsInterface |
46 | 48 | { |
| 49 | + private array $latexFound; |
| 50 | + |
47 | 51 | /** |
48 | 52 | * @param array<int, bool> $renderedSources |
49 | 53 | */ |
@@ -126,6 +130,7 @@ public function getFilters(): array |
126 | 130 | new TwigFilter('medalType', $this->awards->medalType(...)), |
127 | 131 | new TwigFilter('numTableActions', $this->numTableActions(...)), |
128 | 132 | new TwigFilter('extensionToMime', $this->extensionToMime(...)), |
| 133 | + new TwigFilter('domjudgeMarkdownToHtml', $this->domjudgeMarkdownToHTML(...), ['is_safe' => ['html']]), |
129 | 134 | ]; |
130 | 135 | } |
131 | 136 |
|
@@ -1381,4 +1386,35 @@ public function extensionToMime(string $extension): string |
1381 | 1386 | { |
1382 | 1387 | return DOMJudgeService::EXTENSION_TO_MIMETYPE[$extension]; |
1383 | 1388 | } |
| 1389 | + |
| 1390 | + /** |
| 1391 | + * Extract all LaTeX code from the given string, sanitize the markdown and |
| 1392 | + * inject the original LaTeX code back so MathJax can render it. |
| 1393 | + */ |
| 1394 | + public function domjudgeMarkdownToHTML(string $markdown): string |
| 1395 | + { |
| 1396 | + $latexPlaceholder = Uuid::uuid4()->toString(); |
| 1397 | + while(str_contains($markdown, $latexPlaceholder)) { |
| 1398 | + $latexPlaceholder = Uuid::uuid4()->toString(); |
| 1399 | + } |
| 1400 | + |
| 1401 | + $markdown = preg_replace_callback( |
| 1402 | + '/(\$[\s\S]*?\$)/', |
| 1403 | + function (array $matches) use ($latexPlaceholder) { |
| 1404 | + // Store and replace matches |
| 1405 | + $this->latexFound[] = $matches[1]; |
| 1406 | + return $latexPlaceholder; |
| 1407 | + }, |
| 1408 | + $markdown |
| 1409 | + ); |
| 1410 | + |
| 1411 | + /** @var MarkdownRuntime $runtime */ |
| 1412 | + $runtime = $this->twig->getRuntime(MarkdownRuntime::class); |
| 1413 | + $markdown = (string)$runtime->convert($markdown); |
| 1414 | + |
| 1415 | + return preg_replace_callback( |
| 1416 | + '/'.$latexPlaceholder.'/', |
| 1417 | + fn() => array_shift($this->latexFound), $markdown |
| 1418 | + ); |
| 1419 | + } |
1384 | 1420 | } |
0 commit comments