package Text::Dokuwiki; use strict; use warnings; use feature qw/ switch /; use utf8; use Data::Dumper; sub new { my ($class) = @_; my $self = {}; return bless($self, $class); } sub parse { my ($self, $text) = @_; my ($tree, $mode, $attrs, $buf) = ([], 'text', '', ''); my @lines = split /\r?\n/o, $text; my $linenum = 0; foreach my $line (@lines) { $linenum++; given ($mode) { when (m!block/(file|code|nowiki)!o) { if ($line =~ m{^\s*}o) { if ($1 eq 'file') { my $dt = [dt => {}, 0 => $attrs->{file}]; my $dd = [dt => {}, 0 => [pre => {class => $attrs->{class}}, 0 => $buf]]; push @{ $tree }, [dl => {class => 'file'}, [$dt, $dd]]; } elsif ($1 eq 'nowiki') { push @{ $tree }, [pre => {}, 0 => $buf]; } else { push @{ $tree }, [code => {class => $attrs->{class}}, 0 => $buf]; } ($buf, $attrs, $mode) = ('', {}, undef); next; } $buf .= $line . "\n"; } when ("code") { if ($line =~ m/^\s{2}(.+)/o) { $buf .= $line . "\n"; next; } else { push @{ $tree }, [pre => {}, 0 => $buf]; ($buf, $attrs, $mode) = ('', {}, undef); continue; } } when ("list") { if ($line =~ m/^\s{2}([\*-])\s+(.+)/o) { push @{ $buf }, [li => {}, 0 => $2]; next; } else { push @{ $tree }, [ul => {}, @$buf]; # TODO: lost list type ($buf, $attrs, $mode) = ('', {}, undef); continue; } } when ("table") { ... } } given ($line) { # header when (m/^\s?(={2,6}) (.+) \g{1}\s*/o) { my $level = $1 =~ tr/=/=/; $level = 7 - $level; # invert push @{ $tree }, ["h$level" => {}, 0 => $2]; next; } # code/file block when (m/^\s?<(code|file)(?:\s+(\S+)\s+(\S+))?>\s*$/o) { $mode = "block/$1"; $attrs = ($2) ? {class => $2, file => $3} : {}; next; } # nowiki block when (m/\s?/o) { $mode = "block/nowiki"; next; } # lists when (m/^\s{2}([\*-])\s+(.+)/o) { $mode = 'list'; $buf = []; push @{ $buf }, [li => {}, 0 => $2]; next; } # quotes when (m/^\s?(>)+\s*(.+)/o) { my $level = $1 =~ tr/>/>/; push @{ $tree }, [blockquote => {level => $level}, 0 => $2]; next; } # table when (m/^\s?[\|\^]/o) { $mode = 'table'; $buf = $line . "\n"; # render later next; } # code idented with two spaces when (m/^\s{2}(\S.+)/o) { $mode = 'code'; $buf = $line . "\n"; next; } # nonempty line when (m/^\s?(\S.+)/o) { push @{ $tree }, [p => {}, 0 => $1]; next; } # empty lines; when (m/^\s*$/) { push @{ $tree }, [br => {}]; $mode = undef; next; } # catchall default { printf "Unmatched % 3d: %s\n", $linenum, $line; continue; } } } return $tree; } 1; __END__ [div => {class => 'block'}, #
0 => 'text1', # Hello! [strong => {}, 0 => 'bold text'], # user 0 => ', this is converted text.', # , this is converted text. [br => {}], #
[p => {}, 0 => 'Second paragraph'] #

Second paragraph

] #