Turn Pod section into a block comment so it doesn't show up on search.cpan
[catagits/Gitalist.git] / lib / Gitalist / View / SyntaxHighlight.pm
1 package Gitalist::View::SyntaxHighlight;
2 use Moose;
3 use namespace::autoclean;
4
5 extends 'Catalyst::View';
6
7 use Syntax::Highlight::Engine::Kate ();
8 use Syntax::Highlight::Engine::Kate::Perl ();
9
10 use HTML::Entities qw(encode_entities);
11
12 # What should be done, but isn't currently:
13 #
14 # broquaint> Another Cat question - if I want to have arbitrary things highlighted is pushing things through a View at all costs terribly wrong?
15 # broquaint> e.g modifying this slightly to highlight anything (or arrays of anything) http://github.com/broquaint/Gitalist/blob/a7cc1ede5f9729465bb53da9c3a8b300a3aa8a0a/lib/Gitalist/View/SyntaxHighlight.pm
16 #       t0m> no, that's totally fine.. I'd tend to push the rendering logic into a model, so you end up doing something like: $c->model('SyntaxDriver')->highlight_all($stuff, $c->view('SyntaxHighlight'));
17 # broquaint> I'm thinking it's a bad idea because the Controller needs to munge data such that the View knows what to do
18 # broquaint> You just blew my mind ;)
19 #       t0m> ^^ That works _much_ better if you split up your view methods into process & render..
20 #       t0m> ala TT..
21 #       t0m> i.e. I'd have 'highlight this scalar' as the ->render method in the view..
22 #       t0m> And then the 'default' thing (i.e. process method) will do that and shove the output in the body..
23 #       t0m> but then you can write foreach my $thing (@things) { push(@highlighted_things, $c->view('SyntaxHighlight')->render($thing)); }
24 #       t0m> and then I'd move that ^^ loop down into a model which actually knows about / abstracts walking the data structures concerned..
25 #       t0m> But splitting render and process is the most important bit.. :) Otherwise you need to jump through hoops to render things that don't fit 'nicely' into the bits of stash / body that the view uses by 'default'
26 #       t0m> I wouldn't kill you for putting the structure walking code in the view given you're walking simple arrays / hashes.. It becomes more important if you have a more complex visitor..
27 #       t0m> (I use Visitor in the design patterns sense)
28 #       t0m> As the visitor is responsible for walking the structure, delegating to the ->render call in the view which is responsible for actually mangling the content..
29
30 sub process {
31     my($self, $c) = @_;
32
33     for($c->stash->{blobs} ? @{$c->stash->{blobs}} : $c->stash->{blob}) {
34         $_ = $self->highlight($c->stash->{language} => $_);
35     }
36
37     $c->forward('View::Default');
38 }
39
40 # XXX This takes for freakin' ever on big merges. A cache may be needed.
41 sub highlight {
42     my($self, $lang, $blob) = @_;
43
44     my $ret;
45     if($lang) {
46         # via http://github.com/jrockway/angerwhale/blob/master/lib/Angerwhale/Format/Pod.pm#L136
47         $ret = eval {
48             no warnings 'redefine';
49             local *Syntax::Highlight::Engine::Kate::Template::logwarning
50               = sub { die @_ }; # i really don't care
51             my $hl = Syntax::Highlight::Engine::Kate->new(
52                 language      => $lang,
53                 substitutions => {
54                     "<"  => "&lt;",
55                     ">"  => "&gt;",
56                     "&"  => "&amp;",
57                     q{'} => "&apos;",
58                     q{"} => "&quot;",
59                 },
60                 format_table => {
61                     # convert Kate's internal representation into
62                     # <span class="<internal name>"> value </span>
63                     map {
64                         $_ => [ qq{<span class="$_">}, '</span>' ]
65                     }
66                       qw/Alert BaseN BString Char Comment DataType
67                          DecVal Error Float Function IString Keyword
68                          Normal Operator Others RegionMarker Reserved
69                          String Variable Warning/,
70                 },
71             );
72
73             my $hltxt = $hl->highlightText($blob);
74             $hltxt =~ s/([^[:ascii:]])/encode_entities($1)/eg;
75             $hltxt;
76         };
77         warn $@ if $@;
78     }
79
80     return $ret || encode_entities($blob);
81 }
82
83 __PACKAGE__->meta->make_immutable;
84
85 __END__
86
87 =head1 NAME
88
89 Gitalist::View::SyntaxHighlight - Responsible for syntax highlighting code
90
91 =head1 DESCRIPTION
92
93 Catalyst View for Syntax highlighting.
94
95 =head1 AUTHORS
96
97 See L<Gitalist> for authors.
98
99 =head1 LICENSE
100
101 See L<Gitalist> for the license.
102
103 =cut