snow flurry
fb0d94a2c0
- 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
145 lines
3.4 KiB
Perl
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__
|