Files
oddmuse/modules/markdown-rule.pl
2017-05-22 12:23:15 +02:00

180 lines
5.7 KiB
Perl
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#! /usr/bin/perl
# Copyright (C) 20142-17 Alex Schroeder <alex@gnu.org>
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
use strict;
use v5.10;
AddModuleDescription('markdown-rule.pl', 'Markdown Rule Extension');
our ($q, $bol, %RuleOrder, @MyRules, $UrlProtocols, $FullUrlPattern, @HtmlStack);
push(@MyRules, \&MarkdownRule);
# Since we want this package to be a simple add-on, we try and avoid
# all conflicts by going *last*. The use of # for numbered lists by
# Usemod conflicts with the use of # for headings, for example.
$RuleOrder{\&MarkdownRule} = 200;
# http://daringfireball.net/projects/markdown/syntax
# https://help.github.com/articles/markdown-basics
# https://help.github.com/articles/github-flavored-markdown
sub MarkdownRule {
# \escape
if (m/\G\\([-#>*`=])/cg) {
return $1;
}
# atx headers
elsif ($bol and m~\G(\s*\n)*(#{1,6})[ \t]*~cg) {
my $header_depth = length($2);
return CloseHtmlEnvironments()
. AddHtmlEnvironment("h" . $header_depth);
}
# end atx header at a newline
elsif ((InElement('h1') or InElement('h2') or InElement('h3') or
InElement('h4') or InElement('h5') or InElement('h6'))
and m/\G\n/cg) {
return CloseHtmlEnvironments()
. AddHtmlEnvironment("p");
}
# setext headers
elsif ($bol and m/\G((\s*\n)*(.+?)[ \t]*\n(-+|=+)[ \t]*\n)/cg) {
return CloseHtmlEnvironments()
. (substr($4,0,1) eq '=' ? $q->h2($3) : $q->h3($3))
. AddHtmlEnvironment('p');
}
# > blockquote
# with continuation
elsif ($bol and m/\G&gt;/cg) {
return CloseHtmlEnvironments()
. AddHtmlEnvironment('blockquote');
}
# ``` = code
elsif ($bol and m/\G```[ \t]*\n(.*?)\n```[ \t]*(\n|$)/cgs) {
return CloseHtmlEnvironments() . $q->pre($1)
. AddHtmlEnvironment("p");
}
# ` = code
elsif (m/\G`([^`].*?)`/cg) {
return $q->code($1);
}
# ***bold and italic***
elsif (not InElement('strong') and not InElement('em') and m/\G\*\*\*/cg) {
return AddHtmlEnvironment('em') . AddHtmlEnvironment('strong');
}
# **bold**
elsif (m/\G\*\*/cg) {
return AddOrCloseHtmlEnvironment('strong');
}
# *italic*
elsif ($bol and m/\G\*/cg or m/\G(?<=\s)\*/cg) {
return AddHtmlEnvironment('em');
}
elsif (InElement('em') and m/\G\*/cg) {
return CloseHtmlEnvironment('em');
}
# ~~strikethrough~~ (deleted)
elsif (m/\G~~/cg) {
return AddOrCloseHtmlEnvironment('del');
}
# - bullet list
elsif ($bol and m/\G(\s*\n)*-[ \t]*/cg
or InElement('li') and m/\G(\s*\n)+-[ \t]*/cg) {
return CloseHtmlEnvironment('li')
. OpenHtmlEnvironment('ul',1) . AddHtmlEnvironment('li');
}
# 1. numbered list
elsif ($bol and m/\G(\s*\n)*\d+\.[ \t]*/cg
or InElement('li') and m/\G(\s*\n)+\d+\.[ \t]*/cg) {
return CloseHtmlEnvironment('li')
. OpenHtmlEnvironment('ol',1) . AddHtmlEnvironment('li');
}
# beginning of a table
elsif ($bol and !InElement('table') and m/\G\|/cg) {
# warn pos . " beginning of a table";
return OpenHtmlEnvironment('table',1)
. AddHtmlEnvironment('tr')
. AddHtmlEnvironment('th');
}
# end of a row and beginning of a new row
elsif (InElement('table') and m/\G\|?\n\|/cg) {
# warn pos . " end of a row and beginning of a new row";
return CloseHtmlEnvironment('tr')
. AddHtmlEnvironment('tr')
. AddHtmlEnvironment('td');
}
# otherwise the table ends
elsif (InElement('table') and m/\G\|?(\n|$)/cg) {
# warn pos . " otherwise the table ends";
return CloseHtmlEnvironment('table')
. AddHtmlEnvironment('p');
}
# continuation of the first row
elsif (InElement('th') and m/\G\|/cg) {
# warn pos . " continuation of the first row";
return CloseHtmlEnvironment('th')
. AddHtmlEnvironment('th');
}
# continuation of other rows
elsif (InElement('td') and m/\G\|/cg) {
# warn pos . " continuation of other rows";
return CloseHtmlEnvironment('td')
. AddHtmlEnvironment('td');
}
# whitespace indentation = code
elsif ($bol and m/\G(\s*\n)*( .+)\n?/cg) {
my $str = substr($2, 4);
while (m/\G( .*)\n?/cg) {
$str .= "\n" . substr($1, 4);
}
return OpenHtmlEnvironment('pre',1) . $str; # always level 1
}
# [an example](http://example.com/ "Title")
elsif (m/\G\[(.+?)\]\($FullUrlPattern(\s+"(.+?)")?\)/cg) {
my ($text, $url, $title) = ($1, $2, $4);
$url =~ /^($UrlProtocols)/;
my %params;
$params{-href} = $url;
$params{-class} = "url $1";
$params{-title} = $title if $title;
return $q->a(\%params, $text);
}
return;
}
push(@MyRules, \&MarkdownExtraRule);
sub MarkdownExtraRule {
# __italic underline__
if (m/\G__/cg) {
return AddOrCloseHtmlEnvironment('em', 'style="font-style: italic; text-decoration: underline"');
}
# _underline_
elsif (m/\G_/cg) {
return AddOrCloseHtmlEnvironment('em', 'style="font-style: normal; text-decoration: underline";');
}
# //italic//
elsif (m/\G\/\//cg) {
return AddOrCloseHtmlEnvironment('em');
}
# /italic/
elsif ($bol and m/\G\//cg or m/\G(?<=\s)\//cg) {
return AddHtmlEnvironment('em');
}
elsif (InElement('em') and m/\G\//cg) {
return CloseHtmlEnvironment('em');
}
return;
}