Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

[WIP] Drop find and grep in favor of ag / nak #2369

Open
wants to merge 45 commits into from
@gjtorikian

This PR represents a culmination of various 20% time I took over the last few weeks. It is designed to drop support for find/grep for filelist and search. Pull up a chair and a cup of coffee while I describe a change for a feature no one asked for. :sweat_smile:

Why?

find/grep should be dropped for the following reasons:

  1. The code is hard to maintain. (I should know, I wrote or worked on a lot of it.)
    The code is a mess because we have to account for several annoyances, such as BSD vs. GNU flavors, bash-strings-as-scripts passing (which requires all sorts of escaping functions), and, in the case of find/grep missing, we actually compile PCRE support to provide our own binaries.
  2. There's no Windows support. Conceivably, a user could SSH into a Windows box and run Cloud9. Dependence on find/grep limits this.
  3. There's no easy way to maintain a list of accepted file types and ignored directories (see below for more). For example, we aren't overlooking *-backup~ from sm or .c9revisions.
  4. There's no support for users to define their own search settings or exclusions.
  5. There's no support (or simple support) for files without extensions.
    Want to search a Makefile, or a script starting with #!/usr/bin/env? Our current method of assembling in Javascript, writing a grep search, and tossing it over to the system via bash -c isn't supporting this. Good luck figuring out where to start.
  6. It's slow--slow enough to not overlook all the other deficiencies listed above.

At first, I was pretty keen on just supporting ack to overcome all of this. It's written in Perl, it supports ignore files, and it should be good enough, right?

Well, not quite.

Advantages and Problems with Ack

ack 1.96, which is the current stable version, maintains a list of "safe" code files (with and without extensions). In fact, the current searchinfiles code was designed to emulate ack's behavior, and contains a list of known extensions to use.

ack 2.0 will move beyond using extensions to define files. This makes complete sense: every day another new technology drops, and no one wants to keep maintaining a list to add items like .jade, .scss, .styl and so on. So, ack 2.0 uses Perl's -B switch to determine if a file is binary. If it's not, it's searched. Perfect.

Unfortunately, ack 2.0 is alpha, and has been "under development" for around two years. As such, it doesn't really hold up to its promises of just searching non-binary. On top of all that, relying on ack for the filelist module wouldn't work, because it really doesn't even list binary files--it just outright ignores them.

Rather than hack up a solution in Perl, I went and chose something else.

About Ag

ag is written in C. It's fast. It supports all of the above mentioned requirements (can list binaries, but only searches text; allows users to provide their own search settings; supports Windows, e.t.c.), and can be used to replace both find and grep.

Perfect! I figured I would just use ag, and, for replacing files, continue our technique of just using Perl to replace file contents.

Then, I had a panic attack. What if, conceivably, a user's machine didn't have Perl? They'd be SOL. So I needed another solution for replacing contents in files that didn't use Perl.

Enter Nak

After reading Felix's Faster than C notes, I became inspired to just write a fast ack clone, in Node.js. After all, if a user is SSHing into a box, it is guaranteed that they have Node.js installed.

Previously, TJ had written an ack clone in Node, but his code was not very performant. At least, it was slower than ack.

I benchmarked and rewrote and learned a lot. I created nak which, while not supporting everything ack does, does nearly everything ag does, at least, and 100% supports everything we need for Cloud9.

Benchmarks

You like numbers? Me too. They're fun.

Here's the average time for grabbing the filelist in cloud9infra five times (about 33,761 files). The commands do the exact same thing (get hidden files, e.t.c.) and exclude the same nonsense directories ( .git, .c9revisions, sm backups, e.t.c.). :

ag nak ack find
0m0.184s 0m0.940s 0m1.103s 0m1.093s

Here are benchmarks for finding the phrase "va" in cloud9infra:

ag nak ack grep
0m2.599s 0m20.021s 0m29.876s 0m20.891s

What ends up happening is that, with ag, the filelist comes up before the IDE even finishes initializing. Similarly, search results return before the panel finishes animating up. It's some impressive shit.

Ignoring Files

There are now three ways to ignore files:

  1. With a standard Cloud9 IDE .agignore file. This will be loaded for every filelist and searchinfiles command. It follows gitignore-style wildcards. It excludes uninteresting directories, minified JS files, and Cloud9 extraneous content. This makes mainting our own rule-list much, much easier.

  2. Users can define their own .agignore on a per-directory basis in their workspaces.

  3. While searching, users can exclude filetypes with -; for example, -*_test.js excludes all Javascript files ending with "_test.js".

Testing

Mike did a huge favor by rewriting the tests to be compatible with Mocha. I extended his test suite, and also duplicated the commands, one for ag and one for nak; each test also validates that the results of ag and nak are the exact same.

Final Thoughts

My idea is that we provide various binaries for ag, and, in the case that we don't support a platform, we fall back to nak.

By my count, we're missing the following binaries:

  • freebsd
  • sunos
  • win32

In any event, though, all these binaries are built on an 64-bit machines, and if I learned anything from working on Cloud9 Local, it's that people are still using 32-bit machines (I tried to bundle x64 Node binaries for users without Node on their machine, and it wouldn't work for those running x32).

We won't really need to continue dropping new ag binaries, since it's currently fast enough, and, through the mocha tests, we've already covered every feature we need at the moment.

A more real problem, though, is that I'm not at all sure if one Linux binary (built on Ubuntu) will support other Linux distros (Fedora, CentOS, Gentoo...). If that's the case, then we should definitely fall back to nak. I couldn't figure out a way--using process or the os module--to see if we could specifically identify the type of the Linux distro.

Finally, it'd be great to also pull in these two PRs, which rename the packed files to end in .min.js:

I had a lot of fun writing performant Node code. Hooray!

@ajaxorg/liskov

@lennartcl @mostafaeweda @nightwing (as seen above, I am pretty sure non-team members cannot @ a team).

@ggreer

If I ever add user quotes to the Ag readme, "It's some impressive shit." is definitely going in there.

Just FYI, Windows support is almost certainly broken in Ag by now. I barely had it working back in 0.1. The wiki and readme are out of date. :(

But all the other OSes should be fine, including FreeBSD and Solaris.

@mattpardee

This is perhaps the most epic PR I've ever seen. Lots of thought and care obviously went into this.

Just one problem: We're going to have to make the console output bar slide up faster.

Great job Garen.

@basdewachter

Very impressive PR indeed. I like seeing you updated unit tests as well.

plugins-server/cloud9.ide.search/search.js
((26 lines not shown))
if (!query)
return;
- // grep has a funny way of handling new lines (that is to say, it's non-existent)
- // if we're not doing a regex search, then we must split everything between the
- // new lines, escape the content, and then smush it back together; due to
- // new lines, this is also why we're now passing -P as default to grep
- if (!options.replaceAll && !options.regexp) {
- var splitQuery = query.split("\\n");
+ if (this.env.useAg) {

This if statement should be split up into two separate plugins or code-files or anything. Makes unit testing also easier because switching environments isn't necessary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
plugins-server/cloud9.ide.filelist/filelist.js
((26 lines not shown))
});
};
+ this.isAgAvailable = function() {
+ return Fs.existsSync(this.env.agCmd);

Uh wtf, sync code?!?!?!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
plugins-server/cloud9.ide.filelist/filelist.js
((5 lines not shown))
var Path = require("path");
+var Fs = require("fs");
+Fs.existsSync = Fs.existsSync || Path.existsSync;

My eyes!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
plugins-server/cloud9.ide.filelist/filelist-plugin.js
((17 lines not shown))
Filelist.setEnv({
- findCmd: options.findCmd,
- platform: options.platform
+ platform: platform,
+ arch: arch,
+ agCmd: options.agCmd || path.join(__dirname, "..", "cloud9.ide.search", [platform, arch].join("_"), "ag"),

So why isn't this logic all in the config?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@janjongboom

I'd rather have plugins-server/cloud9.ide.search/darwin_x64/ag (plus evt. other builds) in a separate repo like we always do.

plugins-server/cloud9.ide.search/search.js
((25 lines not shown))
});
};
+ this.isAgAvailable = function() {
+ return Fs.existsSync(this.env.agCmd);
@sergi
sergi added a note

Please, make it async!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@zefhemel

I Instapaper'ed this pull request.

@janjongboom

Maybe we should publish it through http://www.lulu.com/

@gjtorikian

@ggreer Thanks for the head's up, and thanks for your work on ag.

@sergi @janjongboom Sheesh, so much anger for such a tiny synch! Ok, I took the sync logic out; I also split the ag/nak "assembleCommands" logic into two separate files. This also cleans up the setEnv stuff considerably because, as Jan points out, we're not ever really going to switch environments.

@sergi

Sorry Garen, I didn't want to transmit any anger about that! It is just that the sync/async stuff is an ongoing theme here, and we were just being idiots by over-commenting on it.

This is the most impressive PR I've seen, if only everybody put some thought on explaining PR rationale like you did the world would be definitely a better place. Or more documented, at least :)

Thanks for this, I've been waiting for ag super-speed for so long!!

@janjongboom

So here's one other idea: if we load the ack/ng stuff through architect the code between switching can be done in config rather than in the plugin itself.

@zefhemel

Question: once this is into cloud9 OSS. How can we deploy this in infra? For the gear projects we can just rsync in a few binaries, but what about SSH projects? We currently are very hands-off and don't intall any tools into SSH projects.

@janjongboom

Fall back on nak when it's not present? Currently we assume that grep is on the machines, so this is already better.

@zefhemel

Right, but then we have to somehow load that into node process with VFS. I think now it just runs it as an external exec call, but I may have read that wrong.

@janjongboom

But that'll work just fine on SSH machines?

@zefhemel

@janjongboom Will nack be installed on the SSH machine? If so, how?

@gjtorikian

So here's one other idea: if we load the ack/ng stuff through architect the code between switching can be done in config rather than in the plugin itself.

@janjongboom I'm not really clear on how to do this. I guess I would do something like:

    {
        packagePath: "./cloud9.ide.search",
        useAg: true
    },

and then use that property later on?

@janjongboom

No, Ag en Nak both have a plugin, and they both provide a file-searcher thingy or something. In the config we'll load either one of them and cloud9.ide.search only consumes the file-searcher.

@gjtorikian

I factored out the plugins into their own separate modules but didn't have time to redo the tests. I'll likely finish that up tomorrow and hopefully this can get merged soon ?

@gjtorikian

Oh hell, who needs sleep.

We now have two plugins, cloud9.search.ag and search.nak, that provide the "codesearcher" function. (filesearch and codesearch were already taken by cloud9.fs. damn).

default.js determines when to use which plugin. filelist and searchinfiles just consume it. tests have been rewritten to take account for this change and they're passing.

@gjtorikian

There was a known issue in ag that directory globs were not being properly ignored: ggreer/the_silver_searcher#100

I updated the ag binaries and the tests to support directory ignoring. I also found a bug around this in nak, and updated that package as well.

@gjtorikian

@basdewachter BTW why are some tests skipped?

./plugins-server/cloud9.ide.filelist/filelist_test.js SKIPPED
./plugins-server/cloud9.ide.revisions/revisions_test.js SKIPPED
./plugins-server/cloud9.ide.search/search_test.js SKIPPED
@sergi

@gjtorikian Because they are blacklisted, they are obsolete and have to be updated. My PR #2301 re-enables the revisions one, but unfortunately it has been waiting for a month.

@sergi

Pinging @ajaxorg/liskov to review this soon. There is a lot of work and awesomeness put into this PR.

@mostafaeweda mostafaeweda was assigned
@mostafaeweda

I see beautiful stuff here
However, I wonder how come after all those comments & still pinging someone from liskov to review this !

Some review: remarks:

  • The tests included are mocha tests & they didn't work for when used mocha. can it be changed to asyncjs tests ? & checked to not fail ?
@gjtorikian

@mostafaeweda See above--these tests are marked as ignored anyway so they're not running.

Plus, it was @mikedeboer who originally converted/wrote these tests into mocha. My understanding is that those sorts of tests will be supported soon.

Also very interesting that it begin to fail after your commits :) So I'll see why that happened suddenly.

