diff --git a/AckMate.xcodeproj/project.pbxproj b/AckMate.xcodeproj/project.pbxproj index cb80328..4eb49b5 100644 --- a/AckMate.xcodeproj/project.pbxproj +++ b/AckMate.xcodeproj/project.pbxproj @@ -51,7 +51,7 @@ outputFiles = ( "$(DERIVED_FILES_DIR)/$(INPUT_FILE_BASE)", ); - script = "/usr/bin/env ragel ${INPUT_FILE_DIR}/${INPUT_FILE_BASE}.rl -o ${DERIVED_FILES_DIR}/${INPUT_FILE_BASE}"; + script = "/usr/local/bin/ragel ${INPUT_FILE_DIR}/${INPUT_FILE_BASE}.rl -o ${DERIVED_FILES_DIR}/${INPUT_FILE_BASE}"; }; /* End PBXBuildRule section */ @@ -295,7 +295,11 @@ }; buildConfigurationList = 1DEB913E08733D840010E9CD /* Build configuration list for PBXProject "AckMate" */; compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; hasScannedForEncodings = 1; + knownRegions = ( + en, + ); mainGroup = 089C166AFE841209C02AAC07 /* AckMate */; projectDirPath = ""; projectRoot = ""; @@ -384,6 +388,7 @@ 1DEB913B08733D840010E9CD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_FIX_AND_CONTINUE = YES; @@ -394,6 +399,7 @@ INFOPLIST_FILE = Info.plist; INSTALL_PATH = "$(HOME)/Library/Bundles"; PRODUCT_NAME = AckMate; + SDKROOT = macosx; WRAPPER_EXTENSION = tmplugin; ZERO_LINK = YES; }; @@ -402,10 +408,7 @@ 1DEB913C08733D840010E9CD /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = ( - ppc, - i386, - ); + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_MODEL_TUNING = G5; GCC_PRECOMPILE_PREFIX_HEADER = YES; @@ -413,6 +416,7 @@ INFOPLIST_FILE = Info.plist; INSTALL_PATH = "$(HOME)/Library/Bundles"; PRODUCT_NAME = AckMate; + SDKROOT = macosx; WRAPPER_EXTENSION = tmplugin; }; name = Release; @@ -420,20 +424,22 @@ 1DEB913F08733D840010E9CD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; PREBINDING = NO; - SDKROOT = macosx10.5; + SDKROOT = macosx; }; name = Debug; }; 1DEB914008733D840010E9CD /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; PREBINDING = NO; - SDKROOT = macosx10.5; + SDKROOT = macosx; }; name = Release; }; diff --git a/Info.plist b/Info.plist index 58e5966..c1eafbd 100644 --- a/Info.plist +++ b/Info.plist @@ -6,20 +6,20 @@ English CFBundleExecutable ${EXECUTABLE_NAME} - CFBundleName - ${PRODUCT_NAME} CFBundleIconFile CFBundleIdentifier com.jetpackpony.AckMate CFBundleInfoDictionaryVersion 6.0 + CFBundleName + ${PRODUCT_NAME} CFBundlePackageType BNDL CFBundleSignature ???? CFBundleVersion - 1.1.2 + 1.1.3 NSPrincipalClass AckMatePlugin diff --git a/README.mdown b/README.mdown index 728c24e..a78a589 100644 --- a/README.mdown +++ b/README.mdown @@ -1,34 +1,38 @@ -## Description +## Modifications -**AckMate** is a [TextMate](http://macromates.com/) plugin for running [Ack](http://betterthangrep.com) in a Cocoa window. +This is is a **modified version** of [AckMate](https://github.com/protocool/AckMate) Once/if [protocool](https://github.com/protocool) pulls these changes, I recommend switching back to his git repo. That said, some of my changes violate his rule about not changing ack; if they never make the cut, you'll still be able to find a copy here. -*This plugin is only compatible with Mac OS X 10.5 and above.* +Changes include: +- Added standard TextMate folder references via ack -G +- Updated the XCode build configuration for 10.6 (and modified ragel path to avoid build confusion) +- Added better UTF-8 error output -## Donations +## Description -Like many of you, I do this sort of thing to keep my family warm, clothed, and fed. Every hour I spend on AckMate is an hour that I'm not billing for. +**AckMate** is a [TextMate](http://macromates.com/) plugin for running [Ack](http://betterthangrep.com) in a Cocoa window. -If you find AckMate useful, a small [donation](http://pledgie.com/campaigns/9779) is a great way to show your appreciation. +*This plugin is only compatible with Mac OS X 10.6 and above.* ## Binary Installation -* Download the latest release from the [downloads section](http://github.com/protocool/AckMate/downloads) -* Save any unsaved documents you have open in TextMate -* Unpack the zip file and double-click the AckMate.tmplugin icon +- Download the latest release from the [downloads section](http://github.com/jswartwood/AckMate/downloads) +- Save any unsaved documents you have open in TextMate +- Unpack the zip file and double-click the AckMate.tmplugin icon ## Usage -Check the wiki for usage instructions. +Check the [wiki](https://github.com/protocool/AckMate/wiki) for usage instructions. ## Building From Source -AckMate's build process requires [Ragel](http://www.complang.org/ragel/) to be in your PATH. +AckMate's build process requires [Ragel](http://www.complang.org/ragel/) to be in */usr/local/bin* if you have it installed elsewhere please update XCode configuration or symlink to your install location. -## Contributing +Installing Ragel is easiest with [Homebrew](http://mxcl.github.com/homebrew/) -I'm always willing to look at a pull request. + brew install ragel -However, **any** pull requests that include changes to the `ackmate_ack.autogenerated` file will be ignored without comment. +## Contributing -Changes to ack itself should be directed to Andy Lester (the author of ack) via his [github repo](http://github.com/petdance/ack). I will periodically rebase AckMate's version of ack against the offical ack release. +I'm all ears... send pull requests if you have them. +If you find AckMate useful, donate to [protcool](http://pledgie.com/campaigns/9779) (the original author) diff --git a/bundle_extras/ackmate_ack.autogenerated b/bundle_extras/ackmate_ack.autogenerated index 833897d..8a2a939 100755 --- a/bundle_extras/ackmate_ack.autogenerated +++ b/bundle_extras/ackmate_ack.autogenerated @@ -14,7 +14,7 @@ use strict; use Unicode::Normalize; use Encode; -our $VERSION = '1.92-ackmate'; +our $VERSION = '1.94-ackmate'; # Check http://betterthangrep.com/ for updates # These are all our globals. @@ -34,13 +34,17 @@ MAIN: { /^--th[pt]+t+$/ && App::Ack::_thpppt($_); # See if we want to ignore the environment. (Don't tell Al Gore.) - if ( $_ eq '--noenv' ) { + if ( /^--(no)?env$/ ) { + $env_is_usable = defined $1 ? 0 : 1; + } + } + if ( $env_is_usable ) { + unshift( @ARGV, App::Ack::read_ackrc() ); + } + else { my @keys = ( 'ACKRC', grep { /^ACK_/ } keys %ENV ); delete @ENV{@keys}; - $env_is_usable = 0; } - } - unshift( @ARGV, App::Ack::read_ackrc() ) if $env_is_usable; App::Ack::load_colors(); if ( exists $ENV{ACK_SWITCHES} ) { @@ -71,15 +75,25 @@ sub main { my $s = $nargs == 1 ? '' : 's'; App::Ack::warn( "Ignoring $nargs argument$s on the command-line while acting as a filter." ); } + my $res = App::Ack::Resource::Basic->new( '-' ); - App::Ack::search_resource( $res, $opt ); + my $nmatches; + if ( $opt->{count} ) { + $nmatches = App::Ack::search_and_list( $res, $opt ); + } + else { + # normal searching + $nmatches = App::Ack::search_resource( $res, $opt ); + } $res->close(); - exit 0; + App::Ack::exit_from_ack( $nmatches ); } my $file_matching = $opt->{f} || $opt->{lines}; - if ( !$file_matching ) { - @ARGV or App::Ack::die( 'No regular expression found.' ); + if ( $file_matching ) { + App::Ack::die( "Can't specify both a regex ($opt->{regex}) and use one of --line, -f or -g." ) if $opt->{regex}; + } + else { $opt->{regex} = App::Ack::build_regex( defined $opt->{regex} ? $opt->{regex} : shift @ARGV, $opt ); } @@ -105,7 +119,7 @@ sub main { $nmatches = App::Ack::print_matches( $iter, $opt ); } close $App::Ack::fh; - exit ($nmatches ? 0 : 1); + App::Ack::exit_from_ack( $nmatches ); } =head1 NAME @@ -208,6 +222,8 @@ each input file. If B<-l> is in effect, it will only show the number of lines for each file that has lines matching. Without B<-l>, some line counts may be zeroes. +If combined with B<-h> (B<--no-filename>) ack outputs only one total count. + =item B<--color>, B<--nocolor> B<--color> highlights the matching text. B<--nocolor> supresses @@ -225,6 +241,10 @@ Sets the color to be used for filenames. Sets the color to be used for matches. +=item B<--color-lineno=I> + +Sets the color to be used for line numbers. + =item B<--column> Show the column number of the first match. This is helpful for editors @@ -298,7 +318,7 @@ Ignore case in the search strings. This applies only to the PATTERN, not to the regexes given for the B<-g> and B<-G> options. -=item B<--[no]ignore-dir=DIRNAME> +=item B<--[no]ignore-dir=I> Ignore directory (as CVS, .svn, etc are ignored). May be used multiple times to ignore multiple directories. For example, mason users may wish to include @@ -306,6 +326,11 @@ B<--ignore-dir=data>. The B<--noignore-dir> option allows users to search directories which would normally be ignored (perhaps to research the contents of F<.svn/props> directories). +The I must always be a simple directory name. Nested directories like +F are NOT supported. You would need to specify B<--ignore-dir=foo> and +then no files from any foo directory are taken into account by ack unless given +explicitly on the command line. + =item B<--line=I> Only print line I of each file. Multiple lines can be given with multiple @@ -340,7 +365,7 @@ Stop reading a file after I matches. Print this manual page. -=item B<-n> +=item B<-n>, B<--no-recurse> No descending into subdirectories. @@ -387,6 +412,11 @@ Quote all metacharacters in PATTERN, it is treated as a literal. This applies only to the PATTERN, not to the regexes given for the B<-g> and B<-G> options. +=item B<-r>, B<-R>, B<--recurse> + +Recurse into sub-directories. This is the default and just here for +compatibility with grep. You can also use it for turning B<--no-recurse> off. + =item B<--smart-case>, B<--no-smart-case> Ignore case in the search strings if PATTERN contains no uppercase @@ -403,6 +433,12 @@ B<-g> and B<-G> options. Sorts the found files lexically. Use this if you want your file listings to be deterministic between runs of I. +=item B<--show-types> + +Outputs the filetypes that ack associates with each file. + +Works with B<-f> and B<-g> options. + =item B<--thpppt> Display the all-important Bill The Cat logo. Note that the exact @@ -601,6 +637,15 @@ This option can also be set with B<--color-match>. See B for the color specifications. +=item ACK_COLOR_LINENO + +Specifies the color of the line number when printed in B<--color> +mode. By default, it's "bold yellow". + +This option can also be set with B<--color-lineno>. + +See B for the color specifications. + =item ACK_PAGER Specifies a pager program, such as C, C or C, to which @@ -735,10 +780,12 @@ them here. =head2 Why isn't ack finding a match in (some file)? -Probably because it's of a type that ack doesn't recognize. +Probably because it's of a type that ack doesn't recognize. ack's +searching behavior is driven by filetype. B -ack's searching behavior is driven by filetype. If ack doesn't -know what kind of file it is, ack ignores it. +Use the C<-f> switch to see a list of files that ack will search +for you. If you want ack to search files that it doesn't recognize, use the C<-a> switch. @@ -766,7 +813,7 @@ switches. You can certainly use ack to select your files to update. For example, to change all "foo" to "bar" in all PHP files, you can do -this form the Unix shell: +this from the Unix shell: $ perl -i -p -e's/foo/bar/g' $(ack -f --php) @@ -793,6 +840,19 @@ To do that, run this with F or as root: ln -s /usr/bin/ack-grep /usr/bin/ack +=head2 What does F mean? + +Nothing. I wanted a name that was easy to type and that you could +pronounce as a single syllable. + +=head2 Can I do multi-line regexes? + +No, ack does not support regexes that match multiple lines. Doing +so would require reading in the entire file at a time. + +If you want to see lines near your match, use the C<--A>, C<--B> +and C<--C> switches for displaying context. + =head1 AUTHOR Andy Lester, C<< >> @@ -852,6 +912,11 @@ L How appropriate to have Inowledgements! Thanks to everyone who has contributed to ack in any way, including +Scott Kyle, +Nick Hooey, +Bo Borgerson, +Mark Szymanski, +Marq Schneider, Packy Anderson, JR Boyens, Dan Sully, @@ -913,20 +978,10 @@ and Pete Krawczyk. =head1 COPYRIGHT & LICENSE -Copyright 2005-2009 Andy Lester. +Copyright 2005-2010 Andy Lester. This program is free software; you can redistribute it and/or modify -it under the terms of either: - -=over 4 - -=item * the GNU General Public License as published by the Free -Software Foundation; either version 1, or (at your option) any later -version, or - -=item * the Artistic License version 2.0. - -=back +it under the terms of the Artistic License v2.0. =cut package File::Next; @@ -1109,8 +1164,8 @@ use strict; our $VERSION; our $COPYRIGHT; BEGIN { - $VERSION = '1.92-ackmate'; - $COPYRIGHT = 'Copyright 2005-2009 Andy Lester.'; + $VERSION = '1.94-ackmate'; + $COPYRIGHT = 'Copyright 2005-2010 Andy Lester.'; } our $fh; @@ -1149,6 +1204,7 @@ BEGIN { '.hg' => 'Mercurial', '.pc' => 'quilt', '.svn' => 'Subversion', + _MTN => 'Monotone', blib => 'Perl module building', CVS => 'CVS', RCS => 'RCS', @@ -1168,12 +1224,16 @@ BEGIN { binary => q{Binary files, as defined by Perl's -B op (default: off)}, cc => [qw( c h xs )], cfmx => [qw( cfc cfm cfml )], + clojure => [qw( clj )], cpp => [qw( cpp cc cxx m hpp hh h hxx )], csharp => [qw( cs )], css => [qw( css )], + delphi => [qw( pas int dfm nfm dof dpk dproj groupproj bdsgroup bdsproj )], elisp => [qw( el )], erlang => [qw( erl hrl )], fortran => [qw( f f77 f90 f95 f03 for ftn fpp )], + go => [qw( go )], + groovy => [qw( groovy gtmpl gpp grunit )], haskell => [qw( hs lhs )], hh => [qw( h )], html => [qw( htm html shtml xhtml )], @@ -1182,7 +1242,7 @@ BEGIN { jsp => [qw( jsp jspx jhtm jhtml )], lisp => [qw( lisp lsp )], lua => [qw( lua )], - make => q{Makefiles}, + make => q{Makefiles (including *.mk and *.mak)}, mason => [qw( mas mhtml mpl mtxt )], objc => [qw( m h )], objcpp => [qw( mm h )], @@ -1193,7 +1253,7 @@ BEGIN { plone => [qw( pt cpt metadata cpy py )], python => [qw( py )], rake => q{Rakefiles}, - ruby => [qw( rb rhtml rjs rxml erb rake )], + ruby => [qw( rb rhtml rjs rxml erb rake spec )], scala => [qw( scala )], scheme => [qw( scm ss )], shell => [qw( sh bash csh tcsh ksh zsh )], @@ -1205,9 +1265,11 @@ BEGIN { text => q{Text files, as defined by Perl's -T op (default: off)}, tt => [qw( tt tt2 ttml )], vb => [qw( bas cls frm ctl vb resx )], + verilog => [qw( v vh sv )], + vhdl => [qw( vhd vhdl )], vim => [qw( vim )], yaml => [qw( yaml yml )], - xml => [qw( xml dtd xslt ent )], + xml => [qw( xml dtd xsl xslt ent )], ); while ( my ($type,$exts) = each %mappings ) { @@ -1217,6 +1279,8 @@ BEGIN { } } } + # add manually Makefile extensions + push @{$types{$_}}, 'make' for qw{ mk mak }; # These have to be checked before any filehandle diddling. $output_to_pipe = not -t *STDOUT; @@ -1246,6 +1310,12 @@ sub read_ackrc { chomp @lines; close $fh or App::Ack::die( "$filename: $!\n" ); + # get rid of leading and trailing whitespaces + for ( @lines ) { + s/^\s+//; + s/\s+$//; + } + return @lines; } } @@ -1272,6 +1342,7 @@ sub get_command_line_options { 'color|colour!' => \$opt{color}, 'color-match=s' => \$ENV{ACK_COLOR_MATCH}, 'color-filename=s' => \$ENV{ACK_COLOR_FILENAME}, + 'color-lineno=s' => \$ENV{ACK_COLOR_LINENO}, 'column!' => \$opt{column}, count => \$opt{count}, 'env!' => sub { }, # ignore this option, it is handled beforehand @@ -1285,6 +1356,7 @@ sub get_command_line_options { 'h|no-filename' => \$opt{h}, 'H|with-filename' => \$opt{H}, 'i|ignore-case' => \$opt{i}, + 'invert-file-match' => \$opt{invert_file_match}, 'lines=s' => sub { shift; my $val = shift; push @{$opt{lines}}, $val }, 'l|files-with-matches' => \$opt{l}, 'L|files-without-matches' => sub { $opt{l} = $opt{v} = 1 }, @@ -1298,7 +1370,8 @@ sub get_command_line_options { 'passthru' => \$opt{passthru}, 'print0' => \$opt{print0}, 'Q|literal' => \$opt{Q}, - 'r|R|recurse' => sub {}, + 'r|R|recurse' => sub { $opt{n} = 0 }, + 'show-types' => \$opt{show_types}, 'smart-case!' => \$opt{smart_case}, 'sort-files' => \$opt{sort_files}, 'u|unrestricted' => \$opt{u}, @@ -1308,11 +1381,17 @@ sub get_command_line_options { 'ignore-dirs=s' => sub { shift; my $dir = remove_dir_sep( shift ); $ignore_dirs{$dir} = '--ignore-dirs' }, 'noignore-dirs=s' => sub { shift; my $dir = remove_dir_sep( shift ); delete $ignore_dirs{$dir} }, - 'version' => sub { print_version_statement(); exit 1; }, + 'version' => sub { print_version_statement(); exit; }, 'help|?:s' => sub { shift; show_help(@_); exit; }, 'help-types'=> sub { show_help_types(); exit; }, 'ackmate-types' => sub { show_ackmate_types(); exit; }, - 'man' => sub { require Pod::Usage; Pod::Usage::pod2usage({-verbose => 2}); exit; }, + 'man' => sub { + require Pod::Usage; + Pod::Usage::pod2usage({ + -verbose => 2, + -exitval => 0, + }); + }, 'type=s' => sub { # Whatever --type=xxx they specify, set it manually in the hash @@ -1500,7 +1579,7 @@ sub delete_type { sub ignoredir_filter { - return !( exists( $ignore_dirs{$_} ) || ( $ignore_dirpattern && $File::Next::dir =~ m/$ignore_dirpattern/ ) ); + return !( exists $ignore_dirs{$_} || exists $ignore_dirs{$File::Next::dir} || ( $ignore_dirpattern && $File::Next::dir =~ m/$ignore_dirpattern/ ) ); } @@ -1523,7 +1602,7 @@ sub filetypes { return 'skipped' unless is_searchable( $basename ); my $lc_basename = lc $basename; - return ('make',TEXT) if $lc_basename eq 'makefile'; + return ('make',TEXT) if $lc_basename eq 'makefile' || $lc_basename eq 'gnumakefile'; return ('rake','ruby',TEXT) if $lc_basename eq 'rakefile'; # If there's an extension, look it up @@ -1557,6 +1636,13 @@ sub filetypes { App::Ack::warn( "$filename: $!" ); return; } + + local $SIG{__WARN__} = sub { + my $e = shift; + App::Ack::warn( "\n$filename\nYou probably want to either convert this file to utf-8, ignore it in ~/.ackrc, or delete it.\n" ); + return; + }; + my $header = <$fh>; close $fh; @@ -1590,6 +1676,8 @@ sub build_regex { my $str = shift; my $opt = shift; + defined $str or App::Ack::die( 'No regular expression found.' ); + $str = quotemeta( $str ) if $opt->{Q}; if ( $opt->{w} ) { $str = "\\b$str" if $str =~ /^\w/; @@ -1739,7 +1827,8 @@ File presentation: output is redirected, or on Windows) --[no]colour Same as --[no]color --color-filename=COLOR - --color-match=COLOR Set the color for matches and filenames. + --color-match=COLOR + --color-lineno=COLOR Set the color for filenames, matches, and line numbers. --flush Flush output immediately, even when ack is used non-interactively (when output goes to a pipe or file). @@ -1749,6 +1838,8 @@ File finding: The PATTERN must not be specified. -g REGEX Same as -f, but only print files matching REGEX. --sort-files Sort the found files lexically. + --invert-file-match Print/search handle files that do not match -g/-G. + --show-types Show which types each file has. File inclusion/exclusion: -a, --all-types All file types searched; @@ -1874,9 +1965,8 @@ Running under Perl $ver at $this_perl $copyright -This program is free software; you can redistribute it and/or modify -it under the terms of either: the GNU General Public License as -published by the Free Software Foundation; or the Artistic License. +This program is free software. You may modify or distribute it +under the terms of the Artistic License v2.0. END_OF_VERSION } @@ -1898,6 +1988,7 @@ sub load_colors { $ENV{ACK_COLOR_MATCH} ||= 'black on_yellow'; $ENV{ACK_COLOR_FILENAME} ||= 'bold green'; + $ENV{ACK_COLOR_LINENO} ||= 'bold yellow'; return; } @@ -1939,18 +2030,30 @@ sub print_count { my $nmatches = shift; my $ors = shift; my $count = shift; + my $show_filename = shift; + if ($show_filename) { App::Ack::print( $filename ); App::Ack::print( ':', $nmatches ) if $count; + } + else { + App::Ack::print( $nmatches ) if $count; + } App::Ack::print( $ors ); } sub print_count0 { my $filename = shift; my $ors = shift; + my $show_filename = shift; + if ($show_filename) { App::Ack::print( $filename, ':0', $ors ); } + else { + App::Ack::print( '0', $ors ); + } +} @@ -2111,7 +2214,11 @@ sub print_match_or_context { if ( $show_filename ) { App::Ack::print_filename($display_filename, $sep) if not $heading; - App::Ack::print_line_no($line_no, $sep) if not $ackmate; + my $display_line_no = + $color + ? Term::ANSIColor::colored( $line_no, $ENV{ACK_COLOR_LINENO} ) + : $line_no; + App::Ack::print_line_no($display_line_no, $sep) if not $ackmate; } if ( $output_func ) { @@ -2157,6 +2264,17 @@ sub print_match_or_context { } # scope around search_resource() and print_match_or_context() +TOTAL_COUNT_SCOPE: { +my $total_count; + +sub get_total_count { + return $total_count; +} + +sub reset_total_count { + $total_count = 0; +} + sub search_and_list { my $res = shift; @@ -2165,6 +2283,7 @@ sub search_and_list { my $nmatches = 0; my $count = $opt->{count}; my $ors = $opt->{print0} ? "\0" : "\n"; # output record separator + my $show_filename = $opt->{show_filename}; my $regex = qr/$opt->{regex}/; @@ -2187,16 +2306,23 @@ sub search_and_list { } } + if ( $opt->{show_total} ) { + $total_count += $nmatches; + } + else { if ( $nmatches ) { - App::Ack::print_count( $res->name, $nmatches, $ors, $count ); + App::Ack::print_count( $res->name, $nmatches, $ors, $count, $show_filename ); } elsif ( $count && !$opt->{l} ) { - App::Ack::print_count0( $res->name, $ors ); + App::Ack::print_count0( $res->name, $ors, $show_filename ); + } } return $nmatches ? 1 : 0; } # search_and_list() +} # scope around $total_count + sub filetypes_supported_set { @@ -2213,7 +2339,7 @@ sub print_files { my $nmatches = 0; while ( defined ( my $file = $iter->() ) ) { - App::Ack::print $file, $ors; + App::Ack::print $file, $opt->{show_types} ? " => " . join( ',', filetypes( $file ) ) : (), $ors; $nmatches++; last if $opt->{1}; } @@ -2226,6 +2352,17 @@ sub print_files_with_matches { my $iter = shift; my $opt = shift; + # if we have -l and only 1 file given on command line (this means + # show_filename is set to 0), we want to see the filename nevertheless + $opt->{show_filename} = 1 if $opt->{l}; + + $opt->{show_filename} = 0 if $opt->{h}; + $opt->{show_filename} = 1 if $opt->{H}; + + # abuse options to hand in the show_total parameter to search_and_list + $opt->{show_total} = $opt->{count} && !$opt->{show_filename}; + reset_total_count(); + my $nmatches = 0; while ( defined ( my $filename = $iter->() ) ) { my $repo = App::Ack::Repository::Basic->new( $filename ); @@ -2238,6 +2375,10 @@ sub print_files_with_matches { $repo->close(); } + if ( $nmatches && $opt->{show_total} ) { + App::Ack::print_count('', get_total_count(), "\n", 1, 0 ) + } + return $nmatches; } @@ -2379,6 +2520,16 @@ sub get_starting_points { return \@what; } +sub _match { + my ( $target, $expression, $invert_flag ) = @_; + + if ( $invert_flag ) { + return $target !~ $expression; + } + else { + return $target =~ $expression; + } +} sub get_iterator { @@ -2393,9 +2544,9 @@ sub get_iterator { if ( $g_regex ) { $file_filter - = $opt->{u} ? sub { $File::Next::name =~ /$g_regex/ } # XXX Maybe this should be a 1, no? - : $opt->{all} ? sub { $starting_point{ $File::Next::name } || ( $File::Next::name =~ /$g_regex/ && is_searchable( $_ ) ) } - : sub { $starting_point{ $File::Next::name } || ( $File::Next::name =~ /$g_regex/ && is_interesting( @_ ) ) } + = $opt->{u} ? sub { _match( $File::Next::name, qr/$g_regex/, $opt->{invert_file_match} ) } # XXX Maybe this should be a 1, no? + : $opt->{all} ? sub { $starting_point{ $File::Next::name } || ( _match( $File::Next::name, qr/$g_regex/, $opt->{invert_file_match} ) && is_searchable( $_ ) ) } + : sub { $starting_point{ $File::Next::name } || ( _match( $File::Next::name, qr/$g_regex/, $opt->{invert_file_match} ) && is_interesting( @ _) ) } ; } else { @@ -2449,6 +2600,14 @@ sub output_to_pipe { } +sub exit_from_ack { + my $nmatches = shift; + + my $rc = $nmatches ? 0 : 1; + exit $rc; +} + + 1; # End of App::Ack package App::Ack::Repository; @@ -2609,6 +2768,12 @@ sub needs_line_scan { } return 0 unless $rc && ( $rc == $size || length(Encode::encode_utf8($buffer)) == $size ); + local $SIG{__WARN__} = sub { + my $e = shift; + App::Ack::warn( "\n$self->{filename}\nYou probably want to either convert this file to utf-8, ignore it in ~/.ackrc, or delete it.\n" ); + return; + }; + my $regex = $opt->{regex}; return $buffer =~ /$regex/m; } diff --git a/source/controllers/JPAckProcess.h b/source/controllers/JPAckProcess.h index c6db67d..af59136 100644 --- a/source/controllers/JPAckProcess.h +++ b/source/controllers/JPAckProcess.h @@ -15,7 +15,7 @@ extern NSString * const JPAckProcessComplete; } - (id)initWithResultHolder:(JPAckResultSource*)resultHolder; -- (void)invokeWithTerm:(NSString*)term path:(NSString*)path searchFolder:(NSString*)searchFolder literal:(BOOL)literal nocase:(BOOL)nocase words:(BOOL)words context:(BOOL)context symlinks:(BOOL)symlinks folderPattern:(NSString*)folderPattern options:(NSArray*)options; +- (void)invokeWithTerm:(NSString*)term path:(NSString*)path searchFolder:(NSString*)searchFolder literal:(BOOL)literal nocase:(BOOL)nocase words:(BOOL)words context:(BOOL)context symlinks:(BOOL)symlinks folderPattern:(NSString*)folderPattern filePattern:(NSString*)filePattern options:(NSArray*)options; - (void)parseData:(NSData*)data; - (void)saveTrailing:(char*)bytes length:(NSUInteger)length; diff --git a/source/controllers/JPAckProcess.m b/source/controllers/JPAckProcess.m index 56d9144..4e3cd36 100644 --- a/source/controllers/JPAckProcess.m +++ b/source/controllers/JPAckProcess.m @@ -44,7 +44,7 @@ - (id)initWithResultHolder:(JPAckResultSource*)resultHolder return self; } -- (void)invokeWithTerm:(NSString*)term path:(NSString*)path searchFolder:(NSString*)searchFolder literal:(BOOL)literal nocase:(BOOL)nocase words:(BOOL)words context:(BOOL)context symlinks:(BOOL)symlinks folderPattern:(NSString*)folderPattern options:(NSArray*)options +- (void)invokeWithTerm:(NSString*)term path:(NSString*)path searchFolder:(NSString*)searchFolder literal:(BOOL)literal nocase:(BOOL)nocase words:(BOOL)words context:(BOOL)context symlinks:(BOOL)symlinks folderPattern:(NSString*)folderPattern filePattern:(NSString*)filePattern options:(NSArray*)options { ackState = ackInitial; [self.ackResult clearContents]; @@ -79,6 +79,13 @@ - (void)invokeWithTerm:(NSString*)term path:(NSString*)path searchFolder:(NSStri [args addObject:folderPattern]; } + if (filePattern) + { + [args addObject:@"--invert-file-match"]; + [args addObject:@"-G"]; + [args addObject:filePattern]; + } + for (NSString* typeOption in options) [args addObject:[NSString stringWithFormat:@"%@%@", ([typeOption hasPrefix:@"-"]) ? @"" : @"--", typeOption]]; diff --git a/source/controllers/JPAckWindowController.m b/source/controllers/JPAckWindowController.m index ddd1f20..1c6e030 100644 --- a/source/controllers/JPAckWindowController.m +++ b/source/controllers/JPAckWindowController.m @@ -243,8 +243,10 @@ - (IBAction)performSearch:(id)sender [ackResult clearContents]; NSString* folderPattern = nil; + NSString* filePattern = nil; if (folders) folderPattern = [[[NSUserDefaults standardUserDefaults] stringForKey:@"OakFolderReferenceFolderPattern"] substringFromIndex:1]; + filePattern = [[[NSUserDefaults standardUserDefaults] stringForKey:@"OakFolderReferenceFilePattern"] substringFromIndex:1]; self.currentProcess = [[[JPAckProcess alloc] initWithResultHolder:ackResult] autorelease]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(currentProcessCompleted:) name:JPAckProcessComplete object:self.currentProcess]; @@ -258,6 +260,7 @@ - (IBAction)performSearch:(id)sender context:context symlinks:symlinks folderPattern:folderPattern + filePattern:filePattern options:[optionsField objectValue]]; }