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