2006-05-04 06:33:56 +02:00
|
|
|
#!/usr/bin/perl
|
|
|
|
package IkiWiki::Plugin::smiley;
|
|
|
|
|
|
|
|
use warnings;
|
|
|
|
use strict;
|
2008-12-23 22:34:19 +01:00
|
|
|
use IkiWiki 3.00;
|
2006-05-04 06:33:56 +02:00
|
|
|
|
|
|
|
my %smileys;
|
|
|
|
my $smiley_regexp;
|
|
|
|
|
2008-12-17 21:22:16 +01:00
|
|
|
sub import {
|
2007-08-28 03:59:01 +02:00
|
|
|
add_underlay("smiley");
|
2008-08-04 01:35:35 +02:00
|
|
|
hook(type => "getsetup", id => "smiley", call => \&getsetup);
|
2008-03-21 08:16:28 +01:00
|
|
|
hook(type => "sanitize", id => "smiley", call => \&sanitize);
|
2008-12-17 21:22:16 +01:00
|
|
|
}
|
2006-05-04 06:33:56 +02:00
|
|
|
|
2008-12-17 21:22:16 +01:00
|
|
|
sub getsetup () {
|
2008-08-04 01:35:35 +02:00
|
|
|
return
|
|
|
|
plugin => {
|
|
|
|
safe => 1,
|
|
|
|
# force a rebuild because turning it off
|
|
|
|
# removes the smileys, which would break links
|
|
|
|
rebuild => 1,
|
|
|
|
},
|
2008-12-17 21:22:16 +01:00
|
|
|
}
|
2008-08-04 01:35:35 +02:00
|
|
|
|
2008-12-17 21:22:16 +01:00
|
|
|
sub build_regexp () {
|
2010-08-13 11:21:11 +02:00
|
|
|
my $srcfile = srcfile("smileys.mdwn", 1);
|
|
|
|
if (! defined $srcfile) {
|
|
|
|
print STDERR sprintf(gettext("smiley plugin will not work without %s"),
|
|
|
|
"smileys.mdwn")."\n";
|
|
|
|
$smiley_regexp='';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
my $list=readfile($srcfile);
|
2008-07-17 18:34:38 +02:00
|
|
|
while ($list =~ m/^\s*\*\s+\\\\([^\s]+)\s+\[\[([^]]+)\]\]/mg) {
|
2008-03-21 08:16:28 +01:00
|
|
|
my $smiley=$1;
|
|
|
|
my $file=$2;
|
|
|
|
|
|
|
|
$smileys{$smiley}=$file;
|
|
|
|
|
|
|
|
# Add a version with < and > escaped, since they probably
|
|
|
|
# will be (by markdown) by the time the sanitize hook runs.
|
|
|
|
$smiley=~s/</</g;
|
|
|
|
$smiley=~s/>/>/g;
|
|
|
|
$smileys{$smiley}=$file;
|
2006-05-04 06:33:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (! %smileys) {
|
2007-04-06 22:36:29 +02:00
|
|
|
debug(gettext("failed to parse any smileys"));
|
|
|
|
$smiley_regexp='';
|
2006-05-04 06:33:56 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
# sort and reverse so that substrings come after longer strings
|
|
|
|
# that contain them, in most cases.
|
|
|
|
$smiley_regexp='('.join('|', map { quotemeta }
|
|
|
|
reverse sort keys %smileys).')';
|
2006-09-10 00:50:27 +02:00
|
|
|
#debug($smiley_regexp);
|
2008-12-17 21:22:16 +01:00
|
|
|
}
|
2006-05-04 06:33:56 +02:00
|
|
|
|
2008-12-17 21:22:16 +01:00
|
|
|
sub sanitize (@) {
|
2006-05-04 06:33:56 +02:00
|
|
|
my %params=@_;
|
2008-03-21 07:43:20 +01:00
|
|
|
|
2007-04-06 22:36:29 +02:00
|
|
|
build_regexp() unless defined $smiley_regexp;
|
2008-03-21 07:43:20 +01:00
|
|
|
|
|
|
|
$_=$params{content};
|
|
|
|
return $_ unless length $smiley_regexp;
|
2008-07-17 18:34:38 +02:00
|
|
|
|
2008-03-21 08:16:28 +01:00
|
|
|
MATCH: while (m{(?:^|(?<=\s|>))(\\?)$smiley_regexp(?:(?=\s|<)|$)}g) {
|
2008-03-21 07:55:14 +01:00
|
|
|
my $escape=$1;
|
|
|
|
my $smiley=$2;
|
2008-03-21 07:57:34 +01:00
|
|
|
my $epos=$-[1];
|
|
|
|
my $spos=$-[2];
|
2008-03-21 08:16:28 +01:00
|
|
|
|
2008-03-21 07:43:20 +01:00
|
|
|
# Smilies are not allowed inside <pre> or <code>.
|
2008-03-21 07:55:14 +01:00
|
|
|
# For each tag in turn, match forward to find the next <tag>
|
|
|
|
# or </tag> after the smiley.
|
2008-03-21 07:43:20 +01:00
|
|
|
my $pos=pos;
|
|
|
|
foreach my $tag ("pre", "code") {
|
2008-03-21 08:16:28 +01:00
|
|
|
if (m/<(\/)?\s*$tag\s*>/isg && defined $1) {
|
2008-03-21 07:55:14 +01:00
|
|
|
# </tag> found first, so the smiley is
|
|
|
|
# inside the tag, so do not expand it.
|
|
|
|
next MATCH;
|
2008-03-21 07:43:20 +01:00
|
|
|
}
|
2008-03-21 07:55:14 +01:00
|
|
|
# Reset pos back to where it was before this test.
|
|
|
|
pos=$pos;
|
2008-03-21 07:43:20 +01:00
|
|
|
}
|
2008-07-17 18:34:38 +02:00
|
|
|
|
2008-03-21 07:55:14 +01:00
|
|
|
if ($escape) {
|
2008-03-21 07:43:20 +01:00
|
|
|
# Remove escape.
|
2008-03-21 07:57:34 +01:00
|
|
|
substr($_, $epos, 1)="";
|
2008-07-17 18:34:38 +02:00
|
|
|
pos=$epos+1;
|
2008-03-21 07:43:20 +01:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
# Replace the smiley with its expanded value.
|
avoid potential infinite loop in smiley expansion
- In 3.05, ikiwiki began expanding templates in scan mode,
for annoying, expensive, but ultimatly necessary reasons
of correctness.
- Smiley processing has a bug: It inserts a span for the smiley,
and then continues searching forward in the content for more,
starting at $end_of_smiley+1. Which means it searches for smilies
in the span too! And if it somehow finds one, we get an infinite loop
here.
- This bug can, probably, only be tickled if a htmllink to
show the smiley fails, because the smiley file doesn't exist,
or because ikiwiki doesn't know about it. In that case,
a link will be inserted to _create_ the missing page,
and that link will include the smiley inside the <a></a>.
- When a template is expanded in scan mode, and it contains
an inline, the sanitize hook is run during scan mode,
which never happened before. That causes the smiley processor
to run, before ikiwiki is, necessarily, aware that all
the smiley files exist (depending on scan order). So
it inserts creation links for them, and triggers the bug.
I've put in the simple fix of jumping forward past the inserted
span, and it does fix the problem. I will need to look in a bit
more detail into why an inline nested inside a template is
fully expanded during the scan pass -- that really shouldn't
be necessary, and it makes things much slower than they need
to be.
2009-03-08 23:46:18 +01:00
|
|
|
my $link=htmllink($params{page}, $params{destpage},
|
2008-03-21 07:55:14 +01:00
|
|
|
$smileys{$smiley}, linktext => $smiley);
|
avoid potential infinite loop in smiley expansion
- In 3.05, ikiwiki began expanding templates in scan mode,
for annoying, expensive, but ultimatly necessary reasons
of correctness.
- Smiley processing has a bug: It inserts a span for the smiley,
and then continues searching forward in the content for more,
starting at $end_of_smiley+1. Which means it searches for smilies
in the span too! And if it somehow finds one, we get an infinite loop
here.
- This bug can, probably, only be tickled if a htmllink to
show the smiley fails, because the smiley file doesn't exist,
or because ikiwiki doesn't know about it. In that case,
a link will be inserted to _create_ the missing page,
and that link will include the smiley inside the <a></a>.
- When a template is expanded in scan mode, and it contains
an inline, the sanitize hook is run during scan mode,
which never happened before. That causes the smiley processor
to run, before ikiwiki is, necessarily, aware that all
the smiley files exist (depending on scan order). So
it inserts creation links for them, and triggers the bug.
I've put in the simple fix of jumping forward past the inserted
span, and it does fix the problem. I will need to look in a bit
more detail into why an inline nested inside a template is
fully expanded during the scan pass -- that really shouldn't
be necessary, and it makes things much slower than they need
to be.
2009-03-08 23:46:18 +01:00
|
|
|
substr($_, $spos, length($smiley))=$link;
|
|
|
|
pos=$epos+length($link);
|
2008-03-21 07:43:20 +01:00
|
|
|
}
|
|
|
|
}
|
2007-02-14 01:11:19 +01:00
|
|
|
|
2008-03-21 07:43:20 +01:00
|
|
|
return $_;
|
2008-12-17 21:22:16 +01:00
|
|
|
}
|
2006-05-04 06:33:56 +02:00
|
|
|
|
|
|
|
1
|