summaryrefslogtreecommitdiff
path: root/IkiWiki/Plugin/smiley.pm
blob: 7a9026025ed94f778aa4b6e666677b27595f605b (plain)
  1. #!/usr/bin/perl
  2. package IkiWiki::Plugin::smiley;
  3. use warnings;
  4. use strict;
  5. use IkiWiki 2.00;
  6. my %smileys;
  7. my $smiley_regexp;
  8. sub import { #{{{
  9. add_underlay("smiley");
  10. hook(type => "getsetup", id => "smiley", call => \&getsetup);
  11. hook(type => "sanitize", id => "smiley", call => \&sanitize);
  12. } # }}}
  13. sub getsetup () { #{{{
  14. return
  15. plugin => {
  16. safe => 1,
  17. # force a rebuild because turning it off
  18. # removes the smileys, which would break links
  19. rebuild => 1,
  20. },
  21. } #}}}
  22. sub build_regexp () { #{{{
  23. my $list=readfile(srcfile("smileys.mdwn"));
  24. while ($list =~ m/^\s*\*\s+\\\\([^\s]+)\s+\[\[([^]]+)\]\]/mg) {
  25. my $smiley=$1;
  26. my $file=$2;
  27. $smileys{$smiley}=$file;
  28. # Add a version with < and > escaped, since they probably
  29. # will be (by markdown) by the time the sanitize hook runs.
  30. $smiley=~s/</&lt;/g;
  31. $smiley=~s/>/&gt;/g;
  32. $smileys{$smiley}=$file;
  33. }
  34. if (! %smileys) {
  35. debug(gettext("failed to parse any smileys"));
  36. $smiley_regexp='';
  37. return;
  38. }
  39. # sort and reverse so that substrings come after longer strings
  40. # that contain them, in most cases.
  41. $smiley_regexp='('.join('|', map { quotemeta }
  42. reverse sort keys %smileys).')';
  43. #debug($smiley_regexp);
  44. } #}}}
  45. sub sanitize (@) { #{{{
  46. my %params=@_;
  47. build_regexp() unless defined $smiley_regexp;
  48. $_=$params{content};
  49. return $_ unless length $smiley_regexp;
  50. MATCH: while (m{(?:^|(?<=\s|>))(\\?)$smiley_regexp(?:(?=\s|<)|$)}g) {
  51. my $escape=$1;
  52. my $smiley=$2;
  53. my $epos=$-[1];
  54. my $spos=$-[2];
  55. # Smilies are not allowed inside <pre> or <code>.
  56. # For each tag in turn, match forward to find the next <tag>
  57. # or </tag> after the smiley.
  58. my $pos=pos;
  59. foreach my $tag ("pre", "code") {
  60. if (m/<(\/)?\s*$tag\s*>/isg && defined $1) {
  61. # </tag> found first, so the smiley is
  62. # inside the tag, so do not expand it.
  63. next MATCH;
  64. }
  65. # Reset pos back to where it was before this test.
  66. pos=$pos;
  67. }
  68. if ($escape) {
  69. # Remove escape.
  70. substr($_, $epos, 1)="";
  71. pos=$epos+1;
  72. }
  73. else {
  74. # Replace the smiley with its expanded value.
  75. substr($_, $spos, length($smiley))=
  76. htmllink($params{page}, $params{destpage},
  77. $smileys{$smiley}, linktext => $smiley);
  78. pos=$epos+1;
  79. }
  80. # Breaks out at end, otherwise it will scan through again,
  81. # replacing de-escaped ones.
  82. #last unless defined pos;
  83. }
  84. return $_;
  85. } # }}}
  86. 1