Skip to content

Commit

Permalink
Add support for footnotes
Browse files Browse the repository at this point in the history
  • Loading branch information
samwilson authored Sep 15, 2023
1 parent 230edb6 commit 6c9c43b
Show file tree
Hide file tree
Showing 11 changed files with 166 additions and 1 deletion.
23 changes: 23 additions & 0 deletions src/Footnotes/FootnoteBackrefRenderer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace Samwilson\CommonMarkLatex\Footnotes;

use League\CommonMark\Extension\Footnote\Node\FootnoteBackref;
use League\CommonMark\Node\Node;
use League\CommonMark\Renderer\ChildNodeRendererInterface;
use League\CommonMark\Renderer\NodeRendererInterface;

final class FootnoteBackrefRenderer implements NodeRendererInterface
{
/**
* {@inheritDoc}
*/
public function render(Node $node, ChildNodeRendererInterface $childRenderer)
{
FootnoteBackref::assertInstanceOf($node);

return '';
}
}
20 changes: 20 additions & 0 deletions src/Footnotes/FootnoteContainerRenderer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace Samwilson\CommonMarkLatex\Footnotes;

use League\CommonMark\Extension\Footnote\Node\FootnoteContainer;
use League\CommonMark\Node\Node;
use League\CommonMark\Renderer\ChildNodeRendererInterface;
use League\CommonMark\Renderer\NodeRendererInterface;

final class FootnoteContainerRenderer implements NodeRendererInterface
{
public function render(Node $node, ChildNodeRendererInterface $childRenderer): string
{
FootnoteContainer::assertInstanceOf($node);

return '';
}
}
25 changes: 25 additions & 0 deletions src/Footnotes/FootnoteRefRenderer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

namespace Samwilson\CommonMarkLatex\Footnotes;

use League\CommonMark\Extension\Footnote\Node\FootnoteRef;
use League\CommonMark\Node\Node;
use League\CommonMark\Renderer\ChildNodeRendererInterface;
use League\CommonMark\Renderer\NodeRendererInterface;

final class FootnoteRefRenderer implements NodeRendererInterface
{
/**
* {@inheritDoc}
*/
public function render(Node $node, ChildNodeRendererInterface $childRenderer)
{
FootnoteRef::assertInstanceOf($node);

$footnote = GatherFootnotesListener::$footnotes[$node->getReference()->getTitle()];

return '\\footnote{' . $childRenderer->renderNodes($footnote->children()) . '}';
}
}
20 changes: 20 additions & 0 deletions src/Footnotes/FootnoteRenderer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace Samwilson\CommonMarkLatex\Footnotes;

use League\CommonMark\Extension\Footnote\Node\Footnote;
use League\CommonMark\Node\Node;
use League\CommonMark\Renderer\ChildNodeRendererInterface;
use League\CommonMark\Renderer\NodeRendererInterface;

final class FootnoteRenderer implements NodeRendererInterface
{
public function render(Node $node, ChildNodeRendererInterface $childRenderer): string
{
Footnote::assertInstanceOf($node);

return '';
}
}
31 changes: 31 additions & 0 deletions src/Footnotes/GatherFootnotesListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace Samwilson\CommonMarkLatex\Footnotes;

use League\CommonMark\Event\DocumentParsedEvent;
use League\CommonMark\Extension\Footnote\Node\Footnote;
use League\CommonMark\Node\NodeIterator;

final class GatherFootnotesListener
{
/** @var Node[] */
public static array $footnotes;

public function onDocumentParsed(DocumentParsedEvent $event): void
{
$document = $event->getDocument();

foreach ($document->iterator(NodeIterator::FLAG_BLOCKS_ONLY) as $node) {
if (! $node instanceof Footnote) {
continue;
}

$ref = $document->getReferenceMap()->get($node->getReference()->getLabel());
if ($ref !== null) {
self::$footnotes[$ref->getTitle()] = $node;
}
}
}
}
24 changes: 24 additions & 0 deletions src/LatexRendererExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Samwilson\CommonMarkLatex;

