package Syntax::Highlight::Shell; use strict; use Shell::Parser; { no strict; $VERSION = '0.04'; @ISA = qw(Shell::Parser); } =head1 NAME Syntax::Highlight::Shell - Highlight shell scripts =head1 VERSION Version 0.04 =cut my %classes = ( metachar => 's-mta', # shell metacharacters (; |, >, &, \) keyword => 's-key', # a shell keyword (if, for, while, do...) builtin => 's-blt', # a builtin command command => 's-cmd', # an external command argument => 's-arg', # command arguments quote => 's-quo', # single (') and double (") quotes variable => 's-var', # an expanded variable ($VARIABLE) assigned => 's-avr', # an assigned variable (VARIABLE=value) value => 's-val', # a value comment => 's-cmt', # a comment line_number => 's-lno', # line number ); my %defaults = ( pre => 1, # add
...
around the result? (default: yes) nnn => 0, # add line numbers (default: no) syntax => 'bourne', # shell syntax (default: Bourne shell) tabs => 4, # convert tabs to this number of spaces; zero to disable ); =head1 SYNOPSIS use Syntax::Highlight::Shell; my $highlighter = new Syntax::Highlight::Shell; $output = $highlighter->parse($script); If C<$script> contains the following shell code: # an if statement if [ -f /etc/passwd ]; then grep $USER /etc/passwd | awk -F: '{print $5}' /etc/passwd fi then the resulting HTML contained in C<$output> will render like this: =begin html
# an if statement
if [ -f /etc/passwd ]; then
    grep $USER /etc/passwd | awk -F: '{print $5}' /etc/passwd
fi
=end html =head1 DESCRIPTION This module is designed to take shell scripts and highlight them in HTML with meaningful colours using CSS. The resulting HTML output is ready for inclusion in a web page. Note that no reformating is done, all spaces are preserved. =head1 METHODS =over 4 =item new() The constructor. Returns a C object, which derives from C. B =over 4 =item * C - Activate line numbering. Default value: 0 (disabled). =item * C
 - Surround result by C<< 
...
>> tags. Default value: 1 (enabled). =item * C - Selects the shell syntax. Check the documentation about the C method in C documentation for more information on the available syntaxes. Default value: C. =item * C - When given a non-nul value, converts tabulations to this number of spaces. Default value: 4. =back B To avoid surrounding the result by the C<<
...
>> tags: my $highlighter = Syntax::Highlight::Shell->new(pre => 0); =cut sub new { my $self = __PACKAGE__->SUPER::new(handlers => { default => \&_generic_highlight }); my $class = ref $_[0] || $_[0]; shift; bless $self, $class; $self->{_shs_options} = { %defaults }; my %args = @_; for my $arg (keys %defaults) { $self->{_shs_options}{$arg} = $args{$arg} if defined $args{$arg} } $self->syntax($self->{_shs_options}{syntax}); $self->{_shs_output} = ''; return $self } =item parse() Parse the shell code given in argument and returns the corresponding HTML code, ready for inclusion in a web page. B $html = $highlighter->parse(q{ echo "hello world" }); $html = $highlighter->parse(<<'END'); # find my name if [ -f /etc/passwd ]; then grep $USER /etc/passwd | awk -F: '{print $5}' /etc/passwd fi END =cut sub parse { my $self = shift; ## parse the shell command $self->{_shs_output} = ''; $self->SUPER::parse($_[0]); $self->eof; ## add line numbering? if($self->{_shs_options}{nnn}) { my $i = 1; $self->{_shs_output} =~ s|^|@{[sprintf '%3d', $i++]} |gm; } ## add
...
? $self->{_shs_output} = "
\n" . $self->{_shs_output} . "
\n" if $self->{_shs_options}{pre}; ## convert tabs? $self->{_shs_output} =~ s/\t/' 'x$self->{_shs_options}{tabs}/ge if $self->{_shs_options}{tabs}; return $self->{_shs_output} } =back =head2 Internal Methods The following methods are for internal use only. =over 4 =item _generic_highlight() C callback that does all the work of highlighting the code. =cut sub _generic_highlight { my $self = shift; my %args = @_; if(index('metachar,keyword,builtin,command,variable,comment', $args{type}) >= 0) { $self->{_shs_output} .= qq|| . $args{token} . qq|| } else { if($args{token} =~ /^(["'])([^"']*)\1$/) { $self->{_shs_output} .= qq|$1| . qq|$2| . qq|$1| } elsif($args{type} eq 'assign') { $args{token} =~ s|^([^=]*)=|$1=|; $args{token} =~ s|$||; $self->{_shs_output} .= $args{token} } else { $self->{_shs_output} .= $args{token} } } } =back =head1 NOTES The resulting HTML uses CSS to colourize the syntax. Here are the classes that you can define in your stylesheet. =over 4 =item * C<.s-key> - for shell keywords, like C, C, C, C... =item * C<.s-blt> - for the builtins commands =item * C<.s-cmd> - for the external commands =item * C<.s-arg> - for the command arguments =item * C<.s-mta> - for shell metacharacters, like C<|>, C<< > >>, C<\>, C<&> =item * C<.s-quo> - for the single (C<'>) and double (C<">) quotes =item * C<.s-var> - for expanded variables: C<$VARIABLE> =item * C<.s-avr> - for assigned variables: C =item * C<.s-val> - for shell values (inside quotes) =item * C<.s-cmt> - for shell comments =back An example stylesheet can be found in F. =head1 EXAMPLE Here is an example of generated HTML output. It was generated with the script F. The following shell script #!/bin/sh user="$1" case "$user" in # check if the user is root 'root') echo "You are the BOFH." ;; # for normal users, grep throught /etc/passwd *) passwd=/etc/passwd if [ -f $passwd ]; then grep "$user" $passwd | awk -F: '{print $5}' else echo "No $passwd" fi esac will be rendered like this (using the CSS stylesheet F): =begin html
  1 #!/bin/sh
  2 
  3 user="$1"
  4 
  5 case "$user" in
  6   # check if the user is root
  7   'root')
  8     echo "You are the BOFH."
  9     ;;
 10 
 11   # for normal users, grep throught /etc/passwd
 12   *)
 13     passwd=/etc/passwd
 14     if [ -f $passwd ]; then 
 15         grep "$user" $passwd | awk -F: '{print $5}'
 16     else
 17         echo "No $passwd"
 18     fi
 19 esac
=end html =head1 CAVEATS C relies on C for parsing the shell code and therefore suffers from the same limitations. =head1 SEE ALSO L =head1 AUTHOR SEbastien Aperghis-Tramoni, Esebastien@aperghis.netE =head1 BUGS Please report any bugs or feature requests to C, or through the web interface at L. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes. =head1 COPYRIGHT & LICENSE Copyright 2004 SEbastien Aperghis-Tramoni, All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1; # End of Syntax::Highlight::Shell