mdwn: Automatically detect which libdiscount flags to use

Unconditionally passing arbitrary numbers as flags turns out to be a
bad idea, because some of the "unused" values have historically had
side-effects internal to libdiscount. Detect whether the known flags
work by rendering short Markdown snippets the first time we htmlize,
checking whether each known flag is both necessary and sufficient.

Signed-off-by: Simon McVittie <smcv@debian.org>
master
Simon McVittie 2018-03-08 23:36:31 +00:00
parent 06953a196a
commit e3279c8b50
3 changed files with 77 additions and 45 deletions

View File

@ -89,6 +89,55 @@ sub htmlize (@) {
(! exists $config{nodiscount} || ! $config{nodiscount})) {
eval q{use Text::Markdown::Discount};
if (! $@) {
my $markdown = \&Text::Markdown::Discount::markdown;
my $always_flags = 0;
# Disable Pandoc-style % Title, % Author, % Date
# Use the meta plugin instead
$always_flags |= Text::Markdown::Discount::MKD_NOHEADER();
# Disable Unicodification of quote marks, em dashes...
# Use the typography plugin instead
$always_flags |= Text::Markdown::Discount::MKD_NOPANTS();
# Workaround for discount's eliding of <style> blocks.
# https://rt.cpan.org/Ticket/Display.html?id=74016
if (Text::Markdown::Discount->can('MKD_NOSTYLE')) {
$always_flags |= Text::Markdown::Discount::MKD_NOSTYLE();
}
elsif ($markdown->('<style>x</style>', 0) !~ '<style>' &&
$markdown->('<style>x</style>', 0x00400000) =~ m{<style>x</style>}) {
$always_flags |= 0x00400000;
}
# Enable fenced code blocks in libmarkdown >= 2.2.0
# https://bugs.debian.org/888055
if (Text::Markdown::Discount->can('MKD_FENCEDCODE')) {
$always_flags |= Text::Markdown::Discount::MKD_FENCEDCODE();
}
elsif ($markdown->("~~~\nx\n~~~", 0) !~ m{<pre\b} &&
$markdown->("~~~\nx\n~~~", 0x02000000) =~ m{<pre\b}) {
$always_flags |= 0x02000000;
}
# PHP Markdown Extra-style term\n: definition -> <dl>
if (Text::Markdown::Discount->can('MKD_DLEXTRA')) {
$always_flags |= Text::Markdown::Discount::MKD_DLEXTRA();
}
elsif ($markdown->("term\n: def\n", 0) !~ m{<dl>} &&
$markdown->("term\n: def\n", 0x01000000) =~ m{<dl>}) {
$always_flags |= 0x01000000;
}
# Allow dashes and underscores in tag names
if (Text::Markdown::Discount->can('MKD_GITHUBTAGS')) {
$always_flags |= Text::Markdown::Discount::MKD_GITHUBTAGS();
}
elsif ($markdown->('<foo_bar>', 0) !~ m{<foo_bar} &&
$markdown->('<foo_bar>', 0x08000000) =~ m{<foo_bar\b}) {
$always_flags |= 0x08000000;
}
$markdown_sub=sub {
my $t=shift;
@ -96,15 +145,7 @@ sub htmlize (@) {
# https://rt.cpan.org/Ticket/Display.html?id=73657
return "" if $t=~/^\s*$/;
my $flags=0;
# Disable Pandoc-style % Title, % Author, % Date
# Use the meta plugin instead
$flags |= Text::Markdown::Discount::MKD_NOHEADER();
# Disable Unicodification of quote marks, em dashes...
# Use the typography plugin instead
$flags |= Text::Markdown::Discount::MKD_NOPANTS();
my $flags=$always_flags;
if ($config{mdwn_footnotes}) {
$flags |= Text::Markdown::Discount::MKD_EXTRA_FOOTNOTE();
@ -114,42 +155,6 @@ sub htmlize (@) {
$flags |= Text::Markdown::Discount::MKD_NOALPHALIST();
}
# Workaround for discount's eliding
# of <style> blocks.
# https://rt.cpan.org/Ticket/Display.html?id=74016
if (Text::Markdown::Discount->can("MKD_NOSTYLE")) {
$flags |= Text::Markdown::Discount::MKD_NOSTYLE();
}
else {
# This is correct for the libmarkdown.so.2 ABI
$flags |= 0x00400000;
}
# Enable fenced code blocks in libmarkdown >= 2.2.0
# https://bugs.debian.org/888055
if (Text::Markdown::Discount->can("MKD_FENCEDCODE")) {
$flags |= Text::Markdown::Discount::MKD_FENCEDCODE();
}
else {
$flags |= 0x02000000;
}
# PHP Markdown Extra-style term\n: definition -> <dl>
if (Text::Markdown::Discount->can("MKD_DLEXTRA")) {
$flags |= Text::Markdown::Discount::MKD_DLEXTRA();
}
else {
$flags |= 0x01000000;
}
# Allow dashes and underscores in tag names
if (Text::Markdown::Discount->can("MKD_GITHUBTAGS")) {
$flags |= Text::Markdown::Discount::MKD_GITHUBTAGS();
}
else {
$flags |= 0x08000000;
}
return Text::Markdown::Discount::markdown($t, $flags);
}
}

View File

@ -34,3 +34,8 @@ Some guesses:
> Orthogonally, pkgsrc should probably use an up-to-date version of Discount, and
> [we already know that Text::Markdown::Discount needs updating](https://rt.cpan.org/Public/Bug/Display.html?id=124188).
> --[[smcv]]
>> This should be [[fixed|done]] in current git. The mdwn module now
>> detects what your version of Discount supports by trying several
>> short HTML fragments that render differently under the different
>> flags. --[[smcv]]

View File

@ -8,6 +8,7 @@ BEGIN { use_ok("IkiWiki"); }
%config=IkiWiki::defaultconfig();
$config{srcdir}=$config{destdir}="/dev/null";
$config{disable_plugins}=["htmlscrubber"];
IkiWiki::loadplugins();
IkiWiki::checkconfig();
@ -41,4 +42,25 @@ like(IkiWiki::htmlize("foo", "foo", "mdwn",
"This works[^1]\n\n[^1]: Sometimes it doesn't.\n"),
qr{<p>This works<sup\W}, "footnotes can be enabled");
SKIP: {
skip 'set $IKIWIKI_TEST_ASSUME_MODERN_DISCOUNT if you have Discount 2.2.0+', 4
unless $ENV{IKIWIKI_TEST_ASSUME_MODERN_DISCOUNT};
like(IkiWiki::htmlize("foo", "foo", "mdwn",
"Definition list\n: A useful HTML structure\n"),
qr{<dl>.*<dt>Definition list</dt>\s*<dd>A useful HTML structure</dd>}s,
"definition lists are enabled by default");
like(IkiWiki::htmlize("foo", "foo", "mdwn",
"```\n#!/bin/sh\n```\n"),
qr{<pre>\s*<code>\s*[#]!/bin/sh\s*</code>\s*</pre>}s,
"code blocks are enabled by default");
like(IkiWiki::htmlize("foo", "foo", "mdwn",
"<foo_bar>"),
qr{<foo_bar>},
"GitHub tag name extensions are enabled by default");
like(IkiWiki::htmlize("foo", "foo", "mdwn",
"<style>foo</style>"),
qr{<style>foo</style>},
"Styles are not stripped by default");
}
done_testing();