From 02873f5116565a4cb7377ce79de569870f7821d8 Mon Sep 17 00:00:00 2001 From: Garen Torikian Date: Tue, 26 Mar 2013 15:02:48 -0700 Subject: [PATCH 01/54] drop in nak for search --- package.json | 3 ++- src/app/project.coffee | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 8f1d8129a..4f7be7832 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,8 @@ "coffee-cache": "0.1.0", "pegjs": "0.7.0", "async": "0.2.6", - "plist": "git://github.com/nathansobo/node-plist.git" + "plist": "git://github.com/nathansobo/node-plist.git", + "nak": "0.2.4" }, "private": true, diff --git a/src/app/project.coffee b/src/app/project.coffee index d6651e727..a3da8a483 100644 --- a/src/app/project.coffee +++ b/src/app/project.coffee @@ -192,8 +192,9 @@ class Project readPath(line) if state is 'readingPath' readLine(line) if state is 'readingLines' - command = require.resolve('ag') - args = ['--ackmate', regex.source, @getPath()] + command = require.resolve 'nak' + args = ['--ackmate', "#{regex.source}", @getPath()] + args.unshift("--addVCSIgnores") if config.get('nak.addVCSIgnores') new BufferedProcess({command, args, stdout, exit}) deferred From 280e527f5a6b174124b3ac4d6fc7087272f4c217 Mon Sep 17 00:00:00 2001 From: Garen Torikian Date: Tue, 26 Mar 2013 15:03:10 -0700 Subject: [PATCH 02/54] Remove unneeded vendor binarys --- vendor/ack | 2784 ---------------------------------------------------- vendor/ag | Bin 226672 -> 0 bytes 2 files changed, 2784 deletions(-) delete mode 100755 vendor/ack delete mode 100755 vendor/ag diff --git a/vendor/ack b/vendor/ack deleted file mode 100755 index a20f9f603..000000000 --- a/vendor/ack +++ /dev/null @@ -1,2784 +0,0 @@ -#!/usr/bin/env perl -# -# This file, ack, is generated code. -# Please DO NOT EDIT or send patches for it. -# -# Please take a look at the source from -# http://github.com/petdance/ack -# and submit patches against the individual files -# that build ack. -# - -use warnings; -use strict; - -our $VERSION = '1.96'; -# Check http://betterthangrep.com/ for updates - -# These are all our globals. - - -MAIN: { - if ( $App::Ack::VERSION ne $main::VERSION ) { - App::Ack::die( "Program/library version mismatch\n\t$0 is $main::VERSION\n\t$INC{'App/Ack.pm'} is $App::Ack::VERSION" ); - } - - # Do preliminary arg checking; - my $env_is_usable = 1; - for ( @ARGV ) { - last if ( $_ eq '--' ); - - # Priorities! Get the --thpppt checking out of the way. - /^--th[pt]+t+$/ && App::Ack::_thpppt($_); - - # See if we want to ignore the environment. (Don't tell Al Gore.) - 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}; - } - App::Ack::load_colors(); - - if ( exists $ENV{ACK_SWITCHES} ) { - App::Ack::warn( 'ACK_SWITCHES is no longer supported. Use ACK_OPTIONS.' ); - } - - if ( !@ARGV ) { - App::Ack::show_help(); - exit 1; - } - - main(); -} - -sub main { - my $opt = App::Ack::get_command_line_options(); - - $| = 1 if $opt->{flush}; # Unbuffer the output if flush mode - - if ( App::Ack::input_from_pipe() ) { - # We're going into filter mode - for ( qw( f g l ) ) { - $opt->{$_} and App::Ack::die( "Can't use -$_ when acting as a filter." ); - } - $opt->{show_filename} = 0; - $opt->{regex} = App::Ack::build_regex( defined $opt->{regex} ? $opt->{regex} : shift @ARGV, $opt ); - if ( my $nargs = @ARGV ) { - 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( '-' ); - 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(); - App::Ack::exit_from_ack( $nmatches ); - } - - my $file_matching = $opt->{f} || $opt->{lines}; - 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 ); - } - - # check that all regexes do compile fine - App::Ack::check_regex( $_ ) for ( $opt->{regex}, $opt->{G} ); - - my $what = App::Ack::get_starting_points( \@ARGV, $opt ); - my $iter = App::Ack::get_iterator( $what, $opt ); - App::Ack::filetype_setup(); - - my $nmatches = 0; - - App::Ack::set_up_pager( $opt->{pager} ) if defined $opt->{pager}; - if ( $opt->{f} ) { - $nmatches = App::Ack::print_files( $iter, $opt ); - } - elsif ( $opt->{l} || $opt->{count} ) { - $nmatches = App::Ack::print_files_with_matches( $iter, $opt ); - } - else { - $nmatches = App::Ack::print_matches( $iter, $opt ); - } - close $App::Ack::fh; - App::Ack::exit_from_ack( $nmatches ); -} - -=head1 NAME - -ack - grep-like text finder - -=head1 SYNOPSIS - - ack [options] PATTERN [FILE...] - ack -f [options] [DIRECTORY...] - -=head1 DESCRIPTION - -Ack is designed as a replacement for 99% of the uses of F. - -Ack searches the named input FILEs (or standard input if no files are -named, or the file name - is given) for lines containing a match to the -given PATTERN. By default, ack prints the matching lines. - -Ack can also list files that would be searched, without actually searching -them, to let you take advantage of ack's file-type filtering capabilities. - -=head1 FILE SELECTION - -I is intelligent about the files it searches. It knows about -certain file types, based on both the extension on the file and, -in some cases, the contents of the file. These selections can be -made with the B<--type> option. - -With no file selections, I only searches files of types that -it recognizes. If you have a file called F, and I -doesn't know what a .wango file is, I won't search it. - -The B<-a> option tells I to select all files, regardless of -type. - -Some files will never be selected by I, even with B<-a>, -including: - -=over 4 - -=item * Backup files: Files matching F<#*#> or ending with F<~>. - -=item * Coredumps: Files matching F - -=back - -However, I always searches the files given on the command line, -no matter what type. Furthermore, by specifying the B<-u> option all -files will be searched. - -=head1 DIRECTORY SELECTION - -I descends through the directory tree of the starting directories -specified. However, it will ignore the shadow directories used by -many version control systems, and the build directories used by the -Perl MakeMaker system. You may add or remove a directory from this -list with the B<--[no]ignore-dir> option. The option may be repeated -to add/remove multiple directories from the ignore list. - -For a complete list of directories that do not get searched, run -F. - -=head1 WHEN TO USE GREP - -I trumps I as an everyday tool 99% of the time, but don't -throw I away, because there are times you'll still need it. - -E.g., searching through huge files looking for regexes that can be -expressed with I syntax should be quicker with I. - -If your script or parent program uses I C<--quiet> or -C<--silent> or needs exit 2 on IO error, use I. - -=head1 OPTIONS - -=over 4 - -=item B<-a>, B<--all> - -Operate on all files, regardless of type (but still skip directories -like F, F, etc.) - -=item B<-A I>, B<--after-context=I> - -Print I lines of trailing context after matching lines. - -=item B<-B I>, B<--before-context=I> - -Print I lines of leading context before matching lines. - -=item B<-C [I]>, B<--context[=I]> - -Print I lines (default 2) of context around matching lines. - -=item B<-c>, B<--count> - -Suppress normal output; instead print a count of matching lines for -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 -the color. This is on by default unless the output is redirected. - -On Windows, this option is off by default unless the -L module is installed or the C -environment variable is used. - -=item B<--color-filename=I> - -Sets the color to be used for filenames. - -=item B<--color-match=I> - -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 -that can place your cursor at a given position. - -=item B<--env>, B<--noenv> - -B<--noenv> disables all environment processing. No F<.ackrc> is read -and all environment variables are ignored. By default, F considers -F<.ackrc> and settings in the environment. - -=item B<--flush> - -B<--flush> flushes output immediately. This is off by default -unless ack is running interactively (when output goes to a pipe -or file). - -=item B<-f> - -Only print the files that would be searched, without actually doing -any searching. PATTERN must not be specified, or it will be taken as -a path to search. - -=item B<--follow>, B<--nofollow> - -Follow or don't follow symlinks, other than whatever starting files -or directories were specified on the command line. - -This is off by default. - -=item B<-G I> - -Only paths matching I are included in the search. The entire -path and filename are matched against I, and I is a -Perl regular expression, not a shell glob. - -The options B<-i>, B<-w>, B<-v>, and B<-Q> do not apply to this I. - -=item B<-g I> - -Print files where the relative path + filename matches I. This option is -a convenience shortcut for B<-f> B<-G I>. - -The options B<-i>, B<-w>, B<-v>, and B<-Q> do not apply to this I. - -=item B<--group>, B<--nogroup> - -B<--group> groups matches by file name with. This is the default when -used interactively. - -B<--nogroup> prints one result per line, like grep. This is the default -when output is redirected. - -=item B<-H>, B<--with-filename> - -Print the filename for each match. - -=item B<-h>, B<--no-filename> - -Suppress the prefixing of filenames on output when multiple files are -searched. - -=item B<--help> - -Print a short help statement. - -=item B<-i>, B<--ignore-case> - -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=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 -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 -B<--line> options or as a comma separated list (B<--line=3,5,7>). B<--line=4-7> -also works. The lines are always output in ascending order, no matter the -order given on the command line. - -=item B<-l>, B<--files-with-matches> - -Only print the filenames of matching files, instead of the matching text. - -=item B<-L>, B<--files-without-matches> - -Only print the filenames of files that do I match. This is equivalent -to specifying B<-l> and B<-v>. - -=item B<--match I> - -Specify the I explicitly. This is helpful if you don't want to put the -regex as your first argument, e.g. when executing multiple searches over the -same set of files. - - # search for foo and bar in given files - ack file1 t/file* --match foo - ack file1 t/file* --match bar - -=item B<-m=I>, B<--max-count=I> - -Stop reading a file after I matches. - -=item B<--man> - -Print this manual page. - -=item B<-n>, B<--no-recurse> - -No descending into subdirectories. - -=item B<-o> - -Show only the part of each line matching PATTERN (turns off text -highlighting) - -=item B<--output=I> - -Output the evaluation of I for each line (turns off text -highlighting) - -=item B<--pager=I> - -Direct ack's output through I. This can also be specified -via the C and C environment variables. - -Using --pager does not suppress grouping and coloring like piping -output on the command-line does. - -=item B<--passthru> - -Prints all lines, whether or not they match the expression. Highlighting -will still work, though, so it can be used to highlight matches while -still seeing the entire file, as in: - - # Watch a log file, and highlight a certain IP address - $ tail -f ~/access.log | ack --passthru 123.45.67.89 - -=item B<--print0> - -Only works in conjunction with -f, -g, -l or -c (filename output). The filenames -are output separated with a null byte instead of the usual newline. This is -helpful when dealing with filenames that contain whitespace, e.g. - - # remove all files of type html - ack -f --html --print0 | xargs -0 rm -f - -=item B<-Q>, B<--literal> - -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 -characters. This is similar to C in vim. This option is -off by default. - -B<-i> always overrides this option. - -This applies only to the PATTERN, not to the regexes given for the -B<-g> and B<-G> options. - -=item B<--sort-files> - -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 -spelling of B<--thpppppt> is not important. It's checked against -a regular expression. - -=item B<--type=TYPE>, B<--type=noTYPE> - -Specify the types of files to include or exclude from a search. -TYPE is a filetype, like I or I. B<--type=perl> can -also be specified as B<--perl>, and B<--type=noperl> can be done -as B<--noperl>. - -If a file is of both type "foo" and "bar", specifying --foo and ---nobar will exclude the file, because an exclusion takes precedence -over an inclusion. - -Type specifications can be repeated and are ORed together. - -See I for a list of valid types. - -=item B<--type-add I=I<.EXTENSION>[,I<.EXT2>[,...]]> - -Files with the given EXTENSION(s) are recognized as being of (the -existing) type TYPE. See also L. - - -=item B<--type-set I=I<.EXTENSION>[,I<.EXT2>[,...]]> - -Files with the given EXTENSION(s) are recognized as being of type -TYPE. This replaces an existing definition for type TYPE. See also -L. - -=item B<-u>, B<--unrestricted> - -All files and directories (including blib/, core.*, ...) are searched, -nothing is skipped. When both B<-u> and B<--ignore-dir> are used, the -B<--ignore-dir> option has no effect. - -=item B<-v>, B<--invert-match> - -Invert match: select non-matching lines - -This applies only to the PATTERN, not to the regexes given for the B<-g> -and B<-G> options. - -=item B<--version> - -Display version and copyright information. - -=item B<-w>, B<--word-regexp> - -Force PATTERN to match only whole words. The PATTERN is wrapped with -C<\b> metacharacters. - -This applies only to the PATTERN, not to the regexes given for the B<-g> -and B<-G> options. - -=item B<-1> - -Stops after reporting first match of any kind. This is different -from B<--max-count=1> or B<-m1>, where only one match per file is -shown. Also, B<-1> works with B<-f> and B<-g>, where B<-m> does -not. - -=back - -=head1 THE .ackrc FILE - -The F<.ackrc> file contains command-line options that are prepended -to the command line before processing. Multiple options may live -on multiple lines. Lines beginning with a # are ignored. A F<.ackrc> -might look like this: - - # Always sort the files - --sort-files - - # Always color, even if piping to a another program - --color - - # Use "less -r" as my pager - --pager=less -r - -Note that arguments with spaces in them do not need to be quoted, -as they are not interpreted by the shell. Basically, each I -in the F<.ackrc> file is interpreted as one element of C<@ARGV>. - -F looks in your home directory for the F<.ackrc>. You can -specify another location with the F variable, below. - -If B<--noenv> is specified on the command line, the F<.ackrc> file -is ignored. - -=head1 Defining your own types - -ack allows you to define your own types in addition to the predefined -types. This is done with command line options that are best put into -an F<.ackrc> file - then you do not have to define your types over and -over again. In the following examples the options will always be shown -on one command line so that they can be easily copy & pasted. - -I searches for foo in all perl files. I -tells you, that perl files are files ending -in .pl, .pm, .pod or .t. So what if you would like to include .xs -files as well when searching for --perl files? I -does this for you. B<--type-add> appends -additional extensions to an existing type. - -If you want to define a new type, or completely redefine an existing -type, then use B<--type-set>. I defines the type I to include files with -the extensions .e or .eiffel. So to search for all eiffel files -containing the word Bertrand use I. -As usual, you can also write B<--type=eiffel> -instead of B<--eiffel>. Negation also works, so B<--noeiffel> excludes -all eiffel files from a search. Redefining also works: I -and I<.xs> files no longer belong to the type I. - -When defining your own types in the F<.ackrc> file you have to use -the following: - - --type-set=eiffel=.e,.eiffel - -or writing on separate lines - - --type-set - eiffel=.e,.eiffel - -The following does B work in the F<.ackrc> file: - - --type-set eiffel=.e,.eiffel - - -In order to see all currently defined types, use I<--help types>, e.g. -I - -Restrictions: - -=over 4 - -=item - -The types 'skipped', 'make', 'binary' and 'text' are considered "builtin" and -cannot be altered. - -=item - -The shebang line recognition of the types 'perl', 'ruby', 'php', 'python', -'shell' and 'xml' cannot be redefined by I<--type-set>, it is always -active. However, the shebang line is only examined for files where the -extension is not recognised. Therefore it is possible to say -I and -only find your shiny new I<.perl> files (and all files with unrecognized extension -and perl on the shebang line). - -=back - -=head1 ENVIRONMENT VARIABLES - -For commonly-used ack options, environment variables can make life much easier. -These variables are ignored if B<--noenv> is specified on the command line. - -=over 4 - -=item ACKRC - -Specifies the location of the F<.ackrc> file. If this file doesn't -exist, F looks in the default location. - -=item ACK_OPTIONS - -This variable specifies default options to be placed in front of -any explicit options on the command line. - -=item ACK_COLOR_FILENAME - -Specifies the color of the filename when it's printed in B<--group> -mode. By default, it's "bold green". - -The recognized attributes are clear, reset, dark, bold, underline, -underscore, blink, reverse, concealed black, red, green, yellow, -blue, magenta, on_black, on_red, on_green, on_yellow, on_blue, -on_magenta, on_cyan, and on_white. Case is not significant. -Underline and underscore are equivalent, as are clear and reset. -The color alone sets the foreground color, and on_color sets the -background color. - -This option can also be set with B<--color-filename>. - -=item ACK_COLOR_MATCH - -Specifies the color of the matching text when printed in B<--color> -mode. By default, it's "black on_yellow". - -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 -ack will send its output. - -Using C does not suppress grouping and coloring like -piping output on the command-line does, except that on Windows -ack will assume that C does not support color. - -C overrides C if both are specified. - -=item ACK_PAGER_COLOR - -Specifies a pager program that understands ANSI color sequences. -Using C does not suppress grouping and coloring -like piping output on the command-line does. - -If you are not on Windows, you never need to use C. - -=back - -=head1 ACK & OTHER TOOLS - -=head2 Vim integration - -F integrates easily with the Vim text editor. Set this in your -F<.vimrc> to use F instead of F: - - set grepprg=ack\ -a - -That examples uses C<-a> to search through all files, but you may -use other default flags. Now you can search with F and easily -step through the results in Vim: - - :grep Dumper perllib - -=head2 Emacs integration - -Phil Jackson put together an F extension that "provides a -simple compilation mode ... has the ability to guess what files you -want to search for based on the major-mode." - -L - -=head2 TextMate integration - -Pedro Melo is a TextMate user who writes "I spend my day mostly -inside TextMate, and the built-in find-in-project sucks with large -projects. So I hacked a TextMate command that was using find + -grep to use ack. The result is the Search in Project with ack, and -you can find it here: -L" - -=head2 Shell and Return Code - -For greater compatibility with I, I in normal use returns -shell return or exit code of 0 only if something is found and 1 if -no match is found. - -(Shell exit code 1 is C<$?=256> in perl with C or backticks.) - -The I code 2 for errors is not used. - -If C<-f> or C<-g> are specified, then 0 is returned if at least one -file is found. If no files are found, then 1 is returned. - -=cut - -=head1 DEBUGGING ACK PROBLEMS - -If ack gives you output you're not expecting, start with a few simple steps. - -=head2 Use B<--noenv> - -Your environment variables and F<.ackrc> may be doing things you're -not expecting, or forgotten you specified. Use B<--noenv> to ignore -your environment and F<.ackrc>. - -=head2 Use B<-f> to see what files you're scanning - -The reason I created B<-f> in the first place was as a debugging -tool. If ack is not finding matches you think it should find, run -F to see what files are being checked. - -=head1 TIPS - -=head2 Use the F<.ackrc> file. - -The F<.ackrc> is the place to put all your options you use most of -the time but don't want to remember. Put all your --type-add and ---type-set definitions in it. If you like --smart-case, set it -there, too. I also set --sort-files there. - -=head2 Use F<-f> for working with big codesets - -Ack does more than search files. C will create a -list of all the Perl files in a tree, ideal for sending into F. -For example: - - # Change all "this" to "that" in all Perl files in a tree. - ack -f --perl | xargs perl -p -i -e's/this/that/g' - -or if you prefer: - - perl -p -i -e's/this/thatg/' $(ack -f --perl) - -=head2 Use F<-Q> when in doubt about metacharacters - -If you're searching for something with a regular expression -metacharacter, most often a period in a filename or IP address, add -the -Q to avoid false positives without all the backslashing. See -the following example for more... - -=head2 Use ack to watch log files - -Here's one I used the other day to find trouble spots for a website -visitor. The user had a problem loading F, so I -took the access log and scanned it with ack twice. - - ack -Q aa.bb.cc.dd /path/to/access.log | ack -Q -B5 troublesome.gif - -The first ack finds only the lines in the Apache log for the given -IP. The second finds the match on my troublesome GIF, and shows -the previous five lines from the log in each case. - -=head2 Share your knowledge - -Join the ack-users mailing list. Send me your tips and I may add -them here. - -=head1 FAQ - -=head2 Why isn't ack finding a match in (some file)? - -Probably because it's of a type that ack doesn't recognize. ack's -searching behavior is driven by filetype. B - -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. - -If you want ack to search every file, even ones that it always -ignores like coredumps and backup files, use the C<-u> switch. - -=head2 Why does ack ignore unknown files by default? - -ack is designed by a programmer, for programmers, for searching -large trees of code. Most codebases have a lot files in them which -aren't source files (like compiled object files, source control -metadata, etc), and grep wastes a lot of time searching through all -of those as well and returning matches from those files. - -That's why ack's behavior of not searching things it doesn't recognize -is one of its greatest strengths: the speed you get from only -searching the things that you want to be looking at. - -=head2 Wouldn't it be great if F did search & replace? - -No, ack will always be read-only. Perl has a perfectly good way -to do search & replace in files, using the C<-i>, C<-p> and C<-n> -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 from the Unix shell: - - $ perl -i -p -e's/foo/bar/g' $(ack -f --php) - -=head2 Can you make ack recognize F<.xyz> files? - -That's an enhancement. Please see the section in the manual about -enhancements. - -=head2 There's already a program/package called ack. - -Yes, I know. - -=head2 Why is it called ack if it's called ack-grep? - -The name of the program is "ack". Some packagers have called it -"ack-grep" when creating packages because there's already a package -out there called "ack" that has nothing to do with this ack. - -I suggest you make a symlink named F that points to F -because one of the crucial benefits of ack is having a name that's -so short and simple to type. - -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<< >> - -=head1 BUGS - -Please report any bugs or feature requests to the issues list at -Github: L - -=head1 ENHANCEMENTS - -All enhancement requests MUST first be posted to the ack-users -mailing list at L. I -will not consider a request without it first getting seen by other -ack users. This includes requests for new filetypes. - -There is a list of enhancements I want to make to F in the ack -issues list at Github: L - -Patches are always welcome, but patches with tests get the most -attention. - -=head1 SUPPORT - -Support for and information about F can be found at: - -=over 4 - -=item * The ack homepage - -L - -=item * The ack issues list at Github - -L - -=item * AnnoCPAN: Annotated CPAN documentation - -L - -=item * CPAN Ratings - -L - -=item * Search CPAN - -L - -=item * Git source repository - -L - -=back - -=head1 ACKNOWLEDGEMENTS - -How appropriate to have Inowledgements! - -Thanks to everyone who has contributed to ack in any way, including -Matthew Wild, -Scott Kyle, -Nick Hooey, -Bo Borgerson, -Mark Szymanski, -Marq Schneider, -Packy Anderson, -JR Boyens, -Dan Sully, -Ryan Niebur, -Kent Fredric, -Mike Morearty, -Ingmar Vanhassel, -Eric Van Dewoestine, -Sitaram Chamarty, -Adam James, -Richard Carlsson, -Pedro Melo, -AJ Schuster, -Phil Jackson, -Michael Schwern, -Jan Dubois, -Christopher J. Madsen, -Matthew Wickline, -David Dyck, -Jason Porritt, -Jjgod Jiang, -Thomas Klausner, -Uri Guttman, -Peter Lewis, -Kevin Riggle, -Ori Avtalion, -Torsten Blix, -Nigel Metheringham, -GEbor SzabE, -Tod Hagan, -Michael Hendricks, -Evar ArnfjErE Bjarmason, -Piers Cawley, -Stephen Steneker, -Elias Lutfallah, -Mark Leighton Fisher, -Matt Diephouse, -Christian Jaeger, -Bill Sully, -Bill Ricker, -David Golden, -Nilson Santos F. Jr, -Elliot Shank, -Merijn Broeren, -Uwe Voelker, -Rick Scott, -Ask BjErn Hansen, -Jerry Gay, -Will Coleda, -Mike O'Regan, -Slaven ReziE<0x107>, -Mark Stosberg, -David Alan Pisoni, -Adriano Ferreira, -James Keenan, -Leland Johnson, -Ricardo Signes -and Pete Krawczyk. - -=head1 COPYRIGHT & LICENSE - -Copyright 2005-2011 Andy Lester. - -This program is free software; you can redistribute it and/or modify -it under the terms of the Artistic License v2.0. - -=cut -package File::Next; - -use strict; -use warnings; - - -our $VERSION = '1.06'; - - - -use File::Spec (); - - -our $name; # name of the current file -our $dir; # dir of the current file - -our %files_defaults; -our %skip_dirs; - -BEGIN { - %files_defaults = ( - file_filter => undef, - descend_filter => undef, - error_handler => sub { CORE::die @_ }, - sort_files => undef, - follow_symlinks => 1, - ); - %skip_dirs = map {($_,1)} (File::Spec->curdir, File::Spec->updir); -} - - -sub files { - ($_[0] eq __PACKAGE__) && die 'File::Next::files must not be invoked as File::Next->files'; - - my ($parms,@queue) = _setup( \%files_defaults, @_ ); - my $filter = $parms->{file_filter}; - - return sub { - while (@queue) { - my ($dir,$file,$fullpath) = splice( @queue, 0, 3 ); - if ( -f $fullpath ) { - if ( $filter ) { - local $_ = $file; - local $File::Next::dir = $dir; - local $File::Next::name = $fullpath; - next if not $filter->(); - } - return wantarray ? ($dir,$file,$fullpath) : $fullpath; - } - elsif ( -d _ ) { - unshift( @queue, _candidate_files( $parms, $fullpath ) ); - } - } # while - - return; - }; # iterator -} - - - - - - - -sub sort_standard($$) { return $_[0]->[1] cmp $_[1]->[1] } -sub sort_reverse($$) { return $_[1]->[1] cmp $_[0]->[1] } - -sub reslash { - my $path = shift; - - my @parts = split( /\//, $path ); - - return $path if @parts < 2; - - return File::Spec->catfile( @parts ); -} - - - -sub _setup { - my $defaults = shift; - my $passed_parms = ref $_[0] eq 'HASH' ? {%{+shift}} : {}; # copy parm hash - - my %passed_parms = %{$passed_parms}; - - my $parms = {}; - for my $key ( keys %{$defaults} ) { - $parms->{$key} = - exists $passed_parms{$key} - ? delete $passed_parms{$key} - : $defaults->{$key}; - } - - # Any leftover keys are bogus - for my $badkey ( keys %passed_parms ) { - my $sub = (caller(1))[3]; - $parms->{error_handler}->( "Invalid option passed to $sub(): $badkey" ); - } - - # If it's not a code ref, assume standard sort - if ( $parms->{sort_files} && ( ref($parms->{sort_files}) ne 'CODE' ) ) { - $parms->{sort_files} = \&sort_standard; - } - my @queue; - - for ( @_ ) { - my $start = reslash( $_ ); - if (-d $start) { - push @queue, ($start,undef,$start); - } - else { - push @queue, (undef,$start,$start); - } - } - - return ($parms,@queue); -} - - -sub _candidate_files { - my $parms = shift; - my $dir = shift; - - my $dh; - if ( !opendir $dh, $dir ) { - $parms->{error_handler}->( "$dir: $!" ); - return; - } - - my @newfiles; - my $descend_filter = $parms->{descend_filter}; - my $follow_symlinks = $parms->{follow_symlinks}; - my $sort_sub = $parms->{sort_files}; - - for my $file ( grep { !exists $skip_dirs{$_} } readdir $dh ) { - my $has_stat; - - # Only do directory checking if we have a descend_filter - my $fullpath = File::Spec->catdir( $dir, $file ); - if ( !$follow_symlinks ) { - next if -l $fullpath; - $has_stat = 1; - } - - if ( $descend_filter ) { - if ( $has_stat ? (-d _) : (-d $fullpath) ) { - local $File::Next::dir = $fullpath; - local $_ = $file; - next if not $descend_filter->(); - } - } - if ( $sort_sub ) { - push( @newfiles, [ $dir, $file, $fullpath ] ); - } - else { - push( @newfiles, $dir, $file, $fullpath ); - } - } - closedir $dh; - - if ( $sort_sub ) { - return map { @{$_} } sort $sort_sub @newfiles; - } - - return @newfiles; -} - - -1; # End of File::Next -package App::Ack; - -use warnings; -use strict; - - - - -our $VERSION; -our $COPYRIGHT; -BEGIN { - $VERSION = '1.96'; - $COPYRIGHT = 'Copyright 2005-2011 Andy Lester.'; -} - -our $fh; - -BEGIN { - $fh = *STDOUT; -} - - -our %types; -our %type_wanted; -our %mappings; -our %ignore_dirs; - -our $input_from_pipe; -our $output_to_pipe; - -our $dir_sep_chars; -our $is_cygwin; -our $is_windows; - -use File::Spec (); -use File::Glob ':glob'; -use Getopt::Long (); - -BEGIN { - %ignore_dirs = ( - '.bzr' => 'Bazaar', - '.cdv' => 'Codeville', - '~.dep' => 'Interface Builder', - '~.dot' => 'Interface Builder', - '~.nib' => 'Interface Builder', - '~.plst' => 'Interface Builder', - '.git' => 'Git', - '.hg' => 'Mercurial', - '.pc' => 'quilt', - '.svn' => 'Subversion', - _MTN => 'Monotone', - blib => 'Perl module building', - CVS => 'CVS', - RCS => 'RCS', - SCCS => 'SCCS', - _darcs => 'darcs', - _sgbak => 'Vault/Fortress', - 'autom4te.cache' => 'autoconf', - 'cover_db' => 'Devel::Cover', - _build => 'Module::Build', - ); - - %mappings = ( - actionscript => [qw( as mxml )], - ada => [qw( ada adb ads )], - asm => [qw( asm s )], - batch => [qw( bat cmd )], - 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 )], - java => [qw( java properties )], - js => [qw( js )], - jsp => [qw( jsp jspx jhtm jhtml )], - lisp => [qw( lisp lsp )], - lua => [qw( lua )], - make => q{Makefiles (including *.mk and *.mak)}, - mason => [qw( mas mhtml mpl mtxt )], - objc => [qw( m h )], - objcpp => [qw( mm h )], - ocaml => [qw( ml mli )], - parrot => [qw( pir pasm pmc ops pod pg tg )], - perl => [qw( pl pm pm6 pod t )], - php => [qw( php phpt php3 php4 php5 phtml)], - plone => [qw( pt cpt metadata cpy py )], - python => [qw( py )], - rake => q{Rakefiles}, - ruby => [qw( rb rhtml rjs rxml erb rake spec )], - scala => [qw( scala )], - scheme => [qw( scm ss )], - shell => [qw( sh bash csh tcsh ksh zsh )], - skipped => q{Files, but not directories, normally skipped by ack (default: off)}, - smalltalk => [qw( st )], - sql => [qw( sql ctl )], - tcl => [qw( tcl itcl itk )], - tex => [qw( tex cls sty )], - 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 xsl xslt ent )], - ); - - while ( my ($type,$exts) = each %mappings ) { - if ( ref $exts ) { - for my $ext ( @{$exts} ) { - push( @{$types{$ext}}, $type ); - } - } - } - # 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; - $input_from_pipe = -p STDIN; - - $is_cygwin = ($^O eq 'cygwin'); - $is_windows = ($^O =~ /MSWin32/); - $dir_sep_chars = $is_windows ? quotemeta( '\\/' ) : quotemeta( File::Spec->catfile( '', '' ) ); -} - - -sub read_ackrc { - my @files = ( $ENV{ACKRC} ); - my @dirs = - $is_windows - ? ( $ENV{HOME}, $ENV{USERPROFILE} ) - : ( '~', $ENV{HOME} ); - for my $dir ( grep { defined } @dirs ) { - for my $file ( '.ackrc', '_ackrc' ) { - push( @files, bsd_glob( "$dir/$file", GLOB_TILDE ) ); - } - } - for my $filename ( @files ) { - if ( defined $filename && -e $filename ) { - open( my $fh, '<', $filename ) or App::Ack::die( "$filename: $!\n" ); - my @lines = grep { /./ && !/^\s*#/ } <$fh>; - 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; - } - } - - return; -} - - -sub get_command_line_options { - my %opt = ( - pager => $ENV{ACK_PAGER_COLOR} || $ENV{ACK_PAGER}, - ); - - my $getopt_specs = { - 1 => sub { $opt{1} = $opt{m} = 1 }, - 'A|after-context=i' => \$opt{after_context}, - 'B|before-context=i' => \$opt{before_context}, - 'C|context:i' => sub { shift; my $val = shift; $opt{before_context} = $opt{after_context} = ($val || 2) }, - 'a|all-types' => \$opt{all}, - 'break!' => \$opt{break}, - c => \$opt{count}, - '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 - f => \$opt{f}, - flush => \$opt{flush}, - 'follow!' => \$opt{follow}, - 'g=s' => sub { shift; $opt{G} = shift; $opt{f} = 1 }, - 'G=s' => \$opt{G}, - 'group!' => sub { shift; $opt{heading} = $opt{break} = shift }, - 'heading!' => \$opt{heading}, - '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 }, - 'm|max-count=i' => \$opt{m}, - 'match=s' => \$opt{regex}, - 'n|no-recurse' => \$opt{n}, - o => sub { $opt{output} = '$&' }, - 'output=s' => \$opt{output}, - 'pager=s' => \$opt{pager}, - 'nopager' => sub { $opt{pager} = undef }, - 'passthru' => \$opt{passthru}, - 'print0' => \$opt{print0}, - 'Q|literal' => \$opt{Q}, - '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}, - 'v|invert-match' => \$opt{v}, - 'w|word-regexp' => \$opt{w}, - - '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; }, - 'help|?:s' => sub { shift; show_help(@_); exit; }, - 'help-types'=> sub { show_help_types(); 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 - my $dummy = shift; - my $type = shift; - my $wanted = ($type =~ s/^no//) ? 0 : 1; # must not be undef later - - if ( exists $type_wanted{ $type } ) { - $type_wanted{ $type } = $wanted; - } - else { - App::Ack::die( qq{Unknown --type "$type"} ); - } - }, # type sub - }; - - # Stick any default switches at the beginning, so they can be overridden - # by the command line switches. - unshift @ARGV, split( ' ', $ENV{ACK_OPTIONS} ) if defined $ENV{ACK_OPTIONS}; - - # first pass through options, looking for type definitions - def_types_from_ARGV(); - - for my $i ( filetypes_supported() ) { - $getopt_specs->{ "$i!" } = \$type_wanted{ $i }; - } - - - my $parser = Getopt::Long::Parser->new(); - $parser->configure( 'bundling', 'no_ignore_case', ); - $parser->getoptions( %{$getopt_specs} ) or - App::Ack::die( 'See ack --help, ack --help-types or ack --man for options.' ); - - my $to_screen = not output_to_pipe(); - my %defaults = ( - all => 0, - color => $to_screen, - follow => 0, - break => $to_screen, - heading => $to_screen, - before_context => 0, - after_context => 0, - ); - if ( $is_windows && $defaults{color} && not $ENV{ACK_PAGER_COLOR} ) { - if ( $ENV{ACK_PAGER} || not eval { require Win32::Console::ANSI } ) { - $defaults{color} = 0; - } - } - if ( $to_screen && $ENV{ACK_PAGER_COLOR} ) { - $defaults{color} = 1; - } - - while ( my ($key,$value) = each %defaults ) { - if ( not defined $opt{$key} ) { - $opt{$key} = $value; - } - } - - if ( defined $opt{m} && $opt{m} <= 0 ) { - App::Ack::die( '-m must be greater than zero' ); - } - - for ( qw( before_context after_context ) ) { - if ( defined $opt{$_} && $opt{$_} < 0 ) { - App::Ack::die( "--$_ may not be negative" ); - } - } - - if ( defined( my $val = $opt{output} ) ) { - $opt{output} = eval qq[ sub { "$val" } ]; - } - if ( defined( my $l = $opt{lines} ) ) { - # --line=1 --line=5 is equivalent to --line=1,5 - my @lines = split( /,/, join( ',', @{$l} ) ); - - # --line=1-3 is equivalent to --line=1,2,3 - @lines = map { - my @ret; - if ( /-/ ) { - my ($from, $to) = split /-/, $_; - if ( $from > $to ) { - App::Ack::warn( "ignoring --line=$from-$to" ); - @ret = (); - } - else { - @ret = ( $from .. $to ); - } - } - else { - @ret = ( $_ ); - }; - @ret - } @lines; - - if ( @lines ) { - my %uniq; - @uniq{ @lines } = (); - $opt{lines} = [ sort { $a <=> $b } keys %uniq ]; # numerical sort and each line occurs only once! - } - else { - # happens if there are only ignored --line directives - App::Ack::die( 'All --line options are invalid.' ); - } - } - - return \%opt; -} - - -sub def_types_from_ARGV { - my @typedef; - - my $parser = Getopt::Long::Parser->new(); - # pass_through => leave unrecognized command line arguments alone - # no_auto_abbrev => otherwise -c is expanded and not left alone - $parser->configure( 'no_ignore_case', 'pass_through', 'no_auto_abbrev' ); - $parser->getoptions( - 'type-set=s' => sub { shift; push @typedef, ['c', shift] }, - 'type-add=s' => sub { shift; push @typedef, ['a', shift] }, - ) or App::Ack::die( 'See ack --help or ack --man for options.' ); - - for my $td (@typedef) { - my ($type, $ext) = split /=/, $td->[1]; - - if ( $td->[0] eq 'c' ) { - # type-set - if ( exists $mappings{$type} ) { - # can't redefine types 'make', 'skipped', 'text' and 'binary' - App::Ack::die( qq{--type-set: Builtin type "$type" cannot be changed.} ) - if ref $mappings{$type} ne 'ARRAY'; - - delete_type($type); - } - } - else { - # type-add - - # can't append to types 'make', 'skipped', 'text' and 'binary' - App::Ack::die( qq{--type-add: Builtin type "$type" cannot be changed.} ) - if exists $mappings{$type} && ref $mappings{$type} ne 'ARRAY'; - - App::Ack::warn( qq{--type-add: Type "$type" does not exist, creating with "$ext" ...} ) - unless exists $mappings{$type}; - } - - my @exts = split /,/, $ext; - s/^\.// for @exts; - - if ( !exists $mappings{$type} || ref($mappings{$type}) eq 'ARRAY' ) { - push @{$mappings{$type}}, @exts; - for my $e ( @exts ) { - push @{$types{$e}}, $type; - } - } - else { - App::Ack::die( qq{Cannot append to type "$type".} ); - } - } - - return; -} - - -sub delete_type { - my $type = shift; - - App::Ack::die( qq{Internal error: Cannot delete builtin type "$type".} ) - unless ref $mappings{$type} eq 'ARRAY'; - - delete $mappings{$type}; - delete $type_wanted{$type}; - for my $ext ( keys %types ) { - $types{$ext} = [ grep { $_ ne $type } @{$types{$ext}} ]; - } -} - - -sub ignoredir_filter { - return !exists $ignore_dirs{$_} && !exists $ignore_dirs{$File::Next::dir}; -} - - -sub remove_dir_sep { - my $path = shift; - $path =~ s/[$dir_sep_chars]$//; - - return $path; -} - - -use constant TEXT => 'text'; - -sub filetypes { - my $filename = shift; - - my $basename = $filename; - $basename =~ s{.*[$dir_sep_chars]}{}; - - return 'skipped' unless is_searchable( $basename ); - - my $lc_basename = lc $basename; - 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 - if ( $filename =~ m{\.([^\.$dir_sep_chars]+)$}o ) { - my $ref = $types{lc $1}; - return (@{$ref},TEXT) if $ref; - } - - # At this point, we can't tell from just the name. Now we have to - # open it and look inside. - - return unless -e $filename; - # From Elliot Shank: - # I can't see any reason that -r would fail on these-- the ACLs look - # fine, and no program has any of them open, so the busted Windows - # file locking model isn't getting in there. If I comment the if - # statement out, everything works fine - # So, for cygwin, don't bother trying to check for readability. - if ( !$is_cygwin ) { - if ( !-r $filename ) { - App::Ack::warn( "$filename: Permission denied" ); - return; - } - } - - return 'binary' if -B $filename; - - # If there's no extension, or we don't recognize it, check the shebang line - my $fh; - if ( !open( $fh, '<', $filename ) ) { - App::Ack::warn( "$filename: $!" ); - return; - } - my $header = <$fh>; - close $fh; - - if ( $header =~ /^#!/ ) { - return ($1,TEXT) if $header =~ /\b(ruby|lua|p(?:erl|hp|ython))-?(\d[\d.]*)?\b/; - return ('shell',TEXT) if $header =~ /\b(?:ba|t?c|k|z)?sh\b/; - } - else { - return ('xml',TEXT) if $header =~ /\Q{Q}; - if ( $opt->{w} ) { - $str = "\\b$str" if $str =~ /^\w/; - $str = "$str\\b" if $str =~ /\w$/; - } - - my $regex_is_lc = $str eq lc $str; - if ( $opt->{i} || ($opt->{smart_case} && $regex_is_lc) ) { - $str = "(?i)$str"; - } - - return $str; -} - - -sub check_regex { - my $regex = shift; - - return unless defined $regex; - - eval { qr/$regex/ }; - if ($@) { - (my $error = $@) =~ s/ at \S+ line \d+.*//; - chomp($error); - App::Ack::die( "Invalid regex '$regex':\n $error" ); - } - - return; -} - - - - -sub warn { - return CORE::warn( _my_program(), ': ', @_, "\n" ); -} - - -sub die { - return CORE::die( _my_program(), ': ', @_, "\n" ); -} - -sub _my_program { - require File::Basename; - return File::Basename::basename( $0 ); -} - - - -sub filetypes_supported { - return keys %mappings; -} - -sub _get_thpppt { - my $y = q{_ /|,\\'!.x',=(www)=, U }; - $y =~ tr/,x!w/\nOo_/; - return $y; -} - -sub _thpppt { - my $y = _get_thpppt(); - App::Ack::print( "$y ack $_[0]!\n" ); - exit 0; -} - -sub _key { - my $str = lc shift; - $str =~ s/[^a-z]//g; - - return $str; -} - - -sub show_help { - my $help_arg = shift || 0; - - return show_help_types() if $help_arg =~ /^types?/; - - my $ignore_dirs = _listify( sort { _key($a) cmp _key($b) } keys %ignore_dirs ); - - App::Ack::print( <<"END_OF_HELP" ); -Usage: ack [OPTION]... PATTERN [FILE] - -Search for PATTERN in each source file in the tree from cwd on down. -If [FILES] is specified, then only those files/directories are checked. -ack may also search STDIN, but only if no FILE are specified, or if -one of FILES is "-". - -Default switches may be specified in ACK_OPTIONS environment variable or -an .ackrc file. If you want no dependency on the environment, turn it -off with --noenv. - -Example: ack -i select - -Searching: - -i, --ignore-case Ignore case distinctions in PATTERN - --[no]smart-case Ignore case distinctions in PATTERN, - only if PATTERN contains no upper case - Ignored if -i is specified - -v, --invert-match Invert match: select non-matching lines - -w, --word-regexp Force PATTERN to match only whole words - -Q, --literal Quote all metacharacters; PATTERN is literal - -Search output: - --line=NUM Only print line(s) NUM of each file - -l, --files-with-matches - Only print filenames containing matches - -L, --files-without-matches - Only print filenames with no matches - -o Show only the part of a line matching PATTERN - (turns off text highlighting) - --passthru Print all lines, whether matching or not - --output=expr Output the evaluation of expr for each line - (turns off text highlighting) - --match PATTERN Specify PATTERN explicitly. - -m, --max-count=NUM Stop searching in each file after NUM matches - -1 Stop searching after one match of any kind - -H, --with-filename Print the filename for each match - -h, --no-filename Suppress the prefixing filename on output - -c, --count Show number of lines matching per file - --column Show the column number of the first match - - -A NUM, --after-context=NUM - Print NUM lines of trailing context after matching - lines. - -B NUM, --before-context=NUM - Print NUM lines of leading context before matching - lines. - -C [NUM], --context[=NUM] - Print NUM lines (default 2) of output context. - - --print0 Print null byte as separator between filenames, - only works with -f, -g, -l, -L or -c. - -File presentation: - --pager=COMMAND Pipes all ack output through COMMAND. For example, - --pager="less -R". Ignored if output is redirected. - --nopager Do not send output through a pager. Cancels any - setting in ~/.ackrc, ACK_PAGER or ACK_PAGER_COLOR. - --[no]heading Print a filename heading above each file's results. - (default: on when used interactively) - --[no]break Print a break between results from different files. - (default: on when used interactively) - --group Same as --heading --break - --nogroup Same as --noheading --nobreak - --[no]color Highlight the matching text (default: on unless - output is redirected, or on Windows) - --[no]colour Same as --[no]color - --color-filename=COLOR - --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). - -File finding: - -f Only print the files found, without searching. - 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; - Ignores CVS, .svn and other ignored directories - -u, --unrestricted All files and directories searched - --[no]ignore-dir=name Add/Remove directory from the list of ignored dirs - -r, -R, --recurse Recurse into subdirectories (ack's default behavior) - -n, --no-recurse No descending into subdirectories - -G REGEX Only search files that match REGEX - - --perl Include only Perl files. - --type=perl Include only Perl files. - --noperl Exclude Perl files. - --type=noperl Exclude Perl files. - See "ack --help type" for supported filetypes. - - --type-set TYPE=.EXTENSION[,.EXT2[,...]] - Files with the given EXTENSION(s) are recognized as - being of type TYPE. This replaces an existing - definition for type TYPE. - --type-add TYPE=.EXTENSION[,.EXT2[,...]] - Files with the given EXTENSION(s) are recognized as - being of (the existing) type TYPE - - --[no]follow Follow symlinks. Default is off. - - Directories ignored by default: - $ignore_dirs - - Files not checked for type: - /~\$/ - Unix backup files - /#.+#\$/ - Emacs swap files - /[._].*\\.swp\$/ - Vi(m) swap files - /core\\.\\d+\$/ - core dumps - /[.-]min\\.js\$/ - Minified javascript files - -Miscellaneous: - --noenv Ignore environment variables and ~/.ackrc - --help This help - --man Man page - --version Display version & copyright - --thpppt Bill the Cat - -Exit status is 0 if match, 1 if no match. - -This is version $VERSION of ack. -END_OF_HELP - - return; - } - - - -sub show_help_types { - App::Ack::print( <<'END_OF_HELP' ); -Usage: ack [OPTION]... PATTERN [FILES] - -The following is the list of filetypes supported by ack. You can -specify a file type with the --type=TYPE format, or the --TYPE -format. For example, both --type=perl and --perl work. - -Note that some extensions may appear in multiple types. For example, -.pod files are both Perl and Parrot. - -END_OF_HELP - - my @types = filetypes_supported(); - my $maxlen = 0; - for ( @types ) { - $maxlen = length if $maxlen < length; - } - for my $type ( sort @types ) { - next if $type =~ /^-/; # Stuff to not show - my $ext_list = $mappings{$type}; - - if ( ref $ext_list ) { - $ext_list = join( ' ', map { ".$_" } @{$ext_list} ); - } - App::Ack::print( sprintf( " --[no]%-*.*s %s\n", $maxlen, $maxlen, $type, $ext_list ) ); - } - - return; -} - -sub _listify { - my @whats = @_; - - return '' if !@whats; - - my $end = pop @whats; - my $str = @whats ? join( ', ', @whats ) . " and $end" : $end; - - no warnings 'once'; - require Text::Wrap; - $Text::Wrap::columns = 75; - return Text::Wrap::wrap( '', ' ', $str ); -} - - -sub get_version_statement { - require Config; - - my $copyright = get_copyright(); - my $this_perl = $Config::Config{perlpath}; - if ($^O ne 'VMS') { - my $ext = $Config::Config{_exe}; - $this_perl .= $ext unless $this_perl =~ m/$ext$/i; - } - my $ver = sprintf( '%vd', $^V ); - - return <<"END_OF_VERSION"; -ack $VERSION -Running under Perl $ver at $this_perl - -$copyright - -This program is free software. You may modify or distribute it -under the terms of the Artistic License v2.0. -END_OF_VERSION -} - - -sub print_version_statement { - App::Ack::print( get_version_statement() ); - - return; -} - - -sub get_copyright { - return $COPYRIGHT; -} - - -sub load_colors { - eval 'use Term::ANSIColor ()'; - - $ENV{ACK_COLOR_MATCH} ||= 'black on_yellow'; - $ENV{ACK_COLOR_FILENAME} ||= 'bold green'; - $ENV{ACK_COLOR_LINENO} ||= 'bold yellow'; - - return; -} - - -sub is_interesting { - return if /^\./; - - my $include; - - for my $type ( filetypes( $File::Next::name ) ) { - if ( defined $type_wanted{$type} ) { - if ( $type_wanted{$type} ) { - $include = 1; - } - else { - return; - } - } - } - - return $include; -} - - - -# print subs added in order to make it easy for a third party -# module (such as App::Wack) to redefine the display methods -# and show the results in a different way. -sub print { print {$fh} @_ } -sub print_first_filename { App::Ack::print( $_[0], "\n" ) } -sub print_blank_line { App::Ack::print( "\n" ) } -sub print_separator { App::Ack::print( "--\n" ) } -sub print_filename { App::Ack::print( $_[0], $_[1] ) } -sub print_line_no { App::Ack::print( $_[0], $_[1] ) } -sub print_column_no { App::Ack::print( $_[0], $_[1] ) } -sub print_count { - my $filename = shift; - 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 ); - } -} - - - -{ - my $filename; - my $regex; - my $display_filename; - - my $keep_context; - - my $last_output_line; # number of the last line that has been output - my $any_output; # has there been any output for the current file yet - my $context_overall_output_count; # has there been any output at all - -sub search_resource { - my $res = shift; - my $opt = shift; - - $filename = $res->name(); - - my $v = $opt->{v}; - my $passthru = $opt->{passthru}; - my $max = $opt->{m}; - my $nmatches = 0; - - $display_filename = undef; - - # for --line processing - my $has_lines = 0; - my @lines; - if ( defined $opt->{lines} ) { - $has_lines = 1; - @lines = ( @{$opt->{lines}}, -1 ); - undef $regex; # Don't match when printing matching line - } - else { - $regex = qr/$opt->{regex}/; - } - - # for context processing - $last_output_line = -1; - $any_output = 0; - my $before_context = $opt->{before_context}; - my $after_context = $opt->{after_context}; - - $keep_context = ($before_context || $after_context) && !$passthru; - - my @before; - my $before_starts_at_line; - my $after = 0; # number of lines still to print after a match - - while ( $res->next_text ) { - # XXX Optimize away the case when there are no more @lines to find. - # XXX $has_lines, $passthru and $v never change. Optimize. - if ( $has_lines - ? $. != $lines[0] # $lines[0] should be a scalar - : $v ? m/$regex/ : !m/$regex/ ) { - if ( $passthru ) { - App::Ack::print( $_ ); - next; - } - - if ( $keep_context ) { - if ( $after ) { - print_match_or_context( $opt, 0, $., $-[0], $+[0], $_ ); - $after--; - } - elsif ( $before_context ) { - if ( @before ) { - if ( @before >= $before_context ) { - shift @before; - ++$before_starts_at_line; - } - } - else { - $before_starts_at_line = $.; - } - push @before, $_; - } - last if $max && ( $nmatches >= $max ) && !$after; - } - next; - } # not a match - - ++$nmatches; - - # print an empty line as a divider before first line in each file (not before the first file) - if ( !$any_output && $opt->{show_filename} && $opt->{break} && defined( $context_overall_output_count ) ) { - App::Ack::print_blank_line(); - } - - shift @lines if $has_lines; - - if ( $res->is_binary ) { - App::Ack::print( "Binary file $filename matches\n" ); - last; - } - if ( $keep_context ) { - if ( @before ) { - print_match_or_context( $opt, 0, $before_starts_at_line, $-[0], $+[0], @before ); - @before = (); - $before_starts_at_line = 0; - } - if ( $max && $nmatches > $max ) { - --$after; - } - else { - $after = $after_context; - } - } - print_match_or_context( $opt, 1, $., $-[0], $+[0], $_ ); - - last if $max && ( $nmatches >= $max ) && !$after; - } # while - - return $nmatches; -} # search_resource() - - - -sub print_match_or_context { - my $opt = shift; # opts array - my $is_match = shift; # is there a match on the line? - my $line_no = shift; - my $match_start = shift; - my $match_end = shift; - - my $color = $opt->{color}; - my $heading = $opt->{heading}; - my $show_filename = $opt->{show_filename}; - my $show_column = $opt->{column}; - - if ( $show_filename ) { - if ( not defined $display_filename ) { - $display_filename = - $color - ? Term::ANSIColor::colored( $filename, $ENV{ACK_COLOR_FILENAME} ) - : $filename; - if ( $heading && !$any_output ) { - App::Ack::print_first_filename($display_filename); - } - } - } - - # Modified for Atom by Nathan Sobo to print a "\0" instead of a ":" as a separator - my $sep = $is_match ? "\0" : '-'; - my $output_func = $opt->{output}; - for ( @_ ) { - if ( $keep_context && !$output_func ) { - if ( ( $last_output_line != $line_no - 1 ) && - ( $any_output || ( !$heading && defined( $context_overall_output_count ) ) ) ) { - App::Ack::print_separator(); - } - # to ensure separators between different files when --noheading - - $last_output_line = $line_no; - } - - if ( $show_filename ) { - App::Ack::print_filename($display_filename, $sep) if not $heading; - 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 ( $output_func ) { - while ( /$regex/go ) { - App::Ack::print( $output_func->() . "\n" ); - } - } - else { - if ( $color && $is_match && $regex && - s/$regex/Term::ANSIColor::colored( substr($_, $-[0], $+[0] - $-[0]), $ENV{ACK_COLOR_MATCH} )/eg ) { - # At the end of the line reset the color and remove newline - s/[\r\n]*\z/\e[0m\e[K/; - } - else { - # remove any kind of newline at the end of the line - s/[\r\n]*\z//; - } - if ( $show_column ) { - App::Ack::print_column_no( $match_start+1, $sep ); - } - App::Ack::print($_ . "\n"); - } - $any_output = 1; - ++$context_overall_output_count; - ++$line_no; - } - - return; -} # 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; - my $opt = shift; - - 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}/; - - if ( $opt->{v} ) { - while ( $res->next_text ) { - if ( /$regex/ ) { - return 0 unless $count; - } - else { - ++$nmatches; - } - } - } - else { - while ( $res->next_text ) { - if ( /$regex/ ) { - ++$nmatches; - last unless $count; - } - } - } - - if ( $opt->{show_total} ) { - $total_count += $nmatches; - } - else { - if ( $nmatches ) { - App::Ack::print_count( $res->name, $nmatches, $ors, $count, $show_filename ); - } - elsif ( $count && !$opt->{l} ) { - App::Ack::print_count0( $res->name, $ors, $show_filename ); - } - } - - return $nmatches ? 1 : 0; -} # search_and_list() - -} # scope around $total_count - - - -sub filetypes_supported_set { - return grep { defined $type_wanted{$_} && ($type_wanted{$_} == 1) } filetypes_supported(); -} - - - -sub print_files { - my $iter = shift; - my $opt = shift; - - my $ors = $opt->{print0} ? "\0" : "\n"; - - my $nmatches = 0; - while ( defined ( my $file = $iter->() ) ) { - App::Ack::print $file, $opt->{show_types} ? " => " . join( ',', filetypes( $file ) ) : (), $ors; - $nmatches++; - last if $opt->{1}; - } - - return $nmatches; -} - - -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 ); - my $res; - while ( $res = $repo->next_resource() ) { - $nmatches += search_and_list( $res, $opt ); - $res->close(); - last if $nmatches && $opt->{1}; - } - $repo->close(); - } - - if ( $nmatches && $opt->{show_total} ) { - App::Ack::print_count('', get_total_count(), "\n", 1, 0 ) - } - - return $nmatches; -} - - -sub print_matches { - my $iter = shift; - my $opt = shift; - - $opt->{show_filename} = 0 if $opt->{h}; - $opt->{show_filename} = 1 if $opt->{H}; - - my $nmatches = 0; - while ( defined ( my $filename = $iter->() ) ) { - my $repo; - my $tarballs_work = 0; - if ( $tarballs_work && $filename =~ /\.tar\.gz$/ ) { - App::Ack::die( 'Not working here yet' ); - require App::Ack::Repository::Tar; # XXX Error checking - $repo = App::Ack::Repository::Tar->new( $filename ); - } - else { - $repo = App::Ack::Repository::Basic->new( $filename ); - } - $repo or next; - - while ( my $res = $repo->next_resource() ) { - my $needs_line_scan; - if ( $opt->{regex} && !$opt->{passthru} ) { - $needs_line_scan = $res->needs_line_scan( $opt ); - if ( $needs_line_scan ) { - $res->reset(); - } - } - else { - $needs_line_scan = 1; - } - if ( $needs_line_scan ) { - $nmatches += search_resource( $res, $opt ); - } - $res->close(); - } - last if $nmatches && $opt->{1}; - $repo->close(); - } - return $nmatches; -} - - -sub filetype_setup { - my $filetypes_supported_set = filetypes_supported_set(); - # If anyone says --no-whatever, we assume all other types must be on. - if ( !$filetypes_supported_set ) { - for my $i ( keys %type_wanted ) { - $type_wanted{$i} = 1 unless ( defined( $type_wanted{$i} ) || $i eq 'binary' || $i eq 'text' || $i eq 'skipped' ); - } - } - return; -} - - -EXPAND_FILENAMES_SCOPE: { - my $filter; - - sub expand_filenames { - my $argv = shift; - - my $attr; - my @files; - - foreach my $pattern ( @{$argv} ) { - my @results = bsd_glob( $pattern ); - - if (@results == 0) { - @results = $pattern; # Glob didn't match, pass it thru unchanged - } - elsif ( (@results > 1) or ($results[0] ne $pattern) ) { - if (not defined $filter) { - eval 'require Win32::File;'; - if ($@) { - $filter = 0; - } - else { - $filter = Win32::File::HIDDEN()|Win32::File::SYSTEM(); - } - } # end unless we've tried to load Win32::File - if ( $filter ) { - # Filter out hidden and system files: - @results = grep { not(Win32::File::GetAttributes($_, $attr) and $attr & $filter) } @results; - App::Ack::warn( "$pattern: Matched only hidden files" ) unless @results; - } # end if we can filter by file attributes - } # end elsif this pattern got expanded - - push @files, @results; - } # end foreach pattern - - return \@files; - } # end expand_filenames -} # EXPAND_FILENAMES_SCOPE - - - -sub get_starting_points { - my $argv = shift; - my $opt = shift; - - my @what; - - if ( @{$argv} ) { - @what = @{ $is_windows ? expand_filenames($argv) : $argv }; - $_ = File::Next::reslash( $_ ) for @what; - - # Show filenames unless we've specified one single file - $opt->{show_filename} = (@what > 1) || (!-f $what[0]); - } - else { - @what = '.'; # Assume current directory - $opt->{show_filename} = 1; - } - - for my $start_point (@what) { - App::Ack::warn( "$start_point: No such file or directory" ) unless -e $start_point; - } - return \@what; -} - -sub _match { - my ( $target, $expression, $invert_flag ) = @_; - - if ( $invert_flag ) { - return $target !~ $expression; - } - else { - return $target =~ $expression; - } -} - - -sub get_iterator { - my $what = shift; - my $opt = shift; - - # Starting points are always searched, no matter what - my %starting_point = map { ($_ => 1) } @{$what}; - - my $g_regex = defined $opt->{G} ? qr/$opt->{G}/ : undef; - my $file_filter; - - if ( $g_regex ) { - $file_filter - = $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 { - $file_filter - = $opt->{u} ? sub {1} - : $opt->{all} ? sub { $starting_point{ $File::Next::name } || is_searchable( $_ ) } - : sub { $starting_point{ $File::Next::name } || is_interesting( @_ ) } - ; - } - - my $descend_filter - = $opt->{n} ? sub {0} - : $opt->{u} ? sub {1} - : \&ignoredir_filter; - - my $iter = - File::Next::files( { - file_filter => $file_filter, - descend_filter => $descend_filter, - error_handler => sub { my $msg = shift; App::Ack::warn( $msg ) }, - sort_files => $opt->{sort_files}, - follow_symlinks => $opt->{follow}, - }, @{$what} ); - return $iter; -} - - -sub set_up_pager { - my $command = shift; - - return if App::Ack::output_to_pipe(); - - my $pager; - if ( not open( $pager, '|-', $command ) ) { - App::Ack::die( qq{Unable to pipe to pager "$command": $!} ); - } - $fh = $pager; - - return; -} - - -sub input_from_pipe { - return $input_from_pipe; -} - - - -sub output_to_pipe { - return $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; - - -use warnings; -use strict; - -sub FAIL { - require Carp; - Carp::confess( 'Must be overloaded' ); -} - - -sub new { - FAIL(); -} - - -sub next_resource { - FAIL(); -} - - -sub close { - FAIL(); -} - -1; -package App::Ack::Resource; - - -use warnings; -use strict; - -sub FAIL { - require Carp; - Carp::confess( 'Must be overloaded' ); -} - - -sub new { - FAIL(); -} - - -sub name { - FAIL(); -} - - -sub is_binary { - FAIL(); -} - - - -sub needs_line_scan { - FAIL(); -} - - -sub reset { - FAIL(); -} - - -sub next_text { - FAIL(); -} - - -sub close { - FAIL(); -} - -1; -package App::Ack::Plugin::Basic; - - - -package App::Ack::Resource::Basic; - - -use warnings; -use strict; - - -our @ISA = qw( App::Ack::Resource ); - - -sub new { - my $class = shift; - my $filename = shift; - - my $self = bless { - filename => $filename, - fh => undef, - could_be_binary => undef, - opened => undef, - id => undef, - }, $class; - - if ( $self->{filename} eq '-' ) { - $self->{fh} = *STDIN; - $self->{could_be_binary} = 0; - } - else { - if ( !open( $self->{fh}, '<', $self->{filename} ) ) { - App::Ack::warn( "$self->{filename}: $!" ); - return; - } - $self->{could_be_binary} = 1; - } - - return $self; -} - - -sub name { - my $self = shift; - - return $self->{filename}; -} - - -sub is_binary { - my $self = shift; - - if ( $self->{could_be_binary} ) { - return -B $self->{filename}; - } - - return 0; -} - - - -sub needs_line_scan { - my $self = shift; - my $opt = shift; - - return 1 if $opt->{v}; - - my $size = -s $self->{fh}; - if ( $size == 0 ) { - return 0; - } - elsif ( $size > 100_000 ) { - return 1; - } - - my $buffer; - my $rc = sysread( $self->{fh}, $buffer, $size ); - if ( not defined $rc ) { - App::Ack::warn( "$self->{filename}: $!" ); - return 1; - } - return 0 unless $rc && ( $rc == $size ); - - my $regex = $opt->{regex}; - return $buffer =~ /$regex/m; -} - - -sub reset { - my $self = shift; - - seek( $self->{fh}, 0, 0 ) - or App::Ack::warn( "$self->{filename}: $!" ); - - return; -} - - -sub next_text { - if ( defined ($_ = readline $_[0]->{fh}) ) { - $. = ++$_[0]->{line}; - return 1; - } - - return; -} - - -sub close { - my $self = shift; - - if ( not close $self->{fh} ) { - App::Ack::warn( $self->name() . ": $!" ); - } - - return; -} - -package App::Ack::Repository::Basic; - - -our @ISA = qw( App::Ack::Repository ); - - -use warnings; -use strict; - -sub new { - my $class = shift; - my $filename = shift; - - my $self = bless { - filename => $filename, - nexted => 0, - }, $class; - - return $self; -} - - -sub next_resource { - my $self = shift; - - return if $self->{nexted}; - $self->{nexted} = 1; - - return App::Ack::Resource::Basic->new( $self->{filename} ); -} - - -sub close { -} - - - -1; diff --git a/vendor/ag b/vendor/ag deleted file mode 100755 index 63e16c228b9f49ca1257e9b516c651a187356e16..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 226672 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

