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