[TxMt] Search in Project with ack

Andy Armstrong andy at hexten.net
Thu Mar 6 12:46:32 UTC 2008


On 6 Mar 2008, at 12:42, Pedro Melo wrote:

> HI,
>
> I hacked Henrik Nyh's Grep in Project to use ack instead. You can  
> download the new command "Search in Project with ack" at this page:
>
> http://www.simplicidade.org/notes/archives/2008/03/ 
> search_in_proje.html
>
> This is the first command that I publish, so if you find any  
> problems, please drop me a note.

Oh cool, thanks Pedro. Ack is a fantastic tool. Highly recommended to  
everyone who regularly searches their source code.

In other ack/TextMate news here's a little Perl program which I keep  
as ~/bin/tack:

     #!/usr/bin/env 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 $/; <DATA> }
         )
       ),
       $h->open( 'body' ),
       $h->open( 'table' );

     my $last_file = '';
     my $tr_style  = {};

     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 ) {
             print $oh $h->tr(
                 $h->th( { colspan => 2 }, $h- 
 >entity_encode( $file ) ) );
             $last_file = $file;
             $tr_style  = {};
         }

         print $oh $h->tr(
             $tr_style,
             [
                 $h->td( { align => 'right', class => 'ln' }, $line ),
                 $h->td( $info )
             ]
         );
         $tr_style = {};
     }
     close $ack;
     print $oh $h->close( 'table' ), $h->close( 'body' ),
       $h->close( 'html' );
     close $oh;
     _open( $oname, 0 );

     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;
     }

     __DATA__

     html, body {
         font-family: monospace;
         background: black;
         color: #eee;
     }

     a {
         background: yellow;
         color: black;
         text-decoration: none;
     }

     .ln {
         color: #666;
     }

     th {
         text-align: left;
         border-bottom: 1px solid #222;
         color: #8f8;
         padding-top: 10px;
         padding-bottom: 3px;
         margin-bottom: 3px;
     }

     td {
         padding: 0px;
         margin: 0px;
         padding-left: 10px;
     }

     .dv td {
         padding-top: 18px;
     }

It's compatible with ack but instead of displaying output to the  
console it creates and opens an HTML document containing the search  
results. Each search hit is a link that jumps to the appropriate  
location in TextMate.


-- 
Andy Armstrong, Hexten




More information about the textmate mailing list