dg-x/lib/Classy/Dialect/SpanParser.pm
snow flurry fb0d94a2c0 Add Markdent GFM extensions
- Per-image classes, to restrict what images a CSS selector acts on
  (in-post vs out-of-post)
- Fenced aside blocks (`!!!`-enclosed, like code blocks)
- Footnotes are handled by the Markdown parser, instead of manually
2024-10-05 17:24:16 -07:00

145 lines
3.4 KiB
Perl

package Classy::Dialect::SpanParser;
use strict;
use warnings;
use namespace::autoclean;
our $VERSION = '0.10';
use Markdent::Event::StartHTMLTag;
use Markdent::Event::EndHTMLTag;
use Markdent::Event::HTMLTag;
use Markdent::Event::StartOrderedList;
use Markdent::Event::EndOrderedList;
use Markdent::Event::HorizontalRule;
use Markdent::Event::StartLink;
use Markdent::Event::EndLink;
use Markdent::Event::Text;
use Markdent::Types;
use Moose::Role;
with 'Markdent::Dialect::GitHub::SpanParser';
has _notes_by_id => (
traits => ['Hash'],
is => 'ro',
isa => t( 'HashRef', of => t('Str') ),
default => sub { {} },
init_arg => undef,
handles => {
_add_fn_by_id => 'set',
_get_fn_by_id => 'get',
_reset_footnotes => 'clear',
},
);
has _note_idx_map => (
traits => ['Array'],
is => 'ro',
isa => t( 'ArrayRef', of => t('Str') ),
default => sub { [] },
handles => {
_add_fn_to_map => 'push',
_get_fn_list => 'get',
_fn_list_count => 'count',
_reset_fn_map => 'clear',
},
);
# Footnotes are kinda like links, but IDs are prefixed with a caret (^)
around extract_link_ids => sub {
my $orig = shift;
my $self = shift;
my $text = shift;
${$text} =~ s/ ^
\p{SpaceSeparator}{0,3}
\[ \^ ([^]]+) \]
:
\p{SpaceSeparator}*
\n?
\p{SpaceSeparator}*
(
(.|\n[^\n])+
)
(?:\n\n|$)
/
$self->_process_id_for_fn( $1, $2 );
''
/egxm;
$self->$orig($text);
};
around _possible_span_matches => sub {
my $orig = shift;
my $self = shift;
my @look_for = $self->$orig();
unshift @look_for, 'footnote';
return @look_for;
};
sub _process_id_for_fn {
my $self = shift;
my $id = shift;
my $id_text = shift;
$id_text =~ s/\s+$//;
$id_text =~ s/\n+/ /g;
$self->_debug_parse_result(
$id,
'footnote',
[ text => $id_text ],
) if $self->debug;
$self->_add_fn_by_id( $id => $id_text );
}
# Matches the inline footnote
sub _match_footnote {
my $self = shift;
my $text = shift;
my $pos = pos ${$text} || 0;
return
unless ${$text} =~ / \G
\[ \^ ([^]]+) \] # footnote id
/xgc;
my $fn_id = $1;
$self->_add_fn_to_map($fn_id);
my $fn_idx = $self->_fn_list_count;
# <sup>[<a href="#fn:id" title="fnref:id">idx</a>]</sup>
my $start_sup = $self->_make_event( StartHTMLTag => { tag => "sup" });
my $start_brack = '[';
my $end_brack = ']';
my $end_sup = $self->_make_event( EndHTMLTag => { tag => "sup" });
my $start_link = $self->_make_event( StartHTMLTag => {
tag => 'a',
attributes => {
href => "#fn:$fn_id",
id => "fnref:$fn_id",
},
});
my $end_link = $self->_make_event('EndLink');
$self->_markup_event($start_sup);
$self->_parse_text( \$start_brack );
$self->_markup_event($start_link);
$self->_parse_text( \$fn_idx );
$self->_markup_event($end_link);
$self->_parse_text( \$end_brack );
$self->_markup_event($end_sup);
return 1;
}
1;
__END__