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