summaryrefslogtreecommitdiffstats
path: root/lib/IkiWiki/Plugin/highlight.pm
blob: f2de12d0d7f88395c73f49aab0f630c00a6b8004 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#!/usr/bin/perl
use strict;
use warnings;
package IkiWiki::Plugin::highlight;
use IkiWiki '3.00';
use Syntax::Highlight::Engine::Kate;

# variables {{{
my %hl_args = (
    substitutions => { },
    format_table  => {
        Alert        => ["<span class='synAlert'>",        "</span>"],
        BaseN        => ["<span class='synBaseN'>",        "</span>"],
        BString      => ["<span class='synBString'>",      "</span>"],
        Char         => ["<span class='synChar'>",         "</span>"],
        Comment      => ["<span class='synComment'>",      "</span>"],
        DataType     => ["<span class='synDataType'>",     "</span>"],
        DecVal       => ["<span class='synDecVal'>",       "</span>"],
        Error        => ["<span class='synError'>",        "</span>"],
        Float        => ["<span class='synFloat'>",        "</span>"],
        Function     => ["<span class='synFunction'>",     "</span>"],
        IString      => ["<span class='synIString'>",      "</span>"],
        Keyword      => ["<span class='synKeyword'>",      "</span>"],
        Normal       => ["",                               ""       ],
        Operator     => ["<span class='synOperator'>",     "</span>"],
        Others       => ["<span class='synOthers'>",       "</span>"],
        RegionMarker => ["<span class='synRegionMarker'>", "</span>"],
        Reserved     => ["<span class='synReserved'>",     "</span>"],
        String       => ["<span class='synString'>",       "</span>"],
        Variable     => ["<span class='synVariable'>",     "</span>"],
        Warning      => ["<span class='synWarning'>",      "</span>"],
    },
);
my %syntaxes;
# }}}

sub import { # {{{
    hook(type => 'sanitize', id => __PACKAGE__, call => \&sanitize, first => 1);
} # }}}

sub sanitize { # {{{
    my %args = @_;
    my $content = '';
    my $in_code = 0;
    for my $line (split /^/m, $args{content}) {
        if ($in_code) {
            if ($line =~ s{(</code></pre>.*)}{}s) {
                my $rest_line = $1;
                $code_block .= $line;
                $content .= highlight($code_block) . $rest_line;
                $code_block = '';
                $in_code = 0;
            }
            else {
                $code_block .= $line;
            }
        }
        else {
            if ($line =~ s{(.*<pre><code>)}{}s) {
                $content .= $1;
                $code_block .= $line;
                $in_code = 1;
            }
            else {
                $content .= $line;
            }
        }
    }
    $content .= $code_block;
    return $content;
} # }}}

sub highlight { # {{{
    my ($code_block) = @_;
    my $filetype = guess_filetype($code_block);
    return unless $filetype;
    my $hl = Syntax::Highlight::Engine::Kate->new(
        language => $filetype, %hl_args
    );
    %syntaxes ||= map { lc($_) => $hl->syntaxes->{$_} } keys %$hl->syntaxes;
    return $hl->highlightText($code_block);
} # }}}

sub guess_filetype { # {{{
    my ($code_block) = @_;
    my ($first_line) = split /\n/, $code_block;
    if ($first_line =~ /^#!(\w+)/) {
        return $syntaxes{$1};
    }
    return;
} # }}}

1;