summaryrefslogtreecommitdiffstats
path: root/Bugzilla/Markdown/GFM/Parser.pm
blob: 5307b49c18b996aa59f35b7927ebf389ab0a744f (plain)
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package Bugzilla::Markdown::GFM::Parser;

use 5.10.1;
use strict;
use warnings;

use FFI::Platypus::Buffer qw( scalar_to_buffer buffer_to_scalar );

sub new {
    my ($class, $options) = @_;
    my $extensions = delete $options->{extensions} // [];
    my $parser = $class->_new($options);
    $parser->{_options} = $options;

    eval {
        foreach my $name (@$extensions) {
            my $extension = Bugzilla::Markdown::GFM::SyntaxExtension->find($name)
                or die "unknown extension: $name";
            $parser->attach_syntax_extension($extension);
        }
    };

    return $parser;
}

sub render_html {
    my ($self, $markdown) = @_;
    $self->feed($markdown);
    my $node = $self->finish;
    return $node->render_html($self->{_options}, $self->get_syntax_extensions);
}

sub SETUP {
    my ($class, $FFI) = @_;

    $FFI->custom_type(
        markdown_parser_t => {
            native_type    => 'opaque',
            native_to_perl => sub {
                bless { _pointer => $_[0] }, $class;
            },
            perl_to_native => sub { $_[0]->{_pointer} },
        }
    );

    $FFI->attach(
        [ cmark_parser_new => '_new' ],
        [ 'markdown_options_t' ] => 'markdown_parser_t',
        sub {
            my $c_func = shift;
            return $c_func->($_[1]);
        }
    );

    $FFI->attach(
        [ cmark_parser_free => 'DESTROY' ],
        [ 'markdown_parser_t' ] => 'void'
    );

    $FFI->attach(
        [ cmark_parser_feed => 'feed'],
        ['markdown_parser_t', 'opaque', 'int'] => 'void',
        sub {
            my $c_func = shift;
            $c_func->($_[0], scalar_to_buffer $_[1]);
        }
    );

    $FFI->attach(
        [ cmark_parser_finish => 'finish' ],
        [ 'markdown_parser_t' ] => 'markdown_node_t',
    );

    $FFI->attach(
        [ cmark_parser_attach_syntax_extension => 'attach_syntax_extension' ],
        [ 'markdown_parser_t', 'markdown_syntax_extension_t' ] => 'void',
    );

    $FFI->attach(
        [ cmark_parser_get_syntax_extensions => 'get_syntax_extensions' ],
        [ 'markdown_parser_t' ] => 'markdown_syntax_extension_list_t',
    );
}

1;

__END__

=head1 NAME

Bugzilla::Markdown::GFM::Parser - Transforms markdown into HTML via libcmark_gfm.

=head1 SYNOPSIS

    use Bugzilla::Markdown::GFM;
    use Bugzilla::Markdown::GFM::Parser;

    my $parser = Bugzilla::Markdown::GFM::Parser->new({
        extensions => [qw( autolink tagfilter table strikethrough )]
    });

    say $parser->render_html(<<'MARKDOWN');
    # My header

    This is **markdown**!

    - list item 1
    - list item 2
    MARKDOWN