use League\CommonMark\Environment\EnvironmentBuilderInterface;
use League\CommonMark\Event\DocumentParsedEvent;
use League\CommonMark\Extension\CommonMark\Node\Block\BlockQuote;
use League\CommonMark\Extension\CommonMark\Node\Block\FencedCode;
use League\CommonMark\Extension\CommonMark\Node\Block\Heading;
Expand All @@ -18,8 +19,18 @@
use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
use League\CommonMark\Extension\CommonMark\Node\Inline\Strong;
use League\CommonMark\Extension\ExtensionInterface;
use League\CommonMark\Extension\Footnote\FootnoteExtension;
use League\CommonMark\Extension\Footnote\Node\Footnote;
use League\CommonMark\Extension\Footnote\Node\FootnoteBackref;
use League\CommonMark\Extension\Footnote\Node\FootnoteContainer;
use League\CommonMark\Extension\Footnote\Node\FootnoteRef;
use League\CommonMark\Node\Block\Paragraph;
use League\CommonMark\Node\Inline\Text;
use Samwilson\CommonMarkLatex\Footnotes\FootnoteBackrefRenderer;
use Samwilson\CommonMarkLatex\Footnotes\FootnoteContainerRenderer;
use Samwilson\CommonMarkLatex\Footnotes\FootnoteRefRenderer;
use Samwilson\CommonMarkLatex\Footnotes\FootnoteRenderer;
use Samwilson\CommonMarkLatex\Footnotes\GatherFootnotesListener;

final class LatexRendererExtension implements ExtensionInterface
{
Expand All @@ -44,5 +55,18 @@ public function register(EnvironmentBuilderInterface $environment): void
->addRenderer(Image::class, new ImageRenderer(), 10)
->addRenderer(Link::class, new LinkRenderer(), 10)
->addRenderer(Strong::class, new StrongRenderer(), 10);

foreach ($environment->getExtensions() as $ext) {
if ($ext instanceof FootnoteExtension) {
$environment
->addRenderer(FootnoteBackref::class, new FootnoteBackrefRenderer(), 15)
->addRenderer(FootnoteContainer::class, new FootnoteContainerRenderer(), 15)
->addRenderer(FootnoteRef::class, new FootnoteRefRenderer(), 15)
->addRenderer(Footnote::class, new FootnoteRenderer(), 15)
->addEventListener(DocumentParsedEvent::class, [new GatherFootnotesListener(), 'onDocumentParsed'], 15);

return;
}
}
}
}
2 changes: 1 addition & 1 deletion src/LatexSpecialCharsParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ final class LatexSpecialCharsParser implements InlineParserInterface
{
public function getMatchDefinition(): InlineParserMatch
{
return InlineParserMatch::oneOf('\\\\', '&', '%', '$', '#', '_', '{', '}', '~', '^');
return InlineParserMatch::regex('(\\\\|&|%|\$|\#|_|\{|\}|~|(?<!\[)(\^)(?=\s*\]?))');
}

public function parse(InlineParserContext $inlineContext): bool
Expand Down
9 changes: 9 additions & 0 deletions tests/data/foonotes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Lorem[^fnlabel] ipsum.

And[^1] another.

[^1]: A multi-

-paragraph footnote.

[^fnlabel]: Footnote *text*.
9 changes: 9 additions & 0 deletions tests/data/foonotes.tex
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Lorem\footnote{Footnote \emph{text}.
} ipsum.

And\footnote{A multi-

-paragraph footnote.
} another.


2 changes: 2 additions & 0 deletions tests/integration/CompileTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use League\CommonMark\Environment\Environment;
use League\CommonMark\Extension\Autolink\AutolinkExtension;
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
use League\CommonMark\Extension\Footnote\FootnoteExtension;
use League\CommonMark\MarkdownConverter;
use PHPUnit\Framework\TestCase;
use Samwilson\CommonMarkLatex\LatexRendererExtension;
Expand All @@ -19,6 +20,7 @@ public function testDataFiles(): void
$environment = new Environment(['html_input' => 'allow']);
$environment->addExtension(new CommonMarkCoreExtension());
$environment->addExtension(new AutolinkExtension());
$environment->addExtension(new FootnoteExtension());
$environment->addExtension(new LatexRendererExtension());
$converter = new MarkdownConverter($environment);
$markdownFiles = \glob(\dirname(__DIR__) . '/data/*.md');
Expand Down
2 changes: 2 additions & 0 deletions tests/unit/RendererTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use League\CommonMark\Environment\Environment;
use League\CommonMark\Extension\Autolink\AutolinkExtension;
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
use League\CommonMark\Extension\Footnote\FootnoteExtension;
use League\CommonMark\MarkdownConverter;
use PHPUnit\Framework\TestCase;
use Samwilson\CommonMarkLatex\LatexRendererExtension;
Expand All @@ -18,6 +19,7 @@ public function testDataFiles(): void
$environment = new Environment(['html_input' => 'allow']);
$environment->addExtension(new CommonMarkCoreExtension());
$environment->addExtension(new AutolinkExtension());
$environment->addExtension(new FootnoteExtension());
$environment->addExtension(new LatexRendererExtension());
$converter = new MarkdownConverter($environment);
$markdownFiles = \glob(\dirname(__DIR__) . '/data/*.md');
Expand Down

0 comments on commit 6c9c43b

Please sign in to comment.