]> git.vanrenterghem.biz Git - git.ikiwiki.info.git/blob - IkiWiki/Plugin/mdwn.pm
eefa29a9711204541c52b2c83fa959103fc05e67
[git.ikiwiki.info.git] / IkiWiki / Plugin / mdwn.pm
1 #!/usr/bin/perl
2 # Markdown markup language
3 package IkiWiki::Plugin::mdwn;
5 use warnings;
6 use strict;
7 use IkiWiki 3.00;
9 sub import {
10         hook(type => "checkconfig", id => "mdwn", call => \&checkconfig);
11         hook(type => "getsetup", id => "mdwn", call => \&getsetup);
12         hook(type => "htmlize", id => "mdwn", call => \&htmlize, longname => "Markdown");
13         hook(type => "htmlize", id => "md", call => \&htmlize, longname => "Markdown (popular file extension)", nocreate => 1);
14 }
16 sub getsetup () {
17         return
18                 plugin => {
19                         safe => 1,
20                         rebuild => 1, # format plugin
21                         section => "format",
22                 },
23                 multimarkdown => {
24                         type => "boolean",
25                         example => 0,
26                         description => "enable multimarkdown features?",
27                         safe => 1,
28                         rebuild => 1,
29                 },
30                 nodiscount => {
31                         type => "boolean",
32                         example => 0,
33                         description => "disable use of markdown discount?",
34                         safe => 1,
35                         rebuild => 1,
36                 },
37                 mdwn_footnotes => {
38                         type => "boolean",
39                         example => 1,
40                         description => "enable footnotes in Markdown (where supported)?",
41                         safe => 1,
42                         rebuild => 1,
43                 },
44                 mdwn_alpha_lists => {
45                         type => "boolean",
46                         example => 0,
47                         description => "interpret line like 'A. First item' as ordered list when using Discount?",
48                         advanced => 1,
49                         safe => 1,
50                         rebuild => 1,
51                 },
52 }
54 sub checkconfig () {
55         $config{mdwn_footnotes} = 1 unless defined $config{mdwn_footnotes};
56         $config{mdwn_alpha_lists} = 0 unless defined $config{mdwn_alpha_lists};
57 }
59 my $markdown_sub;
60 sub htmlize (@) {
61         my %params=@_;
62         my $content = $params{content};
64         if (! defined $markdown_sub) {
65                 # Markdown is forked and splintered upstream and can be
66                 # available in a variety of forms. Support them all.
67                 no warnings 'once';
68                 $blosxom::version="is a proper perl module too much to ask?";
69                 use warnings 'all';
71                 if (exists $config{multimarkdown} && $config{multimarkdown}) {
72                         eval q{use Text::MultiMarkdown};
73                         if ($@) {
74                                 debug(gettext("multimarkdown is enabled, but Text::MultiMarkdown is not installed"));
75                         }
76                         else {
77                                 $markdown_sub=sub {
78                                         my %flags=( use_metadata => 0 );
80                                         if ($config{mdwn_footnotes}) {
81                                                 $flags{disable_footnotes}=1;
82                                         }
84                                         Text::MultiMarkdown::markdown(shift, \%flags);
85                                 }
86                         }
87                 }
88                 if (! defined $markdown_sub &&
89                     (! exists $config{nodiscount} || ! $config{nodiscount})) {
90                         eval q{use Text::Markdown::Discount};
91                         if (! $@) {
92                                 my $markdown = \&Text::Markdown::Discount::markdown;
93                                 my $always_flags = 0;
95                                 # Disable Pandoc-style % Title, % Author, % Date
96                                 # Use the meta plugin instead
97                                 $always_flags |= Text::Markdown::Discount::MKD_NOHEADER();
99                                 # Disable Unicodification of quote marks, em dashes...
100                                 # Use the typography plugin instead
101                                 $always_flags |= Text::Markdown::Discount::MKD_NOPANTS();
103                                 # Workaround for discount's eliding of <style> blocks.
104                                 # https://rt.cpan.org/Ticket/Display.html?id=74016
105                                 if (Text::Markdown::Discount->can('MKD_NOSTYLE')) {
106                                         $always_flags |= Text::Markdown::Discount::MKD_NOSTYLE();
107                                 }
108                                 elsif ($markdown->('<style>x</style>', 0) !~ '<style>' &&
109                                         $markdown->('<style>x</style>', 0x00400000) =~ m{<style>x</style>}) {
110                                         $always_flags |= 0x00400000;
111                                 }
113                                 # Enable fenced code blocks in libmarkdown >= 2.2.0
114                                 # https://bugs.debian.org/888055
115                                 if (Text::Markdown::Discount->can('MKD_FENCEDCODE')) {
116                                         $always_flags |= Text::Markdown::Discount::MKD_FENCEDCODE();
117                                 }
118                                 elsif ($markdown->("~~~\nx\n~~~", 0) !~ m{<pre\b} &&
119                                         $markdown->("~~~\nx\n~~~", 0x02000000) =~ m{<pre\b}) {
120                                         $always_flags |= 0x02000000;
121                                 }
123                                 # PHP Markdown Extra-style term\n: definition -> <dl>
124                                 if (Text::Markdown::Discount->can('MKD_DLEXTRA')) {
125                                         $always_flags |= Text::Markdown::Discount::MKD_DLEXTRA();
126                                 }
127                                 elsif ($markdown->("term\n: def\n", 0) !~ m{<dl>} &&
128                                         $markdown->("term\n: def\n", 0x01000000) =~ m{<dl>}) {
129                                         $always_flags |= 0x01000000;
130                                 }
132                                 # Allow dashes and underscores in tag names
133                                 if (Text::Markdown::Discount->can('MKD_GITHUBTAGS')) {
134                                         $always_flags |= Text::Markdown::Discount::MKD_GITHUBTAGS();
135                                 }
136                                 elsif ($markdown->('<foo_bar>', 0) !~ m{<foo_bar} &&
137                                         $markdown->('<foo_bar>', 0x08000000) =~ m{<foo_bar\b}) {
138                                         $always_flags |= 0x08000000;
139                                 }
141                                 $markdown_sub=sub {
142                                         my $t=shift;
144                                         # Workaround for discount binding bug
145                                         # https://rt.cpan.org/Ticket/Display.html?id=73657
146                                         return "" if $t=~/^\s*$/;
148                                         my $flags=$always_flags;
150                                         if ($config{mdwn_footnotes}) {
151                                                 $flags |= Text::Markdown::Discount::MKD_EXTRA_FOOTNOTE();
152                                         }
154                                         unless ($config{mdwn_alpha_lists}) {
155                                                 $flags |= Text::Markdown::Discount::MKD_NOALPHALIST();
156                                         }
158                                         return Text::Markdown::Discount::markdown($t, $flags);
159                                 }
160                         }
161                 }
162                 if (! defined $markdown_sub) {
163                         eval q{use Text::Markdown};
164                         if (! $@) {
165                                 if (Text::Markdown->can('markdown')) {
166                                         $markdown_sub=\&Text::Markdown::markdown;
167                                 }
168                                 else {
169                                         $markdown_sub=\&Text::Markdown::Markdown;
170                                 }
171                         }
172                         else {
173                                 eval q{use Markdown};
174                                 if (! $@) {
175                                         $markdown_sub=\&Markdown::Markdown;
176                                 }
177                                 else {
178                                         my $error = $@;
179                                         do "/usr/bin/markdown" ||
180                                                 error(sprintf(gettext("failed to load Markdown.pm perl module (%s) or /usr/bin/markdown (%s)"), $error, $!));
181                                         $markdown_sub=\&Markdown::Markdown;
182                                 }
183                         }
184                 }
185                 
186                 require Encode;
187         }
188         
189         # Workaround for perl bug (#376329)
190         $content=Encode::encode_utf8($content);
191         eval {$content=&$markdown_sub($content)};
192         if ($@) {
193                 eval {$content=&$markdown_sub($content)};
194                 print STDERR $@ if $@;
195         }
196         $content=Encode::decode_utf8($content);
198         return $content;