File Coverage

blib/lib/App/podman/Parser/Markdown.pm
Criterion Covered Total %
statement 72 89 80.9
branch 28 36 77.7
condition 7 9 77.7
subroutine 8 9 88.8
pod 0 3 0.0
total 115 146 78.7


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2021 -- leonerd@leonerd.org.uk
5              
6 2     2   78512 use v5.26;
  2         19  
7              
8 2     2   687 use Object::Pad 0.41;
  2         11107  
  2         11  
9              
10             package App::podman::Parser::Markdown 0.01;
11             class App::podman::Parser::Markdown
12 1     1   646 does App::podman::Parser;
  1         3  
  1         20  
13              
14 2     2   1724 use File::Slurper 'read_text';
  2         32138  
  2         273  
15              
16 2     2   20 use constant format => "Markdown";
  2         4  
  2         4735  
17              
18 1         3 sub can_parse_file ( $class, $file )
19 1     1 0 1057 {
  1         2  
  1         3  
20 1         11 return $file =~ m/\.md$/;
21             }
22              
23 0         0 method parse_file ( $fh )
  0         0  
  0         0  
24 0     0 0 0 {
25 0         0 return $self->parse_string( read_text $fh );
26             }
27              
28             has @_paragraphs;
29              
30 5         13 method parse_string ( $str )
  5         15  
  5         11  
31 5     5 0 4642 {
32 5         15 my $in_verb;
33              
34             my @lines;
35              
36 5         42 foreach ( split( m/\n/, $str ), "" ) {
37 37         63 my $line = $_; # So we have a copy, because foreach my ... will alias the readonly ""
38              
39 37 50       71 if( $in_verb ) {
40 0         0 my $para = $_paragraphs[-1];
41              
42 0 0       0 if( $line =~ m/^\`\`\`/ ) {
43 0         0 undef $in_verb;
44             next
45 0         0 }
46              
47 0 0       0 length $para->text and
48             $para->text->append( "\n" );
49              
50 0         0 $para->text->append( $line );
51 0         0 next;
52             }
53              
54 37 50       91 if( $line =~ s/^\`\`\`// ) {
55             # Ignore the type specifier for now
56 0         0 push @_paragraphs, App::podman::Para::Verbatim->new(
57             text => String::Tagged->new,
58             );
59 0         0 $in_verb++;
60 0         0 next;
61             }
62              
63 37 100       73 if( length $line ) {
64 21         37 push @lines, $line;
65 21         40 next;
66             }
67              
68 16         35 while( @lines ) {
69 17 100 100     172 if( $lines[0] =~ m/^ / ) {
    100          
    100          
    100          
70 1         5 my $raw = join "\n", @lines;
71 1         8 $raw =~ s/^ //mg;
72              
73 1         6 push @_paragraphs, App::podman::Para::Verbatim->new(
74             text => String::Tagged->new( $raw ),
75             );
76             }
77             elsif( $lines[0] =~ s/^(#+)\s+// ) {
78 3         13 my $level = length $1;
79 3         12 push @_paragraphs, App::podman::Para::Heading->new(
80             level => $level,
81             text => $self->_handle_spans( shift @lines ),
82             );
83              
84 3         56 next;
85             }
86             elsif( @lines >= 2 and $lines[1] =~ m/^([=-])\1*$/ ) {
87 2 100       10 my $level = ( $1 eq "=" ) ? 1 : 2;
88 2         9 push @_paragraphs, App::podman::Para::Heading->new(
89             level => $level,
90             text => $self->_handle_spans( shift @lines ),
91             );
92              
93 2         30 shift @lines;
94              
95 2         8 next;
96             }
97             elsif( $lines[0] =~ s/^[*+-]\s+// ) {
98 3         7 my $raw = shift @lines;
99 3   66     16 while( @lines and $lines[0] !~ m/^[*+-]/ ) {
100 0         0 $raw .= " " . ( shift(@lines) =~ m/^\s*(.*)$/ )[0];
101             }
102              
103 3         6 my $list;
104 3 100 66     15 if( @_paragraphs and $_paragraphs[-1]->type eq "list-bullet" ) {
105 2         4 $list = $_paragraphs[-1];
106             }
107             else {
108 1         19 push @_paragraphs, $list = App::podman::Para::List->new(
109             listtype => "bullet",
110             indent => 4,
111             );
112             }
113              
114 3         28 $list->push_item( App::podman::Para::ListItem->new(
115             text => $self->_handle_spans( $raw )
116             ) );
117              
118 3         10 next;
119             }
120             else {
121 8         37 push @_paragraphs, App::podman::Para::Plain->new(
122             text => $self->_handle_spans( join " ", @lines ),
123             );
124             }
125              
126 9         166 @lines = ();
127             }
128             }
129              
130 5         25 return @_paragraphs;
131             }
132              
133 16         22 method _handle_spans ( $s )
  16         28  
  16         20  
134 16     16   38 {
135 16         71 my $ret = String::Tagged->new;
136              
137 16         212 my %tags;
138              
139 16         53 while( pos $s < length $s ) {
140 42 50       1266 if( $s =~ m/\G\\(.)/gc ) {
    100          
    100          
    100          
    50          
141 0         0 $ret->append_tagged( $1, %tags );
142             }
143             elsif( $s =~ m/\G`/gc ) {
144             # Pull the contents ourselves so as to disarm the meaning of other
145             # chars, especially * and _, inside the code
146 4         22 $s =~ m/\G(.*?)`/gc;
147 4         13 $ret->append_tagged( $1, C => 1 );
148             }
149             elsif( $s =~ m/\G(([*_])\2?)/gc ) {
150 12 100       39 my $tag = ( length $1 > 1 ) ? "B" : "I";
151 12 100       51 $tags{$tag} ? delete $tags{$tag} : $tags{$tag}++;
152             }
153             elsif( $s =~ m/\G\[(.*?)\]/gc ) {
154 1         3 my $label = $1;
155 1         6 $s =~ m/\((.*?)\)/gc; my $target = $1;
  1         4  
156              
157 1         5 $ret->append_tagged( $label, L => { target => $target }, %tags );
158             }
159             elsif( $s =~ m/\G([^`\\*_[]+)/gc ) {
160 25         87 $ret->append_tagged( $1, %tags );
161             }
162             }
163              
164 16         681 return $ret;
165             }
166              
167             0x55AA;