From ee62e638129c3bfb16ef15e44da2817c6ad3ded3 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 3 Apr 2023 13:16:38 +0200 Subject: [PATCH 01/34] Add Caddy server config files to the list of known formats --- src/Directive/ConfigurationBlockDirective.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Directive/ConfigurationBlockDirective.php b/src/Directive/ConfigurationBlockDirective.php index 8b0c8cb..cefc26c 100644 --- a/src/Directive/ConfigurationBlockDirective.php +++ b/src/Directive/ConfigurationBlockDirective.php @@ -18,6 +18,7 @@ class ConfigurationBlockDirective extends SubDirective { private const LANGUAGE_LABELS = [ + 'caddy' => 'Caddy' 'env' => 'Bash', 'html+jinja' => 'Twig', 'html+php' => 'PHP', From 5d44ed29bea1c488647145b820a7c5afa3925012 Mon Sep 17 00:00:00 2001 From: Alexander Schranz Date: Mon, 3 Apr 2023 21:48:00 +0200 Subject: [PATCH 02/34] Fix language labels array of ConfigurationBlockDirective --- src/Directive/ConfigurationBlockDirective.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Directive/ConfigurationBlockDirective.php b/src/Directive/ConfigurationBlockDirective.php index cefc26c..a13f546 100644 --- a/src/Directive/ConfigurationBlockDirective.php +++ b/src/Directive/ConfigurationBlockDirective.php @@ -18,7 +18,7 @@ class ConfigurationBlockDirective extends SubDirective { private const LANGUAGE_LABELS = [ - 'caddy' => 'Caddy' + 'caddy' => 'Caddy', 'env' => 'Bash', 'html+jinja' => 'Twig', 'html+php' => 'PHP', From 048f43e6056678846325d1fff6d3f66acfd320e4 Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Thu, 23 Mar 2023 20:44:15 +0100 Subject: [PATCH 03/34] Avoid link with same ID's --- src/Renderers/TitleNodeRenderer.php | 55 +++++++++++++++++++ src/SymfonyHTMLFormat.php | 10 ++++ .../default/html/header-title.html.twig | 2 +- src/Templates/rtd/html/header-title.html.twig | 4 +- tests/IntegrationTest.php | 10 ++++ .../fixtures/expected/blocks/nodes/title.html | 3 + tests/fixtures/source/blocks/nodes/title.rst | 3 + 7 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 src/Renderers/TitleNodeRenderer.php diff --git a/src/Renderers/TitleNodeRenderer.php b/src/Renderers/TitleNodeRenderer.php new file mode 100644 index 0000000..2012be6 --- /dev/null +++ b/src/Renderers/TitleNodeRenderer.php @@ -0,0 +1,55 @@ + + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace SymfonyDocsBuilder\Renderers; + +use Doctrine\RST\Environment; +use Doctrine\RST\Nodes\TitleNode; +use Doctrine\RST\Renderers\NodeRenderer; +use Doctrine\RST\Templates\TemplateRenderer; + +class TitleNodeRenderer implements NodeRenderer +{ + /** @var TitleNode */ + private $titleNode; + + /** @var TemplateRenderer */ + private $templateRenderer; + + private static $idUsagesCountByFilename = []; + + public function __construct(TitleNode $titleNode, TemplateRenderer $templateRenderer) + { + $this->titleNode = $titleNode; + $this->templateRenderer = $templateRenderer; + } + + public function render(): string + { + $filename = $this->titleNode->getEnvironment()->getCurrentFileName(); + $id = $this->titleNode->getId(); + + $idUsagesCount = self::$idUsagesCountByFilename[$filename][$id] ?? 0; + + if (0 === $idUsagesCount) { + $computedId = $this->titleNode->getId(); + } else { + $computedId = Environment::slugify($this->titleNode->getValue()->getText().'-'.$idUsagesCount); + } + + self::$idUsagesCountByFilename[$filename][$id] = $idUsagesCount + 1; + + return $this->templateRenderer->render('header-title.html.twig', [ + 'titleNode' => $this->titleNode, + 'id' => $computedId, + ]); + } +} diff --git a/src/SymfonyHTMLFormat.php b/src/SymfonyHTMLFormat.php index 6dcb04b..fd7f35f 100644 --- a/src/SymfonyHTMLFormat.php +++ b/src/SymfonyHTMLFormat.php @@ -14,6 +14,7 @@ use Doctrine\RST\Formats\Format; use Doctrine\RST\Nodes\CodeNode; use Doctrine\RST\Nodes\SpanNode; +use Doctrine\RST\Nodes\TitleNode; use Doctrine\RST\Renderers\CallableNodeRendererFactory; use Doctrine\RST\Renderers\NodeRendererFactory; use Doctrine\RST\Templates\TemplateRenderer; @@ -77,6 +78,15 @@ function (SpanNode $node) { } ); + $nodeRendererFactories[TitleNode::class] = new CallableNodeRendererFactory( + function (TitleNode $node) { + return new Renderers\TitleNodeRenderer( + $node, + $this->templateRenderer + ); + } + ); + return $nodeRendererFactories; } } diff --git a/src/Templates/default/html/header-title.html.twig b/src/Templates/default/html/header-title.html.twig index 0524726..0ffbc46 100644 --- a/src/Templates/default/html/header-title.html.twig +++ b/src/Templates/default/html/header-title.html.twig @@ -1 +1 @@ -{{ titleNode.value.render()|raw }} +{{ titleNode.value.render()|raw }} diff --git a/src/Templates/rtd/html/header-title.html.twig b/src/Templates/rtd/html/header-title.html.twig index f91e370..fe2b810 100644 --- a/src/Templates/rtd/html/header-title.html.twig +++ b/src/Templates/rtd/html/header-title.html.twig @@ -1,4 +1,4 @@ - + {{ titleNode.value.render()|raw }} - + diff --git a/tests/IntegrationTest.php b/tests/IntegrationTest.php index ccc5a49..ca97f97 100644 --- a/tests/IntegrationTest.php +++ b/tests/IntegrationTest.php @@ -17,9 +17,19 @@ use Symfony\Component\Finder\Finder; use SymfonyDocsBuilder\DocBuilder; use SymfonyDocsBuilder\KernelFactory; +use SymfonyDocsBuilder\Renderers\TitleNodeRenderer; class IntegrationTest extends AbstractIntegrationTest { + public static function setUpBeforeClass(): void + { + $reflection = new \ReflectionClass(TitleNodeRenderer::class); + $property = $reflection->getProperty('idUsagesCountByFilename'); + $property->setAccessible(true); + + $property->setValue([]); + } + /** * @dataProvider integrationProvider */ diff --git a/tests/fixtures/expected/blocks/nodes/title.html b/tests/fixtures/expected/blocks/nodes/title.html index 5ba7a4b..2106a60 100644 --- a/tests/fixtures/expected/blocks/nodes/title.html +++ b/tests/fixtures/expected/blocks/nodes/title.html @@ -10,5 +10,8 @@

Перевірка робочого середовища

Lorem ipsum dolor sit amet, consectetur adipisicing elit.

+ diff --git a/tests/fixtures/source/blocks/nodes/title.rst b/tests/fixtures/source/blocks/nodes/title.rst index 7014b14..6026921 100644 --- a/tests/fixtures/source/blocks/nodes/title.rst +++ b/tests/fixtures/source/blocks/nodes/title.rst @@ -12,3 +12,6 @@ Lorem ipsum dolor sit amet, consectetur adipisicing elit. ----------------------------- Lorem ipsum dolor sit amet, consectetur adipisicing elit. + +``Checking your Work Environment`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \ No newline at end of file From 87859d794e031d8f1b615d0712f123895024239a Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 13 Apr 2023 18:02:38 +0200 Subject: [PATCH 04/34] Fix the TOC generation with unique links --- src/DocsKernel.php | 6 +++ src/Generator/JsonGenerator.php | 41 ++++++++++------- src/Listener/DuplicatedHeaderIdListener.php | 25 +++++++++++ src/Renderers/TitleNodeRenderer.php | 5 +++ tests/IntegrationTest.php | 9 ---- tests/JsonIntegrationTest.php | 49 ++++++++++++++++++++- tests/fixtures/source/json/design.rst | 16 ++++++- 7 files changed, 122 insertions(+), 29 deletions(-) create mode 100644 src/Listener/DuplicatedHeaderIdListener.php diff --git a/src/DocsKernel.php b/src/DocsKernel.php index 1f23442..8ffbedd 100644 --- a/src/DocsKernel.php +++ b/src/DocsKernel.php @@ -20,6 +20,7 @@ use SymfonyDocsBuilder\Listener\AdmonitionListener; use SymfonyDocsBuilder\Listener\AssetsCopyListener; use SymfonyDocsBuilder\Listener\CopyImagesListener; +use SymfonyDocsBuilder\Listener\DuplicatedHeaderIdListener; class DocsKernel extends Kernel { @@ -49,6 +50,11 @@ private function initializeListeners(EventManager $eventManager, ErrorManager $e new AdmonitionListener() ); + $eventManager->addEventListener( + PreParseDocumentEvent::PRE_PARSE_DOCUMENT, + new DuplicatedHeaderIdListener() + ); + $eventManager->addEventListener( PreNodeRenderEvent::PRE_NODE_RENDER, new CopyImagesListener($this->buildConfig, $errorManager) diff --git a/src/Generator/JsonGenerator.php b/src/Generator/JsonGenerator.php index 7d429be..51de0de 100644 --- a/src/Generator/JsonGenerator.php +++ b/src/Generator/JsonGenerator.php @@ -69,7 +69,7 @@ public function generateJson(string $masterDocument = 'index'): array $crawler = new Crawler(file_get_contents($this->buildConfig->getOutputDir().'/'.$filename.'.html')); // happens when some doc is a partial included in other doc an it doesn't have any titles - $toc = false === current($metaEntry->getTitles()) ? [] : $this->generateToc($metaEntry, current($metaEntry->getTitles())[1]); + $toc = $this->generateToc($metaEntry, $crawler); $next = $this->determineNext($parserFilename, $flattenedTocTree, $masterDocument); $prev = $this->determinePrev($parserFilename, $flattenedTocTree); $data = [ @@ -102,26 +102,35 @@ public function setOutput(SymfonyStyle $output) $this->output = $output; } - private function generateToc(MetaEntry $metaEntry, ?array $titles, int $level = 1): array + private function generateToc(MetaEntry $metaEntry, Crawler $crawler): array { - if (null === $titles) { - return []; + $flatTocTree = []; + + foreach ($crawler->filter('h2, h3') as $heading) { + $headerId = $heading->getAttribute('id') ?? Environment::slugify($heading->textContent); + + // this tocTree stores items sequentially (h2, h2, h3, h3, h2, h3, etc.) + $flatTocTree[] = [ + 'level' => 'h2' === $heading->tagName ? 1 : 2, + 'url' => sprintf('%s#%s', $metaEntry->getUrl(), $headerId), + 'page' => u($metaEntry->getUrl())->beforeLast('.html')->toString(), + 'fragment' => $headerId, + 'title' => $heading->textContent, + 'children' => [], + ]; } - $tocTree = []; - - foreach ($titles as $title) { - $tocTree[] = [ - 'level' => $level, - 'url' => sprintf('%s#%s', $metaEntry->getUrl(), Environment::slugify($title[0])), - 'page' => u($metaEntry->getUrl())->beforeLast('.html'), - 'fragment' => Environment::slugify($title[0]), - 'title' => $title[0], - 'children' => $this->generateToc($metaEntry, $title[1], $level + 1), - ]; + // this tocTree stores items nested by level (h2, h2[h3, h3], h2[h3], etc.) + $nestedTocTree = []; + foreach ($flatTocTree as $tocItem) { + if (1 === $tocItem['level']) { + $nestedTocTree[] = $tocItem; + } else { + $nestedTocTree[\count($nestedTocTree) - 1]['children'][] = $tocItem; + } } - return $tocTree; + return $nestedTocTree; } private function determineNext(string $parserFilename, array $flattenedTocTree): ?array diff --git a/src/Listener/DuplicatedHeaderIdListener.php b/src/Listener/DuplicatedHeaderIdListener.php new file mode 100644 index 0000000..b0d139b --- /dev/null +++ b/src/Listener/DuplicatedHeaderIdListener.php @@ -0,0 +1,25 @@ + + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace SymfonyDocsBuilder\Listener; + +use Doctrine\RST\Event\PreParseDocumentEvent; +use SymfonyDocsBuilder\Renderers\TitleNodeRenderer; + +final class DuplicatedHeaderIdListener +{ + public function preParseDocument(PreParseDocumentEvent $event): void + { + // needed because we only need to handle duplicated headers within + // the same file, not across all the files being generated + TitleNodeRenderer::resetHeaderIdCache(); + } +} diff --git a/src/Renderers/TitleNodeRenderer.php b/src/Renderers/TitleNodeRenderer.php index 2012be6..10042c5 100644 --- a/src/Renderers/TitleNodeRenderer.php +++ b/src/Renderers/TitleNodeRenderer.php @@ -32,6 +32,11 @@ public function __construct(TitleNode $titleNode, TemplateRenderer $templateRend $this->templateRenderer = $templateRenderer; } + public static function resetHeaderIdCache(): void + { + self::$idUsagesCountByFilename = []; + } + public function render(): string { $filename = $this->titleNode->getEnvironment()->getCurrentFileName(); diff --git a/tests/IntegrationTest.php b/tests/IntegrationTest.php index ca97f97..a9f9c40 100644 --- a/tests/IntegrationTest.php +++ b/tests/IntegrationTest.php @@ -21,15 +21,6 @@ class IntegrationTest extends AbstractIntegrationTest { - public static function setUpBeforeClass(): void - { - $reflection = new \ReflectionClass(TitleNodeRenderer::class); - $property = $reflection->getProperty('idUsagesCountByFilename'); - $property->setAccessible(true); - - $property->setValue([]); - } - /** * @dataProvider integrationProvider */ diff --git a/tests/JsonIntegrationTest.php b/tests/JsonIntegrationTest.php index 7d3d07b..b9ab092 100644 --- a/tests/JsonIntegrationTest.php +++ b/tests/JsonIntegrationTest.php @@ -10,6 +10,7 @@ namespace SymfonyDocsBuilder\Tests; use SymfonyDocsBuilder\DocBuilder; +use SymfonyDocsBuilder\Renderers\TitleNodeRenderer; class JsonIntegrationTest extends AbstractIntegrationTest { @@ -26,7 +27,7 @@ public function testJsonGeneration(string $filename, array $expectedData) $actualFileData = $fJsons[$filename]; foreach ($expectedData as $key => $expectedKeyData) { $this->assertArrayHasKey($key, $actualFileData, sprintf('Missing key "%s" in file "%s"', $key, $filename)); - $this->assertSame($expectedData[$key], $actualFileData[$key], sprintf('Invalid data for key "%s" in file "%s"', $key, $filename)); + $this->assertSame($expectedKeyData, $actualFileData[$key], sprintf('Invalid data for key "%s" in file "%s"', $key, $filename)); } } @@ -76,9 +77,53 @@ public function getJsonTests() 'title' => 'Design', 'toc_options' => [ 'maxDepth' => 2, - 'numVisibleItems' => 3, + 'numVisibleItems' => 5, 'size' => 'md' ], + 'toc' => [ + [ + 'level' => 1, + 'url' => 'design.html#section-1', + 'page' => 'design', + 'fragment' => 'section-1', + 'title' => 'Section 1', + 'children' => [ + [ + 'level' => 2, + 'url' => 'design.html#some-subsection', + 'page' => 'design', + 'fragment' => 'some-subsection', + 'title' => 'Some subsection', + 'children' => [], + ], + [ + 'level' => 2, + 'url' => 'design.html#some-subsection-1', + 'page' => 'design', + 'fragment' => 'some-subsection-1', + 'title' => 'Some subsection', + 'children' => [], + ], + ], + ], + [ + 'level' => 1, + 'url' => 'design.html#section-2', + 'page' => 'design', + 'fragment' => 'section-2', + 'title' => 'Section 2', + 'children' => [ + [ + 'level' => 2, + 'url' => 'design.html#some-subsection-2', + 'page' => 'design', + 'fragment' => 'some-subsection-2', + 'title' => 'Some subsection', + 'children' => [], + ], + ], + ], + ], ], ]; diff --git a/tests/fixtures/source/json/design.rst b/tests/fixtures/source/json/design.rst index b9a4537..2711ac4 100644 --- a/tests/fixtures/source/json/design.rst +++ b/tests/fixtures/source/json/design.rst @@ -11,11 +11,17 @@ The toctree below should affects the next/prev. The first entry is effectively ignored, as it was already included by the toctree in index.rst (which is parsed first). -Subsection 1 -~~~~~~~~~~~~ +Some subsection +~~~~~~~~~~~~~~~ This is a subsection of the first section. That's all. +Some subsection +~~~~~~~~~~~~~~~ + +This sub-section uses the same title as before to test that the tool +never generated two or more headings with the same ID. + Section 2 --------- @@ -23,6 +29,12 @@ However, crud (which is ALSO included in the toctree in index.rst), WILL be read here, as the "crud" in index.rst has not been read yet (design comes first). Also, design/sub-page WILL be considered. +Some subsection +~~~~~~~~~~~~~~~ + +This sub-section also uses the same title as in the previous section +to test that the tool never generated two or more headings with the same ID. + .. toctree:: :maxdepth: 1 From 73c2ab113c9ac71224e4dd8b62924c6a37bc079d Mon Sep 17 00:00:00 2001 From: Mickael Perraud Date: Tue, 25 Apr 2023 08:32:51 +0200 Subject: [PATCH 05/34] fix: unknown caddy's language --- src/Renderers/CodeNodeRenderer.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Renderers/CodeNodeRenderer.php b/src/Renderers/CodeNodeRenderer.php index fc54b41..cfa46a1 100644 --- a/src/Renderers/CodeNodeRenderer.php +++ b/src/Renderers/CodeNodeRenderer.php @@ -21,6 +21,7 @@ class CodeNodeRenderer implements NodeRenderer private static $isHighlighterConfigured = false; private const LANGUAGES_MAPPING = [ + 'caddy' => 'plaintext', 'env' => 'bash', 'html+jinja' => 'twig', 'html+twig' => 'twig', From 12bf347ca720baaa4ad3088b4f18c88e5c7067cc Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Thu, 18 May 2023 19:20:28 +0200 Subject: [PATCH 06/34] Method reference generate link with scoll to text fragment --- src/Reference/MethodReference.php | 3 ++- tests/fixtures/expected/blocks/references/method.html | 2 +- tests/fixtures/expected/main/datetime.html | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Reference/MethodReference.php b/src/Reference/MethodReference.php index baacc46..632aaa2 100644 --- a/src/Reference/MethodReference.php +++ b/src/Reference/MethodReference.php @@ -39,10 +39,11 @@ public function resolve(Environment $environment, string $data): ResolvedReferen $methodName = explode('::', $data)[1]; + $scrollTextFragment = sprintf('#:~:text=%s', rawurlencode('function '.$methodName)); return new ResolvedReference( $environment->getCurrentFileName(), $methodName.'()', - sprintf('%s/%s.php#method_%s', $this->symfonyRepositoryUrl, str_replace('\\', '/', $className), $methodName), + sprintf('%s/%s.php%s', $this->symfonyRepositoryUrl, str_replace('\\', '/', $className), $scrollTextFragment), [], [ 'title' => sprintf('%s::%s()', $className, $methodName), diff --git a/tests/fixtures/expected/blocks/references/method.html b/tests/fixtures/expected/blocks/references/method.html index 4c58d31..6046098 100644 --- a/tests/fixtures/expected/blocks/references/method.html +++ b/tests/fixtures/expected/blocks/references/method.html @@ -1 +1 @@ -

getCurrentRequest()

+

getCurrentRequest()

diff --git a/tests/fixtures/expected/main/datetime.html b/tests/fixtures/expected/main/datetime.html index c75b859..c302637 100644 --- a/tests/fixtures/expected/main/datetime.html +++ b/tests/fixtures/expected/main/datetime.html @@ -76,7 +76,7 @@

Tip

This is a little tip about something! We an also talk about specific -methods: doRequest(). +methods: doRequest(). Or a namespace: Constraints. Or a PHP function: parse_ini_file. Or a PHP method! Locale::getDefault().

From 200f906fdc9fd86a883fb432786ecf0ce69a595b Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Tue, 6 Jun 2023 19:58:53 -0400 Subject: [PATCH 07/34] Adding the "tabs" directive --- src/Directive/ConfigurationBlockDirective.php | 1 + src/Directive/TabDirective.php | 36 +++++++++++ src/Directive/TabsDirective.php | 60 +++++++++++++++++++ src/KernelFactory.php | 2 + src/Node/TabNode.php | 41 +++++++++++++ .../directives/configuration-block.html.twig | 2 +- tests/IntegrationTest.php | 4 ++ .../expected/blocks/directives/tabs.html | 24 ++++++++ .../source/blocks/directives/tabs.rst | 16 +++++ 9 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 src/Directive/TabDirective.php create mode 100644 src/Directive/TabsDirective.php create mode 100644 src/Node/TabNode.php create mode 100644 tests/fixtures/expected/blocks/directives/tabs.html create mode 100644 tests/fixtures/source/blocks/directives/tabs.rst diff --git a/src/Directive/ConfigurationBlockDirective.php b/src/Directive/ConfigurationBlockDirective.php index a13f546..83850ce 100644 --- a/src/Directive/ConfigurationBlockDirective.php +++ b/src/Directive/ConfigurationBlockDirective.php @@ -66,6 +66,7 @@ public function processSub(Parser $parser, ?Node $document, string $variable, st 'directives/configuration-block.html.twig', [ 'blocks' => $blocks, + 'title' => 'Configuration formats', ] ); diff --git a/src/Directive/TabDirective.php b/src/Directive/TabDirective.php new file mode 100644 index 0000000..81e1c27 --- /dev/null +++ b/src/Directive/TabDirective.php @@ -0,0 +1,36 @@ + + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace SymfonyDocsBuilder\Directive; + +use Doctrine\RST\Directives\SubDirective; +use Doctrine\RST\Nodes\Node; +use Doctrine\RST\Parser; +use SymfonyDocsBuilder\Node\TabNode; + +/** + * Directive that only appears within the "tabs" directive. + */ +class TabDirective extends SubDirective +{ + public function getName(): string + { + return 'tab'; + } + + public function processSub(Parser $parser, ?Node $document, string $variable, string $data, array $options): ?Node + { + $tabName = $data; + if (!$tabName) { + throw new \RuntimeException(sprintf('The "tab" directive requires a tab name: ".. tab:: Tab Name".')); + } + + return new TabNode($document->getNodes(), $data); + } +} diff --git a/src/Directive/TabsDirective.php b/src/Directive/TabsDirective.php new file mode 100644 index 0000000..0a8c25e --- /dev/null +++ b/src/Directive/TabsDirective.php @@ -0,0 +1,60 @@ + + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace SymfonyDocsBuilder\Directive; + +use Doctrine\RST\Directives\SubDirective; +use Doctrine\RST\Nodes\Node; +use Doctrine\RST\Parser; +use SymfonyDocsBuilder\Node\TabNode; + +class TabsDirective extends SubDirective +{ + public function getName(): string + { + return 'tabs'; + } + + public function processSub(Parser $parser, ?Node $document, string $variable, string $data, array $options): ?Node + { + $tabsTitle = $data; + if (!$tabsTitle) { + throw new \RuntimeException(sprintf('The "tabs" directive requires a title: ".. tabs:: Title".')); + } + + $blocks = []; + foreach ($document->getNodes() as $tabNode) { + if (!$tabNode instanceof TabNode) { + throw new \RuntimeException(sprintf('Only ".. tab::" content can appear within the "tabs" directive.')); + } + + $content = ''; + foreach ($tabNode->getNodes() as $node) { + $content .= $node->render(); + } + + $blocks[] = [ + 'hash' => hash('sha1', $tabNode->getTabName()), + 'language_label' => $tabNode->getTabName(), + 'language' => $tabNode->getSluggedTabName(), + 'code' => $content, + ]; + } + + $wrapperDiv = $parser->renderTemplate( + 'directives/configuration-block.html.twig', + [ + 'blocks' => $blocks, + 'title' => $tabsTitle, + ] + ); + + return $parser->getNodeFactory()->createWrapperNode(null, $wrapperDiv, ''); + } +} diff --git a/src/KernelFactory.php b/src/KernelFactory.php index 8d640d8..dceed39 100644 --- a/src/KernelFactory.php +++ b/src/KernelFactory.php @@ -91,6 +91,8 @@ private static function getDirectives(): array new SymfonyDirectives\ScreencastDirective(), new SymfonyDirectives\SeeAlsoDirective(), new SymfonyDirectives\SidebarDirective(), + new SymfonyDirectives\TabDirective(), + new SymfonyDirectives\TabsDirective(), new SymfonyDirectives\TipDirective(), new SymfonyDirectives\TopicDirective(), new SymfonyDirectives\WarningDirective(), diff --git a/src/Node/TabNode.php b/src/Node/TabNode.php new file mode 100644 index 0000000..620cc75 --- /dev/null +++ b/src/Node/TabNode.php @@ -0,0 +1,41 @@ +nodes = $nodes; + $this->tabName = $tabName; + + parent::__construct(); + } + + public function getNodes(): array + { + return $this->nodes; + } + + public function getTabName(): string + { + return $this->tabName; + } + + public function getSluggedTabName(): string + { + return strtolower(str_replace(' ', '-', $this->tabName)); + } +} diff --git a/src/Templates/default/html/directives/configuration-block.html.twig b/src/Templates/default/html/directives/configuration-block.html.twig index 03a48d3..47ceaf6 100644 --- a/src/Templates/default/html/directives/configuration-block.html.twig +++ b/src/Templates/default/html/directives/configuration-block.html.twig @@ -1,5 +1,5 @@
-
+
{% for block in blocks %} + +
+ +
+

Webpack Encore stuff!

+
+
+
1
+
I am yaml:
+
+
+
+ +
diff --git a/tests/fixtures/source/blocks/directives/tabs.rst b/tests/fixtures/source/blocks/directives/tabs.rst new file mode 100644 index 0000000..555a732 --- /dev/null +++ b/tests/fixtures/source/blocks/directives/tabs.rst @@ -0,0 +1,16 @@ + +.. tabs:: UX Installation + + .. tab:: Webpack Encore + + Webpack Encore stuff! + + .. code-block:: yaml + + I am yaml: + + .. tab:: AssetMapper + + AssetMapper stuff! + + And another paragraph. From 0706d2cb46f1f059daa21a1e096720bcaafc8d67 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Fri, 6 Oct 2023 12:28:20 +0200 Subject: [PATCH 08/34] Update `scrivo/highlight.php` (#162) --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 9416e83..6529c99 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,7 @@ "ext-json": "*", "ext-curl": "*", "doctrine/rst-parser": "^0.5", - "scrivo/highlight.php": "^9.12.0", + "scrivo/highlight.php": "^9.18.1", "symfony/filesystem": "^5.2 || ^6.0", "symfony/finder": "^5.2 || ^6.0", "symfony/dom-crawler": "^5.2 || ^6.0", From fdaeec79b7a8b715bdf0debad6629721bb0d5f67 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 31 Oct 2023 14:09:56 +0100 Subject: [PATCH 09/34] Allow using Symfony 7.0 dependencies (#165) --- composer.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index 6529c99..dde5a06 100644 --- a/composer.json +++ b/composer.json @@ -19,18 +19,18 @@ "ext-curl": "*", "doctrine/rst-parser": "^0.5", "scrivo/highlight.php": "^9.18.1", - "symfony/filesystem": "^5.2 || ^6.0", - "symfony/finder": "^5.2 || ^6.0", - "symfony/dom-crawler": "^5.2 || ^6.0", - "symfony/css-selector": "^5.2 || ^6.0", - "symfony/console": "^5.2 || ^6.0", - "symfony/http-client": "^5.2 || ^6.0", + "symfony/filesystem": "^5.2 || ^6.0 || ^7.0", + "symfony/finder": "^5.2 || ^6.0 || ^7.0", + "symfony/dom-crawler": "^5.2 || ^6.0 || ^7.0", + "symfony/css-selector": "^5.2 || ^6.0 || ^7.0", + "symfony/console": "^5.2 || ^6.0 || ^7.0", + "symfony/http-client": "^5.2 || ^6.0 || ^7.0", "twig/twig": "^2.14 || ^3.3" }, "require-dev": { "gajus/dindent": "^2.0", - "symfony/phpunit-bridge": "^5.2 || ^6.0", - "symfony/process": "^5.2 || ^6.0", + "symfony/phpunit-bridge": "^5.2 || ^6.0 || ^7.0", + "symfony/process": "^5.2 || ^6.0 || ^7.0", "masterminds/html5": "^2.7" }, "bin": ["bin/docs-builder"] From 746bbd9aed231d1096cbe385d3a74aef3e101d48 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Tue, 31 Oct 2023 14:40:08 +0100 Subject: [PATCH 10/34] Update notes.md --- notes.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/notes.md b/notes.md index 3380b08..f255945 100644 --- a/notes.md +++ b/notes.md @@ -21,10 +21,10 @@ Notes - /!\ tip / caution / node / etc... with nested reference - no more `colgroup` in tables ?? - add ` ` instead of simple space to lines in code blocks -- test if there is only one

in each page +- test if there is only one `

` in each page - we're assuming there is only one toctree per page... - `rst` does not exist in highlight php - `varnish` = C ? (highlight php) - `RoleDirective` ? - `IndexDirective` ? -- toctree maxdepth ? \ No newline at end of file +- toctree maxdepth ? From 1b3e7ec055dfe9812f76afdfbeb4a305ab2ac990 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Wed, 1 Nov 2023 08:58:37 +0100 Subject: [PATCH 11/34] Add dependabot for GithubActions (#166) --- .github/dependabot.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..bd214f7 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,16 @@ +# https://help.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 + +updates: + - + commit-message: + include: "scope" + prefix: "github-actions" + directory: "/" + labels: + - "dependency" + open-pull-requests-limit: 5 + package-ecosystem: "github-actions" + schedule: + interval: "daily" From 9c1c0ba09a735e663e8950f32c404fdf761226fa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Nov 2023 09:01:00 +0100 Subject: [PATCH 12/34] github-actions(deps): bump actions/checkout from 3 to 4 (#167) Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2641d0f..7eafde9 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -14,7 +14,7 @@ jobs: steps: - name: 'Checkout code' - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: 'Install PHP' uses: shivammathur/setup-php@v2 @@ -38,7 +38,7 @@ jobs: steps: - name: 'Checkout code' - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: 'Install PHP' uses: shivammathur/setup-php@v2 From 5cbc4dd373e210a7d76e6a29149ac7753cd3f9e6 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Wed, 1 Nov 2023 09:01:44 +0100 Subject: [PATCH 13/34] Remove useless comments (#168) --- src/KernelFactory.php | 3 --- src/SymfonyHTMLFormat.php | 3 --- 2 files changed, 6 deletions(-) diff --git a/src/KernelFactory.php b/src/KernelFactory.php index dceed39..2feb16a 100644 --- a/src/KernelFactory.php +++ b/src/KernelFactory.php @@ -21,9 +21,6 @@ use SymfonyDocsBuilder\Twig\TocExtension; use function Symfony\Component\String\u; -/** - * Class KernelFactory. - */ final class KernelFactory { public static function createKernel(BuildConfig $buildConfig, ?UrlChecker $urlChecker = null): Kernel diff --git a/src/SymfonyHTMLFormat.php b/src/SymfonyHTMLFormat.php index fd7f35f..9c17ca9 100644 --- a/src/SymfonyHTMLFormat.php +++ b/src/SymfonyHTMLFormat.php @@ -21,9 +21,6 @@ use SymfonyDocsBuilder\CI\UrlChecker; use Doctrine\RST\HTML\Renderers\SpanNodeRenderer as BaseSpanNodeRenderer; -/** - * Class SymfonyHTMLFormat. - */ final class SymfonyHTMLFormat implements Format { protected $templateRenderer; From 2f8985607cd7f0c959a73e5c1a9a2f1dc36806cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Andr=C3=A9?= Date: Fri, 15 Dec 2023 19:46:32 +0100 Subject: [PATCH 14/34] Add directive test for admonition/danger --- src/Templates/default/html/directives/admonition.html.twig | 4 ++-- tests/IntegrationTest.php | 4 ++++ tests/fixtures/expected/blocks/directives/caution.html | 2 +- tests/fixtures/expected/blocks/directives/danger.html | 6 ++++++ tests/fixtures/expected/main/datetime.html | 4 +--- tests/fixtures/source/blocks/directives/danger.rst | 4 ++++ 6 files changed, 18 insertions(+), 6 deletions(-) create mode 100644 tests/fixtures/expected/blocks/directives/danger.html create mode 100644 tests/fixtures/source/blocks/directives/danger.rst diff --git a/src/Templates/default/html/directives/admonition.html.twig b/src/Templates/default/html/directives/admonition.html.twig index f32f327..9fb0327 100644 --- a/src/Templates/default/html/directives/admonition.html.twig +++ b/src/Templates/default/html/directives/admonition.html.twig @@ -5,9 +5,9 @@ {% elseif name in ['hint', 'tip'] %} - {% elseif name in ['attention', 'important', 'warning'] %} + {% elseif name in ['attention', 'caution', 'important', 'warning'] %} - {% elseif name in ['caution', 'danger', 'error'] %} + {% elseif name in ['danger', 'error'] %} {% elseif name in ['versionadded', 'deprecated'] %} {# don't show an icon for these directives #} diff --git a/tests/IntegrationTest.php b/tests/IntegrationTest.php index 5e3cfa0..cf34cde 100644 --- a/tests/IntegrationTest.php +++ b/tests/IntegrationTest.php @@ -158,6 +158,10 @@ public function parserUnitBlockProvider() 'blockName' => 'directives/admonition', ]; + yield 'danger' => [ + 'blockName' => 'directives/danger', + ]; + yield 'note-code-block-nested' => [ 'blockName' => 'directives/note-code-block-nested', ]; diff --git a/tests/fixtures/expected/blocks/directives/caution.html b/tests/fixtures/expected/blocks/directives/caution.html index 500ba6d..717c09f 100644 --- a/tests/fixtures/expected/blocks/directives/caution.html +++ b/tests/fixtures/expected/blocks/directives/caution.html @@ -1,6 +1,6 @@

- + Caution

Using too many sidebars or caution directives can be distracting!

diff --git a/tests/fixtures/expected/blocks/directives/danger.html b/tests/fixtures/expected/blocks/directives/danger.html new file mode 100644 index 0000000..e4fbc9a --- /dev/null +++ b/tests/fixtures/expected/blocks/directives/danger.html @@ -0,0 +1,6 @@ +
+

+ + Danger +

This message is about security risk or data integrity threat.

+
diff --git a/tests/fixtures/expected/main/datetime.html b/tests/fixtures/expected/main/datetime.html index c302637..c1ea089 100644 --- a/tests/fixtures/expected/main/datetime.html +++ b/tests/fixtures/expected/main/datetime.html @@ -215,9 +215,7 @@

- - - + Caution

Using too many sidebars or caution directives can be distracting!

diff --git a/tests/fixtures/source/blocks/directives/danger.rst b/tests/fixtures/source/blocks/directives/danger.rst new file mode 100644 index 0000000..dfc4217 --- /dev/null +++ b/tests/fixtures/source/blocks/directives/danger.rst @@ -0,0 +1,4 @@ + +.. danger:: + + This message is about security risk or data integrity threat. From e0e941f413537e46f2584b2e95499b1ebbdc90ca Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 25 Jan 2024 11:52:45 +0100 Subject: [PATCH 15/34] Test this project on more platforms --- .github/workflows/ci.yaml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 7eafde9..bc16178 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -28,13 +28,16 @@ jobs: run: composer validate --strict stable-tests: - name: Stable Tests - runs-on: ubuntu-latest + name: "${{ matrix.operating-system }} / PHP ${{ matrix.php-version }}" + runs-on: ${{ matrix.operating-system }} strategy: fail-fast: false matrix: - php-version: ['7.4', '8.0', '8.1', '8.2'] + # add here only the PHP versions and OS used in GitHub CI (for tests) + # and on the symfony.com server (where the Symfony Docs are built) + operating-system: ['ubuntu-latest'] + php-version: ['7.4', '8.3'] steps: - name: 'Checkout code' From 9764478dba87e81a0bde9b16677a9c2c2c73089c Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 14 May 2024 18:13:06 +0200 Subject: [PATCH 16/34] Add tests for highlighting PHP attributes --- tests/IntegrationTest.php | 4 + .../blocks/code-blocks/php-attributes.html | 147 ++++++++++++++++++ .../blocks/code-blocks/php-attributes.rst | 51 ++++++ 3 files changed, 202 insertions(+) create mode 100644 tests/fixtures/expected/blocks/code-blocks/php-attributes.html create mode 100644 tests/fixtures/source/blocks/code-blocks/php-attributes.rst diff --git a/tests/IntegrationTest.php b/tests/IntegrationTest.php index cf34cde..69b3681 100644 --- a/tests/IntegrationTest.php +++ b/tests/IntegrationTest.php @@ -290,6 +290,10 @@ public function parserUnitBlockProvider() 'blockName' => 'code-blocks/php-annotations', ]; + yield 'code-block-php-attributes' => [ + 'blockName' => 'code-blocks/php-attributes', + ]; + yield 'code-block-text' => [ 'blockName' => 'code-blocks/text', ]; diff --git a/tests/fixtures/expected/blocks/code-blocks/php-attributes.html b/tests/fixtures/expected/blocks/code-blocks/php-attributes.html new file mode 100644 index 0000000..5b73756 --- /dev/null +++ b/tests/fixtures/expected/blocks/code-blocks/php-attributes.html @@ -0,0 +1,147 @@ +
+
+
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+
+            
+                // src/SomePath/SomeClass.php
+namespace App\SomePath;
+                useSymfony\Component\Validator\Constraints as Assert;
+                
+                    class
+                    SomeClass
+                
+                {
+                #[AttributeName]
+                private
+                
+                    $ property1
+                ;
+                #[AttributeName(
+                )]
+                private
+                
+                    $ property2
+                ;
+                #[AttributeName(
+                'value'
+                )]
+                private
+                
+                    $ property3
+                ;
+                #[AttributeName(
+                'value'
+                , option:
+                'value'
+                )]
+                private
+                
+                    $ property4
+                ;
+                #[AttributeName(
+['value' => 'value'])]
+                private
+                
+                    $ property5
+                ;
+                #[AttributeName(
+                'value'
+                , option:
+                'value'
+                )]
+                private
+                
+                    $ property6
+                ;
+                #[Assert\AttributeName(
+                'value'
+                )]
+                private
+                
+                    $ property7
+                ;
+                #[Assert\AttributeName(
+                'value'
+                , option:
+                'value'
+                )]
+                private
+                
+                    $ property8
+                ;
+                #[Route(
+                '/blog/{page<\d+>}'
+                , name:
+                'blog_list'
+                )]
+                private
+                
+                $ property9
+                ;
+                #[Assert\GreaterThanOrEqual(
+                value:
+                18
+                ,
+                )]
+                private
+                
+                $ property10
+                ;
+                #[ORM\CustomIdGenerator(
+                class:
+                'doctrine.uuid_generator'
+                )]
+                private
+                
+                $ property11
+                ;
+}
+
+
diff --git a/tests/fixtures/source/blocks/code-blocks/php-attributes.rst b/tests/fixtures/source/blocks/code-blocks/php-attributes.rst new file mode 100644 index 0000000..d43f8ad --- /dev/null +++ b/tests/fixtures/source/blocks/code-blocks/php-attributes.rst @@ -0,0 +1,51 @@ +.. code-block:: php-attributes + + // src/SomePath/SomeClass.php + namespace App\SomePath; + + use Symfony\Component\Validator\Constraints as Assert; + + class SomeClass + { + #[AttributeName] + private $property1; + + #[AttributeName()] + private $property2; + + #[AttributeName('value')] + private $property3; + + #[AttributeName('value', option: 'value')] + private $property4; + + #[AttributeName(['value' => 'value'])] + private $property5; + + #[AttributeName( + 'value', + option: 'value' + )] + private $property6; + + #[Assert\AttributeName('value')] + private $property7; + + #[Assert\AttributeName( + 'value', + option: 'value' + )] + private $property8; + + #[Route('/blog/{page<\d+>}', name: 'blog_list')] + private $property9; + + #[Assert\GreaterThanOrEqual( + value: 18, + )] + private $property10; + + #[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')] + private $property11; + } + From 020a28109d304ee7f34ba65eb1ed6658dda54eba Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Fri, 17 May 2024 21:43:04 +0200 Subject: [PATCH 17/34] Add support for PHP attributes --- src/Templates/highlight.php/php.json | 50 ++++++++----- .../blocks/code-blocks/php-attributes.html | 75 +++++++++---------- .../blocks/code-blocks/php-attributes.rst | 7 +- 3 files changed, 73 insertions(+), 59 deletions(-) diff --git a/src/Templates/highlight.php/php.json b/src/Templates/highlight.php/php.json index 50b53fe..3f127b8 100644 --- a/src/Templates/highlight.php/php.json +++ b/src/Templates/highlight.php/php.json @@ -8,8 +8,23 @@ "php7" ], "case_insensitive": true, - "keywords": "and include_once list abstract global private echo interface as static endswitch array null if endwhile or const for endforeach self var while isset public protected exit foreach throw elseif include __FILE__ empty require_once do xor return parent clone use __CLASS__ __LINE__ else break print eval new catch __METHOD__ case exception default die require __FUNCTION__ enddeclare final try switch continue endfor endif declare unset true false trait goto instanceof insteadof __DIR__ __NAMESPACE__ yield finally", + "keywords": "and include_once list abstract global private echo interface as static endswitch array null if endwhile or const for endforeach self var while isset public protected exit foreach throw elseif include __FILE__ empty require_once do xor return parent clone use __CLASS__ __LINE__ else break print eval new catch __METHOD__ case exception default die require __FUNCTION__ enddeclare final try match switch continue endfor endif declare unset true false goto instanceof insteadof __DIR__ __NAMESPACE__ yield finally", "contains": [ + { + "className": "php-attribute", + "begin": "#\\[\\s*(\\\\?[A-Z][A-Za-z0-9_\\x7f-\\xff]+|\\\\?[A-Z]+(?=[A-Z][a-z0-9_\\x7f-\\xff])){1,}(?![A-Za-z0-9])(?![$])", + "end": "]", + "contains": [ + { + "begin": "\\(", + "end": "\\)", + "keywords": "true false null new array", + "contains": { + "$ref": "#contains.10.contains.1.contains" + } + } + ] + }, { "className": "comment", "begin": "#", @@ -35,7 +50,7 @@ "begin": "<\\?(php)?|\\?>" }, { - "$ref": "#contains.0.contains.0" + "$ref": "#contains.1.contains.0" }, { "className": "doctag", @@ -54,7 +69,7 @@ "begin": "@[A-Za-z]+" }, { - "$ref": "#contains.0.contains.0" + "$ref": "#contains.1.contains.0" }, { "className": "doctag", @@ -69,7 +84,7 @@ "end": false, "contains": [ { - "$ref": "#contains.0.contains.0" + "$ref": "#contains.1.contains.0" }, { "className": "doctag", @@ -105,7 +120,7 @@ ] }, { - "$ref": "#contains.1.contains.0" + "$ref": "#contains.2.contains.0" }, { "className": "variable", @@ -137,10 +152,11 @@ "className": "params", "begin": "\\(", "end": "\\)", + "keywords": "true false null new array", "contains": [ "self", { - "$ref": "#contains.7" + "$ref": "#contains.8" }, { "className": "comment", @@ -148,7 +164,7 @@ "end": "\\*/", "contains": [ { - "$ref": "#contains.0.contains.0" + "$ref": "#contains.1.contains.0" }, { "className": "doctag", @@ -161,10 +177,10 @@ "className": "string", "contains": [ { - "$ref": "#contains.4.contains.0" + "$ref": "#contains.5.contains.0" }, { - "$ref": "#contains.1.contains.0" + "$ref": "#contains.2.contains.0" } ], "variants": [ @@ -183,7 +199,7 @@ "illegal": null, "contains": [ { - "$ref": "#contains.4.contains.0" + "$ref": "#contains.5.contains.0" } ] }, @@ -194,7 +210,7 @@ "illegal": null, "contains": [ { - "$ref": "#contains.4.contains.0" + "$ref": "#contains.5.contains.0" }, { "className": "subst", @@ -230,7 +246,7 @@ }, { "className": "class", - "beginKeywords": "class interface", + "beginKeywords": "class interface trait enum", "end": "{", "excludeEnd": true, "illegal": "[:\\(\\$\"]", @@ -239,7 +255,7 @@ "beginKeywords": "extends implements" }, { - "$ref": "#contains.9.contains.0" + "$ref": "#contains.10.contains.0" } ] }, @@ -249,7 +265,7 @@ "illegal": "[\\.']", "contains": [ { - "$ref": "#contains.9.contains.0" + "$ref": "#contains.10.contains.0" } ] }, @@ -258,7 +274,7 @@ "end": ";", "contains": [ { - "$ref": "#contains.9.contains.0" + "$ref": "#contains.10.contains.0" } ] }, @@ -266,10 +282,10 @@ "begin": "=>" }, { - "$ref": "#contains.9.contains.1.contains.3" + "$ref": "#contains.10.contains.1.contains.3" }, { - "$ref": "#contains.9.contains.1.contains.4" + "$ref": "#contains.10.contains.1.contains.4" } ] } diff --git a/tests/fixtures/expected/blocks/code-blocks/php-attributes.html b/tests/fixtures/expected/blocks/code-blocks/php-attributes.html index 5b73756..541681c 100644 --- a/tests/fixtures/expected/blocks/code-blocks/php-attributes.html +++ b/tests/fixtures/expected/blocks/code-blocks/php-attributes.html @@ -1,4 +1,4 @@ -
+
1
 2
@@ -47,7 +47,13 @@
 45
 46
 47
-48
+48 +49 +50 +51 +52 +53 +54
             
                 // src/SomePath/SomeClass.php
@@ -63,85 +69,72 @@
                 
                     $ property1
                 ;
-                #[AttributeName(
-                )]
+                #[AttributeName()]
                 private
                 
                     $ property2
                 ;
-                #[AttributeName(
-                'value'
-                )]
+                #[AttributeName('value')]
                 private
                 
                     $ property3
                 ;
-                #[AttributeName(
-                'value'
-                , option:
-                'value'
-                )]
+                #[AttributeName('value', option: 'value')]
                 private
                 
                     $ property4
                 ;
-                #[AttributeName(
-['value' => 'value'])]
+                #[AttributeName(['value' => 'value'])]
                 private
                 
                     $ property5
                 ;
-                #[AttributeName(
-                'value'
-                , option:
-                'value'
-                )]
+                #[AttributeName(
+                    'value',
+                    option: 'value'
+                )]
                 private
                 
                     $ property6
                 ;
-                #[Assert\AttributeName(
-                'value'
-                )]
+                #[Assert\AttributeName('value')]
                 private
                 
                     $ property7
                 ;
-                #[Assert\AttributeName(
-                'value'
-                , option:
-                'value'
-                )]
+                #[Assert\AttributeName(
+                    'value',
+                    option: 'value'
+                )]
                 private
                 
                     $ property8
                 ;
-                #[Route(
-                '/blog/{page<\d+>}'
-                , name:
-                'blog_list'
-                )]
+                #[Route('/blog/{page<\d+>}', name: 'blog_list')]
                 private
                 
                 $ property9
                 ;
-                #[Assert\GreaterThanOrEqual(
-                value:
-                18
-                ,
-                )]
+                #[Assert\GreaterThanOrEqual(
+                    value: 18,
+                )]
                 private
                 
                 $ property10
                 ;
-                #[ORM\CustomIdGenerator(
-                class:
-                'doctrine.uuid_generator'
-                )]
+                #[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
                 private
                 
                 $ property11
                 ;
+                #[Assert\AtLeastOneOf([
+                    new Assert\Regex('/#/'),
+                    new Assert\Length(min: 10),
+                ])]
+                private
+                
+                $ property12
+                ;
 }
diff --git a/tests/fixtures/source/blocks/code-blocks/php-attributes.rst b/tests/fixtures/source/blocks/code-blocks/php-attributes.rst index d43f8ad..31b5f99 100644 --- a/tests/fixtures/source/blocks/code-blocks/php-attributes.rst +++ b/tests/fixtures/source/blocks/code-blocks/php-attributes.rst @@ -47,5 +47,10 @@ #[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')] private $property11; - } + #[Assert\AtLeastOneOf([ + new Assert\Regex('/#/'), + new Assert\Length(min: 10), + ])] + private $property12; + } From de706b5ad7bd7f9ee79b945ed87375e1b7aec970 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Tue, 21 May 2024 16:19:09 +0200 Subject: [PATCH 18/34] Fixes for PHP attribute parsing --- src/Templates/highlight.php/php.json | 55 ++++++++++++------ .../blocks/code-blocks/php-attributes.html | 57 +++++++++++++------ .../blocks/code-blocks/php-attributes.rst | 11 ++++ 3 files changed, 87 insertions(+), 36 deletions(-) diff --git a/src/Templates/highlight.php/php.json b/src/Templates/highlight.php/php.json index 3f127b8..7295ab9 100644 --- a/src/Templates/highlight.php/php.json +++ b/src/Templates/highlight.php/php.json @@ -11,17 +11,30 @@ "keywords": "and include_once list abstract global private echo interface as static endswitch array null if endwhile or const for endforeach self var while isset public protected exit foreach throw elseif include __FILE__ empty require_once do xor return parent clone use __CLASS__ __LINE__ else break print eval new catch __METHOD__ case exception default die require __FUNCTION__ enddeclare final try match switch continue endfor endif declare unset true false goto instanceof insteadof __DIR__ __NAMESPACE__ yield finally", "contains": [ { - "className": "php-attribute", - "begin": "#\\[\\s*(\\\\?[A-Z][A-Za-z0-9_\\x7f-\\xff]+|\\\\?[A-Z]+(?=[A-Z][a-z0-9_\\x7f-\\xff])){1,}(?![A-Za-z0-9])(?![$])", + "className": "meta", + "begin": "#\\[\\s*(\\\\?[A-Z][A-Za-z0-9_\\x7f-\\xff]+)+\\]" + }, + { + "begin": "#\\[\\s*(\\\\?[A-Z][A-Za-z0-9_\\x7f-\\xff]+)+(?![A-Za-z0-9])(?![$])", "end": "]", + "returnBegin": true, "contains": [ + { + "className": "meta", + "begin": "#\\[\\s*(\\\\?[A-Z][A-Za-z0-9_\\x7f-\\xff]+)+(?![A-Za-z0-9])(?![$])" + }, { "begin": "\\(", "end": "\\)", "keywords": "true false null new array", "contains": { - "$ref": "#contains.10.contains.1.contains" + "$ref": "#contains.11.contains.1.contains" } + }, + { + "className": "meta", + "begin": "]", + "endsParent": true } ] }, @@ -50,7 +63,7 @@ "begin": "<\\?(php)?|\\?>" }, { - "$ref": "#contains.1.contains.0" + "$ref": "#contains.2.contains.0" }, { "className": "doctag", @@ -69,7 +82,7 @@ "begin": "@[A-Za-z]+" }, { - "$ref": "#contains.1.contains.0" + "$ref": "#contains.2.contains.0" }, { "className": "doctag", @@ -84,7 +97,7 @@ "end": false, "contains": [ { - "$ref": "#contains.1.contains.0" + "$ref": "#contains.2.contains.0" }, { "className": "doctag", @@ -120,7 +133,7 @@ ] }, { - "$ref": "#contains.2.contains.0" + "$ref": "#contains.3.contains.0" }, { "className": "variable", @@ -156,7 +169,7 @@ "contains": [ "self", { - "$ref": "#contains.8" + "$ref": "#contains.9" }, { "className": "comment", @@ -164,7 +177,7 @@ "end": "\\*/", "contains": [ { - "$ref": "#contains.1.contains.0" + "$ref": "#contains.2.contains.0" }, { "className": "doctag", @@ -177,10 +190,10 @@ "className": "string", "contains": [ { - "$ref": "#contains.5.contains.0" + "$ref": "#contains.6.contains.0" }, { - "$ref": "#contains.2.contains.0" + "$ref": "#contains.3.contains.0" } ], "variants": [ @@ -199,7 +212,7 @@ "illegal": null, "contains": [ { - "$ref": "#contains.5.contains.0" + "$ref": "#contains.6.contains.0" } ] }, @@ -210,7 +223,7 @@ "illegal": null, "contains": [ { - "$ref": "#contains.5.contains.0" + "$ref": "#contains.6.contains.0" }, { "className": "subst", @@ -239,6 +252,12 @@ "relevance": 0 } ] + }, + { + "$ref": "#contains.0" + }, + { + "$ref": "#contains.1" } ] } @@ -255,7 +274,7 @@ "beginKeywords": "extends implements" }, { - "$ref": "#contains.10.contains.0" + "$ref": "#contains.11.contains.0" } ] }, @@ -265,7 +284,7 @@ "illegal": "[\\.']", "contains": [ { - "$ref": "#contains.10.contains.0" + "$ref": "#contains.11.contains.0" } ] }, @@ -274,7 +293,7 @@ "end": ";", "contains": [ { - "$ref": "#contains.10.contains.0" + "$ref": "#contains.11.contains.0" } ] }, @@ -282,10 +301,10 @@ "begin": "=>" }, { - "$ref": "#contains.10.contains.1.contains.3" + "$ref": "#contains.11.contains.1.contains.3" }, { - "$ref": "#contains.10.contains.1.contains.4" + "$ref": "#contains.11.contains.1.contains.4" } ] } diff --git a/tests/fixtures/expected/blocks/code-blocks/php-attributes.html b/tests/fixtures/expected/blocks/code-blocks/php-attributes.html index 541681c..9ea143e 100644 --- a/tests/fixtures/expected/blocks/code-blocks/php-attributes.html +++ b/tests/fixtures/expected/blocks/code-blocks/php-attributes.html @@ -1,4 +1,4 @@ -
+
1
 2
@@ -53,7 +53,18 @@
 51
 52
 53
-54
+54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65
             
                 // src/SomePath/SomeClass.php
@@ -64,77 +75,87 @@
                     SomeClass
                 
                 {
-                #[AttributeName]
+                #[AttributeName]
                 private
                 
                     $ property1
                 ;
-                #[AttributeName()]
+                #[AttributeName()]
                 private
                 
                     $ property2
                 ;
-                #[AttributeName('value')]
+                #[AttributeName('value')]
                 private
                 
                     $ property3
                 ;
-                #[AttributeName('value', option: 'value')]
+                #[AttributeName('value', option: 'value')]
                 private
                 
                     $ property4
                 ;
-                #[AttributeName(['value' => 'value'])]
+                #[AttributeName(['value' => 'value'])]
                 private
                 
                     $ property5
                 ;
-                #[AttributeName(
+                #[AttributeName(
                     'value',
                     option: 'value'
-                )]
+                )]
                 private
                 
                     $ property6
                 ;
-                #[Assert\AttributeName('value')]
+                #[Assert\AttributeName('value')]
                 private
                 
                     $ property7
                 ;
-                #[Assert\AttributeName(
+                #[Assert\AttributeName(
                     'value',
                     option: 'value'
-                )]
+                )]
                 private
                 
                     $ property8
                 ;
-                #[Route('/blog/{page<\d+>}', name: 'blog_list')]
+                #[Route('/blog/{page<\d+>}', name: 'blog_list')]
                 private
                 
                 $ property9
                 ;
-                #[Assert\GreaterThanOrEqual(
+                #[Assert\GreaterThanOrEqual(
                     value: 18,
-                )]
+                )]
                 private
                 
                 $ property10
                 ;
-                #[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
+                #[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
                 private
                 
                 $ property11
                 ;
-                #[Assert\AtLeastOneOf([
+                #[Assert\AtLeastOneOf([
                     new Assert\Regex('/#/'),
                     new Assert\Length(min: 10),
-                ])]
+                ])]
                 private
                 
                 $ property12
                 ;
+                public function __construct(
+                        #[TaggedIterator('app.handlers')]
+                        iterable $handlers,
+                ){
+                }
+
+                #[AsController]
+                public functionsomeAction(#[CurrentUser] User $user)
+                {
+                }
 }
diff --git a/tests/fixtures/source/blocks/code-blocks/php-attributes.rst b/tests/fixtures/source/blocks/code-blocks/php-attributes.rst index 31b5f99..808e6c4 100644 --- a/tests/fixtures/source/blocks/code-blocks/php-attributes.rst +++ b/tests/fixtures/source/blocks/code-blocks/php-attributes.rst @@ -53,4 +53,15 @@ new Assert\Length(min: 10), ])] private $property12; + + public function __construct( + #[TaggedIterator('app.handlers')] + iterable $handlers, + ) { + } + + #[AsController] + public function someAction(#[CurrentUser] User $user) + { + } } From 0642507c99fb18751ce7c1143a64ff9948c4e3f1 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sat, 25 May 2024 16:26:23 +0200 Subject: [PATCH 19/34] Add more modern PHP syntax highlighting --- src/Renderers/CodeNodeRenderer.php | 3 - src/Templates/highlight.php/php.json | 155 +++++++++++++++--- tests/IntegrationTest.php | 9 +- tests/Templates/fixtures/php.output.html | 6 +- .../blocks/code-blocks/php-attributes.html | 2 +- .../expected/blocks/code-blocks/php.html | 91 +++++++++- .../expected/blocks/nodes/literal.html | 4 +- tests/fixtures/expected/main/datetime.html | 12 +- .../source/blocks/code-blocks/php.rst | 46 +++++- 9 files changed, 277 insertions(+), 51 deletions(-) diff --git a/src/Renderers/CodeNodeRenderer.php b/src/Renderers/CodeNodeRenderer.php index cfa46a1..a9e5643 100644 --- a/src/Renderers/CodeNodeRenderer.php +++ b/src/Renderers/CodeNodeRenderer.php @@ -70,9 +70,6 @@ public function render(): string $highLighter = new Highlighter(); $highlightedCode = $highLighter->highlight($languageMapping, $code)->value; - - // this allows to highlight the $ in PHP variable names - $highlightedCode = str_replace('$', '$', $highlightedCode); } if ('terminal' === $language) { diff --git a/src/Templates/highlight.php/php.json b/src/Templates/highlight.php/php.json index 7295ab9..c31251a 100644 --- a/src/Templates/highlight.php/php.json +++ b/src/Templates/highlight.php/php.json @@ -8,7 +8,7 @@ "php7" ], "case_insensitive": true, - "keywords": "and include_once list abstract global private echo interface as static endswitch array null if endwhile or const for endforeach self var while isset public protected exit foreach throw elseif include __FILE__ empty require_once do xor return parent clone use __CLASS__ __LINE__ else break print eval new catch __METHOD__ case exception default die require __FUNCTION__ enddeclare final try match switch continue endfor endif declare unset true false goto instanceof insteadof __DIR__ __NAMESPACE__ yield finally", + "keywords": "PHP_VERSION PHP_MAJOR_VERSION PHP_MINOR_VERSION PHP_RELEASE_VERSION PHP_VERSION_ID PHP_EXTRA_VERSION ZEND_THREAD_SAFE ZEND_DEBUG_BUILD PHP_ZTS PHP_DEBUG PHP_MAXPATHLEN PHP_OS PHP_OS_FAMILY PHP_SAPI PHP_EOL PHP_INT_MAX PHP_INT_MIN PHP_INT_SIZE PHP_FLOAT_DIG PHP_FLOAT_EPSILON PHP_FLOAT_MIN PHP_FLOAT_MAX DEFAULT_INCLUDE_PATH PEAR_INSTALL_DIR PEAR_EXTENSION_DIR PHP_EXTENSION_DIR PHP_PREFIX PHP_BINDIR PHP_BINARY PHP_MANDIR PHP_LIBDIR PHP_DATADIR PHP_SYSCONFDIR PHP_LOCALSTATEDIR PHP_CONFIG_FILE_PATH PHP_CONFIG_FILE_SCAN_DIR PHP_SHLIB_SUFFIX PHP_FD_SETSIZE E_ERROR E_WARNING E_PARSE E_NOTICE E_CORE_ERROR E_CORE_WARNING E_COMPILE_ERROR E_COMPILE_WARNING E_USER_ERROR E_USER_WARNING E_USER_NOTICE E_RECOVERABLE_ERROR E_DEPRECATED E_USER_DEPRECATED E_ALL E_STRICT __COMPILER_HALT_OFFSET__ PHP_WINDOWS_EVENT_CTRL_C PHP_WINDOWS_EVENT_CTRL_BREAK PHP_CLI_PROCESS_TITLE STDERR STDIN STDOUT __CLASS__ __DIR__ __FILE__ __FUNCTION__ __LINE__ __METHOD__ __NAMESPACE__ __TRAIT__ die echo exit include include_once print require require_once abstract and as binary break case catch class clone const continue declare default do double else elseif empty enddeclare endfor endforeach endif endswitch endwhile enum eval extends final finally for foreach from global goto if implements instanceof insteadof interface isset list match|0 new or parent private protected public readonly return switch throw trait try unset use var void while xor yield array bool boolean callable float int integer iterable mixed never numeric object real string resource self static false FALSE null NULL true TRUE", "contains": [ { "className": "meta", @@ -26,9 +26,10 @@ { "begin": "\\(", "end": "\\)", - "keywords": "true false null new array", + "keywords": "array bool boolean float int integer new real string false FALSE null NULL true TRUE PHP_VERSION PHP_MAJOR_VERSION PHP_MINOR_VERSION PHP_RELEASE_VERSION PHP_VERSION_ID PHP_EXTRA_VERSION ZEND_THREAD_SAFE ZEND_DEBUG_BUILD PHP_ZTS PHP_DEBUG PHP_MAXPATHLEN PHP_OS PHP_OS_FAMILY PHP_SAPI PHP_EOL PHP_INT_MAX PHP_INT_MIN PHP_INT_SIZE PHP_FLOAT_DIG PHP_FLOAT_EPSILON PHP_FLOAT_MIN PHP_FLOAT_MAX DEFAULT_INCLUDE_PATH PEAR_INSTALL_DIR PEAR_EXTENSION_DIR PHP_EXTENSION_DIR PHP_PREFIX PHP_BINDIR PHP_BINARY PHP_MANDIR PHP_LIBDIR PHP_DATADIR PHP_SYSCONFDIR PHP_LOCALSTATEDIR PHP_CONFIG_FILE_PATH PHP_CONFIG_FILE_SCAN_DIR PHP_SHLIB_SUFFIX PHP_FD_SETSIZE E_ERROR E_WARNING E_PARSE E_NOTICE E_CORE_ERROR E_CORE_WARNING E_COMPILE_ERROR E_COMPILE_WARNING E_USER_ERROR E_USER_WARNING E_USER_NOTICE E_RECOVERABLE_ERROR E_DEPRECATED E_USER_DEPRECATED E_ALL E_STRICT __COMPILER_HALT_OFFSET__ PHP_WINDOWS_EVENT_CTRL_C PHP_WINDOWS_EVENT_CTRL_BREAK PHP_CLI_PROCESS_TITLE STDERR STDIN STDOUT __CLASS__ __DIR__ __FILE__ __FUNCTION__ __LINE__ __METHOD__ __NAMESPACE__ __TRAIT__", "contains": { - "$ref": "#contains.11.contains.1.contains" + "$ref": "#contains.10.contains.3.contains", + "_": "params" } }, { @@ -137,39 +138,124 @@ }, { "className": "variable", - "begin": "\\$this\\b" - }, - { - "className": "variable", - "begin": "\\$+[a-zA-Z_-ÿ][a-zA-Z0-9_-ÿ]*" + "begin": "\\$+[a-zA-Z_-ÿ][a-zA-Z0-9_-ÿ]*", + "returnBegin": true, + "contains": [ + { + "className": "variable-other-marker", + "begin": "\\$" + }, + { + "begin": "\\$*[a-zA-Z_-ÿ][a-zA-Z0-9_-ÿ]*" + } + ] }, { - "className": "operator", - "begin": "(::|->)", - "end": "[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*", - "excludeEnd": true + "begin": "\\b(?!fn\\b|function\\b|__CLASS__\\b|__DIR__\\b|__FILE__\\b|__FUNCTION__\\b|__COMPILER_HALT_OFFSET__\\b|__LINE__\\b|__METHOD__\\b|__NAMESPACE__\\b|__TRAIT__\\b|die\\b|echo\\b|exit\\b|include\\b|include_once\\b|print\\b|require\\b|require_once\\b|array\\b|abstract\\b|and\\b|as\\b|binary\\b|bool\\b|boolean\\b|break\\b|callable\\b|case\\b|catch\\b|class\\b|clone\\b|const\\b|continue\\b|declare\\b|default\\b|do\\b|double\\b|else\\b|elseif\\b|empty\\b|enddeclare\\b|endfor\\b|endforeach\\b|endif\\b|endswitch\\b|endwhile\\b|enum\\b|eval\\b|extends\\b|final\\b|finally\\b|float\\b|for\\b|foreach\\b|from\\b|global\\b|goto\\b|if\\b|implements\\b|instanceof\\b|insteadof\\b|int\\b|integer\\b|interface\\b|isset\\b|iterable\\b|list\\b|match\\b|mixed\\b|new\\b|never\\b|object\\b|or\\b|private\\b|protected\\b|public\\b|readonly\\b|real\\b|return\\b|string\\b|switch\\b|throw\\b|trait\\b|try\\b|unset\\b|use\\b|var\\b|void\\b|while\\b|xor\\b|yield|Countable\\b|OuterIterator\\b|RecursiveIterator\\b|SeekableIterator\\b|ArrayAccess\\b|BackedEnum\\b|Generator\\b|Iterator\\b|IteratorAggregate\\b|Serializable\\b|Stringable\\b|Throwable\\b|Traversable\\b|UnitEnum\\b|__PHP_Incomplete_Class\\b|parent\\b|php_user_filter\\b|self\\b|static\\b)[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*(?![A-Za-z0-9])(?![$])[ \\t\\n]*(?=(?=\\())", + "end": "\\)", + "returnBegin": true, + "contains": [ + { + "className": "title invoke__", + "begin": "[a-zA-Z0-9_\\x7f-\\xff]\\w*", + "relevance": 0 + }, + { + "begin": "\\(", + "endsWithParent": true, + "keywords": "array bool boolean float int integer new real string false FALSE null NULL true TRUE PHP_VERSION PHP_MAJOR_VERSION PHP_MINOR_VERSION PHP_RELEASE_VERSION PHP_VERSION_ID PHP_EXTRA_VERSION ZEND_THREAD_SAFE ZEND_DEBUG_BUILD PHP_ZTS PHP_DEBUG PHP_MAXPATHLEN PHP_OS PHP_OS_FAMILY PHP_SAPI PHP_EOL PHP_INT_MAX PHP_INT_MIN PHP_INT_SIZE PHP_FLOAT_DIG PHP_FLOAT_EPSILON PHP_FLOAT_MIN PHP_FLOAT_MAX DEFAULT_INCLUDE_PATH PEAR_INSTALL_DIR PEAR_EXTENSION_DIR PHP_EXTENSION_DIR PHP_PREFIX PHP_BINDIR PHP_BINARY PHP_MANDIR PHP_LIBDIR PHP_DATADIR PHP_SYSCONFDIR PHP_LOCALSTATEDIR PHP_CONFIG_FILE_PATH PHP_CONFIG_FILE_SCAN_DIR PHP_SHLIB_SUFFIX PHP_FD_SETSIZE E_ERROR E_WARNING E_PARSE E_NOTICE E_CORE_ERROR E_CORE_WARNING E_COMPILE_ERROR E_COMPILE_WARNING E_USER_ERROR E_USER_WARNING E_USER_NOTICE E_RECOVERABLE_ERROR E_DEPRECATED E_USER_DEPRECATED E_ALL E_STRICT __COMPILER_HALT_OFFSET__ PHP_WINDOWS_EVENT_CTRL_C PHP_WINDOWS_EVENT_CTRL_BREAK PHP_CLI_PROCESS_TITLE STDERR STDIN STDOUT __CLASS__ __DIR__ __FILE__ __FUNCTION__ __LINE__ __METHOD__ __NAMESPACE__ __TRAIT__", + "contains": [ + { + "className": "attr", + "begin": "[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*(?![A-Za-z0-9])(?![$])(?=:)(?=(?!::))" + }, + { + "variants": [ + { + "begin": "::(?=(?!class\\b))[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*(?![A-Za-z0-9])(?![$])\\b(?!\\()", + "returnBegin": true, + "contains": [ + { + "begin": "::" + }, + { + "className": "variable constant_", + "begin": "[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*(?![A-Za-z0-9])(?![$])\\b(?!\\()" + } + ] + }, + { + "begin": "::class", + "returnBegin": true, + "contains": [ + { + "begin": "::" + }, + { + "className": "variable language_", + "begin": "class" + } + ] + } + ] + }, + { + "$ref": "#contains.8", + "_": "variable" + }, + { + "$ref": "#contains.10.contains.3.contains.2", + "_": "comment" + }, + { + "$ref": "#contains.10.contains.3.contains.3", + "_": "string" + }, + { + "$ref": "#contains.10.contains.3.contains.4", + "_": "number" + }, + { + "$ref": "#contains.10", + "_": "closure" + }, + { + "$ref": "#contains.9", + "_": "invoke" + } + ] + } + ] }, { "className": "function", - "beginKeywords": "function", + "beginKeywords": "fn function", "end": "[;{]", "excludeEnd": true, "illegal": "\\$|\\[|%", "contains": [ + { + "beginKeywords": "use" + }, { "className": "title", "begin": "[a-zA-Z_]\\w*", "relevance": 0 }, + { + "begin": "=>", + "endsParent": true + }, { "className": "params", "begin": "\\(", "end": "\\)", - "keywords": "true false null new array", + "keywords": "array bool boolean callable float int integer iterable mixed never numeric object real string resource self static false FALSE null NULL true TRUE", "contains": [ "self", { - "$ref": "#contains.9" + "$ref": "#contains.8", + "_": "variable" }, { "className": "comment", @@ -254,27 +340,42 @@ ] }, { - "$ref": "#contains.0" + "$ref": "#contains.0", + "_": "simple-attribute" }, { - "$ref": "#contains.1" + "$ref": "#contains.1", + "_": "attribute" } ] } ] }, + { + "$ref": "#contains.9.contains.1.contains.1", + "_": "constant" + }, { "className": "class", - "beginKeywords": "class interface trait enum", - "end": "{", + "variants": [ + { + "beginKeywords": "enum", + "illegal": "[($\"]" + }, + { + "beginKeywords": "class interface trait", + "illegal": "[:($\"]" + } + ], + "end": "\\{", "excludeEnd": true, - "illegal": "[:\\(\\$\"]", "contains": [ { "beginKeywords": "extends implements" }, { - "$ref": "#contains.11.contains.0" + "$ref": "#contains.10.contains.1", + "_": "title" } ] }, @@ -284,7 +385,8 @@ "illegal": "[\\.']", "contains": [ { - "$ref": "#contains.11.contains.0" + "$ref": "#contains.10.contains.1", + "_": "title" } ] }, @@ -293,7 +395,8 @@ "end": ";", "contains": [ { - "$ref": "#contains.11.contains.0" + "$ref": "#contains.10.contains.1", + "_": "title" } ] }, @@ -301,10 +404,12 @@ "begin": "=>" }, { - "$ref": "#contains.11.contains.1.contains.3" + "$ref": "#contains.10.contains.3.contains.3", + "_": "string" }, { - "$ref": "#contains.11.contains.1.contains.4" + "$ref": "#contains.10.contains.3.contains.4", + "_": "number" } ] } diff --git a/tests/IntegrationTest.php b/tests/IntegrationTest.php index 69b3681..f121ba3 100644 --- a/tests/IntegrationTest.php +++ b/tests/IntegrationTest.php @@ -115,8 +115,8 @@ public function testParseUnitBlock(string $blockName) $expected = preg_replace('/<\!\-\- REMOVE(.)+\-\->/', '', $expected); $this->assertSame( - $indenter->indent($expected), - $indenter->indent(trim($actualCrawler->filter('body')->html())) + $this->normalize($indenter->indent($expected)), + $this->normalize($indenter->indent(trim($actualCrawler->filter('body')->html()))) ); } @@ -351,6 +351,11 @@ public function testParseString() $this->assertSame($htmlString, (new DocBuilder())->buildString($rstString)->getStringResult()); } + private function normalize(string $str): string + { + return preg_replace('/\s+$/m', '', $str); + } + private function createIndenter(): Indenter { $indenter = new Indenter(); diff --git a/tests/Templates/fixtures/php.output.html b/tests/Templates/fixtures/php.output.html index b8a1b33..2ce6dcb 100644 --- a/tests/Templates/fixtures/php.output.html +++ b/tests/Templates/fixtures/php.output.html @@ -11,10 +11,10 @@ * * @Route("/blog/{slug}", name="blog_list") */ - public function list(UrlGeneratorInterface $urlGenerator, string $slug) + public function list(UrlGeneratorInterface $urlGenerator, string $slug) { - return $this->render('foo/bar.html.twig', [ - 'key' => $value + return $this->render('foo/bar.html.twig', [ + 'key' => $value ] } } \ No newline at end of file diff --git a/tests/fixtures/expected/blocks/code-blocks/php-attributes.html b/tests/fixtures/expected/blocks/code-blocks/php-attributes.html index 9ea143e..2b77434 100644 --- a/tests/fixtures/expected/blocks/code-blocks/php-attributes.html +++ b/tests/fixtures/expected/blocks/code-blocks/php-attributes.html @@ -148,7 +148,7 @@ ; public function __construct( #[TaggedIterator('app.handlers')] - iterable $handlers, + iterable $handlers, ){ } diff --git a/tests/fixtures/expected/blocks/code-blocks/php.html b/tests/fixtures/expected/blocks/code-blocks/php.html index c005a13..f7bd021 100644 --- a/tests/fixtures/expected/blocks/code-blocks/php.html +++ b/tests/fixtures/expected/blocks/code-blocks/php.html @@ -1,4 +1,4 @@ -
+
1
 2
@@ -6,13 +6,94 @@
 4
 5
 6
-7
+7 +8 +9
// config/routes.php
 namespace Symfony\Component\Routing\Loader\Configurator;
 
-return function (RoutingConfigurator $routes) {
-    $routes->add('about_us', ['nl' => '/over-ons', 'en' => '/about-us'])
-        ->controller('App\Controller\CompanyController::about');
+    use App\Controller\CompanyController;
+
+return static function (RoutingConfigurator $routes): void {
+    $routes->add('about_us', ['nl' => '/over-ons', 'en' => '/about-us'])
+        ->controller(CompanyController::class.'::about');
 };
+
+
+
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+

+enum TextAlign: string implements TranslatableInterface
+{
+    case Left = 'Left aligned';
+    case Center = 'Center aligned';
+    case Right = 'Right aligned';
+
+    public function trans(TranslatorInterface $translator, ?string $locale = null): string
+    {
+        // Translate enum using custom labels
+        return match ($this) {
+            self::Left => $translator->trans('text_align.left.label', locale: $locale),
+            self::Center => $translator->trans('text_align.center.label', locale: $locale),
+            self::Right => $translator->trans('text_align.right.label', locale: $locale),
+        };
+    }
+}
+            
+        
+
+
+
+
+
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+

+public function getUserBadgeFrom(string $accessToken): UserBadge
+{
+    // get the data from the token
+    $payload = ...;
+
+    return new UserBadge(
+        $payload->getUserId(),
+        fn (string $userIdentifier): User => new User($userIdentifier, $payload->getRoles())
+    );
+
+    // or
+    return new UserBadge(
+        $payload->getUserId(),
+        $this->loadUser(...)
+    );
+}
+        
+
+
diff --git a/tests/fixtures/expected/blocks/nodes/literal.html b/tests/fixtures/expected/blocks/nodes/literal.html index 1c12afa..28eb3bf 100644 --- a/tests/fixtures/expected/blocks/nodes/literal.html +++ b/tests/fixtures/expected/blocks/nodes/literal.html @@ -12,8 +12,8 @@ namespace Symfony\Component\Routing\Loader\Configurator; return function (RoutingConfigurator $routes) { - $routes->add('about_us', ['nl' => '/over-ons', 'en' => '/about-us']) - ->controller('App\Controller\CompanyController::about'); + $routes->add('about_us', ['nl' => '/over-ons', 'en' => '/about-us']) + ->controller('App\Controller\CompanyController::about'); };
diff --git a/tests/fixtures/expected/main/datetime.html b/tests/fixtures/expected/main/datetime.html index c1ea089..f36ddc3 100644 --- a/tests/fixtures/expected/main/datetime.html +++ b/tests/fixtures/expected/main/datetime.html @@ -143,12 +143,10 @@

$ builder - -> - add( + -> + add( 'startDateTime' - , DateTimeType - :: - class, + , DateTimeType::class, array ( 'placeholder' @@ -417,8 +415,8 @@

$ container - -> - loadFromExtension( + -> + loadFromExtension( 'framework' , array diff --git a/tests/fixtures/source/blocks/code-blocks/php.rst b/tests/fixtures/source/blocks/code-blocks/php.rst index e9d6593..6498028 100644 --- a/tests/fixtures/source/blocks/code-blocks/php.rst +++ b/tests/fixtures/source/blocks/code-blocks/php.rst @@ -1,9 +1,49 @@ - .. code-block:: php + // config/routes.php namespace Symfony\Component\Routing\Loader\Configurator; - return function (RoutingConfigurator $routes) { + use App\Controller\CompanyController; + + return static function (RoutingConfigurator $routes): void { $routes->add('about_us', ['nl' => '/over-ons', 'en' => '/about-us']) - ->controller('App\Controller\CompanyController::about'); + ->controller(CompanyController::class.'::about'); }; + +.. code-block:: php + + enum TextAlign: string implements TranslatableInterface + { + case Left = 'Left aligned'; + case Center = 'Center aligned'; + case Right = 'Right aligned'; + + public function trans(TranslatorInterface $translator, ?string $locale = null): string + { + // Translate enum using custom labels + return match ($this) { + self::Left => $translator->trans('text_align.left.label', locale: $locale), + self::Center => $translator->trans('text_align.center.label', locale: $locale), + self::Right => $translator->trans('text_align.right.label', locale: $locale), + }; + } + } + +.. code-block:: php + + public function getUserBadgeFrom(string $accessToken): UserBadge + { + // get the data from the token + $payload = ...; + + return new UserBadge( + $payload->getUserId(), + fn (string $userIdentifier): User => new User($userIdentifier, $payload->getRoles()) + ); + + // or + return new UserBadge( + $payload->getUserId(), + $this->loadUser(...) + ); + } From a467bd93dfa28f02f5dc04bb7bfd7076cf0648a1 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Wed, 31 Jul 2024 12:13:32 +0200 Subject: [PATCH 20/34] Fix attribute arguments highlighting and better support CPP --- src/Templates/highlight.php/php.json | 4 ++-- .../blocks/code-blocks/php-attributes.html | 16 ++++++++-------- .../expected/blocks/code-blocks/php.html | 14 ++++++++++++++ tests/fixtures/source/blocks/code-blocks/php.rst | 7 +++++++ 4 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/Templates/highlight.php/php.json b/src/Templates/highlight.php/php.json index c31251a..6f69970 100644 --- a/src/Templates/highlight.php/php.json +++ b/src/Templates/highlight.php/php.json @@ -28,7 +28,7 @@ "end": "\\)", "keywords": "array bool boolean float int integer new real string false FALSE null NULL true TRUE PHP_VERSION PHP_MAJOR_VERSION PHP_MINOR_VERSION PHP_RELEASE_VERSION PHP_VERSION_ID PHP_EXTRA_VERSION ZEND_THREAD_SAFE ZEND_DEBUG_BUILD PHP_ZTS PHP_DEBUG PHP_MAXPATHLEN PHP_OS PHP_OS_FAMILY PHP_SAPI PHP_EOL PHP_INT_MAX PHP_INT_MIN PHP_INT_SIZE PHP_FLOAT_DIG PHP_FLOAT_EPSILON PHP_FLOAT_MIN PHP_FLOAT_MAX DEFAULT_INCLUDE_PATH PEAR_INSTALL_DIR PEAR_EXTENSION_DIR PHP_EXTENSION_DIR PHP_PREFIX PHP_BINDIR PHP_BINARY PHP_MANDIR PHP_LIBDIR PHP_DATADIR PHP_SYSCONFDIR PHP_LOCALSTATEDIR PHP_CONFIG_FILE_PATH PHP_CONFIG_FILE_SCAN_DIR PHP_SHLIB_SUFFIX PHP_FD_SETSIZE E_ERROR E_WARNING E_PARSE E_NOTICE E_CORE_ERROR E_CORE_WARNING E_COMPILE_ERROR E_COMPILE_WARNING E_USER_ERROR E_USER_WARNING E_USER_NOTICE E_RECOVERABLE_ERROR E_DEPRECATED E_USER_DEPRECATED E_ALL E_STRICT __COMPILER_HALT_OFFSET__ PHP_WINDOWS_EVENT_CTRL_C PHP_WINDOWS_EVENT_CTRL_BREAK PHP_CLI_PROCESS_TITLE STDERR STDIN STDOUT __CLASS__ __DIR__ __FILE__ __FUNCTION__ __LINE__ __METHOD__ __NAMESPACE__ __TRAIT__", "contains": { - "$ref": "#contains.10.contains.3.contains", + "$ref": "#contains.9.contains.1.contains", "_": "params" } }, @@ -250,7 +250,7 @@ "className": "params", "begin": "\\(", "end": "\\)", - "keywords": "array bool boolean callable float int integer iterable mixed never numeric object real string resource self static false FALSE null NULL true TRUE", + "keywords": "array bool boolean callable float int integer iterable mixed never numeric object private protected public real string resource self static false FALSE null NULL true TRUE", "contains": [ "self", { diff --git a/tests/fixtures/expected/blocks/code-blocks/php-attributes.html b/tests/fixtures/expected/blocks/code-blocks/php-attributes.html index 2b77434..363b21f 100644 --- a/tests/fixtures/expected/blocks/code-blocks/php-attributes.html +++ b/tests/fixtures/expected/blocks/code-blocks/php-attributes.html @@ -90,7 +90,7 @@ $ property3 ; - #[AttributeName('value', option: 'value')] + #[AttributeName('value', option: 'value')] private $ property4 @@ -102,7 +102,7 @@ ; #[AttributeName( 'value', - option: 'value' + option: 'value' )] private @@ -115,32 +115,32 @@ ; #[Assert\AttributeName( 'value', - option: 'value' + option: 'value' )] private $ property8 ; - #[Route('/blog/{page<\d+>}', name: 'blog_list')] + #[Route('/blog/{page<\d+>}', name: 'blog_list')] private $ property9 ; #[Assert\GreaterThanOrEqual( - value: 18, + value: 18, )] private $ property10 ; - #[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')] + #[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')] private $ property11 ; #[Assert\AtLeastOneOf([ - new Assert\Regex('/#/'), - new Assert\Length(min: 10), + new Assert\Regex('/#/'), + new Assert\Length(min: 10), ])] private diff --git a/tests/fixtures/expected/blocks/code-blocks/php.html b/tests/fixtures/expected/blocks/code-blocks/php.html index f7bd021..163de59 100644 --- a/tests/fixtures/expected/blocks/code-blocks/php.html +++ b/tests/fixtures/expected/blocks/code-blocks/php.html @@ -97,3 +97,17 @@

+
+
+
1
+2
+3
+4
+

+public function __construct(
+    private string $username
+) {
+}
+        
+
+
diff --git a/tests/fixtures/source/blocks/code-blocks/php.rst b/tests/fixtures/source/blocks/code-blocks/php.rst index 6498028..33ed08e 100644 --- a/tests/fixtures/source/blocks/code-blocks/php.rst +++ b/tests/fixtures/source/blocks/code-blocks/php.rst @@ -47,3 +47,10 @@ $this->loadUser(...) ); } + +.. code-block:: php + + public function __construct( + private string $username + ) { + } From 8f09af6ad644414af3ed60f40a473ae4d8340f4f Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 26 Aug 2024 13:07:21 +0200 Subject: [PATCH 21/34] Highlight nested PHP comments --- tests/IntegrationTest.php | 4 ++ .../code-blocks/php-nested-comments.html | 72 +++++++++++++++++++ .../code-blocks/php-nested-comments.rst | 12 ++++ 3 files changed, 88 insertions(+) create mode 100644 tests/fixtures/expected/blocks/code-blocks/php-nested-comments.html create mode 100644 tests/fixtures/source/blocks/code-blocks/php-nested-comments.rst diff --git a/tests/IntegrationTest.php b/tests/IntegrationTest.php index f121ba3..95fef1d 100644 --- a/tests/IntegrationTest.php +++ b/tests/IntegrationTest.php @@ -294,6 +294,10 @@ public function parserUnitBlockProvider() 'blockName' => 'code-blocks/php-attributes', ]; + yield 'code-block-php-nested-comments' => [ + 'blockName' => 'code-blocks/php-nested-comments', + ]; + yield 'code-block-text' => [ 'blockName' => 'code-blocks/text', ]; diff --git a/tests/fixtures/expected/blocks/code-blocks/php-nested-comments.html b/tests/fixtures/expected/blocks/code-blocks/php-nested-comments.html new file mode 100644 index 0000000..e1f7078 --- /dev/null +++ b/tests/fixtures/expected/blocks/code-blocks/php-nested-comments.html @@ -0,0 +1,72 @@ +

You can do that by adding a "stamp" to your message:

+
+
+
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+
+            
+                use
+                Symfony
+                \
+                Component
+                \
+                Messenger
+                \
+                MessageBusInterface
+                ;
+                use
+                Symfony
+                \
+                Component
+                \
+                Messenger
+                \
+                Stamp
+                \
+                DelayStamp
+                ;
+                public
+                
+                    function
+                    index
+                    
+                        (MessageBusInterface
+                        
+                            $
+                            bus
+                        
+                        )
+                    
+                
+                {
+                
+                    $
+                    bus
+                
+                ->
+                dispatch
+                (
+                new
+                SmsNotification
+                (
+                '...'
+                ), [
+                // wait 5 seconds before processing
+                new
+                DelayStamp
+                (
+                5000
+                ), ]);
+}
+            
+        
+
+
diff --git a/tests/fixtures/source/blocks/code-blocks/php-nested-comments.rst b/tests/fixtures/source/blocks/code-blocks/php-nested-comments.rst new file mode 100644 index 0000000..ea8dc0f --- /dev/null +++ b/tests/fixtures/source/blocks/code-blocks/php-nested-comments.rst @@ -0,0 +1,12 @@ +You can do that by adding a "stamp" to your message:: + + use Symfony\Component\Messenger\MessageBusInterface; + use Symfony\Component\Messenger\Stamp\DelayStamp; + + public function index(MessageBusInterface $bus) + { + $bus->dispatch(new SmsNotification('...'), [ + // wait 5 seconds before processing + new DelayStamp(5000), + ]); + } From e7c0a063f5eba8f3a5a279cf1a6b9305078c59ff Mon Sep 17 00:00:00 2001 From: Guillaume Date: Thu, 1 Aug 2024 20:03:55 +0200 Subject: [PATCH 22/34] :bug: Fix yaml number rendering --- src/Renderers/CodeNodeRenderer.php | 1 + src/Templates/highlight.php/yaml.json | 127 ++++++++++++++++++ .../expected/blocks/code-blocks/yaml.html | 37 ++++- .../source/blocks/code-blocks/yaml.rst | 9 ++ 4 files changed, 170 insertions(+), 4 deletions(-) create mode 100644 src/Templates/highlight.php/yaml.json diff --git a/src/Renderers/CodeNodeRenderer.php b/src/Renderers/CodeNodeRenderer.php index a9e5643..d5e771e 100644 --- a/src/Renderers/CodeNodeRenderer.php +++ b/src/Renderers/CodeNodeRenderer.php @@ -121,6 +121,7 @@ private function configureHighlighter() if (false === self::$isHighlighterConfigured) { Highlighter::registerLanguage('php', __DIR__.'/../Templates/highlight.php/php.json', true); Highlighter::registerLanguage('twig', __DIR__.'/../Templates/highlight.php/twig.json', true); + Highlighter::registerLanguage('yaml', __DIR__.'/../Templates/highlight.php/yaml.json', true); } self::$isHighlighterConfigured = true; diff --git a/src/Templates/highlight.php/yaml.json b/src/Templates/highlight.php/yaml.json new file mode 100644 index 0000000..3db70a8 --- /dev/null +++ b/src/Templates/highlight.php/yaml.json @@ -0,0 +1,127 @@ +{ + "case_insensitive": true, + "aliases": [ + "yml", + "YAML", + "yaml" + ], + "contains": [ + { + "className": "attr", + "variants": [ + { + "begin": "\\w[\\w :\\\/.-]*:(?=[ \t]|$)" + }, + { + "begin": "\"\\w[\\w :\\\/.-]*\":(?=[ \t]|$)" + }, + { + "begin": "'\\w[\\w :\\\/.-]*':(?=[ \t]|$)" + } + ] + }, + { + "className": "meta", + "begin": "^---s*$", + "relevance": 10 + }, + { + "className": "string", + "begin": "[\\|>]([0-9]?[+-])?[ ]*\\n( *)[\\S ]+\\n(\\2[\\S ]+\\n?)*" + }, + { + "begin": "<%[%=-]?", + "end": "[%-]?%>", + "subLanguage": "ruby", + "excludeBegin": true, + "excludeEnd": true, + "relevance": 0 + }, + { + "className": "type", + "begin": "![a-zA-Z_]\\w*" + }, + { + "className": "type", + "begin": "!![a-zA-Z_]\\w*" + }, + { + "className": "meta", + "begin": "&[a-zA-Z_]\\w*$" + }, + { + "className": "meta", + "begin": "\\*[a-zA-Z_]\\w*$" + }, + { + "className": "bullet", + "begin": "\\-(?=[ ]|$)", + "relevance": 0 + }, + { + "className": "comment", + "begin": "#", + "end": "$", + "contains": [ + { + "begin": "\\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\\b" + }, + { + "className": "doctag", + "begin": "(?:TODO|FIXME|NOTE|BUG|XXX):", + "relevance": 0 + } + ] + }, + { + "beginKeywords": "true false yes no null", + "keywords": { + "literal": "true false yes no null" + } + }, + { + "className": "number", + "begin": "\\b([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(([Tt]|[ \\t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(\\.([0-9]*))?([ \\t]*(Z|([-+])([0-9][0-9]?)(:([0-9][0-9]))?))?)?\\b" + }, + { + "className": "number", + "begin": "(-?)(\\b0[xX][a-fA-F0-9_]+|(\\b\\d[\\d_]*(\\.[\\d_]*)?|\\.\\d[\\d_]*)([eE][-+]?\\d[\\d_]*)?)\\b" + }, + { + "className": "string", + "relevance": 0, + "variants": [ + { + "begin": "'", + "end": "'" + }, + { + "begin": "\"", + "end": "\"" + }, + { + "begin": "\\S+" + } + ], + "contains": [ + { + "begin": "\\\\[\\s\\S]", + "relevance": 0 + }, + { + "className": "template-variable", + "variants": [ + { + "begin": "{{", + "end": "}}" + }, + { + "begin": "%{", + "end": "}" + } + ] + } + ] + } + ] +} diff --git a/tests/fixtures/expected/blocks/code-blocks/yaml.html b/tests/fixtures/expected/blocks/code-blocks/yaml.html index fceca11..2de3b7b 100644 --- a/tests/fixtures/expected/blocks/code-blocks/yaml.html +++ b/tests/fixtures/expected/blocks/code-blocks/yaml.html @@ -1,7 +1,36 @@ -
+
-
1
-
# some code
-
+
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+
+            
+                # some code
+                parameters:
+                credit_card_number:
+                1234_5678_9012_3456
+                long_number:
+                10_000_000_000
+                pi:
+                3.14159_26535_89793
+                hex_words:
+                0x_CAFE_F00D
+                canonical:
+                2001-12-15T02:59:43.1Z
+                iso8601:
+                2001-12-14t21:59:43.10-05:00
+                spaced:
+                2001-12-14 21:59:43.10 -5
+                date:
+                2002-12-14
+            
+        
diff --git a/tests/fixtures/source/blocks/code-blocks/yaml.rst b/tests/fixtures/source/blocks/code-blocks/yaml.rst index 45ce98d..f56652d 100644 --- a/tests/fixtures/source/blocks/code-blocks/yaml.rst +++ b/tests/fixtures/source/blocks/code-blocks/yaml.rst @@ -1,3 +1,12 @@ .. code-block:: yaml # some code + parameters: + credit_card_number: 1234_5678_9012_3456 + long_number: 10_000_000_000 + pi: 3.14159_26535_89793 + hex_words: 0x_CAFE_F00D + canonical: 2001-12-15T02:59:43.1Z + iso8601: 2001-12-14t21:59:43.10-05:00 + spaced: 2001-12-14 21:59:43.10 -5 + date: 2002-12-14 From 3a300ac19a9338c4e05fd1a8434309eb83805269 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 11 Sep 2024 11:19:33 +0200 Subject: [PATCH 23/34] Add support for tilde characters --- tests/IntegrationTest.php | 4 ++++ tests/fixtures/expected/blocks/nodes/text.html | 7 +++++++ tests/fixtures/source/blocks/nodes/text.rst | 7 +++++++ 3 files changed, 18 insertions(+) create mode 100644 tests/fixtures/expected/blocks/nodes/text.html create mode 100644 tests/fixtures/source/blocks/nodes/text.rst diff --git a/tests/IntegrationTest.php b/tests/IntegrationTest.php index f121ba3..3045334 100644 --- a/tests/IntegrationTest.php +++ b/tests/IntegrationTest.php @@ -142,6 +142,10 @@ public function parserUnitBlockProvider() 'blockName' => 'nodes/span-link', ]; + yield 'text' => [ + 'blockName' => 'nodes/text', + ]; + yield 'title' => [ 'blockName' => 'nodes/title', ]; diff --git a/tests/fixtures/expected/blocks/nodes/text.html b/tests/fixtures/expected/blocks/nodes/text.html new file mode 100644 index 0000000..afc3337 --- /dev/null +++ b/tests/fixtures/expected/blocks/nodes/text.html @@ -0,0 +1,7 @@ +

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ut enim ad minim +veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea +commodo consequat. Duis aute irure dolor in reprehenderit in voluptate +velit esse cillum dolore eu fugiat nulla pariatur.

+ +

Excepteur ~1,000 sint! Occaecat cupidatat non proident, sunt in culpa qui officia +deserunt mollit anim id est laborum. áàâäãåéèêëíìîïóòôöõúùûüñçÿ

diff --git a/tests/fixtures/source/blocks/nodes/text.rst b/tests/fixtures/source/blocks/nodes/text.rst new file mode 100644 index 0000000..f5dbb33 --- /dev/null +++ b/tests/fixtures/source/blocks/nodes/text.rst @@ -0,0 +1,7 @@ +**Lorem ipsum** dolor sit amet, consectetur adipisicing elit. Ut enim ad minim +veniam, quis nostrud *exercitation ullamco laboris* nisi ut aliquip ex ea +commodo consequat. ``Duis aute irure dolor`` in reprehenderit in voluptate +velit esse cillum dolore eu fugiat nulla pariatur. + +Excepteur ~1,000 sint! Occaecat cupidatat non proident, sunt in culpa qui officia +deserunt mollit anim id est laborum. áàâäãåéèêëíìîïóòôöõúùûüñçÿ From 9223ccc89e6c7b0ab78c0af755ce85ebaa918668 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Wed, 11 Sep 2024 15:51:17 +0200 Subject: [PATCH 24/34] Temporary replace tildes to avoid it being parsed as NBSP --- src/Renderers/SpanNodeRenderer.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Renderers/SpanNodeRenderer.php b/src/Renderers/SpanNodeRenderer.php index 65598bd..f9db721 100644 --- a/src/Renderers/SpanNodeRenderer.php +++ b/src/Renderers/SpanNodeRenderer.php @@ -42,6 +42,19 @@ public function __construct( $this->symfonyVersion = $symfonyVersion; } + public function render(): string + { + // Work around "~" being parsed as non-breaking space by rst-parser, + // while this is not part of the specification. + $spanValue = $this->span->getValue(); + $spanValue = str_replace('~', '__TILDE__', $spanValue); + $this->span->setValue($spanValue); + + $rendered = parent::render(); + + return str_replace('__TILDE__', '~', $rendered); + } + /** @inheritDoc */ public function link(?string $url, string $title, array $attributes = []): string { From caacb35c69edfe26451c4bb6e3cabb4156938c07 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 12 Sep 2024 11:27:42 +0200 Subject: [PATCH 25/34] Minor tweak --- src/Renderers/SpanNodeRenderer.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Renderers/SpanNodeRenderer.php b/src/Renderers/SpanNodeRenderer.php index f9db721..927c3fa 100644 --- a/src/Renderers/SpanNodeRenderer.php +++ b/src/Renderers/SpanNodeRenderer.php @@ -47,6 +47,11 @@ public function render(): string // Work around "~" being parsed as non-breaking space by rst-parser, // while this is not part of the specification. $spanValue = $this->span->getValue(); + + if (str_contains($spanValue, '__TILDE__')) { + throw new \Exception('Cannot render content containing the text "__TILDE__" as it is used as a special placeholder in the build.'); + } + $spanValue = str_replace('~', '__TILDE__', $spanValue); $this->span->setValue($spanValue); From f34b7a73d98a77db5b492c9a53fe8d520cda8279 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 12 Sep 2024 12:03:00 +0200 Subject: [PATCH 26/34] Don't use the deprecated spaceless filter --- src/Templates/default/html/figure.html.twig | 8 +------- src/Templates/default/html/link.html.twig | 2 -- src/Templates/default/html/toc-level.html.twig | 12 +++++------- src/Templates/default/html/toc.html.twig | 10 ++++------ tests/fixtures/expected/build-pdf/book.html | 4 ++-- tests/fixtures/expected/main/index.html | 2 +- tests/fixtures/expected/toctree/index.html | 10 +++++----- 7 files changed, 18 insertions(+), 30 deletions(-) diff --git a/src/Templates/default/html/figure.html.twig b/src/Templates/default/html/figure.html.twig index e1786c0..5836788 100644 --- a/src/Templates/default/html/figure.html.twig +++ b/src/Templates/default/html/figure.html.twig @@ -1,12 +1,7 @@ {# Overridden to fix lack of figclass support (class attribute on +
{{ figureNode.image.render()|raw }} {% if figureNode.document %} @@ -17,4 +12,3 @@ Overridden to fix lack of figclass support (class attribute on -{% endapply %} diff --git a/src/Templates/default/html/link.html.twig b/src/Templates/default/html/link.html.twig index 8b9ca5b..7c82a66 100644 --- a/src/Templates/default/html/link.html.twig +++ b/src/Templates/default/html/link.html.twig @@ -1,5 +1,3 @@ -{% apply spaceless %} {% set domElement = attributes.domElement|default %} {% set class = (attributes.class|default ? attributes.class ~ ' ' : '') ~ 'reference ' ~ (('://' in url) ? 'external' : 'internal') %} key != 'domElement' and key != 'class') %} {{ key }}="{{ value }}"{% endfor %}>{% if domElement %}<{{ domElement }}>{% endif %}{{ title|raw }}{% if domElement %}{% endif %} -{% endapply %} diff --git a/src/Templates/default/html/toc-level.html.twig b/src/Templates/default/html/toc-level.html.twig index 1bdaef8..8c3eb34 100644 --- a/src/Templates/default/html/toc-level.html.twig +++ b/src/Templates/default/html/toc-level.html.twig @@ -1,7 +1,5 @@ -{% apply spaceless %} -
    - {% for tocItem in tocItems %} - {% include "toc-item.html.twig" with { toc_deep_level: 1 } %} - {% endfor %} -
-{% endapply %} +
    + {% for tocItem in tocItems %} + {% include "toc-item.html.twig" with { toc_deep_level: 1 } %} + {% endfor %} +
diff --git a/src/Templates/default/html/toc.html.twig b/src/Templates/default/html/toc.html.twig index 55b8737..8b9c883 100644 --- a/src/Templates/default/html/toc.html.twig +++ b/src/Templates/default/html/toc.html.twig @@ -1,6 +1,4 @@ -{% apply spaceless %} - {% set toc_options = toc_options(tocItems) %} -
- {% include "toc-level.html.twig" %} -
-{% endapply %} +{% set toc_options = toc_options(tocItems) %} +
+ {% include "toc-level.html.twig" %} +
diff --git a/tests/fixtures/expected/build-pdf/book.html b/tests/fixtures/expected/build-pdf/book.html index a214463..4454f94 100644 --- a/tests/fixtures/expected/build-pdf/book.html +++ b/tests/fixtures/expected/build-pdf/book.html @@ -8,8 +8,8 @@

Book

Here is a link to the main index

diff --git a/tests/fixtures/expected/main/index.html b/tests/fixtures/expected/main/index.html index 1346373..628cc91 100644 --- a/tests/fixtures/expected/main/index.html +++ b/tests/fixtures/expected/main/index.html @@ -10,7 +10,7 @@

Some Test Docs!

- +

A header

diff --git a/tests/fixtures/expected/toctree/index.html b/tests/fixtures/expected/toctree/index.html index e07a28e..676005a 100644 --- a/tests/fixtures/expected/toctree/index.html +++ b/tests/fixtures/expected/toctree/index.html @@ -9,11 +9,11 @@ From b4a10315d9e2074d490a01cb78706e0015b65b60 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Thu, 26 Sep 2024 22:09:28 +0200 Subject: [PATCH 27/34] Enhancement: Drop PHP 7.4 support (#183) --- .github/workflows/ci.yaml | 4 ++-- composer.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index bc16178..4db2db0 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -20,7 +20,7 @@ jobs: uses: shivammathur/setup-php@v2 with: coverage: none - php-version: 7.4 + php-version: 8.3 tools: composer:v2 ini-values: date.timezone=UTC @@ -37,7 +37,7 @@ jobs: # add here only the PHP versions and OS used in GitHub CI (for tests) # and on the symfony.com server (where the Symfony Docs are built) operating-system: ['ubuntu-latest'] - php-version: ['7.4', '8.3'] + php-version: ['8.3'] steps: - name: 'Checkout code' diff --git a/composer.json b/composer.json index dde5a06..8e66ada 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,7 @@ } }, "require": { - "php": ">=7.4", + "php": ">=8.3", "ext-json": "*", "ext-curl": "*", "doctrine/rst-parser": "^0.5", From 126cfbff31822a56f39935f64d8da06265804a2b Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 27 Sep 2024 09:31:34 +0200 Subject: [PATCH 28/34] Add support for inline Twig comments Co-authored-by: Wouter de Jong --- src/Templates/highlight.php/twig.json | 18 +++++++++-- .../expected/blocks/code-blocks/twig.html | 30 +++++++++++++++++-- .../source/blocks/code-blocks/twig.rst | 10 ++++++- 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/src/Templates/highlight.php/twig.json b/src/Templates/highlight.php/twig.json index b961028..ceb675d 100644 --- a/src/Templates/highlight.php/twig.json +++ b/src/Templates/highlight.php/twig.json @@ -25,6 +25,12 @@ "begin": "\\{%", "end": "%}", "contains": [ + { + "className": "comment", + "begin": "#", + "end": "$", + "endsWithParent": true + }, { "className": "name", "begin": "\\w+", @@ -32,6 +38,9 @@ "starts": { "endsWithParent": true, "contains": [ + { + "$ref": "#contains.1.contains.0" + }, { "begin": "\\|[A-Za-z_]+:?", "keywords": "abs batch capitalize column convert_encoding date date_modify default escape filter first format inky_to_html inline_css join json_encode keys last length lower map markdown merge nl2br number_format raw reduce replace reverse round slice sort spaceless split striptags title trim upper url_encode", @@ -53,7 +62,7 @@ ] }, { - "$ref": "#contains.1.contains.0.starts.contains.0.contains.0" + "$ref": "#contains.1.contains.1.starts.contains.1.contains.0" } ], "relevance": 0 @@ -68,10 +77,13 @@ "contains": [ "self", { - "$ref": "#contains.1.contains.0.starts.contains.0" + "$ref": "#contains.1.contains.0" + }, + { + "$ref": "#contains.1.contains.1.starts.contains.1" }, { - "$ref": "#contains.1.contains.0.starts.contains.0.contains.0" + "$ref": "#contains.1.contains.1.starts.contains.1.contains.0" } ] } diff --git a/tests/fixtures/expected/blocks/code-blocks/twig.html b/tests/fixtures/expected/blocks/code-blocks/twig.html index fab139d..83c841c 100644 --- a/tests/fixtures/expected/blocks/code-blocks/twig.html +++ b/tests/fixtures/expected/blocks/code-blocks/twig.html @@ -1,6 +1,30 @@ -
+
-
1
-
{# some code #}
+
1
+2
+3
+4
+5
+6
+7
+8
+9
+
+            
+                {# some code #}
+                
+                
+                    {%
+                        set some_var = 'some value' # some inline comment
+                    %}
+                
+                
+                {{
+                    # another inline comment
+                    'Lorem Ipsum'|uppercase
+                    # final inline comment
+                }}
+            
+        
diff --git a/tests/fixtures/source/blocks/code-blocks/twig.rst b/tests/fixtures/source/blocks/code-blocks/twig.rst index 01d0685..229041d 100644 --- a/tests/fixtures/source/blocks/code-blocks/twig.rst +++ b/tests/fixtures/source/blocks/code-blocks/twig.rst @@ -1,3 +1,11 @@ - .. code-block:: twig + {# some code #} + {% + set some_var = 'some value' # some inline comment + %} + {{ + # another inline comment + 'Lorem Ipsum'|uppercase + # final inline comment + }} From d05cf4202737306c383016e18f6454865a2492a1 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 12 Dec 2024 11:19:15 +0100 Subject: [PATCH 29/34] Fix PHP 8.4 deprecations --- src/Renderers/SpanNodeRenderer.php | 2 +- src/SymfonyHTMLFormat.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Renderers/SpanNodeRenderer.php b/src/Renderers/SpanNodeRenderer.php index 927c3fa..e1e7775 100644 --- a/src/Renderers/SpanNodeRenderer.php +++ b/src/Renderers/SpanNodeRenderer.php @@ -32,7 +32,7 @@ public function __construct( SpanNode $span, BaseSpanNodeRenderer $decoratedSpanNodeRenderer, ?UrlChecker $urlChecker = null, - string $symfonyVersion = null + ?string $symfonyVersion = null ) { parent::__construct($environment, $span); diff --git a/src/SymfonyHTMLFormat.php b/src/SymfonyHTMLFormat.php index 9c17ca9..16ea957 100644 --- a/src/SymfonyHTMLFormat.php +++ b/src/SymfonyHTMLFormat.php @@ -29,7 +29,7 @@ final class SymfonyHTMLFormat implements Format private $urlChecker; private $symfonyVersion; - public function __construct(TemplateRenderer $templateRenderer, Format $HTMLFormat, ?UrlChecker $urlChecker = null, string $symfonyVersion = null) + public function __construct(TemplateRenderer $templateRenderer, Format $HTMLFormat, ?UrlChecker $urlChecker = null, ?string $symfonyVersion = null) { $this->templateRenderer = $templateRenderer; $this->htmlFormat = $HTMLFormat; From f05792a72a09602f9c992d40d00c205b8d139ab9 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 12 Dec 2024 12:37:03 +0100 Subject: [PATCH 30/34] Fix a Twig deprecation (#186) --- src/Templates/default/html/image.html.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Templates/default/html/image.html.twig b/src/Templates/default/html/image.html.twig index f7ff3ff..14f090e 100644 --- a/src/Templates/default/html/image.html.twig +++ b/src/Templates/default/html/image.html.twig @@ -2,7 +2,7 @@ Overridden so we can control the path to the image based on our copying logic. See CopyImagesListener. #} -{% set wrap_image_with_browser = 'with-browser' in imageNode.options.class ?? '' %} +{% set wrap_image_with_browser = 'with-browser' in (imageNode.options.class ?? '') %} {% if wrap_image_with_browser %}
{% endif %} {% if wrap_image_with_browser %}
{% endif %} From b5a4aed0e702ce8cc30a82632e9dc6775d54510f Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 12 Dec 2024 13:41:00 +0100 Subject: [PATCH 31/34] Test code in PHP 8.4 too (#187) --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 4db2db0..f85af4b 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -37,7 +37,7 @@ jobs: # add here only the PHP versions and OS used in GitHub CI (for tests) # and on the symfony.com server (where the Symfony Docs are built) operating-system: ['ubuntu-latest'] - php-version: ['8.3'] + php-version: ['8.3', '8.4'] steps: - name: 'Checkout code' From af7ee47654250144e2c41b7ee9f869d50a7196a1 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Tue, 31 Dec 2024 15:49:09 +0100 Subject: [PATCH 32/34] Allow one line comments in argument list --- src/Templates/highlight.php/php.json | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/Templates/highlight.php/php.json b/src/Templates/highlight.php/php.json index 6f69970..0db2cb8 100644 --- a/src/Templates/highlight.php/php.json +++ b/src/Templates/highlight.php/php.json @@ -204,7 +204,15 @@ "_": "variable" }, { - "$ref": "#contains.10.contains.3.contains.2", + "$ref": "#contains.3", + "_": "comment" + }, + { + "$ref": "#contains.4", + "_": "comment" + }, + { + "$ref": "#contains.5", "_": "comment" }, { @@ -258,19 +266,8 @@ "_": "variable" }, { - "className": "comment", - "begin": "/\\*", - "end": "\\*/", - "contains": [ - { - "$ref": "#contains.2.contains.0" - }, - { - "className": "doctag", - "begin": "(?:TODO|FIXME|NOTE|BUG|XXX):", - "relevance": 0 - } - ] + "$ref": "#contains.5", + "_": "comment" }, { "className": "string", From 9a75cd7ebc7b195831b1a9f218e34c3da6d8fa24 Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Thu, 20 Mar 2025 21:44:07 +0100 Subject: [PATCH 33/34] Add support for phpclass reference with namespace --- src/Reference/PhpClassReference.php | 3 ++- tests/fixtures/expected/blocks/references/php-class.html | 1 + tests/fixtures/source/blocks/references/php-class.rst | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Reference/PhpClassReference.php b/src/Reference/PhpClassReference.php index 4e104e1..0bb0ba8 100644 --- a/src/Reference/PhpClassReference.php +++ b/src/Reference/PhpClassReference.php @@ -29,10 +29,11 @@ public function getName(): string public function resolve(Environment $environment, string $data): ResolvedReference { + $classnamePath = str_replace('\\', '-', strtolower($data)); return new ResolvedReference( $environment->getCurrentFileName(), $data, - sprintf('%s/class.%s.php', $this->phpDocUrl, strtolower($data)), + sprintf('%s/class.%s.php', $this->phpDocUrl, $classnamePath), [], [ 'title' => $data, diff --git a/tests/fixtures/expected/blocks/references/php-class.html b/tests/fixtures/expected/blocks/references/php-class.html index 271b968..b1e018e 100644 --- a/tests/fixtures/expected/blocks/references/php-class.html +++ b/tests/fixtures/expected/blocks/references/php-class.html @@ -1 +1,2 @@

ArrayAccess

+

BcMath\Number

diff --git a/tests/fixtures/source/blocks/references/php-class.rst b/tests/fixtures/source/blocks/references/php-class.rst index 5708c64..f0782b4 100644 --- a/tests/fixtures/source/blocks/references/php-class.rst +++ b/tests/fixtures/source/blocks/references/php-class.rst @@ -1,2 +1,4 @@ :phpclass:`ArrayAccess` + +:phpclass:`BcMath\Number` From 44b5818ee8c238b07ec8a16f8a863ed644d0b8f5 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Mon, 7 Apr 2025 13:02:32 +0200 Subject: [PATCH 34/34] Make behavior of PHP and GitHub references consistent (#191) --- src/Reference/MethodReference.php | 11 +++++------ src/Reference/PhpClassReference.php | 10 ++++++---- src/Reference/PhpMethodReference.php | 15 +++++++++++---- .../expected/blocks/references/php-class.html | 2 +- .../expected/blocks/references/php-method.html | 3 ++- tests/fixtures/expected/main/datetime.html | 2 +- .../source/blocks/references/php-class.rst | 2 +- .../source/blocks/references/php-method.rst | 2 ++ 8 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/Reference/MethodReference.php b/src/Reference/MethodReference.php index 632aaa2..b068f33 100644 --- a/src/Reference/MethodReference.php +++ b/src/Reference/MethodReference.php @@ -30,20 +30,19 @@ public function getName(): string public function resolve(Environment $environment, string $data): ResolvedReference { - $className = explode('::', $data)[0]; - $className = str_replace('\\\\', '\\', $className); - - if (!u($data)->containsAny('::')) { + $data = u($data); + if (!$data->containsAny('::')) { throw new \RuntimeException(sprintf('Malformed method reference "%s" in file "%s"', $data, $environment->getCurrentFileName())); } - $methodName = explode('::', $data)[1]; + [$className, $methodName] = $data->split('::', 2); + $className = $className->replace('\\\\', '\\'); $scrollTextFragment = sprintf('#:~:text=%s', rawurlencode('function '.$methodName)); return new ResolvedReference( $environment->getCurrentFileName(), $methodName.'()', - sprintf('%s/%s.php%s', $this->symfonyRepositoryUrl, str_replace('\\', '/', $className), $scrollTextFragment), + sprintf('%s/%s.php%s', $this->symfonyRepositoryUrl, $className->replace('\\', '/'), $scrollTextFragment), [], [ 'title' => sprintf('%s::%s()', $className, $methodName), diff --git a/src/Reference/PhpClassReference.php b/src/Reference/PhpClassReference.php index 0bb0ba8..fbaabe4 100644 --- a/src/Reference/PhpClassReference.php +++ b/src/Reference/PhpClassReference.php @@ -12,6 +12,7 @@ use Doctrine\RST\Environment; use Doctrine\RST\References\Reference; use Doctrine\RST\References\ResolvedReference; +use function Symfony\Component\String\u; class PhpClassReference extends Reference { @@ -29,14 +30,15 @@ public function getName(): string public function resolve(Environment $environment, string $data): ResolvedReference { - $classnamePath = str_replace('\\', '-', strtolower($data)); + $className = u($data)->replace('\\\\', '\\'); + return new ResolvedReference( $environment->getCurrentFileName(), - $data, - sprintf('%s/class.%s.php', $this->phpDocUrl, $classnamePath), + $className->afterLast('\\'), + sprintf('%s/class.%s.php', $this->phpDocUrl, $className->replace('\\', '-')->lower()), [], [ - 'title' => $data, + 'title' => $className, ] ); } diff --git a/src/Reference/PhpMethodReference.php b/src/Reference/PhpMethodReference.php index ac53744..9a85a91 100644 --- a/src/Reference/PhpMethodReference.php +++ b/src/Reference/PhpMethodReference.php @@ -12,6 +12,7 @@ use Doctrine\RST\Environment; use Doctrine\RST\References\Reference; use Doctrine\RST\References\ResolvedReference; +use function Symfony\Component\String\u; class PhpMethodReference extends Reference { @@ -29,15 +30,21 @@ public function getName(): string public function resolve(Environment $environment, string $data): ResolvedReference { - [$class, $method] = explode('::', $data, 2); + $data = u($data); + if (!$data->containsAny('::')) { + throw new \RuntimeException(sprintf('Malformed method reference "%s" in file "%s"', $data, $environment->getCurrentFileName())); + } + + [$className, $methodName] = $data->split('::', 2); + $className = $className->replace('\\\\', '\\'); return new ResolvedReference( $environment->getCurrentFileName(), - $data.'()', - sprintf('%s/%s.%s.php', $this->phpDocUrl, strtolower($class), strtolower($method)), + $methodName.'()', + sprintf('%s/%s.%s.php', $this->phpDocUrl, $className->replace('\\', '-')->lower(), $methodName->lower()), [], [ - 'title' => $class, + 'title' => sprintf('%s::%s()', $className, $methodName), ] ); } diff --git a/tests/fixtures/expected/blocks/references/php-class.html b/tests/fixtures/expected/blocks/references/php-class.html index b1e018e..a91b1fd 100644 --- a/tests/fixtures/expected/blocks/references/php-class.html +++ b/tests/fixtures/expected/blocks/references/php-class.html @@ -1,2 +1,2 @@

ArrayAccess

-

BcMath\Number

+

Number

diff --git a/tests/fixtures/expected/blocks/references/php-method.html b/tests/fixtures/expected/blocks/references/php-method.html index e86c571..59323ad 100644 --- a/tests/fixtures/expected/blocks/references/php-method.html +++ b/tests/fixtures/expected/blocks/references/php-method.html @@ -1 +1,2 @@ -

Locale::getDefault()

+

getDefault()

+

add()

diff --git a/tests/fixtures/expected/main/datetime.html b/tests/fixtures/expected/main/datetime.html index f36ddc3..d6892fa 100644 --- a/tests/fixtures/expected/main/datetime.html +++ b/tests/fixtures/expected/main/datetime.html @@ -79,7 +79,7 @@

methods: doRequest(). Or a namespace: Constraints. Or a PHP function: parse_ini_file. -Or a PHP method! Locale::getDefault().

+Or a PHP method! getDefault().

diff --git a/tests/fixtures/source/blocks/references/php-class.rst b/tests/fixtures/source/blocks/references/php-class.rst index f0782b4..284a901 100644 --- a/tests/fixtures/source/blocks/references/php-class.rst +++ b/tests/fixtures/source/blocks/references/php-class.rst @@ -1,4 +1,4 @@ :phpclass:`ArrayAccess` -:phpclass:`BcMath\Number` +:phpclass:`BcMath\\Number` diff --git a/tests/fixtures/source/blocks/references/php-method.rst b/tests/fixtures/source/blocks/references/php-method.rst index 11705cd..26d782d 100644 --- a/tests/fixtures/source/blocks/references/php-method.rst +++ b/tests/fixtures/source/blocks/references/php-method.rst @@ -1,2 +1,4 @@ :phpmethod:`Locale::getDefault` + +:phpmethod:`BcMath\\Number::add`