JEt#ZZM?@a_}J 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 Y*i^38YG6%JX~kD(BrHtAM;Jo Date: Wed, 27 Mar 2013 01:06:34 -0700 Subject: [PATCH 03/54] Start figuring out where the pieces go --- src/app/project.coffee | 1 + .../command-panel/lib/command-panel-view.coffee | 11 +++++------ .../commands/select-all-matches-in-project.coffee | 12 ++++++++---- src/packages/command-panel/lib/preview-list.coffee | 3 ++- .../fuzzy-finder/lib/fuzzy-finder-view.coffee | 1 + 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/app/project.coffee b/src/app/project.coffee index a3da8a483..a70c548ff 100644 --- a/src/app/project.coffee +++ b/src/app/project.coffee @@ -177,6 +177,7 @@ class Project for [column, length] in matchPositions range = new Range([row, column], [row, column + length]) match = lineText.substr(column, length) + console.log(path) iterator({path, range, match}) deferred = $.Deferred() diff --git a/src/packages/command-panel/lib/command-panel-view.coffee b/src/packages/command-panel/lib/command-panel-view.coffee index ff574caa6..980df48a5 100644 --- a/src/packages/command-panel/lib/command-panel-view.coffee +++ b/src/packages/command-panel/lib/command-panel-view.coffee @@ -11,8 +11,8 @@ module.exports = class CommandPanelView extends View @content: -> @div class: 'command-panel tool-panel', => - @div class: 'loading is-loading', outlet: 'loadingMessage', 'Searching...' @div class: 'header', outlet: 'previewHeader', => + @span outlet: 'searchLoadingMessage', class: 'loading', 'Searching...' @ul outlet: 'expandCollapse', class: 'expand-collapse', => @li class: 'expand', 'Expand All' @li class: 'collapse', 'Collapse All' @@ -53,7 +53,7 @@ class CommandPanelView extends View @previewList.hide() @previewHeader.hide() @errorMessages.hide() - @loadingMessage.hide() + @searchLoadingMessage.hide() @prompt.iconSize(@miniEditor.getFontSize()) @history = state.history ? [] @@ -116,12 +116,13 @@ class CommandPanelView extends View @miniEditor.getText() execute: (command=@escapedCommand()) -> - @loadingMessage.show() + @previewHeader.show() + @searchLoadingMessage.show() @errorMessages.empty() try @commandInterpreter.eval(command, rootView.getActivePaneItem()).done ({operationsToPreview, errorMessages}) => - @loadingMessage.hide() + @searchLoadingMessage.hide() @history.push(command) @historyIndex = @history.length @@ -131,8 +132,6 @@ class CommandPanelView extends View @errorMessages.append $$ -> @li errorMessage for errorMessage in errorMessages else if operationsToPreview?.length - @previewHeader.show() - @previewList.populate(operationsToPreview) @previewList.focus() @previewCount.text("#{_.pluralize(operationsToPreview.length, 'match', 'matches')} in #{_.pluralize(@previewList.getPathCount(), 'file')}").show() else diff --git a/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee b/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee index 619378ed3..0bb1480b0 100644 --- a/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee +++ b/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee @@ -8,17 +8,21 @@ class SelectAllMatchesInProject extends Command previewOperations: true constructor: (pattern) -> - @regex = new RegExp(pattern, 'g') + debugger; + @regex = new RegExp(pattern) compile: (project, buffer, range) -> deferred = $.Deferred() operations = [] promise = project.scan @regex, ({path, range}) -> - operations.push(new Operation( + debugger; + op = new Operation( project: project path: path bufferRange: range - )) + ) + deferred.resolve([op]) + operations.push(op) - promise.done -> deferred.resolve(operations) + promise.done# -> deferred.resolve(operations) deferred.promise() diff --git a/src/packages/command-panel/lib/preview-list.coffee b/src/packages/command-panel/lib/preview-list.coffee index 7f70db89d..28169abe6 100644 --- a/src/packages/command-panel/lib/preview-list.coffee +++ b/src/packages/command-panel/lib/preview-list.coffee @@ -39,7 +39,8 @@ class PreviewList extends ScrollView hasOperations: -> @operations? populate: (operations) -> - @destroyOperations() if @operations + debugger; + #@destroyOperations() if @operations @operations = operations @lastRenderedOperationIndex = 0 @empty() diff --git a/src/packages/fuzzy-finder/lib/fuzzy-finder-view.coffee b/src/packages/fuzzy-finder/lib/fuzzy-finder-view.coffee index 538988957..0748ac8d2 100644 --- a/src/packages/fuzzy-finder/lib/fuzzy-finder-view.coffee +++ b/src/packages/fuzzy-finder/lib/fuzzy-finder-view.coffee @@ -147,6 +147,7 @@ class FuzzyFinderView extends SelectList path.indexOf(options.filter) >= 0 else @projectPaths + console.log listedItems @setArray(listedItems) options.done(listedItems) if options.done? else From 416f654d2c16c936e8b44014052670409aa6460c Mon Sep 17 00:00:00 2001 From: Garen Torikian Date: Wed, 27 Mar 2013 15:19:35 -0700 Subject: [PATCH 04/54] Restore operations pushing --- .../lib/commands/select-all-matches-in-project.coffee | 10 +++------- src/packages/command-panel/lib/preview-list.coffee | 2 +- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee b/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee index 0bb1480b0..c9255a4fc 100644 --- a/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee +++ b/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee @@ -8,21 +8,17 @@ class SelectAllMatchesInProject extends Command previewOperations: true constructor: (pattern) -> - debugger; @regex = new RegExp(pattern) compile: (project, buffer, range) -> deferred = $.Deferred() operations = [] promise = project.scan @regex, ({path, range}) -> - debugger; - op = new Operation( + operations.push(new Operation( project: project path: path bufferRange: range - ) - deferred.resolve([op]) - operations.push(op) + )) - promise.done# -> deferred.resolve(operations) + promise.done -> deferred.resolve(operations) deferred.promise() diff --git a/src/packages/command-panel/lib/preview-list.coffee b/src/packages/command-panel/lib/preview-list.coffee index 28169abe6..0f7bea1d3 100644 --- a/src/packages/command-panel/lib/preview-list.coffee +++ b/src/packages/command-panel/lib/preview-list.coffee @@ -40,7 +40,7 @@ class PreviewList extends ScrollView populate: (operations) -> debugger; - #@destroyOperations() if @operations + @destroyOperations() if @operations @operations = operations @lastRenderedOperationIndex = 0 @empty() From 6a08827830fd2fbc4f050048efe5df0d0e7de0e1 Mon Sep 17 00:00:00 2001 From: Garen Torikian Date: Wed, 27 Mar 2013 16:18:25 -0700 Subject: [PATCH 05/54] Properly append and count matches --- src/app/project.coffee | 1 - .../lib/command-panel-view.coffee | 3 ++- .../select-all-matches-in-project.coffee | 6 ++++-- .../command-panel/lib/preview-list.coffee | 20 ++++++++++++++++--- 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/app/project.coffee b/src/app/project.coffee index a70c548ff..a3da8a483 100644 --- a/src/app/project.coffee +++ b/src/app/project.coffee @@ -177,7 +177,6 @@ class Project for [column, length] in matchPositions range = new Range([row, column], [row, column + length]) match = lineText.substr(column, length) - console.log(path) iterator({path, range, match}) deferred = $.Deferred() diff --git a/src/packages/command-panel/lib/command-panel-view.coffee b/src/packages/command-panel/lib/command-panel-view.coffee index 980df48a5..bd72f93ee 100644 --- a/src/packages/command-panel/lib/command-panel-view.coffee +++ b/src/packages/command-panel/lib/command-panel-view.coffee @@ -119,6 +119,7 @@ class CommandPanelView extends View @previewHeader.show() @searchLoadingMessage.show() @errorMessages.empty() + project.previewList = @previewList try @commandInterpreter.eval(command, rootView.getActivePaneItem()).done ({operationsToPreview, errorMessages}) => @@ -133,7 +134,7 @@ class CommandPanelView extends View @li errorMessage for errorMessage in errorMessages else if operationsToPreview?.length @previewList.focus() - @previewCount.text("#{_.pluralize(operationsToPreview.length, 'match', 'matches')} in #{_.pluralize(@previewList.getPathCount(), 'file')}").show() + @previewCount.text("#{_.pluralize(operationsToPreview.length, 'match', 'matches')} in #{_.pluralize(@previewList.getPathCount(operationsToPreview), 'file')}").show() else @detach() catch error diff --git a/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee b/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee index c9255a4fc..155d792cf 100644 --- a/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee +++ b/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee @@ -14,11 +14,13 @@ class SelectAllMatchesInProject extends Command deferred = $.Deferred() operations = [] promise = project.scan @regex, ({path, range}) -> - operations.push(new Operation( + op = new Operation( project: project path: path bufferRange: range - )) + ) + project.previewList.populateSingle(op) + operations.push(op) promise.done -> deferred.resolve(operations) deferred.promise() diff --git a/src/packages/command-panel/lib/preview-list.coffee b/src/packages/command-panel/lib/preview-list.coffee index 0f7bea1d3..8569868fd 100644 --- a/src/packages/command-panel/lib/preview-list.coffee +++ b/src/packages/command-panel/lib/preview-list.coffee @@ -39,7 +39,6 @@ class PreviewList extends ScrollView hasOperations: -> @operations? populate: (operations) -> - debugger; @destroyOperations() if @operations @operations = operations @lastRenderedOperationIndex = 0 @@ -51,6 +50,14 @@ class PreviewList extends ScrollView @find('.operation:first').addClass('selected') + populateSingle: (operation) -> + @viewsForPath = {} + + @show() + @renderOperation(operation) + + @find('.operation:first').addClass('selected') + renderOperations: ({renderAll}={}) -> renderAll ?= false startingScrollHeight = @prop('scrollHeight') @@ -60,6 +67,13 @@ class PreviewList extends ScrollView @lastRenderedOperationIndex++ break if not renderAll and @prop('scrollHeight') >= startingScrollHeight + @pixelOverdraw and @prop('scrollHeight') > @height() + @pixelOverdraw + renderOperation: (operation, {renderAll}={}) -> + renderAll ?= false + startingScrollHeight = @prop('scrollHeight') + pathView = @pathViewForPath(operation.getPath()) + pathView.addOperation(operation) + + pathViewForPath: (path) -> pathView = @viewsForPath[path] if not pathView @@ -97,8 +111,8 @@ class PreviewList extends ScrollView previousView.addClass('selected') previousView.scrollTo() - getPathCount: -> - _.keys(_.groupBy(@operations, (operation) -> operation.getPath())).length + getPathCount: (operations=@operations)-> + _.keys(_.groupBy(operations, (operation) -> operation.getPath())).length getOperations: -> new Array(@operations...) From a585df6d2c09c7668d64ba89016443a9aadd3079 Mon Sep 17 00:00:00 2001 From: Garen Torikian Date: Wed, 27 Mar 2013 16:45:11 -0700 Subject: [PATCH 06/54] Use nak for fuzzyfinder, too --- .../fuzzy-finder/lib/fuzzy-finder-view.coffee | 2 +- .../fuzzy-finder/lib/load-paths-task.coffee | 36 ++++++++++--------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/packages/fuzzy-finder/lib/fuzzy-finder-view.coffee b/src/packages/fuzzy-finder/lib/fuzzy-finder-view.coffee index 0748ac8d2..330e50fb3 100644 --- a/src/packages/fuzzy-finder/lib/fuzzy-finder-view.coffee +++ b/src/packages/fuzzy-finder/lib/fuzzy-finder-view.coffee @@ -147,7 +147,7 @@ class FuzzyFinderView extends SelectList path.indexOf(options.filter) >= 0 else @projectPaths - console.log listedItems + @setArray(listedItems) options.done(listedItems) if options.done? else diff --git a/src/packages/fuzzy-finder/lib/load-paths-task.coffee b/src/packages/fuzzy-finder/lib/load-paths-task.coffee index 60a716688..12c80c327 100644 --- a/src/packages/fuzzy-finder/lib/load-paths-task.coffee +++ b/src/packages/fuzzy-finder/lib/load-paths-task.coffee @@ -1,5 +1,6 @@ _ = require 'underscore' -fs = require 'fs-utils' +BufferedProcess = require 'buffered-process' +$ = require 'jquery' module.exports = class LoadPathsTask @@ -13,21 +14,24 @@ class LoadPathsTask ignoredNames = ignoredNames.concat(config.get('core.ignoredNames') ? []) ignoreGitIgnoredFiles = config.get('core.hideGitIgnoredFiles') - paths = [] - isIgnored = (path) -> - for segment in path.split('/') - return true if _.contains(ignoredNames, segment) - ignoreGitIgnoredFiles and git?.isPathIgnored(fs.join(rootPath, path)) - onFile = (path) -> - return if @aborted - path = path.substring(rootPath.length + 1) - paths.push(path) unless isIgnored(path) - onDirectory = (path) => - not @aborted and not isIgnored(path.substring(rootPath.length + 1)) - onDone = => - @callback(paths) unless @aborted + command = require.resolve 'nak' + args = ['-l', rootPath] + args.unshift("--addVCSIgnores") if config.get('nak.addVCSIgnores') + args.unshift("-d", "#{ignoredNames.join(',')}") if ignoredNames.length > 0 - fs.traverseTree(rootPath, onFile, onDirectory, onDone) + paths = [] + deferred = $.Deferred() + exit = (code) => + if code is -1 + deferred.reject({command, code}) + else + @callback(paths) + deferred.resolve() + stdout = (data) -> + paths = paths.concat(data.split("\n")) + + new BufferedProcess({command, args, stdout, exit}) + deferred abort: -> - @aborted = true + @aborted = true \ No newline at end of file From 12bc89ca5006b2e4b638b06afa4c5fbaade5ab3b Mon Sep 17 00:00:00 2001 From: Garen Torikian Date: Wed, 27 Mar 2013 16:48:22 -0700 Subject: [PATCH 07/54] Add newline --- src/packages/fuzzy-finder/lib/load-paths-task.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/packages/fuzzy-finder/lib/load-paths-task.coffee b/src/packages/fuzzy-finder/lib/load-paths-task.coffee index 12c80c327..b6ce1a368 100644 --- a/src/packages/fuzzy-finder/lib/load-paths-task.coffee +++ b/src/packages/fuzzy-finder/lib/load-paths-task.coffee @@ -34,4 +34,5 @@ class LoadPathsTask deferred abort: -> - @aborted = true \ No newline at end of file + @aborted = true + \ No newline at end of file From af78a6b50f81d59945243bb959c6f15a1fa8b9f0 Mon Sep 17 00:00:00 2001 From: Garen Torikian Date: Wed, 27 Mar 2013 19:40:20 -0700 Subject: [PATCH 08/54] Remove unneeded quotes --- src/app/project.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/project.coffee b/src/app/project.coffee index a3da8a483..d404495bc 100644 --- a/src/app/project.coffee +++ b/src/app/project.coffee @@ -193,7 +193,7 @@ class Project readLine(line) if state is 'readingLines' command = require.resolve 'nak' - args = ['--ackmate', "#{regex.source}", @getPath()] + args = ['--ackmate', regex.source, @getPath()] args.unshift("--addVCSIgnores") if config.get('nak.addVCSIgnores') new BufferedProcess({command, args, stdout, exit}) deferred From 9e3935f34970d92e9f366a54b38d572f299e56ad Mon Sep 17 00:00:00 2001 From: Garen Torikian Date: Thu, 28 Mar 2013 12:09:14 -0700 Subject: [PATCH 09/54] Fix scan specs --- spec/app/project-spec.coffee | 4 ++-- src/app/project.coffee | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/spec/app/project-spec.coffee b/spec/app/project-spec.coffee index 48f483fc5..53d17d5e0 100644 --- a/spec/app/project-spec.coffee +++ b/spec/app/project-spec.coffee @@ -251,12 +251,12 @@ describe "Project", -> expect(iterator.argsForCall[0][0]).toEqual path: project.resolve('a') - match: 'aaa' + match: 'aa ' range: [[0, 0], [0, 3]] expect(iterator.argsForCall[1][0]).toEqual path: project.resolve('a') - match: 'aa' + match: 'a ' range: [[1, 3], [1, 5]] describe "serialization", -> diff --git a/src/app/project.coffee b/src/app/project.coffee index d404495bc..04413e126 100644 --- a/src/app/project.coffee +++ b/src/app/project.coffee @@ -176,7 +176,7 @@ class Project for [column, length] in matchPositions range = new Range([row, column], [row, column + length]) - match = lineText.substr(column, length) + match = lineText.substr(column + 1, length) iterator({path, range, match}) deferred = $.Deferred() @@ -195,6 +195,7 @@ class Project command = require.resolve 'nak' args = ['--ackmate', regex.source, @getPath()] args.unshift("--addVCSIgnores") if config.get('nak.addVCSIgnores') + #console.log(args) new BufferedProcess({command, args, stdout, exit}) deferred From 226611d2ec54aa86558e4b80f53667f696f0a4fa Mon Sep 17 00:00:00 2001 From: Garen Torikian Date: Thu, 28 Mar 2013 13:04:25 -0700 Subject: [PATCH 10/54] Fix fuzzy specs --- package.json | 2 +- src/packages/fuzzy-finder/lib/load-paths-task.coffee | 4 ++-- src/packages/fuzzy-finder/spec/fuzzy-finder-spec.coffee | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index a1152052b..03ebffbd5 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "coffee-cache": "0.1.0", "pegjs": "0.7.0", "async": "0.2.6", - "nak": "0.2.4", + "nak": "0.2.5", "spellchecker": "0.2.0", "plist": "git://github.com/nathansobo/node-plist.git", "space-pen": "git://github.com/nathansobo/space-pen.git" diff --git a/src/packages/fuzzy-finder/lib/load-paths-task.coffee b/src/packages/fuzzy-finder/lib/load-paths-task.coffee index b6ce1a368..9e5c9489d 100644 --- a/src/packages/fuzzy-finder/lib/load-paths-task.coffee +++ b/src/packages/fuzzy-finder/lib/load-paths-task.coffee @@ -18,7 +18,7 @@ class LoadPathsTask args = ['-l', rootPath] args.unshift("--addVCSIgnores") if config.get('nak.addVCSIgnores') args.unshift("-d", "#{ignoredNames.join(',')}") if ignoredNames.length > 0 - + paths = [] deferred = $.Deferred() exit = (code) => @@ -28,7 +28,7 @@ class LoadPathsTask @callback(paths) deferred.resolve() stdout = (data) -> - paths = paths.concat(data.split("\n")) + paths = paths.concat(_.compact(data.split("\n"))) new BufferedProcess({command, args, stdout, exit}) deferred diff --git a/src/packages/fuzzy-finder/spec/fuzzy-finder-spec.coffee b/src/packages/fuzzy-finder/spec/fuzzy-finder-spec.coffee index 15c89721e..d93b82264 100644 --- a/src/packages/fuzzy-finder/spec/fuzzy-finder-spec.coffee +++ b/src/packages/fuzzy-finder/spec/fuzzy-finder-spec.coffee @@ -365,7 +365,7 @@ describe 'FuzzyFinder', -> expect(finderView).toBeVisible() expect(rootView.find('.fuzzy-finder input:focus')).toExist() - it "opens a file directly when there is a single match", -> + fit "opens a file directly when there is a single match", -> editor.setText("sample.txt") jasmine.unspy(window, "setTimeout") rootView.trigger 'fuzzy-finder:find-under-cursor' @@ -379,7 +379,7 @@ describe 'FuzzyFinder', -> runs -> expect(finderView).not.toBeVisible() - expect(openedPath).toBe "sample.txt" + expect(openedPath).toBe "#{project.getPath()}/sample.txt" it "displays an error when the word under the cursor doesn't match any files", -> editor.setText("moogoogaipan") From daf5b9cb14bfa7bab2575232c50ea277dccc11c9 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 28 Mar 2013 22:12:03 -0400 Subject: [PATCH 11/54] Un-f fuzzy finder spec --- src/packages/fuzzy-finder/spec/fuzzy-finder-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/packages/fuzzy-finder/spec/fuzzy-finder-spec.coffee b/src/packages/fuzzy-finder/spec/fuzzy-finder-spec.coffee index d93b82264..8e75f8d9c 100644 --- a/src/packages/fuzzy-finder/spec/fuzzy-finder-spec.coffee +++ b/src/packages/fuzzy-finder/spec/fuzzy-finder-spec.coffee @@ -365,7 +365,7 @@ describe 'FuzzyFinder', -> expect(finderView).toBeVisible() expect(rootView.find('.fuzzy-finder input:focus')).toExist() - fit "opens a file directly when there is a single match", -> + it "opens a file directly when there is a single match", -> editor.setText("sample.txt") jasmine.unspy(window, "setTimeout") rootView.trigger 'fuzzy-finder:find-under-cursor' From 346a3c94aa24cf698e99653aea2d4b5a53b838ea Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 28 Mar 2013 22:12:16 -0400 Subject: [PATCH 12/54] Bring back a newline --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 03ebffbd5..c5ba41b71 100644 --- a/package.json +++ b/package.json @@ -24,4 +24,4 @@ "scripts": { "preinstall": "true" } -} \ No newline at end of file +} From e5b89e559ef520ea56caa86dc214a853363646bb Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 28 Mar 2013 22:15:12 -0400 Subject: [PATCH 13/54] :lipstick: --- src/packages/fuzzy-finder/lib/load-paths-task.coffee | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/packages/fuzzy-finder/lib/load-paths-task.coffee b/src/packages/fuzzy-finder/lib/load-paths-task.coffee index 9e5c9489d..545c5bc9a 100644 --- a/src/packages/fuzzy-finder/lib/load-paths-task.coffee +++ b/src/packages/fuzzy-finder/lib/load-paths-task.coffee @@ -18,7 +18,7 @@ class LoadPathsTask args = ['-l', rootPath] args.unshift("--addVCSIgnores") if config.get('nak.addVCSIgnores') args.unshift("-d", "#{ignoredNames.join(',')}") if ignoredNames.length > 0 - + paths = [] deferred = $.Deferred() exit = (code) => @@ -35,4 +35,3 @@ class LoadPathsTask abort: -> @aborted = true - \ No newline at end of file From 44cd588bf9b1d4ec012cd66d7ed113eafbd6c892 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 28 Mar 2013 22:16:48 -0400 Subject: [PATCH 14/54] Drop unneeded quotes --- src/packages/fuzzy-finder/lib/load-paths-task.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/packages/fuzzy-finder/lib/load-paths-task.coffee b/src/packages/fuzzy-finder/lib/load-paths-task.coffee index 545c5bc9a..ad3b81ab0 100644 --- a/src/packages/fuzzy-finder/lib/load-paths-task.coffee +++ b/src/packages/fuzzy-finder/lib/load-paths-task.coffee @@ -17,7 +17,7 @@ class LoadPathsTask command = require.resolve 'nak' args = ['-l', rootPath] args.unshift("--addVCSIgnores") if config.get('nak.addVCSIgnores') - args.unshift("-d", "#{ignoredNames.join(',')}") if ignoredNames.length > 0 + args.unshift("-d", ignoredNames.join(',')) if ignoredNames.length > 0 paths = [] deferred = $.Deferred() From 95218ca9f54fe88b0cd94d0a8263ec533892c40f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 28 Mar 2013 22:29:05 -0400 Subject: [PATCH 15/54] Remove commented out logging --- src/app/project.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app/project.coffee b/src/app/project.coffee index 04413e126..886e7a059 100644 --- a/src/app/project.coffee +++ b/src/app/project.coffee @@ -195,7 +195,6 @@ class Project command = require.resolve 'nak' args = ['--ackmate', regex.source, @getPath()] args.unshift("--addVCSIgnores") if config.get('nak.addVCSIgnores') - #console.log(args) new BufferedProcess({command, args, stdout, exit}) deferred From 5f9c643ae9f0939762a4436ec8de0b5f42284180 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 28 Mar 2013 22:51:47 -0400 Subject: [PATCH 16/54] Kill process when task is aborted --- .../fuzzy-finder/lib/load-paths-task.coffee | 5 ++++- src/stdlib/buffered-process.coffee | 21 ++++++++++++++----- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/packages/fuzzy-finder/lib/load-paths-task.coffee b/src/packages/fuzzy-finder/lib/load-paths-task.coffee index ad3b81ab0..538aac6ba 100644 --- a/src/packages/fuzzy-finder/lib/load-paths-task.coffee +++ b/src/packages/fuzzy-finder/lib/load-paths-task.coffee @@ -30,8 +30,11 @@ class LoadPathsTask stdout = (data) -> paths = paths.concat(_.compact(data.split("\n"))) - new BufferedProcess({command, args, stdout, exit}) + @process = new BufferedProcess({command, args, stdout, exit}) deferred abort: -> @aborted = true + if @process? + @process.kill() + @process = null diff --git a/src/stdlib/buffered-process.coffee b/src/stdlib/buffered-process.coffee index 04fcf3ce9..eda128601 100644 --- a/src/stdlib/buffered-process.coffee +++ b/src/stdlib/buffered-process.coffee @@ -2,32 +2,36 @@ ChildProcess = require 'child_process' module.exports = class BufferedProcess + process: null + killed: false + constructor: ({command, args, options, stdout, stderr, exit}={}) -> - process = ChildProcess.spawn(command, args, options) + @process = ChildProcess.spawn(command, args, options) stdoutClosed = true stderrClosed = true processExited = true exitCode = 0 triggerExitCallback = -> + return if @killed if stdoutClosed and stderrClosed and processExited exit?(exitCode) if stdout stdoutClosed = false - @bufferStream process.stdout, stdout, -> + @bufferStream @process.stdout, stdout, -> stdoutClosed = true triggerExitCallback() if stderr stderrClosed = false - @bufferStream process.stderr, stderr, -> + @bufferStream @process.stderr, stderr, -> stderrClosed = true triggerExitCallback() if exit processExited = false - process.on 'exit', (code) -> + @process.on 'exit', (code) -> exitCode = code processExited = true triggerExitCallback() @@ -36,7 +40,8 @@ class BufferedProcess stream.setEncoding('utf8') buffered = '' - stream.on 'data', (data) -> + stream.on 'data', (data) => + return if @killed buffered += data lastNewlineIndex = buffered.lastIndexOf('\n') if lastNewlineIndex isnt -1 @@ -44,5 +49,11 @@ class BufferedProcess buffered = buffered.substring(lastNewlineIndex + 1) stream.on 'close', => + return if @killed onLines(buffered) if buffered.length > 0 onDone() + + kill: -> + @killed = true + @process.kill() + @process = null From 1ccfbe22dc83716092d9fe983c4eba7b987e1129 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 28 Mar 2013 23:12:53 -0400 Subject: [PATCH 17/54] Remove unneeded unspy calls for setTimeout --- src/packages/fuzzy-finder/spec/fuzzy-finder-spec.coffee | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/packages/fuzzy-finder/spec/fuzzy-finder-spec.coffee b/src/packages/fuzzy-finder/spec/fuzzy-finder-spec.coffee index 8e75f8d9c..fb6c8ceb3 100644 --- a/src/packages/fuzzy-finder/spec/fuzzy-finder-spec.coffee +++ b/src/packages/fuzzy-finder/spec/fuzzy-finder-spec.coffee @@ -43,7 +43,6 @@ describe 'FuzzyFinder', -> it "shows all relative file paths for the current project and selects the first", -> rootView.attachToDom() finderView.maxItems = Infinity - jasmine.unspy(window, "setTimeout") rootView.trigger 'fuzzy-finder:toggle-file-finder' paths = null expect(finderView.find(".loading")).toBeVisible() @@ -279,7 +278,6 @@ describe 'FuzzyFinder', -> describe "cached file paths", -> it "caches file paths after first time", -> spyOn(LoadPathsTask.prototype, "start").andCallThrough() - jasmine.unspy(window, "setTimeout") rootView.trigger 'fuzzy-finder:toggle-file-finder' waitsFor -> @@ -299,7 +297,6 @@ describe 'FuzzyFinder', -> it "doesn't cache buffer paths", -> spyOn(project, "getEditSessions").andCallThrough() - jasmine.unspy(window, "setTimeout") rootView.trigger 'fuzzy-finder:toggle-buffer-finder' waitsFor -> @@ -319,7 +316,6 @@ describe 'FuzzyFinder', -> it "busts the cache when the window gains focus", -> spyOn(LoadPathsTask.prototype, "start").andCallThrough() - jasmine.unspy(window, "setTimeout") rootView.trigger 'fuzzy-finder:toggle-file-finder' waitsFor -> @@ -336,7 +332,6 @@ describe 'FuzzyFinder', -> describe "path ignoring", -> it "ignores paths that match entries in config.fuzzyFinder.ignoredNames", -> config.set("fuzzyFinder.ignoredNames", ["tree-view.js"]) - jasmine.unspy(window, "setTimeout") rootView.trigger 'fuzzy-finder:toggle-file-finder' finderView.maxItems = Infinity @@ -355,7 +350,6 @@ describe 'FuzzyFinder', -> it "opens the fuzzy finder window when there are multiple matches", -> editor.setText("sample") - jasmine.unspy(window, "setTimeout") rootView.trigger 'fuzzy-finder:find-under-cursor' waitsFor -> @@ -367,7 +361,6 @@ describe 'FuzzyFinder', -> it "opens a file directly when there is a single match", -> editor.setText("sample.txt") - jasmine.unspy(window, "setTimeout") rootView.trigger 'fuzzy-finder:find-under-cursor' openedPath = null @@ -385,7 +378,6 @@ describe 'FuzzyFinder', -> editor.setText("moogoogaipan") editor.setCursorBufferPosition([0,5]) - jasmine.unspy(window, "setTimeout") rootView.trigger 'fuzzy-finder:find-under-cursor' waitsFor -> From 327b49797bec365562c364105ccc1228927f2e01 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 28 Mar 2013 23:14:15 -0400 Subject: [PATCH 18/54] Relativize paths to project for folder label --- src/packages/fuzzy-finder/lib/fuzzy-finder-view.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/packages/fuzzy-finder/lib/fuzzy-finder-view.coffee b/src/packages/fuzzy-finder/lib/fuzzy-finder-view.coffee index b49f096da..5ad9be5e2 100644 --- a/src/packages/fuzzy-finder/lib/fuzzy-finder-view.coffee +++ b/src/packages/fuzzy-finder/lib/fuzzy-finder-view.coffee @@ -60,7 +60,7 @@ class FuzzyFinderView extends SelectList typeClass = 'text-name' @span fs.base(path), class: "file label #{typeClass}" - if folder = fs.directory(path) + if folder = fs.directory(project.relativize(path)) @span " - #{folder}/", class: 'directory' openPath: (path) -> From 082acf438665027a7b3c7fd554b0e2481e0127b7 Mon Sep 17 00:00:00 2001 From: Garen Torikian Date: Fri, 29 Mar 2013 09:35:40 -0700 Subject: [PATCH 19/54] Stash filestream work --- src/app/project.coffee | 2 +- .../lib/commands/select-all-matches-in-project.coffee | 3 ++- src/packages/command-panel/lib/operation.coffee | 11 +++++------ src/packages/command-panel/lib/preview-list.coffee | 2 -- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/app/project.coffee b/src/app/project.coffee index 886e7a059..6c5ad78c6 100644 --- a/src/app/project.coffee +++ b/src/app/project.coffee @@ -177,7 +177,7 @@ class Project for [column, length] in matchPositions range = new Range([row, column], [row, column + length]) match = lineText.substr(column + 1, length) - iterator({path, range, match}) + iterator({path, range, match, lineText}) deferred = $.Deferred() exit = (code) -> diff --git a/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee b/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee index 155d792cf..65737f9cd 100644 --- a/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee +++ b/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee @@ -13,11 +13,12 @@ class SelectAllMatchesInProject extends Command compile: (project, buffer, range) -> deferred = $.Deferred() operations = [] - promise = project.scan @regex, ({path, range}) -> + promise = project.scan @regex, ({path, range, match, lineText}) -> op = new Operation( project: project path: path bufferRange: range + lineText: lineText ) project.previewList.populateSingle(op) operations.push(op) diff --git a/src/packages/command-panel/lib/operation.coffee b/src/packages/command-panel/lib/operation.coffee index 9be9ad7f6..c0adac184 100644 --- a/src/packages/command-panel/lib/operation.coffee +++ b/src/packages/command-panel/lib/operation.coffee @@ -1,6 +1,6 @@ module.exports = class Operation - constructor: ({@project, @path, @buffer, @bufferRange, @newText, @preserveSelection, @errorMessage}) -> + constructor: ({@project, @path, @buffer, @bufferRange, @lineText, @newText, @preserveSelection, @errorMessage}) -> if @buffer? @buffer.retain() @getMarker() @@ -23,11 +23,10 @@ class Operation @getBufferRange() unless @preserveSelection preview: -> - range = @getBuffer().getMarkerRange(@getMarker()) - line = @getBuffer().lineForRow(range.start.row) - prefix = line[0...range.start.column] - match = line[range.start.column...range.end.column] - suffix = line[range.end.column..] + range = @bufferRange + prefix = @lineText[0...range.start.column] + match = @lineText[range.start.column + 1...range.end.column] + suffix = @lineText[range.end.column..] {prefix, suffix, match, range} diff --git a/src/packages/command-panel/lib/preview-list.coffee b/src/packages/command-panel/lib/preview-list.coffee index 8569868fd..fe4c8a6b6 100644 --- a/src/packages/command-panel/lib/preview-list.coffee +++ b/src/packages/command-panel/lib/preview-list.coffee @@ -1,7 +1,6 @@ $ = require 'jquery' ScrollView = require 'scroll-view' _ = require 'underscore' -fs = require 'fs-utils' PathView = require './path-view' OperationView = require './operation-view' @@ -73,7 +72,6 @@ class PreviewList extends ScrollView pathView = @pathViewForPath(operation.getPath()) pathView.addOperation(operation) - pathViewForPath: (path) -> pathView = @viewsForPath[path] if not pathView From b8d054451790c8fbdd771743911e1326d93050ee Mon Sep 17 00:00:00 2001 From: Garen Torikian Date: Sat, 30 Mar 2013 11:20:27 -0700 Subject: [PATCH 20/54] Improve UX Properly compress all results to one heading Merge Expand/Collapse Button into one --- .../command-panel/lib/command-panel-view.coffee | 14 +++++++++++--- src/packages/command-panel/lib/preview-list.coffee | 9 +++------ 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/packages/command-panel/lib/command-panel-view.coffee b/src/packages/command-panel/lib/command-panel-view.coffee index 9ed6533d5..878b11399 100644 --- a/src/packages/command-panel/lib/command-panel-view.coffee +++ b/src/packages/command-panel/lib/command-panel-view.coffee @@ -6,6 +6,7 @@ PreviewList = require './preview-list' Editor = require 'editor' {SyntaxError} = require('pegjs').parser _ = require 'underscore' +$ = require 'jquery' module.exports = class CommandPanelView extends View @@ -14,7 +15,6 @@ class CommandPanelView extends View @div class: 'header', outlet: 'previewHeader', => @span outlet: 'searchLoadingMessage', class: 'loading', 'Searching...' @ul outlet: 'expandCollapse', class: 'expand-collapse', => - @li class: 'expand', 'Expand All' @li class: 'collapse', 'Collapse All' @span outlet: 'previewCount', class: 'preview-count' @@ -54,6 +54,7 @@ class CommandPanelView extends View @previewHeader.hide() @errorMessages.hide() @searchLoadingMessage.hide() + @expandCollapse.hide() @prompt.iconSize(@miniEditor.getFontSize()) @history = state.history ? [] @@ -92,11 +93,17 @@ class CommandPanelView extends View @miniEditor.focus() onExpandAll: (event) => - @previewList.expandAllPaths() + elButton = $(event.currentTarget) + @previewList.expandAllPaths() + elButton.removeClass("expand").addClass("collapse") + elButton.text("Collapse All") @previewList.focus() onCollapseAll: (event) => + elButton = $(event.currentTarget) @previewList.collapseAllPaths() + elButton.removeClass("collapse").addClass("expand") + elButton.text("Expand All") @previewList.focus() attach: (text='', options={}) -> @@ -123,10 +130,11 @@ class CommandPanelView extends View @searchLoadingMessage.show() @errorMessages.empty() project.previewList = @previewList - + try @commandInterpreter.eval(command, rootView.getActivePaneItem()).done ({operationsToPreview, errorMessages}) => @searchLoadingMessage.hide() + @expandCollapse.show() @history.push(command) @historyIndex = @history.length diff --git a/src/packages/command-panel/lib/preview-list.coffee b/src/packages/command-panel/lib/preview-list.coffee index fe4c8a6b6..36a40cc79 100644 --- a/src/packages/command-panel/lib/preview-list.coffee +++ b/src/packages/command-panel/lib/preview-list.coffee @@ -19,8 +19,6 @@ class PreviewList extends ScrollView @on 'core:move-down', => @selectNextOperation(); false @on 'core:move-up', => @selectPreviousOperation(); false - @on 'scroll', => - @renderOperations() if @scrollBottom() >= (@prop('scrollHeight')) @command 'command-panel:collapse-all', => @collapseAllPaths() @command 'command-panel:expand-all', => @expandAllPaths() @@ -29,7 +27,6 @@ class PreviewList extends ScrollView @children().each (index, element) -> $(element).view().expand() collapseAllPaths: -> - @renderOperations(renderAll: true) @children().each (index, element) -> $(element).view().collapse() destroy: -> @@ -50,7 +47,7 @@ class PreviewList extends ScrollView @find('.operation:first').addClass('selected') populateSingle: (operation) -> - @viewsForPath = {} + @viewsForPath ||= {} @show() @renderOperation(operation) @@ -66,14 +63,14 @@ class PreviewList extends ScrollView @lastRenderedOperationIndex++ break if not renderAll and @prop('scrollHeight') >= startingScrollHeight + @pixelOverdraw and @prop('scrollHeight') > @height() + @pixelOverdraw - renderOperation: (operation, {renderAll}={}) -> - renderAll ?= false + renderOperation: (operation) -> startingScrollHeight = @prop('scrollHeight') pathView = @pathViewForPath(operation.getPath()) pathView.addOperation(operation) pathViewForPath: (path) -> pathView = @viewsForPath[path] + console.log(path) if not pathView pathView = new PathView({path: path, previewList: this}) @viewsForPath[path] = pathView From 209eceee6af9307e73ee617b07fea8d5fa11ba19 Mon Sep 17 00:00:00 2001 From: Garen Torikian Date: Sat, 30 Mar 2013 18:36:50 -0700 Subject: [PATCH 21/54] stash --- src/packages/command-panel/lib/command-panel-view.coffee | 4 ++-- src/packages/command-panel/lib/preview-list.coffee | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/packages/command-panel/lib/command-panel-view.coffee b/src/packages/command-panel/lib/command-panel-view.coffee index 878b11399..311b5b7f2 100644 --- a/src/packages/command-panel/lib/command-panel-view.coffee +++ b/src/packages/command-panel/lib/command-panel-view.coffee @@ -130,7 +130,7 @@ class CommandPanelView extends View @searchLoadingMessage.show() @errorMessages.empty() project.previewList = @previewList - + try @commandInterpreter.eval(command, rootView.getActivePaneItem()).done ({operationsToPreview, errorMessages}) => @searchLoadingMessage.hide() @@ -149,7 +149,7 @@ class CommandPanelView extends View else @detach() catch error - @loadingMessage.hide() + @searchLoadingMessage.hide() if error.name is "SyntaxError" @flashError() return diff --git a/src/packages/command-panel/lib/preview-list.coffee b/src/packages/command-panel/lib/preview-list.coffee index 36a40cc79..cf700af2d 100644 --- a/src/packages/command-panel/lib/preview-list.coffee +++ b/src/packages/command-panel/lib/preview-list.coffee @@ -70,7 +70,6 @@ class PreviewList extends ScrollView pathViewForPath: (path) -> pathView = @viewsForPath[path] - console.log(path) if not pathView pathView = new PathView({path: path, previewList: this}) @viewsForPath[path] = pathView From 7f8e2aba1b15ced53121b2aadca055be6bca6259 Mon Sep 17 00:00:00 2001 From: Garen Torikian Date: Sun, 31 Mar 2013 00:22:27 -0700 Subject: [PATCH 22/54] Stash changes --- src/app/project.coffee | 4 ++-- src/packages/command-panel/lib/command-panel-view.coffee | 1 + src/packages/command-panel/lib/operation.coffee | 2 +- src/packages/command-panel/lib/preview-list.coffee | 3 ++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/app/project.coffee b/src/app/project.coffee index 6c5ad78c6..dea39f3c1 100644 --- a/src/app/project.coffee +++ b/src/app/project.coffee @@ -176,7 +176,7 @@ class Project for [column, length] in matchPositions range = new Range([row, column], [row, column + length]) - match = lineText.substr(column + 1, length) + match = lineText.substr(column , length) iterator({path, range, match, lineText}) deferred = $.Deferred() @@ -192,7 +192,7 @@ class Project readPath(line) if state is 'readingPath' readLine(line) if state is 'readingLines' - command = require.resolve 'nak' + command = require.resolve('nak') args = ['--ackmate', regex.source, @getPath()] args.unshift("--addVCSIgnores") if config.get('nak.addVCSIgnores') new BufferedProcess({command, args, stdout, exit}) diff --git a/src/packages/command-panel/lib/command-panel-view.coffee b/src/packages/command-panel/lib/command-panel-view.coffee index 311b5b7f2..7893f1145 100644 --- a/src/packages/command-panel/lib/command-panel-view.coffee +++ b/src/packages/command-panel/lib/command-panel-view.coffee @@ -144,6 +144,7 @@ class CommandPanelView extends View @errorMessages.append $$ -> @li errorMessage for errorMessage in errorMessages else if operationsToPreview?.length + @previewList.show() @previewList.focus() @previewCount.text("#{_.pluralize(operationsToPreview.length, 'match', 'matches')} in #{_.pluralize(@previewList.getPathCount(operationsToPreview), 'file')}").show() else diff --git a/src/packages/command-panel/lib/operation.coffee b/src/packages/command-panel/lib/operation.coffee index c0adac184..af963d8ca 100644 --- a/src/packages/command-panel/lib/operation.coffee +++ b/src/packages/command-panel/lib/operation.coffee @@ -25,7 +25,7 @@ class Operation preview: -> range = @bufferRange prefix = @lineText[0...range.start.column] - match = @lineText[range.start.column + 1...range.end.column] + match = @lineText[range.start.column...range.end.column] suffix = @lineText[range.end.column..] {prefix, suffix, match, range} diff --git a/src/packages/command-panel/lib/preview-list.coffee b/src/packages/command-panel/lib/preview-list.coffee index cf700af2d..101eb99ae 100644 --- a/src/packages/command-panel/lib/preview-list.coffee +++ b/src/packages/command-panel/lib/preview-list.coffee @@ -49,7 +49,7 @@ class PreviewList extends ScrollView populateSingle: (operation) -> @viewsForPath ||= {} - @show() + @lastRenderedOperationIndex ||= 0 @renderOperation(operation) @find('.operation:first').addClass('selected') @@ -67,6 +67,7 @@ class PreviewList extends ScrollView startingScrollHeight = @prop('scrollHeight') pathView = @pathViewForPath(operation.getPath()) pathView.addOperation(operation) + @lastRenderedOperationIndex++ pathViewForPath: (path) -> pathView = @viewsForPath[path] From ea65421120bea48a55836ae85f8186c4910a3a2a Mon Sep 17 00:00:00 2001 From: Garen Torikian Date: Sun, 31 Mar 2013 00:30:39 -0700 Subject: [PATCH 23/54] Remove streaming changes --- .../lib/command-panel-view.coffee | 5 ++--- .../select-all-matches-in-project.coffee | 4 +--- .../command-panel/lib/preview-list.coffee | 22 +++++-------------- 3 files changed, 8 insertions(+), 23 deletions(-) diff --git a/src/packages/command-panel/lib/command-panel-view.coffee b/src/packages/command-panel/lib/command-panel-view.coffee index 7893f1145..b87aff9d2 100644 --- a/src/packages/command-panel/lib/command-panel-view.coffee +++ b/src/packages/command-panel/lib/command-panel-view.coffee @@ -129,7 +129,6 @@ class CommandPanelView extends View @previewHeader.show() @searchLoadingMessage.show() @errorMessages.empty() - project.previewList = @previewList try @commandInterpreter.eval(command, rootView.getActivePaneItem()).done ({operationsToPreview, errorMessages}) => @@ -144,9 +143,9 @@ class CommandPanelView extends View @errorMessages.append $$ -> @li errorMessage for errorMessage in errorMessages else if operationsToPreview?.length - @previewList.show() + @previewList.populate(operationsToPreview) @previewList.focus() - @previewCount.text("#{_.pluralize(operationsToPreview.length, 'match', 'matches')} in #{_.pluralize(@previewList.getPathCount(operationsToPreview), 'file')}").show() + @previewCount.text("#{_.pluralize(operationsToPreview.length, 'match', 'matches')} in #{_.pluralize(@previewList.getPathCount(), 'file')}").show() else @detach() catch error diff --git a/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee b/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee index 65737f9cd..b0dd65e9e 100644 --- a/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee +++ b/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee @@ -14,14 +14,12 @@ class SelectAllMatchesInProject extends Command deferred = $.Deferred() operations = [] promise = project.scan @regex, ({path, range, match, lineText}) -> - op = new Operation( + operations.push(new Operation( project: project path: path bufferRange: range lineText: lineText ) - project.previewList.populateSingle(op) - operations.push(op) promise.done -> deferred.resolve(operations) deferred.promise() diff --git a/src/packages/command-panel/lib/preview-list.coffee b/src/packages/command-panel/lib/preview-list.coffee index 101eb99ae..49cb95835 100644 --- a/src/packages/command-panel/lib/preview-list.coffee +++ b/src/packages/command-panel/lib/preview-list.coffee @@ -19,7 +19,8 @@ class PreviewList extends ScrollView @on 'core:move-down', => @selectNextOperation(); false @on 'core:move-up', => @selectPreviousOperation(); false - + @on 'scroll', => + @renderOperations() if @scrollBottom() >= (@prop('scrollHeight')) @command 'command-panel:collapse-all', => @collapseAllPaths() @command 'command-panel:expand-all', => @expandAllPaths() @@ -27,6 +28,7 @@ class PreviewList extends ScrollView @children().each (index, element) -> $(element).view().expand() collapseAllPaths: -> + @renderOperations(renderAll: true) @children().each (index, element) -> $(element).view().collapse() destroy: -> @@ -46,14 +48,6 @@ class PreviewList extends ScrollView @find('.operation:first').addClass('selected') - populateSingle: (operation) -> - @viewsForPath ||= {} - - @lastRenderedOperationIndex ||= 0 - @renderOperation(operation) - - @find('.operation:first').addClass('selected') - renderOperations: ({renderAll}={}) -> renderAll ?= false startingScrollHeight = @prop('scrollHeight') @@ -62,12 +56,6 @@ class PreviewList extends ScrollView pathView.addOperation(operation) @lastRenderedOperationIndex++ break if not renderAll and @prop('scrollHeight') >= startingScrollHeight + @pixelOverdraw and @prop('scrollHeight') > @height() + @pixelOverdraw - - renderOperation: (operation) -> - startingScrollHeight = @prop('scrollHeight') - pathView = @pathViewForPath(operation.getPath()) - pathView.addOperation(operation) - @lastRenderedOperationIndex++ pathViewForPath: (path) -> pathView = @viewsForPath[path] @@ -106,8 +94,8 @@ class PreviewList extends ScrollView previousView.addClass('selected') previousView.scrollTo() - getPathCount: (operations=@operations)-> - _.keys(_.groupBy(operations, (operation) -> operation.getPath())).length + getPathCount: -> + _.keys(_.groupBy(@operations, (operation) -> operation.getPath())).length getOperations: -> new Array(@operations...) From 5e5437502f4f823aeebb980ab81ff6de39fc4a5e Mon Sep 17 00:00:00 2001 From: Garen Torikian Date: Sun, 31 Mar 2013 00:45:05 -0700 Subject: [PATCH 24/54] reset --- src/app/project.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/project.coffee b/src/app/project.coffee index d6651e727..bb0d30ecf 100644 --- a/src/app/project.coffee +++ b/src/app/project.coffee @@ -192,7 +192,7 @@ class Project readPath(line) if state is 'readingPath' readLine(line) if state is 'readingLines' - command = require.resolve('ag') + command = require.resolve('nak') args = ['--ackmate', regex.source, @getPath()] new BufferedProcess({command, args, stdout, exit}) deferred From 4cd181022d6105020efda3e2c1d1f582a5505b4d Mon Sep 17 00:00:00 2001 From: Garen Torikian Date: Sun, 31 Mar 2013 01:02:53 -0700 Subject: [PATCH 25/54] Restore old UI --- src/app/project.coffee | 3 +-- .../command-panel/lib/command-panel-view.coffee | 15 +++++++-------- .../commands/select-all-matches-in-project.coffee | 6 +++--- src/packages/command-panel/lib/operation.coffee | 6 +++--- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/app/project.coffee b/src/app/project.coffee index dea39f3c1..fa8f0d864 100644 --- a/src/app/project.coffee +++ b/src/app/project.coffee @@ -176,8 +176,7 @@ class Project for [column, length] in matchPositions range = new Range([row, column], [row, column + length]) - match = lineText.substr(column , length) - iterator({path, range, match, lineText}) + iterator({path, range, lineText}) deferred = $.Deferred() exit = (code) -> diff --git a/src/packages/command-panel/lib/command-panel-view.coffee b/src/packages/command-panel/lib/command-panel-view.coffee index b87aff9d2..0c8a8ccd0 100644 --- a/src/packages/command-panel/lib/command-panel-view.coffee +++ b/src/packages/command-panel/lib/command-panel-view.coffee @@ -12,8 +12,8 @@ module.exports = class CommandPanelView extends View @content: -> @div class: 'command-panel tool-panel', => + @div class: 'loading is-loading', outlet: 'loadingMessage', 'Searching...' @div class: 'header', outlet: 'previewHeader', => - @span outlet: 'searchLoadingMessage', class: 'loading', 'Searching...' @ul outlet: 'expandCollapse', class: 'expand-collapse', => @li class: 'collapse', 'Collapse All' @span outlet: 'previewCount', class: 'preview-count' @@ -53,8 +53,7 @@ class CommandPanelView extends View @previewList.hide() @previewHeader.hide() @errorMessages.hide() - @searchLoadingMessage.hide() - @expandCollapse.hide() + @loadingMessage.hide() @prompt.iconSize(@miniEditor.getFontSize()) @history = state.history ? [] @@ -126,14 +125,13 @@ class CommandPanelView extends View @miniEditor.getText() execute: (command=@escapedCommand()) -> - @previewHeader.show() - @searchLoadingMessage.show() + @loadingMessage.show() + @previewList.hide() @errorMessages.empty() try @commandInterpreter.eval(command, rootView.getActivePaneItem()).done ({operationsToPreview, errorMessages}) => - @searchLoadingMessage.hide() - @expandCollapse.show() + @loadingMessage.hide() @history.push(command) @historyIndex = @history.length @@ -143,13 +141,14 @@ class CommandPanelView extends View @errorMessages.append $$ -> @li errorMessage for errorMessage in errorMessages else if operationsToPreview?.length + @previewHeader.show() @previewList.populate(operationsToPreview) @previewList.focus() @previewCount.text("#{_.pluralize(operationsToPreview.length, 'match', 'matches')} in #{_.pluralize(@previewList.getPathCount(), 'file')}").show() else @detach() catch error - @searchLoadingMessage.hide() + @loadingMessage.hide() if error.name is "SyntaxError" @flashError() return diff --git a/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee b/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee index b0dd65e9e..35742ef46 100644 --- a/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee +++ b/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee @@ -13,13 +13,13 @@ class SelectAllMatchesInProject extends Command compile: (project, buffer, range) -> deferred = $.Deferred() operations = [] - promise = project.scan @regex, ({path, range, match, lineText}) -> + promise = project.scan @regex, ({path, range, lineText}) -> operations.push(new Operation( project: project path: path bufferRange: range lineText: lineText - ) + )) promise.done -> deferred.resolve(operations) - deferred.promise() + deferred.promise() \ No newline at end of file diff --git a/src/packages/command-panel/lib/operation.coffee b/src/packages/command-panel/lib/operation.coffee index af963d8ca..f9b22973c 100644 --- a/src/packages/command-panel/lib/operation.coffee +++ b/src/packages/command-panel/lib/operation.coffee @@ -24,9 +24,9 @@ class Operation preview: -> range = @bufferRange - prefix = @lineText[0...range.start.column] - match = @lineText[range.start.column...range.end.column] - suffix = @lineText[range.end.column..] + prefix = @lineText[0...range.start.column + 1] + match = @lineText[range.start.column + 1...range.end.column + 1] + suffix = @lineText[range.end.column + 1..] {prefix, suffix, match, range} From 6f982c7c4cc1d91a74d69d960fa10256995ae853 Mon Sep 17 00:00:00 2001 From: Garen Torikian Date: Sun, 31 Mar 2013 01:11:19 -0700 Subject: [PATCH 26/54] Fix spec --- spec/app/project-spec.coffee | 4 +++- src/app/project.coffee | 3 ++- .../lib/commands/select-all-matches-in-project.coffee | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/spec/app/project-spec.coffee b/spec/app/project-spec.coffee index 53d17d5e0..cc3d3879e 100644 --- a/spec/app/project-spec.coffee +++ b/spec/app/project-spec.coffee @@ -188,7 +188,7 @@ describe "Project", -> runs -> expect(paths).not.toContain('ignored/ignored.txt') - describe ".scan(options, callback)", -> + fdescribe ".scan(options, callback)", -> describe "when called with a regex", -> it "calls the callback with all regex matches in all files in the project", -> matches = [] @@ -253,11 +253,13 @@ describe "Project", -> path: project.resolve('a') match: 'aa ' range: [[0, 0], [0, 3]] + lineText: 'aaa bbb' expect(iterator.argsForCall[1][0]).toEqual path: project.resolve('a') match: 'a ' range: [[1, 3], [1, 5]] + lineText: 'cc aa cc' describe "serialization", -> it "restores the project path", -> diff --git a/src/app/project.coffee b/src/app/project.coffee index fa8f0d864..3c10f744a 100644 --- a/src/app/project.coffee +++ b/src/app/project.coffee @@ -176,7 +176,8 @@ class Project for [column, length] in matchPositions range = new Range([row, column], [row, column + length]) - iterator({path, range, lineText}) + match = lineText.substr(column + 1, length) + iterator({path, range, match, lineText}) deferred = $.Deferred() exit = (code) -> diff --git a/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee b/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee index 35742ef46..20df613a3 100644 --- a/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee +++ b/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee @@ -13,7 +13,7 @@ class SelectAllMatchesInProject extends Command compile: (project, buffer, range) -> deferred = $.Deferred() operations = [] - promise = project.scan @regex, ({path, range, lineText}) -> + promise = project.scan @regex, ({path, range, match, lineText}) -> operations.push(new Operation( project: project path: path From da2cea4a24dc8fe95f2a0416cf47f25c9926f773 Mon Sep 17 00:00:00 2001 From: Garen Torikian Date: Sun, 31 Mar 2013 01:20:50 -0700 Subject: [PATCH 27/54] Hide header on subsequent search --- src/packages/command-panel/lib/command-panel-view.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/packages/command-panel/lib/command-panel-view.coffee b/src/packages/command-panel/lib/command-panel-view.coffee index 0c8a8ccd0..6709db163 100644 --- a/src/packages/command-panel/lib/command-panel-view.coffee +++ b/src/packages/command-panel/lib/command-panel-view.coffee @@ -127,6 +127,7 @@ class CommandPanelView extends View execute: (command=@escapedCommand()) -> @loadingMessage.show() @previewList.hide() + @previewHeader.hide() @errorMessages.empty() try From ae544e0c7e5a8822403592ee8eacec8a56dbbbc4 Mon Sep 17 00:00:00 2001 From: Garen Torikian Date: Sun, 31 Mar 2013 01:20:56 -0700 Subject: [PATCH 28/54] Bump nak --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 61c45b630..55518bde9 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "coffee-cache": "0.1.0", "pegjs": "0.7.0", "async": "0.2.6", - "nak": "0.2.5", + "nak": "0.2.6", "spellchecker": "0.2.0", "plist": "git://github.com/nathansobo/node-plist.git", "space-pen": "git://github.com/nathansobo/space-pen.git" From a4d8ed6ce68826e574851b76ca63fa769da24a7b Mon Sep 17 00:00:00 2001 From: Garen Torikian Date: Sun, 31 Mar 2013 17:07:30 -0700 Subject: [PATCH 29/54] Bump nak --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 55518bde9..adb5638b0 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "coffee-cache": "0.1.0", "pegjs": "0.7.0", "async": "0.2.6", - "nak": "0.2.6", + "nak": "0.2.7", "spellchecker": "0.2.0", "plist": "git://github.com/nathansobo/node-plist.git", "space-pen": "git://github.com/nathansobo/space-pen.git" From 2ae5cacc6ffef82b32bda4a9b01c9d399d0b4063 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 2 Apr 2013 13:25:21 -0700 Subject: [PATCH 30/54] Un-f project spec --- spec/app/project-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/app/project-spec.coffee b/spec/app/project-spec.coffee index cc3d3879e..c7b420650 100644 --- a/spec/app/project-spec.coffee +++ b/spec/app/project-spec.coffee @@ -188,7 +188,7 @@ describe "Project", -> runs -> expect(paths).not.toContain('ignored/ignored.txt') - fdescribe ".scan(options, callback)", -> + describe ".scan(options, callback)", -> describe "when called with a regex", -> it "calls the callback with all regex matches in all files in the project", -> matches = [] From d64c3e773de9ca33f11c4775259f3a762a6ea62e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 2 Apr 2013 13:30:39 -0700 Subject: [PATCH 31/54] :lipstick: --- .../lib/commands/select-all-matches-in-project.coffee | 2 +- src/packages/command-panel/lib/preview-list.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee b/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee index 20df613a3..6cf583596 100644 --- a/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee +++ b/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee @@ -22,4 +22,4 @@ class SelectAllMatchesInProject extends Command )) promise.done -> deferred.resolve(operations) - deferred.promise() \ No newline at end of file + deferred.promise() diff --git a/src/packages/command-panel/lib/preview-list.coffee b/src/packages/command-panel/lib/preview-list.coffee index 49cb95835..58cb0f799 100644 --- a/src/packages/command-panel/lib/preview-list.coffee +++ b/src/packages/command-panel/lib/preview-list.coffee @@ -56,7 +56,7 @@ class PreviewList extends ScrollView pathView.addOperation(operation) @lastRenderedOperationIndex++ break if not renderAll and @prop('scrollHeight') >= startingScrollHeight + @pixelOverdraw and @prop('scrollHeight') > @height() + @pixelOverdraw - + pathViewForPath: (path) -> pathView = @viewsForPath[path] if not pathView From d2f2011ea3ea08fb54a8681f8946942ad91bea42 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 2 Apr 2013 13:50:48 -0700 Subject: [PATCH 32/54] Skip leading space after colon in nak output This was causing a spec to fail since the line text now had a leading space for all results since the separator before the line text is now ': ' instead of just ':'. --- src/app/project.coffee | 6 +++--- src/packages/command-panel/lib/operation.coffee | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/app/project.coffee b/src/app/project.coffee index 3c10f744a..e2ad125d3 100644 --- a/src/app/project.coffee +++ b/src/app/project.coffee @@ -164,9 +164,9 @@ class Project state = 'readingPath' path = null else - colonIndex = line.indexOf(':') + colonIndex = line.indexOf(': ') matchInfo = line.substring(0, colonIndex) - lineText = line.substring(colonIndex + 1) + lineText = line.substring(colonIndex + 2) readMatches(matchInfo, lineText) readMatches = (matchInfo, lineText) -> @@ -176,7 +176,7 @@ class Project for [column, length] in matchPositions range = new Range([row, column], [row, column + length]) - match = lineText.substr(column + 1, length) + match = lineText.substr(column, length) iterator({path, range, match, lineText}) deferred = $.Deferred() diff --git a/src/packages/command-panel/lib/operation.coffee b/src/packages/command-panel/lib/operation.coffee index f9b22973c..af963d8ca 100644 --- a/src/packages/command-panel/lib/operation.coffee +++ b/src/packages/command-panel/lib/operation.coffee @@ -24,9 +24,9 @@ class Operation preview: -> range = @bufferRange - prefix = @lineText[0...range.start.column + 1] - match = @lineText[range.start.column + 1...range.end.column + 1] - suffix = @lineText[range.end.column + 1..] + prefix = @lineText[0...range.start.column] + match = @lineText[range.start.column...range.end.column] + suffix = @lineText[range.end.column..] {prefix, suffix, match, range} From 9b19b4512f39d6b29ccdb414dbce8a11e3f4eef2 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 2 Apr 2013 13:53:49 -0700 Subject: [PATCH 33/54] Use getBufferRange() when previewing This is for the case where the marker may move between construction and previewing. --- src/packages/command-panel/lib/operation.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/packages/command-panel/lib/operation.coffee b/src/packages/command-panel/lib/operation.coffee index af963d8ca..3dc17b29e 100644 --- a/src/packages/command-panel/lib/operation.coffee +++ b/src/packages/command-panel/lib/operation.coffee @@ -23,7 +23,7 @@ class Operation @getBufferRange() unless @preserveSelection preview: -> - range = @bufferRange + range = @getBufferRange() prefix = @lineText[0...range.start.column] match = @lineText[range.start.column...range.end.column] suffix = @lineText[range.end.column..] From 7caddc6c10f86a74c6f23d28ed6bc3fcc0dbd7ad Mon Sep 17 00:00:00 2001 From: Garen Torikian Date: Tue, 2 Apr 2013 14:04:38 -0700 Subject: [PATCH 34/54] Put the Expand/Collapse buttons back --- .../command-panel/lib/command-panel-view.coffee | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/packages/command-panel/lib/command-panel-view.coffee b/src/packages/command-panel/lib/command-panel-view.coffee index 6709db163..487af1730 100644 --- a/src/packages/command-panel/lib/command-panel-view.coffee +++ b/src/packages/command-panel/lib/command-panel-view.coffee @@ -6,7 +6,6 @@ PreviewList = require './preview-list' Editor = require 'editor' {SyntaxError} = require('pegjs').parser _ = require 'underscore' -$ = require 'jquery' module.exports = class CommandPanelView extends View @@ -15,6 +14,7 @@ class CommandPanelView extends View @div class: 'loading is-loading', outlet: 'loadingMessage', 'Searching...' @div class: 'header', outlet: 'previewHeader', => @ul outlet: 'expandCollapse', class: 'expand-collapse', => + @li class: 'expand', 'Expand All' @li class: 'collapse', 'Collapse All' @span outlet: 'previewCount', class: 'preview-count' @@ -92,17 +92,11 @@ class CommandPanelView extends View @miniEditor.focus() onExpandAll: (event) => - elButton = $(event.currentTarget) - @previewList.expandAllPaths() - elButton.removeClass("expand").addClass("collapse") - elButton.text("Collapse All") - @previewList.focus() + @previewList.expandAllPaths() + @previewList.focus() onCollapseAll: (event) => - elButton = $(event.currentTarget) @previewList.collapseAllPaths() - elButton.removeClass("collapse").addClass("expand") - elButton.text("Expand All") @previewList.focus() attach: (text='', options={}) -> From 1ee5eb32b418cc6aa90cb1303441604ada5332bf Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 2 Apr 2013 14:10:19 -0700 Subject: [PATCH 35/54] Restore scan spec asserts now that leading space is gone --- spec/app/project-spec.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/app/project-spec.coffee b/spec/app/project-spec.coffee index c7b420650..ab7e944de 100644 --- a/spec/app/project-spec.coffee +++ b/spec/app/project-spec.coffee @@ -247,17 +247,17 @@ describe "Project", -> stdout = BufferedProcess.prototype.bufferStream.argsForCall[0][1] stdout ":#{fs.resolveOnLoadPath('fixtures/dir/a')}\n" - stdout "1;0 3:aaa bbb\n2;3 2:cc aa cc\n" + stdout "1;0 3: aaa bbb\n2;3 2: cc aa cc\n" expect(iterator.argsForCall[0][0]).toEqual path: project.resolve('a') - match: 'aa ' + match: 'aaa' range: [[0, 0], [0, 3]] lineText: 'aaa bbb' expect(iterator.argsForCall[1][0]).toEqual path: project.resolve('a') - match: 'a ' + match: 'aa' range: [[1, 3], [1, 5]] lineText: 'cc aa cc' From 699212a13e3fc88806f93b6d020c1151d7a2d7e7 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 2 Apr 2013 14:17:47 -0700 Subject: [PATCH 36/54] Always pull line text from buffer This accounts for positional changes that may occur if the marker the operation is tracking moves. --- spec/app/project-spec.coffee | 2 -- src/app/project.coffee | 2 +- .../lib/commands/select-all-matches-in-project.coffee | 3 +-- src/packages/command-panel/lib/operation.coffee | 9 +++++---- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/spec/app/project-spec.coffee b/spec/app/project-spec.coffee index ab7e944de..5faf96952 100644 --- a/spec/app/project-spec.coffee +++ b/spec/app/project-spec.coffee @@ -253,13 +253,11 @@ describe "Project", -> path: project.resolve('a') match: 'aaa' range: [[0, 0], [0, 3]] - lineText: 'aaa bbb' expect(iterator.argsForCall[1][0]).toEqual path: project.resolve('a') match: 'aa' range: [[1, 3], [1, 5]] - lineText: 'cc aa cc' describe "serialization", -> it "restores the project path", -> diff --git a/src/app/project.coffee b/src/app/project.coffee index 6b29bab09..220c468a9 100644 --- a/src/app/project.coffee +++ b/src/app/project.coffee @@ -178,7 +178,7 @@ class Project for [column, length] in matchPositions range = new Range([row, column], [row, column + length]) match = lineText.substr(column, length) - iterator({path, range, match, lineText}) + iterator({path, range, match}) deferred = $.Deferred() exit = (code) -> diff --git a/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee b/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee index 6cf583596..c9255a4fc 100644 --- a/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee +++ b/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee @@ -13,12 +13,11 @@ class SelectAllMatchesInProject extends Command compile: (project, buffer, range) -> deferred = $.Deferred() operations = [] - promise = project.scan @regex, ({path, range, match, lineText}) -> + promise = project.scan @regex, ({path, range}) -> operations.push(new Operation( project: project path: path bufferRange: range - lineText: lineText )) promise.done -> deferred.resolve(operations) diff --git a/src/packages/command-panel/lib/operation.coffee b/src/packages/command-panel/lib/operation.coffee index 3dc17b29e..7f70b75e0 100644 --- a/src/packages/command-panel/lib/operation.coffee +++ b/src/packages/command-panel/lib/operation.coffee @@ -1,6 +1,6 @@ module.exports = class Operation - constructor: ({@project, @path, @buffer, @bufferRange, @lineText, @newText, @preserveSelection, @errorMessage}) -> + constructor: ({@project, @path, @buffer, @bufferRange, @newText, @preserveSelection, @errorMessage}) -> if @buffer? @buffer.retain() @getMarker() @@ -24,9 +24,10 @@ class Operation preview: -> range = @getBufferRange() - prefix = @lineText[0...range.start.column] - match = @lineText[range.start.column...range.end.column] - suffix = @lineText[range.end.column..] + line = @getBuffer().lineForRow(range.start.row) + prefix = line[0...range.start.column] + match = line[range.start.column...range.end.column] + suffix = line[range.end.column..] {prefix, suffix, match, range} From f33a8538e3ab2144d1cc836870d837e7ac530653 Mon Sep 17 00:00:00 2001 From: Garen Torikian Date: Tue, 2 Apr 2013 14:57:20 -0700 Subject: [PATCH 37/54] Bump nak version to allow for multiple matches --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bed01f2da..437fcb20a 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "coffee-cache": "0.1.0", "pegjs": "0.7.0", "async": "0.2.6", - "nak": "0.2.7", + "nak": "0.2.8", "spellchecker": "0.2.0", "plist": "git://github.com/nathansobo/node-plist.git", "space-pen": "git://github.com/nathansobo/space-pen.git" From 79ac5d606d523512e69a67d2f433591f1bff0ce0 Mon Sep 17 00:00:00 2001 From: Garen Torikian Date: Tue, 2 Apr 2013 15:39:40 -0700 Subject: [PATCH 38/54] Bump nak again --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 437fcb20a..babfbd378 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "coffee-cache": "0.1.0", "pegjs": "0.7.0", "async": "0.2.6", - "nak": "0.2.8", + "nak": "0.2.9", "spellchecker": "0.2.0", "plist": "git://github.com/nathansobo/node-plist.git", "space-pen": "git://github.com/nathansobo/space-pen.git" From 955e1571a2677a84e8e7883d1abf3b98f1331680 Mon Sep 17 00:00:00 2001 From: Garen Torikian Date: Tue, 2 Apr 2013 16:40:32 -0700 Subject: [PATCH 39/54] Bump nak version to add @kevinsawicki changes --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index babfbd378..9cae1eb37 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "coffee-cache": "0.1.0", "pegjs": "0.7.0", "async": "0.2.6", - "nak": "0.2.9", + "nak": "0.2.10", "spellchecker": "0.2.0", "plist": "git://github.com/nathansobo/node-plist.git", "space-pen": "git://github.com/nathansobo/space-pen.git" From 34ca5ce9490c57faf33d100a82dfcbb98749f73a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 2 Apr 2013 16:49:17 -0700 Subject: [PATCH 40/54] nak no longer includes a space after the colon --- spec/app/project-spec.coffee | 2 +- src/app/project.coffee | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/app/project-spec.coffee b/spec/app/project-spec.coffee index 5faf96952..48f483fc5 100644 --- a/spec/app/project-spec.coffee +++ b/spec/app/project-spec.coffee @@ -247,7 +247,7 @@ describe "Project", -> stdout = BufferedProcess.prototype.bufferStream.argsForCall[0][1] stdout ":#{fs.resolveOnLoadPath('fixtures/dir/a')}\n" - stdout "1;0 3: aaa bbb\n2;3 2: cc aa cc\n" + stdout "1;0 3:aaa bbb\n2;3 2:cc aa cc\n" expect(iterator.argsForCall[0][0]).toEqual path: project.resolve('a') diff --git a/src/app/project.coffee b/src/app/project.coffee index 220c468a9..0ad04ed57 100644 --- a/src/app/project.coffee +++ b/src/app/project.coffee @@ -165,9 +165,9 @@ class Project state = 'readingPath' path = null else - colonIndex = line.indexOf(': ') + colonIndex = line.indexOf(':') matchInfo = line.substring(0, colonIndex) - lineText = line.substring(colonIndex + 2) + lineText = line.substring(colonIndex + 1) readMatches(matchInfo, lineText) readMatches = (matchInfo, lineText) -> From 22af597c429e9d718a1147a8436695856068636c Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 2 Apr 2013 16:50:53 -0700 Subject: [PATCH 41/54] :lipstick: --- src/packages/command-panel/lib/command-panel-view.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/packages/command-panel/lib/command-panel-view.coffee b/src/packages/command-panel/lib/command-panel-view.coffee index 487af1730..13d773e41 100644 --- a/src/packages/command-panel/lib/command-panel-view.coffee +++ b/src/packages/command-panel/lib/command-panel-view.coffee @@ -92,8 +92,8 @@ class CommandPanelView extends View @miniEditor.focus() onExpandAll: (event) => - @previewList.expandAllPaths() - @previewList.focus() + @previewList.expandAllPaths() + @previewList.focus() onCollapseAll: (event) => @previewList.collapseAllPaths() From acf538cf4b49d10b09ab32acbb1d36f8c8d3aa62 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 3 Apr 2013 08:18:00 -0700 Subject: [PATCH 42/54] Remove unused aborted ivar --- src/packages/fuzzy-finder/lib/load-paths-task.coffee | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/packages/fuzzy-finder/lib/load-paths-task.coffee b/src/packages/fuzzy-finder/lib/load-paths-task.coffee index 538aac6ba..038da2f5f 100644 --- a/src/packages/fuzzy-finder/lib/load-paths-task.coffee +++ b/src/packages/fuzzy-finder/lib/load-paths-task.coffee @@ -4,8 +4,6 @@ $ = require 'jquery' module.exports = class LoadPathsTask - aborted: false - constructor: (@callback) -> start: -> @@ -34,7 +32,6 @@ class LoadPathsTask deferred abort: -> - @aborted = true if @process? @process.kill() @process = null From 320d177038579c7ba7a6e8a8e8fa19b27cfc4d38 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 3 Apr 2013 08:19:04 -0700 Subject: [PATCH 43/54] Use consistent quotes --- src/packages/fuzzy-finder/lib/load-paths-task.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/packages/fuzzy-finder/lib/load-paths-task.coffee b/src/packages/fuzzy-finder/lib/load-paths-task.coffee index 038da2f5f..0849f5a87 100644 --- a/src/packages/fuzzy-finder/lib/load-paths-task.coffee +++ b/src/packages/fuzzy-finder/lib/load-paths-task.coffee @@ -14,8 +14,8 @@ class LoadPathsTask command = require.resolve 'nak' args = ['-l', rootPath] - args.unshift("--addVCSIgnores") if config.get('nak.addVCSIgnores') - args.unshift("-d", ignoredNames.join(',')) if ignoredNames.length > 0 + args.unshift('--addVCSIgnores') if config.get('nak.addVCSIgnores') + args.unshift('-d', ignoredNames.join(',')) if ignoredNames.length > 0 paths = [] deferred = $.Deferred() @@ -26,7 +26,7 @@ class LoadPathsTask @callback(paths) deferred.resolve() stdout = (data) -> - paths = paths.concat(_.compact(data.split("\n"))) + paths = paths.concat(_.compact(data.split('\n'))) @process = new BufferedProcess({command, args, stdout, exit}) deferred From 2dc1817807e4aff179a15624af603a5151bcc9d8 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 3 Apr 2013 08:24:31 -0700 Subject: [PATCH 44/54] Push new paths onto existing array --- src/packages/fuzzy-finder/lib/load-paths-task.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/packages/fuzzy-finder/lib/load-paths-task.coffee b/src/packages/fuzzy-finder/lib/load-paths-task.coffee index 0849f5a87..6342a9f9e 100644 --- a/src/packages/fuzzy-finder/lib/load-paths-task.coffee +++ b/src/packages/fuzzy-finder/lib/load-paths-task.coffee @@ -26,7 +26,7 @@ class LoadPathsTask @callback(paths) deferred.resolve() stdout = (data) -> - paths = paths.concat(_.compact(data.split('\n'))) + paths.push.apply(paths, _.compact(data.split('\n'))) @process = new BufferedProcess({command, args, stdout, exit}) deferred From 917fbaadad5b038e5149fcebd93e761aa87635b3 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 3 Apr 2013 08:27:36 -0700 Subject: [PATCH 45/54] Use splat instead of apply --- src/packages/fuzzy-finder/lib/load-paths-task.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/packages/fuzzy-finder/lib/load-paths-task.coffee b/src/packages/fuzzy-finder/lib/load-paths-task.coffee index 6342a9f9e..cc10cb2a2 100644 --- a/src/packages/fuzzy-finder/lib/load-paths-task.coffee +++ b/src/packages/fuzzy-finder/lib/load-paths-task.coffee @@ -26,7 +26,7 @@ class LoadPathsTask @callback(paths) deferred.resolve() stdout = (data) -> - paths.push.apply(paths, _.compact(data.split('\n'))) + paths.push(_.compact(data.split('\n'))...) @process = new BufferedProcess({command, args, stdout, exit}) deferred From aa8fb3eb4bee8f450638e146d2c75753d5f8557f Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 3 Apr 2013 08:33:16 -0700 Subject: [PATCH 46/54] Add failing symlink spec --- .../fuzzy-finder/spec/fuzzy-finder-spec.coffee | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/packages/fuzzy-finder/spec/fuzzy-finder-spec.coffee b/src/packages/fuzzy-finder/spec/fuzzy-finder-spec.coffee index c71a090c5..9b9a5b983 100644 --- a/src/packages/fuzzy-finder/spec/fuzzy-finder-spec.coffee +++ b/src/packages/fuzzy-finder/spec/fuzzy-finder-spec.coffee @@ -60,6 +60,17 @@ describe 'FuzzyFinder', -> expect(finderView.list.children().first()).toHaveClass 'selected' expect(finderView.find(".loading")).not.toBeVisible() + it "includes symlinked file paths", -> + rootView.attachToDom() + finderView.maxItems = Infinity + rootView.trigger 'fuzzy-finder:toggle-file-finder' + + waitsFor "all project paths to load", 5000, -> + not finderView.reloadProjectPaths + + runs -> + expect(finderView.list.find("li:contains(symlink-to-file)")).toExist() + describe "when root view's project has no path", -> beforeEach -> project.setPath(null) From ee1585538321a96ba944a5e86778f301ede98961 Mon Sep 17 00:00:00 2001 From: Garen Torikian Date: Wed, 3 Apr 2013 11:04:15 -0700 Subject: [PATCH 47/54] Bump nak --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9cae1eb37..f957af416 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "coffee-cache": "0.1.0", "pegjs": "0.7.0", "async": "0.2.6", - "nak": "0.2.10", + "nak": "0.2.11", "spellchecker": "0.2.0", "plist": "git://github.com/nathansobo/node-plist.git", "space-pen": "git://github.com/nathansobo/space-pen.git" From e1761418468b7361f4d163fd41e113ed262f664e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 3 Apr 2013 11:22:20 -0700 Subject: [PATCH 48/54] Follow symlinks loading paths --- src/packages/fuzzy-finder/lib/load-paths-task.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/packages/fuzzy-finder/lib/load-paths-task.coffee b/src/packages/fuzzy-finder/lib/load-paths-task.coffee index cc10cb2a2..530ade9dc 100644 --- a/src/packages/fuzzy-finder/lib/load-paths-task.coffee +++ b/src/packages/fuzzy-finder/lib/load-paths-task.coffee @@ -16,6 +16,7 @@ class LoadPathsTask args = ['-l', rootPath] args.unshift('--addVCSIgnores') if config.get('nak.addVCSIgnores') args.unshift('-d', ignoredNames.join(',')) if ignoredNames.length > 0 + args.unshift('--follow') paths = [] deferred = $.Deferred() From 19cf333e52fa93e24bf57ecf3aefe07d425d9819 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 3 Apr 2013 11:22:35 -0700 Subject: [PATCH 49/54] Use long opts for readability --- src/packages/fuzzy-finder/lib/load-paths-task.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/packages/fuzzy-finder/lib/load-paths-task.coffee b/src/packages/fuzzy-finder/lib/load-paths-task.coffee index 530ade9dc..496693a3c 100644 --- a/src/packages/fuzzy-finder/lib/load-paths-task.coffee +++ b/src/packages/fuzzy-finder/lib/load-paths-task.coffee @@ -13,9 +13,9 @@ class LoadPathsTask ignoreGitIgnoredFiles = config.get('core.hideGitIgnoredFiles') command = require.resolve 'nak' - args = ['-l', rootPath] + args = ['--list', rootPath] args.unshift('--addVCSIgnores') if config.get('nak.addVCSIgnores') - args.unshift('-d', ignoredNames.join(',')) if ignoredNames.length > 0 + args.unshift('--ignore', ignoredNames.join(',')) if ignoredNames.length > 0 args.unshift('--follow') paths = [] From ace71acb3c2b387ca9142aa332314770d400f86b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 3 Apr 2013 11:34:27 -0700 Subject: [PATCH 50/54] Invoke callback even when command fails --- src/packages/fuzzy-finder/lib/load-paths-task.coffee | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/packages/fuzzy-finder/lib/load-paths-task.coffee b/src/packages/fuzzy-finder/lib/load-paths-task.coffee index 496693a3c..77d5b4c0b 100644 --- a/src/packages/fuzzy-finder/lib/load-paths-task.coffee +++ b/src/packages/fuzzy-finder/lib/load-paths-task.coffee @@ -1,6 +1,5 @@ _ = require 'underscore' BufferedProcess = require 'buffered-process' -$ = require 'jquery' module.exports = class LoadPathsTask @@ -19,18 +18,12 @@ class LoadPathsTask args.unshift('--follow') paths = [] - deferred = $.Deferred() - exit = (code) => - if code is -1 - deferred.reject({command, code}) - else - @callback(paths) - deferred.resolve() + exit = => + @callback(paths) stdout = (data) -> paths.push(_.compact(data.split('\n'))...) @process = new BufferedProcess({command, args, stdout, exit}) - deferred abort: -> if @process? From 0b3a91b5feb6f38734c144cd48f8df5ce278cb6b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 3 Apr 2013 11:35:24 -0700 Subject: [PATCH 51/54] Rename VCS ignore config setting to fuzzyFinder.hideVcsIgnoredPaths --- src/packages/fuzzy-finder/lib/load-paths-task.coffee | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/packages/fuzzy-finder/lib/load-paths-task.coffee b/src/packages/fuzzy-finder/lib/load-paths-task.coffee index 77d5b4c0b..fab6e99cc 100644 --- a/src/packages/fuzzy-finder/lib/load-paths-task.coffee +++ b/src/packages/fuzzy-finder/lib/load-paths-task.coffee @@ -9,11 +9,10 @@ class LoadPathsTask rootPath = project.getPath() ignoredNames = config.get('fuzzyFinder.ignoredNames') ? [] ignoredNames = ignoredNames.concat(config.get('core.ignoredNames') ? []) - ignoreGitIgnoredFiles = config.get('core.hideGitIgnoredFiles') command = require.resolve 'nak' args = ['--list', rootPath] - args.unshift('--addVCSIgnores') if config.get('nak.addVCSIgnores') + args.unshift('--addVCSIgnores') if config.get('fuzzyFinder.hideVcsIgnoredPaths') args.unshift('--ignore', ignoredNames.join(',')) if ignoredNames.length > 0 args.unshift('--follow') From a5870cedd201cb786182ad8990fc92c0dd8f312a Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 3 Apr 2013 11:45:55 -0700 Subject: [PATCH 52/54] Use more generic core.excludeVcsIgnoredPaths config key --- src/app/project.coffee | 2 +- src/packages/fuzzy-finder/lib/load-paths-task.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/project.coffee b/src/app/project.coffee index 3d50f6272..bc4c6187e 100644 --- a/src/app/project.coffee +++ b/src/app/project.coffee @@ -193,7 +193,7 @@ class Project command = require.resolve('nak') args = ['--ackmate', regex.source, @getPath()] - args.unshift("--addVCSIgnores") if config.get('nak.addVCSIgnores') + args.unshift("--addVCSIgnores") if config.get('core.excludeVcsIgnoredPaths') new BufferedProcess({command, args, stdout, exit}) deferred diff --git a/src/packages/fuzzy-finder/lib/load-paths-task.coffee b/src/packages/fuzzy-finder/lib/load-paths-task.coffee index fab6e99cc..fff7c0b5e 100644 --- a/src/packages/fuzzy-finder/lib/load-paths-task.coffee +++ b/src/packages/fuzzy-finder/lib/load-paths-task.coffee @@ -12,7 +12,7 @@ class LoadPathsTask command = require.resolve 'nak' args = ['--list', rootPath] - args.unshift('--addVCSIgnores') if config.get('fuzzyFinder.hideVcsIgnoredPaths') + args.unshift('--addVCSIgnores') if config.get('core.excludeVcsIgnoredPaths') args.unshift('--ignore', ignoredNames.join(',')) if ignoredNames.length > 0 args.unshift('--follow') From a3ef9c204bb4d2d439cc006462a65339b348d2c0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 3 Apr 2013 13:28:34 -0700 Subject: [PATCH 53/54] Use repository URL for nak dependency This is temporary until https://github.com/gjtorikian/nak/pull/17/files is merged and released. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f957af416..1d2e2541e 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "coffee-cache": "0.1.0", "pegjs": "0.7.0", "async": "0.2.6", - "nak": "0.2.11", + "nak": "git://github.com/kevinsawicki/nak.git", "spellchecker": "0.2.0", "plist": "git://github.com/nathansobo/node-plist.git", "space-pen": "git://github.com/nathansobo/space-pen.git" From d1fd3c8d7c69ef7d70d274a4f76c81f69a3e6481 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 3 Apr 2013 13:54:35 -0700 Subject: [PATCH 54/54] Invoke callback with empty array on non-zero exit code --- src/packages/fuzzy-finder/lib/load-paths-task.coffee | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/packages/fuzzy-finder/lib/load-paths-task.coffee b/src/packages/fuzzy-finder/lib/load-paths-task.coffee index fff7c0b5e..bb358db8e 100644 --- a/src/packages/fuzzy-finder/lib/load-paths-task.coffee +++ b/src/packages/fuzzy-finder/lib/load-paths-task.coffee @@ -17,8 +17,11 @@ class LoadPathsTask args.unshift('--follow') paths = [] - exit = => - @callback(paths) + exit = (code) => + if code is 0 + @callback(paths) + else + @callback([]) stdout = (data) -> paths.push(_.compact(data.split('\n'))...)