@mostafaeweda

Yes, strange ! - I double checked my changes because of that :)

Also, plz include a c9 infra PR representing how will this (work / fallback) in various configurations: ssh, ftp & openshift ?

@gjtorikian

@mostafaeweda Ok I found the root cause and fixed the problem.

The build server uses linux_ia32 as their os_architecture. The tests, unlike the code, does not check if "ag" is present on a machine before running. I changed the test to only run ag if the binary is still there.

On top of that, I decided to build the 32-bit linux binary for ag, so that our tests pass with ag (and it'll help users sshing into such machines). Hooray!

plugins-server/cloud9.search.nak/codesearcher-nak.js
((5 lines not shown))
+ * @license GPLv3 <http://www.gnu.org/licenses/gpl.txt>
+ */
+
+"use strict";
+
+var path = require("path");
+
+module.exports = function setup(options, imports, register) {
+ var nakCmd = options.nakCmd;
+
+ var codesearcher = {
+ assembleFilelistCommand: function (options) {
+ var args;
+
+ args = ["-l", // filenames only
+ "-p", path.join(__dirname, "..", "cloud9.ide.search", ".agignore")]; // use the Cloud9 ignore file
@nightwing Owner

i think this won't work over vfs, since in that case args are sent to remote machine where __dirname doesn't exist

With who can I confirm this further? It works on EC2/cloud9infra so I'm not sure what else to check.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@piscisaureus

@ggreer

Just FYI, Windows support is almost certainly broken in Ag by now. I barely had it working back in 0.1. The wiki and readme are out of date. :(

What is the issue with that? I can probably help you out here.

PS, do I know you as angryparsley or did I get some people mixed up?

@gjtorikian

Ah yeah, this whole house of cards has come tumbling down. @nightwing was right (for a different reason), this apparently does not work on cloud9infra. At least, I couldn't get the right paths for either ag or nak after cloning a project and placing it on an openshift server.

This makes me sad. I'll need someone's help figuring this piecing out, because I'm not sure how the architecture works in this area.

@ggreer

@piscisaureus

I don't know. I don't have a Windows VM anymore. I added pthreads a little while ago, and that's not something that normally comes with Windows. There are probably a couple other issues, but the code itself shouldn't be that hard to port. I've made sure it's always C89 in the hopes that Visual Studio could one day compile it.

Also yes I am AngryParsley. Small world!

@janjongboom

@gjtorikian Put it in the c9pm repo and run c9pm install ag on first use of the plugin? (Can even do this from the client, we have some nifty 'run this on server' command that we use for deployments as well. if which heroku doesnt result into anything -> install tools). After that it's always in the same place (~/lib/pkg/ag f.e.)

@mostafaeweda

Maybe easier & better to put it on the shared gear
We now have openshift shared space among all gears
in openshift.js
PATH += ":/usr/libexec/openshift/cartridges/c9-0.1/root/bin"
& add all the needed binaries there (ag, node 0.6 & node 0.8, ....etc)

That maybe better than waiting for installation & syncing stuff to gears

@janjongboom

Yes that seems nicer

@gjtorikian

Will putting it in openshift.js work for SSH machines? @mostafaeweda

@zefhemel

No, that is a good point...

@mostafaeweda

For SSH machines, it won't either have the c9pm command
We have to fallback to something
Maybe back to find & grep :-1: ?
OR how SSH machines will have that anyway ?

@zefhemel

Or we upload a OS-specific binary, but that's nasty. Or we require the tool to be installed, if it's not, we show instructions on how to do that.

@mostafaeweda

Can't we run something like npm install -g nack upon connection initiation with SSH machines ?

@zefhemel

That could work. Generally I'm not a big fan of installing stuff in our SSH workspaces, but in this case it may be the best way to go.

@gjtorikian

What if we just stop nak as an npm dependency, and I just rewrite the search plugin to use the nak code ?

At this point, any updates to the code would be made for performance reasons. We don't have to have it as a separate NPM module.

@zefhemel

That code still has to make it to the SSH server/gear right? Perhaps a VFS extension can be used for that. Maybe @creationix could help out there.

@gjtorikian

In case someone is out there thinking "dear Lord what's going on with this PR?!" we've decided to drop the ag binaries (sorry @ggreer :( ) and implement a pure Node solution that's going to be streamed through a VFS extension to work on openshift and ssh.

On top of that, I did some optimizations that turned the above searched in cloud9infra from 20s to 11s. That's damned good enough.

@c9bot
Collaborator

Build Status: :broken_heart: Failed (17bd2ce, job info)

@c9bot
Collaborator

Build Status: :broken_heart: Failed (97c32a1, job info)

@c9bot
Collaborator

Build Status: :broken_heart: Failed (56b06bd, job info)

@sergi

Dear Lord what's going on with this PR?!

@gjtorikian

I already explained, @sergi !!!!!!

No but nak now works nicely with VFS; @mattpardee has more info on this, as he's got a project using it.

@gjtorikian gjtorikian referenced this pull request in atom/atom
Closed

Consider using nak instead of ack #129

@javruben
Owner

I'm gonna make sure this PR gets into Cloud9 v3. This is epic.

@sergi

:+1: BLAZING fast!

@gjtorikian

Hey guys, glad you like it. :)

I made some non-insignificant changes recently and bumped the minor version to 0.2.0. As far as I can remember, nothing should break regarding Cloud9's implementation.

I did also, however, drop a huge boatload of changes to shave something like another 150ms off large queries. This will come out in 0.2.1 in the next few days. If you guys need or want something please let me know or log an issue and I'll make it happen.

@javruben
Owner

@gjtorikian I need your help! :). Please talk to me on Skype, Cell or Mail. Thanks!

@mansona

Hey Guys, any update on this? I don't see it marked as any milestone and it's been quite for quite a while now

@javruben
Owner
@mansona

So.. will it be committed to this repo when it is done?

@javruben
Owner

We'll release that new version as OSS, yes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jul 2, 2012
  1. @gjtorikian

    Add ack

    gjtorikian authored
Commits on Aug 27, 2012
  1. @gjtorikian
Commits on Aug 31, 2012
  1. @gjtorikian
Commits on Sep 1, 2012
  1. @gjtorikian

    Stash initial work for ag

    gjtorikian authored
  2. @gjtorikian

    Stash

    gjtorikian authored
  3. @gjtorikian

    New ag, update filelist.

    gjtorikian authored
Commits on Sep 4, 2012
  1. @gjtorikian

    Update work

    gjtorikian authored
  2. @gjtorikian

    Continue updates

    gjtorikian authored
Commits on Sep 5, 2012
  1. @gjtorikian

    Stash binary

    gjtorikian authored
Commits on Sep 25, 2012
  1. @gjtorikian

    Stash

    gjtorikian authored
Commits on Oct 6, 2012
  1. @gjtorikian

    Mergee master

    gjtorikian authored
  2. @gjtorikian
  3. @gjtorikian

    Start ack work

    gjtorikian authored
Commits on Oct 8, 2012
  1. @gjtorikian

    Start ack support

    gjtorikian authored
Commits on Oct 15, 2012
  1. @gjtorikian

    Quick update of agignore

    gjtorikian authored
  2. @gjtorikian

    More updates

    gjtorikian authored
Commits on Oct 26, 2012
  1. @gjtorikian
  2. @gjtorikian
  3. @gjtorikian

    Merge master

    gjtorikian authored
  4. @gjtorikian

    Fully functional

    gjtorikian authored
  5. @gjtorikian

    Testing updates

    gjtorikian authored
  6. @gjtorikian

    Add linux/openshift binary

    gjtorikian authored
  7. @gjtorikian

    Update test

    gjtorikian authored
Commits on Oct 27, 2012
  1. @gjtorikian
  2. @gjtorikian
Commits on Oct 28, 2012
  1. @gjtorikian
Commits on Oct 29, 2012
  1. @gjtorikian

    By default, colors are off

    gjtorikian authored
  2. @gjtorikian

    Add hint in searchinfiles

    gjtorikian authored
  3. @gjtorikian

    Add license file

    gjtorikian authored
Commits on Oct 30, 2012
  1. @gjtorikian
Commits on Nov 1, 2012
  1. @gjtorikian

    Remove unneeded FS

    gjtorikian authored
  2. @gjtorikian

    Remove unneeded FS

    gjtorikian authored
Commits on Nov 7, 2012
  1. @gjtorikian
  2. @gjtorikian
Commits on Nov 8, 2012
  1. @mostafaeweda

    Some cleanup

    mostafaeweda authored
  2. @mostafaeweda
  3. @mostafaeweda

    Fix failing node 0.6

    mostafaeweda authored
  4. @gjtorikian

    Update ag binary for linux

    gjtorikian authored
  5. @gjtorikian

    Update ag binary for osx

    gjtorikian authored
Commits on Nov 9, 2012
  1. @gjtorikian
  2. @gjtorikian
  3. @gjtorikian
Commits on Nov 29, 2012
  1. @gjtorikian

    Merge master

    gjtorikian authored
Commits on Nov 30, 2012
  1. @gjtorikian
  2. @gjtorikian
This page is out of date. Refresh to see the latest.
Showing with 776 additions and 460 deletions.
  1. +3 −0  configs/default.js
  2. +3 −2 package.json
  3. +15 −1 plugins-client/ext.searchinfiles/searchinfiles.js
  4. +1 −1  plugins-client/ext.searchinfiles/searchinfiles.xml
  5. +2 −5 plugins-server/cloud9.ide.filelist/filelist-plugin.js
  6. +14 −65 plugins-server/cloud9.ide.filelist/filelist.js
  7. +62 −25 plugins-server/cloud9.ide.filelist/filelist_test.js
  8. BIN  plugins-server/cloud9.ide.filelist/fixtures/level1/Toasty.gif
  9. +1 −0  plugins-server/cloud9.ide.filelist/fixtures/level1/level2/.level3a/.hidden
  10. +2 −1  plugins-server/cloud9.ide.filelist/package.json
  11. +20 −0 plugins-server/cloud9.ide.search/.nakignore
  12. +82 −0 plugins-server/cloud9.ide.search/fixtures/.file8_hidden.js
  13. +2 −0  plugins-server/cloud9.ide.search/fixtures/.nakignore
  14. +84 −0 plugins-server/cloud9.ide.search/fixtures/dir/file7_ignorable.rb
  15. +5 −0 plugins-server/cloud9.ide.search/fixtures/file1.txt
  16. +3 −0  plugins-server/cloud9.ide.search/fixtures/file2.txt
  17. +11 −0 plugins-server/cloud9.ide.search/fixtures/file3.txt
  18. +22 −0 plugins-server/cloud9.ide.search/fixtures/file4_noext
  19. +12 −0 plugins-server/cloud9.ide.search/fixtures/file5_not_really_image.gif
  20. +26 −0 plugins-server/cloud9.ide.search/fixtures/file6_contains_nonascii.dat
  21. +84 −0 plugins-server/cloud9.ide.search/fixtures/file9_ignored_by_this_dir.txt
  22. +2 −1  plugins-server/cloud9.ide.search/package.json
  23. +4 −7 plugins-server/cloud9.ide.search/search-plugin.js
  24. +21 −281 plugins-server/cloud9.ide.search/search.js
  25. +194 −71 plugins-server/cloud9.ide.search/search_test.js
  26. +89 −0 plugins-server/cloud9.search.nak/codesearcher-nak.js
  27. +12 −0 plugins-server/cloud9.search.nak/package.json
View
3  configs/default.js
@@ -3,6 +3,8 @@
var fs = require("fs");
var argv = require('optimist').argv;
var path = require("path");
+var os = require("os");
+fs.existsSync = fs.existsSync || path.existsSync;
var clientExtensions = {};
var clientDirs = fs.readdirSync(__dirname + "/../plugins-client");
@@ -201,6 +203,7 @@ var config = [
"./cloud9.ide.filelist",
"./cloud9.ide.search",
"./cloud9.ide.run-node",
+ "./cloud9.search.nak",
{
packagePath: "./cloud9.ide.run-npm-module",
allowShell: true
View
5 package.json
@@ -32,7 +32,8 @@
"smith": "0.1.9",
"smith.io": "0.0.36",
"vfs-architect": "0.0.2",
- "jsDAV": "0.2.3"
+ "jsDAV": "0.2.3",
+ "nak": "0.1.7"
},
"devDependencies": {
@@ -67,4 +68,4 @@
"build-debug": "node ./scripts/build-debug",
"build-packed": "node ./scripts/build-packed"
}
-}
+}
View
16 plugins-client/ext.searchinfiles/searchinfiles.js
@@ -164,6 +164,20 @@ module.exports = ext.register("ext/searchinfiles/searchinfiles", apf.extend({
});
});
+ tooltip.add(txtSFPatterns.$ext, {
+ message : txtSFPatterns.label,
+ width : "auto",
+ timeout : 0,
+ tooltip : tt,
+ animate : false,
+ getPosition : function(){
+ var pos = apf.getAbsolutePosition(winSearchInFiles.$ext);
+ var left = pos[0] + txtSFPatterns.getLeft();
+ var top = pos[1];
+ return [left, top - 16];
+ }
+ });
+
ide.addEventListener("aftereditorfocus", function(e) {
if (_self.searchConsole && _self.returnFocus)
_self.searchConsole.focus();
@@ -591,7 +605,7 @@ module.exports = ext.register("ext/searchinfiles/searchinfiles", apf.extend({
if (this.replaceAll)
replacement = "', replaced as '" + options.replacement ;
- return "Searching for '" + options.query + replacement + "' in " + path + optionsDesc + "\n";
+ return "Searching for '" + options.query + replacement + "' in " + path + " " + optionsDesc + "\n";
},
messageFooter : function(countJSON) {
View
2  plugins-client/ext.searchinfiles/searchinfiles.xml
@@ -16,7 +16,7 @@
onclick="require('ext/searchinfiles/searchinfiles').execFind()">Find</a:button>
</a:hbox>
<a:hbox padding="5" align="start" height="27" edge="0 85 0 126">
- <a:codebox id="txtSFPatterns" tabindex="1001" skin="searchbox" flex="1" initial-message="*.*" focusselect="true"/>
+ <a:codebox id="txtSFPatterns" tabindex="1001" skin="searchbox" flex="1" initial-message="*.*" label="Wildcards accepted. Prefix with - to exclude a pattern." focusselect="true"/>
<a:radiobutton margin="3 0 0 0"
group = "grpSFScope"
skin = "radio_black"
View
7 plugins-server/cloud9.ide.filelist/filelist-plugin.js
@@ -18,10 +18,6 @@ var name = "filelist";
module.exports = function setup(options, imports, register) {
var Filelist = new FilelistLib();
- Filelist.setEnv({
- findCmd: options.findCmd,
- platform: options.platform
- });
var Vfs = imports["vfs"];
var IdeRoutes = imports["ide-routes"];
@@ -34,6 +30,7 @@ module.exports = function setup(options, imports, register) {
this.ws = ide.workspace.workspaceId;
Filelist.setEnv({
+ searchType: imports["codesearcher"],
workspaceId: this.ws,
basePath: ide.workspace.workspaceDir
});
@@ -54,7 +51,7 @@ module.exports = function setup(options, imports, register) {
if (!uid)
return next(new error.Unauthorized());
- // does this user has read-permissions...
+ // does this user have read-permissions...
Permissions.getPermissions(uid, this.ws, "fs_filelist", function(err, perms) {
if (err)
return next(err);
View
79 plugins-server/cloud9.ide.filelist/filelist.js
@@ -7,23 +7,16 @@
"use strict";
-var Os = require("os");
+var Fs = require("fs");
var Path = require("path");
module.exports = function() {
- this.env = {
- findCmd: "find",
- perlCmd: "perl",
- platform: Os.platform(),
- basePath: "",
- workspaceId: ""
- };
+ this.env = { };
this.setEnv = function(newEnv) {
var self = this;
- Object.keys(this.env).forEach(function(e) {
- if (newEnv[e])
- self.env[e] = newEnv[e];
+ Object.keys(newEnv).forEach(function(e) {
+ self.env[e] = newEnv[e];
});
};
@@ -41,67 +34,23 @@ module.exports = function() {
if (Path.relative(this.env.basePath, options.path).indexOf("../") === 0)
return onExit(1, "Invalid path");
- var args = this.assembleCommand(options);
+ var args = this.env.searchType.assembleFilelistCommand(options);
if (!args)
return onExit(1, "Invalid arguments");
- vfs.spawn(args.command, { args: args, cwd: options.path, stdoutEncoding: "utf8", stderrEncoding: "utf8" }, function(err, meta) {
- if (err || !meta.process)
- return onExit(1, err);
+ var nakstream = Fs.createReadStream(Path.normalize(__dirname + "/../../node_modules/nak/build/nak.vfs_concat.js"));
- var stderr = "";
- meta.process.stdout.on("data", function(data) {
- onData(data);
- });
+ vfs.extend("nak_filelist", {stream: nakstream, redefine: true}, function (err, meta) {
+ if (err) throw err;
+ var api = meta.api;
+
+ api.execute(args, function (err, result) {
+ if (err) return onExit(1, err);
- meta.process.stderr.on("data", function(data) {
- stderr += data;
- });
-
- meta.process.on("exit", function(code) {
- onExit(code, stderr);
+ onData(result);
+ onExit(0, null);
});
});
};
-
- this.assembleCommand = function(options) {
- var excludeExtensions = [
- "\\.gz", "\\.bzr", "\\.cdv", "\\.dep", "\\.dot", "\\.nib",
- "\\.plst", "_darcs", "_sgbak", "autom4te\\.cache", "cover_db",
- "_build", "\\.tmp"
- ];
-
- var excludeDirectories = [
- "\\.c9revisions", "\\.architect", "\\.sourcemint",
- "\\.git", "\\.hg", "\\.pc", "\\.svn", "blib",
- "CVS", "RCS", "SCCS", "\\.DS_Store"
- ];
-
- var args = ["-L", ".", "-type", "f", "-a"];
-
- if (this.env.platform === "darwin")
- args.unshift("-E");
-
- //Hidden Files
- if (!options.showHiddenFiles)
- args.push("(", "!", "-regex", ".*/\\..*", ")");
-
- if (options.maxdepth)
- args.push("-maxdepth", options.maxdepth);
-
- excludeExtensions.forEach(function(pattern){
- args.push("(", "!", "-regex", ".*\\/" + pattern + "$", ")");
- });
-
- excludeDirectories.forEach(function(pattern){
- args.push("(", "!", "-regex", ".*\\/" + pattern + "\\/.*", ")");
- });
-
- if (this.env.platform !== "darwin")
- args.push("-regextype", "posix-extended", "-print");
-
- args.command = this.env.findCmd;
- return args;
- };
};
View
87 plugins-server/cloud9.ide.filelist/filelist_test.js
@@ -13,28 +13,50 @@ var Assert = require("assert");
var VfsLocal = require("vfs-local");
var Filelist = require("./filelist");
-var basePath = __dirname + "/fixtures";
-var workspaceId = "user/mikedeboer/cloud9";
+var Path = require("path");
+
+var nakModule = require("../cloud9.search.nak");
+
+var basePath = Path.join(__dirname, "fixtures");
+
+var outsidePath = "/../../../../../etc";
+
+var options1 = {
+ showHiddenFiles: true
+ },
+ options2 = {
+ showHiddenFiles: false
+ },
+ options3 = {
+ path: outsidePath,
+ showHiddenFiles: true
+ };
describe("filelist", function() {
- var o;
+ var o = new Filelist();
var vfs = VfsLocal({ root: "/" });
- beforeEach(function() {
- o = new Filelist();
- o.setEnv({
+ var nakCmd = "node " + Path.join(__dirname, "..", "..", "node_modules", "nak", "build", "nak.vfs_concat.js");
+
+ var NakLib = nakModule({
+ nakCmd: nakCmd,
+ test: true
+ });
+
+ o = new Filelist();
+ o.setEnv({
basePath: basePath,
- workspaceId: workspaceId
+ searchType: NakLib
});
+
+ afterEach(function(done) {
+ vfs.unextend("nak_filelist", {}, done);
});
- it("should get filelist, including hidden files", function(next) {
+ it("should get filelist, including hidden files and binaries", function(next) {
var out = "";
- o.exec({
- path: "",
- showHiddenFiles: true
- }, vfs,
+ o.exec(options1, vfs,
// data
function(data) {
out += data;
@@ -43,8 +65,10 @@ describe("filelist", function() {
function(code, stderr) {
Assert.equal(code, 0);
var files = out.split("\n").filter(function(file) { return !!file; }).sort();
- Assert.equal(files[2], "./level1/level2/.hidden");
- Assert.equal(files[3], "./level1/level2/.level3a/.hidden");
+
+ Assert.equal(files[2], basePath + "/level1/Toasty.gif");
+ Assert.equal(files[3], basePath + "/level1/level2/.hidden");
+ Assert.equal(files[4], basePath + "/level1/level2/.level3a/.hidden");
next();
}
@@ -54,10 +78,7 @@ describe("filelist", function() {
it("should get filelist, without hidden files", function(next) {
var out = "";
- o.exec({
- path: "",
- showHiddenFiles: false
- }, vfs,
+ o.exec(options2, vfs,
// data
function(data) {
out += data;
@@ -66,8 +87,8 @@ describe("filelist", function() {
function(code, stderr) {
Assert.equal(code, 0);
var files = out.split("\n").filter(function(file) { return !!file; }).sort();
- Assert.equal(files[2], "./level1/level2/level2.rb");
- Assert.equal(files[3], "./level1/level2/level3/level4/level4.txt");
+ Assert.equal(files[3], basePath + "/level1/level2/level2.rb");
+ Assert.equal(files[4], basePath + "/level1/level2/level3/level4/level4.txt");
next();
}
@@ -77,10 +98,7 @@ describe("filelist", function() {
it("should not be possible to get a filelist from outside the root path ", function(next) {
var out = "";
- o.exec({
- path: "/../../../../../etc",
- showHiddenFiles: true
- }, vfs,
+ o.exec(options3, vfs,
// data
function(data) {
out += data;
@@ -90,7 +108,26 @@ describe("filelist", function() {
Assert.equal(code, 1);
Assert.equal(stderr, "Invalid path");
- next();
+ o.setEnv({
+ searchType: NakLib
+ });
+
+ out = "";
+ options3.path = outsidePath;
+
+ o.exec(options3, vfs,
+ // data
+ function(data) {
+ out += data;
+ },
+ // exit
+ function(code, stderr) {
+ Assert.equal(code, 1);
+ Assert.equal(stderr, "Invalid path");
+
+ next();
+ }
+ );
}
);
});
View
BIN  plugins-server/cloud9.ide.filelist/fixtures/level1/Toasty.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
1  plugins-server/cloud9.ide.filelist/fixtures/level1/level2/.level3a/.hidden
@@ -0,0 +1 @@
+/Users/gjtorikian/Developer/cloud9/plugins-server/cloud9.ide.search/darwin_x64/ag --nocolor -p /Users/gjtorikian/Developer/cloud9/plugins-server/cloud9.ide.filelist/.agignore -U -l --search-binary --hidden .+|\s* /Users/gjtorikian/Developer/cloud9/plugins-server/cloud9.ide.filelist/fixtures
View
3  plugins-server/cloud9.ide.filelist/package.json
@@ -9,7 +9,8 @@
"ide",
"vfs",
"ide-routes",
- "workspace-permissions"
+ "workspace-permissions",
+ "codesearcher"
]
}
}
View
20 plugins-server/cloud9.ide.search/.nakignore
@@ -0,0 +1,20 @@
+*~backup-*
+.c9revisions
+.git
+.svn
+.DS_Store
+.bzr
+.cdv
+~.dep
+~.dot
+~.nib
+~.plst
+.hg
+.pc
+*.min.js
+core.packed.js
+loader.crush.js
+diff_match_patch.js
+
+# the only purpose of this is to test this default nakignore file
+dir/file7_ignorable.rb
View
82 plugins-server/cloud9.ide.search/fixtures/.file8_hidden.js
@@ -0,0 +1,82 @@
+Exactly like #7 in that it contains all the other files, but it's hidden!
+
+Lo-fi sriracha odd future photo booth synth you probably haven't heard of
+them master cleanse authentic. Dreamcatcher raw denim skateboard, squid biodiesel williamsburg leggings single-origin coffee photo booth chillwave high life ennui retro jean shorts mcsweeney's.
+ Seitan mcsweeney's cliche +1 sustainable trust fund, polaroid squid ennui stumptown. Brooklyn gentrify Austin craft beer, squid food truck polaroid post-ironic
+
+ mumblecore pork belly scenester. Bushwick cardigan quinoa banksy occupy, biodiesel selvage dreamcatcher. Messenger bag kogi stumptown 8-bit, swag cray helvetica. Trust fund street art thundercats organic leggings tofu.
+
+
+Нык эрат льюкяльиюч конкльюдатюрквюэ э
+
+Sustainable pickled keffiyeh, tofu carles ethical butcher +1. You probably haven't heard of them PBR post-ironic selvage. Kale chips williamsburg chillwave cred. Sustainable pitchfork tumblr
+
+
+PBR DIY, brooklyn salvia post-ironic artisan master cleanse four loko hoodie umami thundercats.
+
+sriracha
+
+
+Jean shorts synth aesthetic, yr seitan swag readymade. Cred mumblecore portland raw denim shoreditch. Semiotics cred pork belly, VHS pour-over readymade cliche ennui raw denim high life marfa.
+
+
+gastro
+
+
+Sustainable pickled keffiyeh, tofu carles ethical butcher +1. You probably haven't heard of them PBR post-ironic selvage. Kale chips williamsburg chillwave cred. Sustainable pitchfork tumblr
+
+
+PBR DIY, brooklyn salvia post-ironic artisan master cleanse four loko hoodie umami thundercats.
+
+sriracha
+
+
+Jean shorts synth aesthetic, yr seitan swag readymade. Cred mumblecore portland raw denim shoreditch. Semiotics cred pork belly, VHS pour-over readymade cliche ennui raw denim high life marfa.
+
+Sartorial gluten-free scenester seitan, messenger bag bespoke mustache VHS flexitarian odd future pour-over brooklyn. 8-bit swag
+
+
+sriracha gastro pub umami. Marfa mustache godard umami, sriracha tofu cred scenester. Messenger bag bicycle rights godard, chambray put a bird on it cray bushwick blog fanny pack vinyl portland cosby sweater scenester. Direct trade gastropub craft beer, sriracha brooklyn Austin scenester wes anderson artisan pinterest sustainable. Austin sustainable kogi mumblecore salvia, fixie polaroid chillwave
+
+
+cardigan vinyl street art wolf butcher. 3 wolf moon VHS retro truffaut gentrify you probably haven't heard of them.
+
+
+Forage pickled salvia mcsweeney's, swag mustache single-origin coffee keytar
+
+
+
+
+
+
+pinterest cray kale chips pop-up pork belly. Tattooed marfa mcsweeney's before
+
+
+gastro
+
+
+
+they sold out locavore, odd future 3 wolf moon VHS street art occupy master cleanse stumptown trust fund PBR. Sustainable keytar semiotics organic kale chips thundercats. Food truck semiotics high life,
+
+
+
+
+
+
+whatever gastropub mcsweeney's banh mi pour-over chillwave williamsburg bespoke. Forage chillwave banksy pop-up 8-bit, skateboard DIY etsy cliche williamsburg. Scenester stumptown jean shorts artisan williamsburg. Synth kogi street art pitchfork photo booth sartorial, skateboard high life gentrify Austin butcher keytar.
+
+
+Sustainable pickled keffiyeh, tofu carles ethical butcher +1. You probably haven't heard of them PBR post-ironic selvage. Kale chips williamsburg chillwave cred. Sustainable pitchfork tumblr
+
+
+PBR DIY, brooklyn salvia post-ironic artisan master cleanse four loko hoodie umami thundercats.
+
+
+sriracha
+
+Jean shorts synth aesthetic, yr seitan swag readymade. Cred mumblecore portland raw denim shoreditch. Semiotics cred pork belly, VHS pour-over readymade cliche ennui raw denim high life marfa.
+
+
+sriracha
+
+Gentrify yr swag salvia mcsweeney's sustainable skateboard hoodie craft beer. Sartorial mixtape marfa trust fund, cliche seitan 3 wolf moon banh mi keffiyeh. Food truck small batch chillwave photo booth blog ethnic, fap +1 american apparel. Portland semiotics post-ironic etsy cliche photo booth. Wolf bicycle rights yr, keffiyeh godard odd future marfa. Yr authentic raw denim, DIY portland photo booth banh mi hoodie before they sold out PBR mumblecore vinyl blog direct trade mixtape. Ethical twee forage vice ethnic beard food truck, organic Austin authentic kale chips thundercats.
View
2  plugins-server/cloud9.ide.search/fixtures/.nakignore
@@ -0,0 +1,2 @@
+# the only purpose of this is to test directory-level nakignore files
+file9_ignored_by_this_dir.txt
View
84 plugins-server/cloud9.ide.search/fixtures/dir/file7_ignorable.rb
@@ -0,0 +1,84 @@
+Contains all the other files.
+
+And yet it never shows up, because it's in the default exclude.
+
+Lo-fi sriracha odd future photo booth synth you probably haven't heard of
+them master cleanse authentic. Dreamcatcher raw denim skateboard, squid biodiesel williamsburg leggings single-origin coffee photo booth chillwave high life ennui retro jean shorts mcsweeney's.
+ Seitan mcsweeney's cliche +1 sustainable trust fund, polaroid squid ennui stumptown. Brooklyn gentrify Austin craft beer, squid food truck polaroid post-ironic
+
+ mumblecore pork belly scenester. Bushwick cardigan quinoa banksy occupy, biodiesel selvage dreamcatcher. Messenger bag kogi stumptown 8-bit, swag cray helvetica. Trust fund street art thundercats organic leggings tofu.
+
+
+Нык эрат льюкяльиюч конкльюдатюрквюэ э
+
+Sustainable pickled keffiyeh, tofu carles ethical butcher +1. You probably haven't heard of them PBR post-ironic selvage. Kale chips williamsburg chillwave cred. Sustainable pitchfork tumblr
+
+
+PBR DIY, brooklyn salvia post-ironic artisan master cleanse four loko hoodie umami thundercats.
+
+sriracha
+
+
+Jean shorts synth aesthetic, yr seitan swag readymade. Cred mumblecore portland raw denim shoreditch. Semiotics cred pork belly, VHS pour-over readymade cliche ennui raw denim high life marfa.
+
+
+gastro
+
+
+Sustainable pickled keffiyeh, tofu carles ethical butcher +1. You probably haven't heard of them PBR post-ironic selvage. Kale chips williamsburg chillwave cred. Sustainable pitchfork tumblr
+
+
+PBR DIY, brooklyn salvia post-ironic artisan master cleanse four loko hoodie umami thundercats.
+
+sriracha
+
+
+Jean shorts synth aesthetic, yr seitan swag readymade. Cred mumblecore portland raw denim shoreditch. Semiotics cred pork belly, VHS pour-over readymade cliche ennui raw denim high life marfa.
+
+Sartorial gluten-free scenester seitan, messenger bag bespoke mustache VHS flexitarian odd future pour-over brooklyn. 8-bit swag
+
+
+sriracha gastro pub umami. Marfa mustache godard umami, sriracha tofu cred scenester. Messenger bag bicycle rights godard, chambray put a bird on it cray bushwick blog fanny pack vinyl portland cosby sweater scenester. Direct trade gastropub craft beer, sriracha brooklyn Austin scenester wes anderson artisan pinterest sustainable. Austin sustainable kogi mumblecore salvia, fixie polaroid chillwave
+
+
+cardigan vinyl street art wolf butcher. 3 wolf moon VHS retro truffaut gentrify you probably haven't heard of them.
+
+
+Forage pickled salvia mcsweeney's, swag mustache single-origin coffee keytar
+
+
+
+
+
+
+pinterest cray kale chips pop-up pork belly. Tattooed marfa mcsweeney's before
+
+
+gastro
+
+
+
+they sold out locavore, odd future 3 wolf moon VHS street art occupy master cleanse stumptown trust fund PBR. Sustainable keytar semiotics organic kale chips thundercats. Food truck semiotics high life,
+
+
+
+
+
+
+whatever gastropub mcsweeney's banh mi pour-over chillwave williamsburg bespoke. Forage chillwave banksy pop-up 8-bit, skateboard DIY etsy cliche williamsburg. Scenester stumptown jean shorts artisan williamsburg. Synth kogi street art pitchfork photo booth sartorial, skateboard high life gentrify Austin butcher keytar.
+
+
+Sustainable pickled keffiyeh, tofu carles ethical butcher +1. You probably haven't heard of them PBR post-ironic selvage. Kale chips williamsburg chillwave cred. Sustainable pitchfork tumblr
+
+
+PBR DIY, brooklyn salvia post-ironic artisan master cleanse four loko hoodie umami thundercats.
+
+
+sriracha
+
+Jean shorts synth aesthetic, yr seitan swag readymade. Cred mumblecore portland raw denim shoreditch. Semiotics cred pork belly, VHS pour-over readymade cliche ennui raw denim high life marfa.
+
+
+sriracha
+
+Gentrify yr swag salvia mcsweeney's sustainable skateboard hoodie craft beer. Sartorial mixtape marfa trust fund, cliche seitan 3 wolf moon banh mi keffiyeh. Food truck small batch chillwave photo booth blog ethnic, fap +1 american apparel. Portland semiotics post-ironic etsy cliche photo booth. Wolf bicycle rights yr, keffiyeh godard odd future marfa. Yr authentic raw denim, DIY portland photo booth banh mi hoodie before they sold out PBR mumblecore vinyl blog direct trade mixtape. Ethical twee forage vice ethnic beard food truck, organic Austin authentic kale chips thundercats.
View
5 plugins-server/cloud9.ide.search/fixtures/file1.txt
@@ -0,0 +1,5 @@
+Lo-fi sriracha odd future photo booth synth you probably haven't heard of
+them master cleanse authentic. Dreamcatcher raw denim skateboard, squid biodiesel williamsburg leggings single-origin coffee photo booth chillwave high life ennui retro jean shorts mcsweeney's.
+ Seitan mcsweeney's cliche +1 sustainable trust fund, polaroid squid ennui stumptown. Brooklyn gentrify Austin craft beer, squid food truck polaroid post-ironic
+
+ mumblecore pork belly scenester. Bushwick cardigan quinoa banksy occupy, biodiesel selvage dreamcatcher. Messenger bag kogi stumptown 8-bit, swag cray helvetica. Trust fund street art thundercats organic leggings tofu.
View
3  plugins-server/cloud9.ide.search/fixtures/file2.txt
@@ -0,0 +1,3 @@
+Gentrify yr swag salvia mcsweeney's sustainable skateboard hoodie craft beer. Sartorial mixtape marfa trust fund, cliche seitan 3 wolf moon banh mi keffiyeh. Food truck small batch chillwave photo booth blog ethnic, fap +1 american apparel. Portland semiotics post-ironic etsy cliche photo booth. Wolf bicycle rights yr, keffiyeh godard odd future marfa. Yr authentic raw denim, DIY portland photo booth banh mi hoodie before they sold out PBR mumblecore vinyl blog direct trade mixtape. Ethical twee forage vice ethnic beard food truck, organic Austin authentic kale chips thundercats.
+
+williamsburg
View
11 plugins-server/cloud9.ide.search/fixtures/file3.txt
@@ -0,0 +1,11 @@
+Sartorial gluten-free scenester seitan, messenger bag bespoke mustache VHS flexitarian odd future pour-over brooklyn. 8-bit swag
+
+
+sriracha gastro pub umami. Marfa mustache godard umami, sriracha tofu cred scenester. Messenger bag bicycle rights godard, chambray put a bird on it cray bushwick blog fanny pack vinyl portland cosby sweater scenester. Direct trade gastropub craft beer, sriracha brooklyn Austin scenester wes anderson artisan pinterest sustainable. Austin sustainable kogi mumblecore salvia, fixie polaroid chillwave
+
+williamsburg
+
+cardigan vinyl street art wolf butcher. 3 wolf moon VHS retro truffaut gentrify you probably haven't heard of them.
+
+
+williamsburg
View
22 plugins-server/cloud9.ide.search/fixtures/file4_noext
@@ -0,0 +1,22 @@
+Forage pickled salvia mcsweeney's, swag mustache single-origin coffee keytar
+
+
+
+
+
+
+pinterest cray kale chips pop-up pork belly. Tattooed marfa mcsweeney's before
+
+
+gastro
+
+
+
+they sold out locavore, odd future 3 wolf moon VHS street art occupy master cleanse stumptown trust fund PBR. Sustainable keytar semiotics organic kale chips thundercats. Food truck semiotics high life,
+
+
+
+williamsburg
+
+
+whatever gastropub mcsweeney's banh mi pour-over chillwave williamsburg bespoke. Forage chillwave banksy pop-up 8-bit, skateboard DIY etsy cliche williamsburg. Scenester stumptown jean shorts artisan williamsburg. Synth kogi street art pitchfork photo booth sartorial, skateboard high life gentrify Austin butcher keytar.
View
12 plugins-server/cloud9.ide.search/fixtures/file5_not_really_image.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
26 plugins-server/cloud9.ide.search/fixtures/file6_contains_nonascii.dat
@@ -0,0 +1,26 @@
+
+Нык эрат льюкяльиюч конкльюдатюрквюэ э
+
+Sustainable pickled keffiyeh, tofu carles ethical butcher +1. You probably haven't heard of them PBR post-ironic selvage. Kale chips williamsburg chillwave cred. Sustainable pitchfork tumblr
+
+
+PBR DIY, brooklyn salvia post-ironic artisan master cleanse four loko hoodie umami thundercats.
+
+sriracha
+
+
+Jean shorts synth aesthetic, yr seitan swag readymade. Cred mumblecore portland raw denim shoreditch. Semiotics cred pork belly, VHS pour-over readymade cliche ennui raw denim high life marfa.
+
+
+gastro
+
+
+Sustainable pickled keffiyeh, tofu carles ethical butcher +1. You probably haven't heard of them PBR post-ironic selvage. Kale chips williamsburg chillwave cred. Sustainable pitchfork tumblr
+
+
+PBR DIY, brooklyn salvia post-ironic artisan master cleanse four loko hoodie umami thundercats.
+
+sriracha
+
+
+Jean shorts synth aesthetic, yr seitan swag readymade. Cred mumblecore portland raw denim shoreditch. Semiotics cred pork belly, VHS pour-over readymade cliche ennui raw denim high life marfa.
View
84 plugins-server/cloud9.ide.search/fixtures/file9_ignored_by_this_dir.txt
@@ -0,0 +1,84 @@
+Like file 7 in that it contains all other files, but it should be blocked by this directory's .agignore.
+
+It will never show up!
+
+Lo-fi sriracha odd future photo booth synth you probably haven't heard of
+them master cleanse authentic. Dreamcatcher raw denim skateboard, squid biodiesel williamsburg leggings single-origin coffee photo booth chillwave high life ennui retro jean shorts mcsweeney's.
+ Seitan mcsweeney's cliche +1 sustainable trust fund, polaroid squid ennui stumptown. Brooklyn gentrify Austin craft beer, squid food truck polaroid post-ironic
+
+ mumblecore pork belly scenester. Bushwick cardigan quinoa banksy occupy, biodiesel selvage dreamcatcher. Messenger bag kogi stumptown 8-bit, swag cray helvetica. Trust fund street art thundercats organic leggings tofu.
+
+
+Нык эрат льюкяльиюч конкльюдатюрквюэ э
+
+Sustainable pickled keffiyeh, tofu carles ethical butcher +1. You probably haven't heard of them PBR post-ironic selvage. Kale chips williamsburg chillwave cred. Sustainable pitchfork tumblr
+
+
+PBR DIY, brooklyn salvia post-ironic artisan master cleanse four loko hoodie umami thundercats.
+
+sriracha
+
+
+Jean shorts synth aesthetic, yr seitan swag readymade. Cred mumblecore portland raw denim shoreditch. Semiotics cred pork belly, VHS pour-over readymade cliche ennui raw denim high life marfa.
+
+
+gastro
+
+
+Sustainable pickled keffiyeh, tofu carles ethical butcher +1. You probably haven't heard of them PBR post-ironic selvage. Kale chips williamsburg chillwave cred. Sustainable pitchfork tumblr
+
+
+PBR DIY, brooklyn salvia post-ironic artisan master cleanse four loko hoodie umami thundercats.
+
+sriracha
+
+
+Jean shorts synth aesthetic, yr seitan swag readymade. Cred mumblecore portland raw denim shoreditch. Semiotics cred pork belly, VHS pour-over readymade cliche ennui raw denim high life marfa.
+
+Sartorial gluten-free scenester seitan, messenger bag bespoke mustache VHS flexitarian odd future pour-over brooklyn. 8-bit swag
+
+
+sriracha gastro pub umami. Marfa mustache godard umami, sriracha tofu cred scenester. Messenger bag bicycle rights godard, chambray put a bird on it cray bushwick blog fanny pack vinyl portland cosby sweater scenester. Direct trade gastropub craft beer, sriracha brooklyn Austin scenester wes anderson artisan pinterest sustainable. Austin sustainable kogi mumblecore salvia, fixie polaroid chillwave
+
+
+cardigan vinyl street art wolf butcher. 3 wolf moon VHS retro truffaut gentrify you probably haven't heard of them.
+
+
+Forage pickled salvia mcsweeney's, swag mustache single-origin coffee keytar
+
+
+
+
+
+
+pinterest cray kale chips pop-up pork belly. Tattooed marfa mcsweeney's before
+
+
+gastro
+
+
+
+they sold out locavore, odd future 3 wolf moon VHS street art occupy master cleanse stumptown trust fund PBR. Sustainable keytar semiotics organic kale chips thundercats. Food truck semiotics high life,
+
+
+
+
+
+
+whatever gastropub mcsweeney's banh mi pour-over chillwave williamsburg bespoke. Forage chillwave banksy pop-up 8-bit, skateboard DIY etsy cliche williamsburg. Scenester stumptown jean shorts artisan williamsburg. Synth kogi street art pitchfork photo booth sartorial, skateboard high life gentrify Austin butcher keytar.
+
+
+Sustainable pickled keffiyeh, tofu carles ethical butcher +1. You probably haven't heard of them PBR post-ironic selvage. Kale chips williamsburg chillwave cred. Sustainable pitchfork tumblr
+
+
+PBR DIY, brooklyn salvia post-ironic artisan master cleanse four loko hoodie umami thundercats.
+
+
+sriracha
+
+Jean shorts synth aesthetic, yr seitan swag readymade. Cred mumblecore portland raw denim shoreditch. Semiotics cred pork belly, VHS pour-over readymade cliche ennui raw denim high life marfa.
+
+
+sriracha
+
+Gentrify yr swag salvia mcsweeney's sustainable skateboard hoodie craft beer. Sartorial mixtape marfa trust fund, cliche seitan 3 wolf moon banh mi keffiyeh. Food truck small batch chillwave photo booth blog ethnic, fap +1 american apparel. Portland semiotics post-ironic etsy cliche photo booth. Wolf bicycle rights yr, keffiyeh godard odd future marfa. Yr authentic raw denim, DIY portland photo booth banh mi hoodie before they sold out PBR mumblecore vinyl blog direct trade mixtape. Ethical twee forage vice ethnic beard food truck, organic Austin authentic kale chips thundercats.
View
3  plugins-server/cloud9.ide.search/package.json
@@ -7,7 +7,8 @@
"plugin": {
"consumes": [
"ide",
- "vfs"
+ "vfs",
+ "codesearcher"
]
}
}
View
11 plugins-server/cloud9.ide.search/search-plugin.js
@@ -15,11 +15,6 @@ var name = "search";
module.exports = function setup(options, imports, register) {
var Search = new SearchLib();
- Search.setEnv({
- grepCmd: options.grepCmd || "grep",
- perlCmd: options.perlCmd || "perl",
- platform: options.platform || require("os").platform()
- });
var Vfs = imports["vfs"];
@@ -27,8 +22,9 @@ module.exports = function setup(options, imports, register) {
Plugin.call(this, ide, workspace);
this.hooks = ["command"];
this.name = name;
- this.processCount = 0;
- Search.setEnv({ basePath: ide.workspace.workspaceDir });
+ this.processCount = 0;
+
+ Search.setEnv({ searchType: imports["codesearcher"], basePath: ide.workspace.workspaceDir });
};
util.inherits(SearchPlugin, Plugin);
@@ -56,6 +52,7 @@ module.exports = function setup(options, imports, register) {
msg.stderr = stderr;
msg.extra = "codesearch";
msg.type = "exit";
+
self.ide.broadcast(JSON.stringify(msg), self.name);
}
);
View
302 plugins-server/cloud9.ide.search/search.js
@@ -7,22 +7,16 @@
"use strict";
-var Os = require("os");
+var Fs = require("fs");
var Path = require("path");
module.exports = function() {
- this.env = {
- grepCmd: "grep",
- perlCmd: "perl",
- platform: Os.platform(),
- basePath: ""
- };
+ this.env = { };
this.setEnv = function(newEnv) {
var self = this;
- Object.keys(this.env).forEach(function(e) {
- if (newEnv[e])
- self.env[e] = newEnv[e];
+ Object.keys(newEnv).forEach(function(e) {
+ self.env[e] = newEnv[e];
});
};
@@ -31,7 +25,7 @@ module.exports = function() {
if (options.path === null)
return true;
-
+
options.uri = path;
options.path = Path.normalize(this.env.basePath + (path ? "/" + path : ""));
// if the relative path FROM the workspace directory TO the requested path
@@ -40,7 +34,7 @@ module.exports = function() {
if (Path.relative(this.env.basePath, options.path).indexOf("../") === 0)
return false;
- var args = this.assembleCommand(options);
+ var args = this.env.searchType.assembleSearchCommand(options);
if (!args)
return false;
@@ -51,282 +45,28 @@ module.exports = function() {
if (this.activeProcess)
this.activeProcess.kill("SIGKILL");
- vfs.spawn(args.command, { args: args, cwd: options.path, stdoutEncoding: "utf8", stderrEncoding: "utf8" }, function(err, meta) {
- if (err || !meta.process)
- return onExit(1, err, {
- count: 0,
- filecount: 0
- });
-
- var child = meta.process;
- self.activeProcess = child;
- var stderr = "";
- var prevFile = null;
- var filecount = 0;
- var count = 0;
+ var nakstream = Fs.createReadStream(Path.normalize(__dirname + "/../../node_modules/nak/build/nak.vfs_concat.js"));
- child.stdout.on("data", function(data) {
- var msg = self.parseResult(prevFile, options, data);
- count += msg.count;
- filecount += msg.filecount;
- prevFile = msg.prevFile;
+ vfs.extend("nak_search", {stream: nakstream, redefine: true}, function (err, meta) {
+ if (err) throw err;
+ var api = meta.api;
+
+ api.execute(args, function (err, result) {
+ if (err) return onExit(1, err);
- if (msg)
- onData(msg);
- });
-
- child.stderr.on("data", function(data) {
- stderr += data;
- });
+ if (/^Found/.test(result)) {
+ // fetch the "Found %d matches in %d files" result
+ var tally = result.match(/\d+/g);
- child.on("exit", function(code) {
- self.processCount -= 1;
- onExit(code, stderr, {
- count: count,
- filecount: filecount
- });
+ onExit(0, null, {data: result, count: tally[0], filecount: tally[1]});
+ }
+
+ else
+ onData({data: result});
});
});
return true;
};
-
- this.assembleCommand = function(options) {
- var include = "";
- var cmd = this.env.grepCmd + " -s -r --color=never --binary-files=without-match -n " +
- (!options.casesensitive ? "-i " : "") +
- (process.platform != "darwin" ? "-P " : "");
-
- if (options.pattern) { // handles grep peculiarities with --include
- if (options.pattern.split(",").length > 1)
- include = "{" + options.pattern + "}";
- else
- include = options.pattern;
- }
- else {
- include = (process.platform != "darwin" ? "\\" : "") + "*{" + PATTERN_EXT + "}";
- }
-
- if (options.maxresults)
- cmd += "-m " + parseInt(options.maxresults, 10);
- if (options.wholeword)
- cmd += " -w";
-
- var query = options.query;
- if (!query)
- return;
-
- // grep has a funny way of handling new lines (that is to say, it's non-existent)
- // if we're not doing a regex search, then we must split everything between the
- // new lines, escape the content, and then smush it back together; due to
- // new lines, this is also why we're now passing -P as default to grep
- if (!options.replaceAll && !options.regexp) {
- var splitQuery = query.split("\\n");
-
- for (var q in splitQuery) {
- splitQuery[q] = grepEscapeRegExp(splitQuery[q]);
- }
- query = splitQuery.join("\\n");
- }
-
- query = query.replace(new RegExp("\\\'", "g"), "'\\''"); // ticks must be double escaped for BSD grep
-
- cmd += " --exclude=*{" + PATTERN_EDIR + "}*" +
- " --include=" + include +
- " '" + query.replace(/-/g, "\\-") + "'" +
- " \"" + escapeShell(options.path) + "\"";
-
- if (options.replaceAll) {
- if (!options.replacement)
- options.replacement = "";
-
- if (options.regexp)
- query = escapeRegExp(query);
-
- // pipe the grep results into perl
- cmd += " -l | xargs " + this.env.perlCmd +
- // print the grep result to STDOUT (to arrange in parseSearchResult())
- " -pi -e 'print STDOUT \"$ARGV:$.:$_\"" +
- // do the actual replace
- " if s/" + query + "/" + options.replacement + "/mg" + ( options.casesensitive ? "" : "i" ) + ";'";
- }
-
- var args = ["-c", cmd];
- args.command = "bash";
- return args;
- };
-
- this.parseResult = function(prevFile, options, data) {
- if (typeof data !== "string" || data.indexOf("\n") === -1)
- return { count: 0, filecount: 0, data: "" };
-
- var parts, file, lineno, result = "";
- var aLines = data.split(/([\n\r]+)/g);
- var count = 0;
- var filecount = 0;
-
- if (options) {
- for (var i = 0, l = aLines.length; i < l; ++i) {
- parts = aLines[i].split(":");
-
- if (parts.length < 3)
- continue;
-
- var _path = parts.shift().replace(options.path, "").trimRight();
- file = encodeURI(options.uri + _path, "/");
-
- lineno = parseInt(parts.shift(), 10);
- if (!lineno)
- continue;
-
- ++count;
- if (file !== prevFile) {
- ++filecount;
- if (prevFile)
- result += "\n \n";
-
- result += file + ":";
- prevFile = file;
- }
-
- result += "\n\t" + lineno + ": " + parts.join(":");
- }
- }
- else {
- console.error("options object doesn't exist", data);
- }
-
- return {
- count: count,
- filecount: filecount,
- prevFile: prevFile,
- data: result
- };
- };
-
- // util
- var makeUnique = function(arr){
- var i, length, newArr = [];
- for (i = 0, length = arr.length; i < length; i++) {
- if (newArr.indexOf(arr[i]) == -1)
- newArr.push(arr[i]);
- }
-
- arr.length = 0;
- for (i = 0, length = newArr.length; i < length; i++)
- arr.push(newArr[i]);
-
- return arr;
- };
-
- var escapeRegExp = function(str) {
- return str.replace(/([.*+?\^${}()|\[\]\/\\])/g, "\\$1");
- };
-
- // taken from http://xregexp.com/
- var grepEscapeRegExp = function(str) {
- return str.replace(/[[\]{}()*+?.,\\^$|#\s"']/g, "\\$&");
- };
-
- var escapeShell = function(str) {
- return str.replace(/([\\"'`$\s\(\)<>])/g, "\\$1");
- };
-
- // file types
-
- var 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"
- };
-
- var MAPPINGS = {
- "actionscript": ["as", "mxml"],
- "ada" : ["ada", "adb", "ads"],
- "asm" : ["asm", "s"],
- "batch" : ["bat", "cmd"],
- //"binary" : q{Binary files, as defined by Perl's -B op (default: off)},
- "cc" : ["c", "h", "xs"],
- "cfmx" : ["cfc", "cfm", "cfml"],
- "clojure" : ["clj"],
- "cpp" : ["cpp", "cc", "cxx", "m", "hpp", "hh", "h", "hxx"],
- "csharp" : ["cs"],
- "css" : ["css", "less", "scss", "sass"],
- "coffee" : ["coffee"],
- "elisp" : ["el"],
- "erlang" : ["erl", "hrl"],
- "fortran" : ["f", "f77", "f90", "f95", "f03", "for", "ftn", "fpp"],
- "haskell" : ["hs", "lhs"],
- "hh" : ["h"],
- "html" : ["htm", "html", "shtml", "xhtml"],
- "jade" : ["jade"],
- "java" : ["java", "properties"],
- "groovy" : ["groovy"],
- "js" : ["js"],
- "json" : ["json"],
- "latex" : ["latex", "ltx"],
- "jsp" : ["jsp", "jspx", "jhtm", "jhtml"],
- "lisp" : ["lisp", "lsp"],
- "lua" : ["lua"],
- "make" : ["makefile", "Makefile"],
- "mason" : ["mas", "mhtml", "mpl", "mtxt"],
- "markdown" : ["md", "markdown"],
- "objc" : ["m", "h"],
- "objcpp" : ["mm", "h"],
- "ocaml" : ["ml", "mli"],
- "parrot" : ["pir", "pasm", "pmc", "ops", "pod", "pg", "tg"],
- "perl" : ["pl", "pm", "pod", "t"],
- "php" : ["php", "phpt", "php3", "php4", "php5", "phtml"],
- "plone" : ["pt", "cpt", "metadata", "cpy", "py"],
- "powershell" : ["ps1"],
- "python" : ["py"],
- "rake" : ["rakefile"],
- "ruby" : ["rb", "ru", "rhtml", "rjs", "rxml", "erb", "rake", "gemspec"],
- "scala" : ["scala"],
- "scheme" : ["scm", "ss"],
- "shell" : ["sh", "bash", "csh", "tcsh", "ksh", "zsh"],
- //"skipped" : "q"{"Files but not directories normally skipped by ack ("default": "off")},
- "smalltalk" : ["st"],
- "sql" : ["sql", "ctl"],
- "tcl" : ["tcl", "itcl", "itk"],
- "tex" : ["tex", "cls", "sty"],
- "text" : ["txt"],
- "textile" : ["textile"],
- "tt" : ["tt", "tt2", "ttml"],
- "vb" : ["bas", "cls", "frm", "ctl", "vb", "resx"],
- "vim" : ["vim"],
- "yaml" : ["yaml", "yml"],
- "xml" : ["xml", "dtd", "xslt", "ent", "rdf", "rss", "svg", "wsdl", "atom", "mathml", "mml"]
- };
- var exts = [];
- for (var type in MAPPINGS) {
- exts = exts.concat(MAPPINGS[type]);
- }
- // grep pattern matching for extensions
- var PATTERN_EXT = makeUnique(exts).join(",");
- var dirs = [];
- for (type in IGNORE_DIRS) {
- dirs.push(type);
- }
- dirs = makeUnique(dirs);
- var PATTERN_DIR = escapeRegExp(dirs.join("|"));
- var PATTERN_EDIR = dirs.join(",");
};
View
265 plugins-server/cloud9.ide.search/search_test.js
@@ -10,36 +10,128 @@
"mocha";
var Assert = require("assert");
+
var VfsLocal = require("vfs-local");
var Search = require("./search");
-var basePath = __dirname;
-var workspaceId = "user/mikedeboer/cloud9";
+var Path = require("path");
-describe("search", function() {
- var o;
- var vfs = VfsLocal({ root: "/" });
+var nakModule = require("../cloud9.search.nak");
- beforeEach(function() {
- o = new Search();
- o.setEnv({ basePath: basePath });
- });
+var basePath = Path.join(__dirname, "fixtures");
- it("should find matches without regexp, case-sensitive ON and word boundaries OFF", function(next) {
- var out = "";
-
- o.exec({
- query: "Search",
- needle: "Search",
+var options1 = {
+ query: "sriracha",
+ needle: "sriracha",
+ pattern: "",
+ casesensitive: false,
+ regexp: false,
+ replaceAll: false,
+ replacement: "",
+ wholeword: false,
+ command: "codesearch",
+ path: ""
+ },
+ options2 = {
+ query: "Messenger",
+ needle: "Messenger",
+ pattern: "",
+ casesensitive: true,
+ regexp: false,
+ replaceAll: false,
+ replacement: "",
+ wholeword: false,
+ command: "codesearch",
+ path: ""
+ },
+ options3 = {
+ query: "gastro",
+ needle: "gastro",
pattern: "",
casesensitive: false,
regexp: false,
replaceAll: false,
replacement: "",
+ wholeword: true,
+ command: "codesearch",
+ path: ""
+ },
+ options4 = {
+ query: "pb.",
+ needle: "pb.",
+ pattern: "",
+ casesensitive: false,
+ regexp: true,
+ replaceAll: false,
+ replacement: "",
wholeword: false,
command: "codesearch",
path: ""
- }, vfs,
+ },
+ options5 = {
+ query: ".+wave",
+ needle: ".+wave",
+ pattern: "",
+ casesensitive: true,
+ regexp: true,
+ replaceAll: false,
+ replacement: "",
+ wholeword: false,
+ command: "codesearch",
+ path: "",
+ hidden: true
+ },
+ options6 = {
+ query: "shorts",
+ needle: "shorts",
+ pattern: "*.txt, file*.gif",
+ casesensitive: true,
+ regexp: true,
+ replaceAll: false,
+ replacement: "",
+ wholeword: false,
+ command: "codesearch",
+ path: ""
+ },
+ options7 = {
+ query: "williamsburg",
+ needle: "williamsburg",
+ pattern: "-file*.txt",
+ casesensitive: true,
+ regexp: true,
+ replaceAll: false,
+ replacement: "",
+ wholeword: false,
+ command: "codesearch",
+ path: "",
+ hidden: true
+ };
+
+describe("search", function() {
+ var o;
+ var vfs = VfsLocal({ root: "/" });
+
+ var nakCmd = "node " + Path.join(__dirname, "..", "..", "node_modules", "nak", "build", "nak.vfs_concat.js");
+
+ var NakLib = nakModule({
+ nakCmd: nakCmd,
+ test: true
+ });
+
+ o = new Search();
+ o.setEnv({
+ basePath: basePath,
+ searchType: NakLib
+ });
+
+ afterEach(function(done) {
+ vfs.unextend("nak_search", {}, done);
+ });
+
+ it("should find matches without regexp, case-sensitive OFF and word boundaries OFF", function(next) {
+ var out = "";
+
+ o.exec(options1, vfs,
// data
function(msg) {
out += msg.data;
@@ -47,31 +139,19 @@ describe("search", function() {
// exit
function(code, stderr, msg) {
Assert.equal(code, 0);
- Assert.equal(msg.count, 36);
- Assert.equal(msg.filecount, 6);
+ Assert.equal(msg.count, 8);
+ Assert.equal(msg.filecount, 4);
var lines = out.split("\n");
- Assert.equal(lines.length, 47);
-
+ Assert.equal(lines.length, 7);
next();
}
);
});
- it("should find matches without regexp, case-insensitive ON and word boundaries OFF", function(next) {
+ it("should find matches without regexp, case-sensitive ON and word boundaries OFF", function(next) {
var out = "";
- o.exec({
- query: "Search",
- needle: "Search",
- pattern: "",
- casesensitive: true,
- regexp: false,
- replaceAll: false,
- replacement: "",
- wholeword: false,
- command: "codesearch",
- path: ""
- }, vfs,
+ o.exec(options2, vfs,
// data
function(msg) {
out += msg.data;
@@ -79,31 +159,20 @@ describe("search", function() {
// exit
function(code, stderr, msg) {
Assert.equal(code, 0);
- Assert.equal(msg.count, 23);
- Assert.equal(msg.filecount, 3);
+ Assert.equal(msg.count, 2);
+ Assert.equal(msg.filecount, 2);
var lines = out.split("\n");
- Assert.equal(lines.length, 28);
-
+ Assert.equal(lines.length, 3);
+
next();
}
);
});
- it("should find matches without regexp, case-sensitive ON and word boundaries ON", function(next) {
+ it("should find matches without regexp, case-sensitive OFF and word boundaries ON", function(next) {
var out = "";
-
- o.exec({
- query: "Search",
- needle: "Search",
- pattern: "",
- casesensitive: true,
- regexp: false,
- replaceAll: false,
- replacement: "",
- wholeword: false,
- command: "codesearch",
- path: ""
- }, vfs,
+
+ o.exec(options3, vfs,
// data
function(msg) {
out += msg.data;
@@ -111,31 +180,20 @@ describe("search", function() {
// exit
function(code, stderr, msg) {
Assert.equal(code, 0);
- Assert.equal(msg.count, 23);
+ Assert.equal(msg.count, 3);
Assert.equal(msg.filecount, 3);
var lines = out.split("\n");
- Assert.equal(lines.length, 28);
-
+ Assert.equal(lines.length, 4);
+
next();
}
);
});
- it("should find matches with a regexp", function(next) {
+ it("should find matches with a regexp, case-sensitive OFF", function(next) {
var out = "";
-
- o.exec({
- query: "Search.*",
- needle: "Search.*",
- pattern: "",
- casesensitive: true,
- regexp: true,
- replaceAll: false,
- replacement: "",
- wholeword: true,
- command: "codesearch",
- path: ""
- }, vfs,
+
+ o.exec(options4, vfs,
// data
function(msg) {
out += msg.data;
@@ -143,11 +201,76 @@ describe("search", function() {
// exit
function(code, stderr, msg) {
Assert.equal(code, 0);
- Assert.equal(msg.count, 22);
- Assert.equal(msg.filecount, 3);
+ Assert.equal(msg.count, 8);
+ Assert.equal(msg.filecount, 4);
+ var lines = out.split("\n");
+ Assert.equal(lines.length, 9);
+
+ next();
+ }
+ );
+ });
+
+ it("should find matches with a regexp, case-sensitive ON, including the default .agignore file, and hidden files", function(next) {
+ var out = "";
+
+ o.exec(options5, vfs,
+ // data
+ function(msg) {
+ out += msg.data;
+ },
+ // exit
+ function(code, stderr, msg) {
+ Assert.equal(code, 0);
+ Assert.equal(msg.count, 14);
+ Assert.equal(msg.filecount, 7);
var lines = out.split("\n");
- Assert.equal(lines.length, 27);
+ Assert.equal(lines.length, 15);
+
+ next();
+ }
+ );
+ });
+
+ it("should find matches without regexp, only two file types, and no hidden files (even if they contain the string)", function(next) {
+ var out = "";
+
+ o.exec(options6, vfs,
+ // data
+ function(msg) {
+ out += msg.data;
+ },
+ // exit
+ function(code, stderr, msg) {
+ Assert.equal(code, 0);
+ Assert.equal(msg.count, 2);
+ Assert.equal(msg.filecount, 2);
+ var lines = out.split("\n");
+ Assert.equal(lines.length, 3);
+ Assert.equal(/.file8_hidden.txt/.test(lines), false);
+
+ next();
+ }
+ );
+ });
+
+ it("should find matches without regexp, excluding txt files", function(next) {
+ var out = "";
+
+ o.exec(options7, vfs,
+ // data
+ function(msg) {
+ out += msg.data;
+ },
+ // exit
+ function(code, stderr, msg) {
+ Assert.equal(code, 0);
+ Assert.equal(msg.count, 14);
+ Assert.equal(msg.filecount, 4);
+ var lines = out.split("\n");
+ Assert.equal(lines.length, 11);
+
next();
}
);
View