summaryrefslogtreecommitdiff
path: root/IkiWiki/Plugin/highlight.pm
blob: 9bdde85ae3bfd725ee83265b923eb445021a15c4 (plain)
  1. #!/usr/bin/perl
  2. package IkiWiki::Plugin::highlight;
  3. use warnings;
  4. use strict;
  5. use IkiWiki 3.00;
  6. use Encode;
  7. # locations of highlight's files
  8. my $filetypes="/etc/highlight/filetypes.conf";
  9. my $langdefdir="/usr/share/highlight/langDefs";
  10. sub import {
  11. hook(type => "getsetup", id => "highlight", call => \&getsetup);
  12. hook(type => "checkconfig", id => "highlight", call => \&checkconfig);
  13. # this hook is used by the format plugin
  14. hook(type => "htmlizefallback", id => "highlight", call =>
  15. \&htmlizefallback);
  16. }
  17. sub getsetup () {
  18. return
  19. plugin => {
  20. safe => 1,
  21. rebuild => 1, # format plugin
  22. },
  23. tohighlight => {
  24. type => "string",
  25. example => ".c .h .cpp .pl .py Makefile:make",
  26. description => "types of source files to syntax highlight",
  27. safe => 1,
  28. rebuild => 1,
  29. },
  30. }
  31. sub checkconfig () {
  32. if (exists $config{tohighlight}) {
  33. foreach my $file (split ' ', $config{tohighlight}) {
  34. my @opts = $file=~s/^\.// ?
  35. (keepextension => 1) :
  36. (noextension => 1);
  37. my $ext = $file=~s/:(.*)// ? $1 : $file;
  38. my $langfile=ext2langfile($ext);
  39. if (! defined $langfile) {
  40. error(sprintf(gettext(
  41. "tohighlight contains unknown file type '%s'"),
  42. $ext));
  43. }
  44. hook(
  45. type => "htmlize",
  46. id => $file,
  47. call => sub {
  48. my %params=@_;
  49. highlight($langfile, $params{content});
  50. },
  51. longname => sprintf(gettext("Source code: %s"), $file),
  52. @opts,
  53. );
  54. }
  55. }
  56. }
  57. sub htmlizefallback {
  58. my $format=lc shift;
  59. my $langfile=ext2langfile($format);
  60. if (! defined $langfile) {
  61. return;
  62. }
  63. return Encode::decode_utf8(highlight($langfile, shift));
  64. }
  65. my %ext2lang;
  66. my $filetypes_read=0;
  67. my %highlighters;
  68. # Parse highlight's config file to get extension => language mappings.
  69. sub read_filetypes () {
  70. open (IN, $filetypes);
  71. while (<IN>) {
  72. chomp;
  73. if (/^\$ext\((.*)\)=(.*)$/) {
  74. $ext2lang{$_}=$1 foreach $1, split ' ', $2;
  75. }
  76. }
  77. close IN;
  78. $filetypes_read=1;
  79. }
  80. # Given a filename extension, determines the language definition to
  81. # use to highlight it.
  82. sub ext2langfile ($) {
  83. my $ext=shift;
  84. my $langfile="$langdefdir/$ext.lang";
  85. return $langfile if exists $highlighters{$langfile};
  86. read_filetypes() unless $filetypes_read;
  87. if (exists $ext2lang{$ext}) {
  88. return "$langdefdir/$ext2lang{$ext}.lang";
  89. }
  90. # If a language only has one common extension, it will not
  91. # be listed in filetypes, so check the langfile.
  92. elsif (-e $langfile) {
  93. return $langfile;
  94. }
  95. else {
  96. return undef;
  97. }
  98. }
  99. # Interface to the highlight C library.
  100. sub highlight ($$) {
  101. my $langfile=shift;
  102. my $input=shift;
  103. eval q{use highlight};
  104. if ($@) {
  105. print STDERR gettext("warning: highlight perl module not available; falling back to pass through");
  106. return $input;
  107. }
  108. my $gen;
  109. if (! exists $highlighters{$langfile}) {
  110. $gen = highlightc::CodeGenerator_getInstance($highlightc::XHTML);
  111. $gen->setFragmentCode(1); # generate html fragment
  112. $gen->setHTMLEnclosePreTag(1); # include stylish <pre>
  113. $gen->initTheme("/dev/null"); # theme is not needed because CSS is not emitted
  114. $gen->initLanguage($langfile); # must come after initTheme
  115. $gen->setEncoding("utf-8");
  116. $highlighters{$langfile}=$gen;
  117. }
  118. else {
  119. $gen=$highlighters{$langfile};
  120. }
  121. return $gen->generateString($input);
  122. }
  123. 1