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