#!/usr/bin/perl use strict; use warnings; use TextMate::JumpTo qw( tm_location ); use HTML::Tiny; use File::Temp qw( tempfile ); $| = 1; my @args = grep { $_ ne '--nocolor' } @ARGV; unshift @args, '--color' unless grep { $_ eq '--color' } @args; my $h = HTML::Tiny->new; my ( $oh, $oname ) = tempfile( SUFFIX => '.html' ); print $oh $h->open( 'html' ), $h->head( [ $h->title( 'Search results' ), $h->style( do { local $/; } ), $h->script( _js() ) ] ), $h->open( 'body' ), $h->open( 'form' ), $h->open( 'table' ); my $last_file = ''; my $tr_style = {}; my $next_id = 1; my $close_group = ''; open my $ack, '-|', 'ack', @args or die "Can't run ack ($!)"; LINE: while ( defined( my $line = <$ack> ) ) { chomp $line; if ( $line =~ /^--\s*$/ ) { $tr_style = { class => 'dv' }; next LINE; } my @parts = grep { $_ } split /(\x1b\[(?:K|\d+(?:;\d+)*m))/, $line; my ( $file, $line, @info ); for ( @parts ) { if ( /^([-:])(\d+)\1(.*)/ ) { ( $line, @info ) = ( $2, $3 ); } elsif ( @info ) { push @info, $_ unless /^\x1b\[K/; } elsif ( $_ !~ /^\x1b/ ) { $file = $_; } } my $state = ''; my $pos = 1; my $column = 0; my $info = join '', map { /^\x1b\[(.+)/ ? $state eq $1 ? '' : do { $state = $1; $column ||= $pos; $_ eq "\x1b[0m" ? $h->close( 'a' ) : $h->open( 'a', { href => tm_location( file => $file, line => $line, column => $pos ) } ); } : do { $pos += length $_; _ns( $h->entity_encode( $_ ) ); } } @info; if ( $last_file ne $file ) { my $id = 'file' . $next_id++; print $oh $close_group, $h->open( 'tbody', { id => $id } ); $close_group = $h->close( 'tbody' ); print $oh $h->tr( [ $h->th( _hide_control( $h, $id ), { colspan => 2 }, $h->entity_encode( $file ) ) ] ); $last_file = $file; $tr_style = {}; } my $id = 'line' . $next_id++; print $oh $h->tr( $tr_style, { id => $id }, [ $h->td( _hide_control( $h, $id ) ), $h->td( { align => 'right', class => 'ln' }, $line ), $h->td( $info ) ] ); $tr_style = {}; } close $ack; print $oh $close_group; print $oh $h->close( 'table' ), $h->close( 'form' ), $h->close( 'body' ), $h->close( 'html' ); close $oh; _open( $oname, 0 ); sub _hide_control { my ( $h, $id ) = @_; return $h->input( { type => 'checkbox', onclick => "tick_off('$id', this.checked)" } ); } sub _open { my ( $url, $bg ) = @_; my @cmd = ( '/usr/bin/open', ( $bg ? ( '-g' ) : () ), $url ); system @cmd and die "Can't open $url ($?)"; } sub _ns { my $s = shift; $s =~ s/\s/ /g; return $s; } sub _js { return <