# vim: set ts=2 sts=2 sw=2 expandtab smarttab: # # This file is part of HTML-FromANSI-Tiny # # This software is copyright (c) 2011 by Randy Stauner. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use strict; use warnings; package HTML::FromANSI::Tiny; { $HTML::FromANSI::Tiny::VERSION = '0.102'; } # git description: v0.101-3-g4d12212 BEGIN { $HTML::FromANSI::Tiny::AUTHORITY = 'cpan:RWSTAUNER'; } # ABSTRACT: Easily convert colored command line output to HTML our @COLORS = map { "#$_" } qw( 000 f33 2c2 bb0 55c d3d 0cc bbb 555 f66 6d6 dd6 99f f6f 6dd fff ); sub new { my $class = shift; my $self = { class_prefix => '', selector_prefix => '', tag => 'span', @_ == 1 ? %{ $_[0] } : @_, }; require Parse::ANSIColor::Tiny if !$self->{ansi_parser}; require HTML::Entities if !$self->{html_encode}; bless $self, $class; } sub ansi_parser { my ($self) = @_; return $self->{ansi_parser} ||= do { # hash slice my (@fields, %copy) = qw(auto_reverse foreground background); @copy{ @fields } = @$self{ @fields }; Parse::ANSIColor::Tiny->new(%copy); }; } sub css { my ($self) = @_; my $prefix = $self->{selector_prefix} . '.' . $self->{class_prefix}; my $styles = $self->_css_class_attr; my @css = ( map { "${prefix}$_ { " . $self->_css_attr_string($styles->{$_}) . " }" } sort keys %$styles ); return wantarray ? @css : join('', @css); } sub _css_class_attr { my ($self) = @_; return $self->{_all_styles} ||= do { my $parser = $self->ansi_parser; my $styles = { bold => { 'font-weight' => 'bold' }, dark => { 'opacity' => '0.7' }, underline => { 'text-decoration' => 'underline' }, concealed => { 'visibility' => 'hidden' }, }; { my $i = 0; foreach my $fg ( $parser->foreground_colors ){ $styles->{$fg} = { color => $COLORS[$i++] }; } $i = 0; foreach my $bg ( $parser->background_colors ){ $styles->{$bg} = { 'background-color' => $COLORS[$i++] }; } } # return +{ %$styles, %{ $self->{styles} || {} }, }; }; } sub _css_attr_string { my ($self, $attr) = @_; return join ' ', map { "$_: $attr->{$_};" } keys %$attr; } sub html { my ($self, $text) = @_; $text = $self->ansi_parser->parse($text) unless ref($text) eq 'ARRAY'; my $tag = $self->{tag}; my $prefix = $self->{class_prefix}; # Preload if needed; Don't load if not. my $styles = $self->{inline_style} ? $self->_css_class_attr : {}; local $_; my @html = map { my ($attr, $text) = @$_; my $h = $self->html_encode($text); $self->{no_plain_tags} && !@$attr ? $h : do { sprintf q[<%s %s="%s">%s], $tag, ($self->{inline_style} ? (style => join ' ', map { $self->_css_attr_string($styles->{$_}) } @$attr) : (class => join ' ', map { $prefix . $_ } @$attr) ), $h, $tag; } } @$text; return wantarray ? @html : join('', @html); } sub html_encode { my ($self, $text) = @_; return $self->{html_encode}->($text) if $self->{html_encode}; return HTML::Entities::encode_entities($text); } sub style_tag { my ($self) = @_; my @style = (''); return wantarray ? @style : join('', @style); } our @EXPORT_OK = qw( html_from_ansi ); sub html_from_ansi { __PACKAGE__->new->html(@_) } sub import { my $class = shift; return unless @_; my $caller = caller; no strict 'refs'; ## no critic (NoStrict) foreach my $arg ( @_ ){ die "'$arg' is not exported by $class" unless grep { $arg eq $_ } @EXPORT_OK; *{"${caller}::$arg"} = *{"${class}::$arg"}{CODE}; } } 1; __END__ =pod =encoding utf-8 =for :stopwords Randy Stauner ACKNOWLEDGEMENTS inline hashrefs Stephen Thirlwall html cpan testmatrix url annocpan anno bugtracker rt cpants kwalitee diff irc mailto metadata placeholders metacpan =head1 NAME HTML::FromANSI::Tiny - Easily convert colored command line output to HTML =head1 VERSION version 0.102 =head1 SYNOPSIS use HTML::FromANSI::Tiny; my $h = HTML::FromANSI::Tiny->new( auto_reverse => 1, background => 'white', foreground => 'black', ); # output from some command my $output = "\e[31mfoo\033[1;32mbar\033[0m"; # include the default styles if you don't want to define your own: print $h->style_tag(); # or just $h->css() to insert into your own stylesheet print $h->html($output); # prints 'foobar' =head1 DESCRIPTION Convert the output from a terminal command that is decorated with ANSI escape sequences into customizable HTML (with a small amount of code). This module complements L by providing a simple HTML markup around its output. L returns a data structure that's easy to reformat into any desired output. Reformatting to HTML seemed simple and common enough to warrant this module as well. =head1 METHODS =head2 new Constructor. Takes a hash or hash ref of options: =over 4 =item * C - Instance of L; One will be created automatically, but you can provide one if you want to configure it. =item * C - String to prefix class names; Blank by default for brevity. See L. =item * C - Code ref that should encode HTML entities; See L. =item * C - Boolean to toggle using inline C attributes instead of C attributes. =item * C - Boolean for omitting the C when the text has no style attributes; Defaults to false for consistency. =item * C - String to prefix each css selector; Blank by default. See L. =item * C - Tree of hashrefs for customizing style output (for C<<