From 8dc6d57901b6a53155cd69054e8010251b2769a3 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 16 Sep 2013 15:54:14 -0700 Subject: [PATCH 01/20] Ignore test --- spec/project-spec.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/project-spec.coffee b/spec/project-spec.coffee index 0918c755f..34f26846d 100644 --- a/spec/project-spec.coffee +++ b/spec/project-spec.coffee @@ -349,7 +349,8 @@ describe "Project", -> expect(paths[0]).toBe filePath expect(matches.length).toBe 1 - it "excludes values in core.ignoredNames", -> + xit "excludes values in core.ignoredNames", -> + # FIXME: this test doesnt make any sense. Why should it ignore the whole project dir? projectPath = '/tmp/atom-tests/folder-with-dot-git/.git' filePath = path.join(projectPath, 'test.txt') fs.writeSync(filePath, 'match this') From d8fdbcf1b19502aa0aae6bd36a807578243674c5 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 16 Sep 2013 16:11:01 -0700 Subject: [PATCH 02/20] Use the -G param in project::scan to search within directories --- spec/project-spec.coffee | 18 ++++++++++++++++++ src/project.coffee | 9 ++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/spec/project-spec.coffee b/spec/project-spec.coffee index 34f26846d..017bb6a13 100644 --- a/spec/project-spec.coffee +++ b/spec/project-spec.coffee @@ -332,6 +332,24 @@ describe "Project", -> expect(paths.length).toBe 0 expect(matches.length).toBe 0 + it "includes only files when a directory filter is specified", -> + projectPath = fsUtils.resolveOnLoadPath('fixtures/dir') + project.setPath(projectPath) + + filePath = path.join(projectPath, 'a-dir', 'oh-git') + + paths = [] + matches = [] + waitsForPromise -> + project.scan /aaa/, paths: ['a-dir/'], (result) -> + paths.push(result.path) + matches.push(result.match) + + runs -> + expect(paths.length).toBe 1 + expect(paths[0]).toBe filePath + expect(matches.length).toBe 1 + it "includes files and folders that begin with a '.'", -> projectPath = '/tmp/atom-tests/folder-with-dot-file' filePath = path.join(projectPath, '.text') diff --git a/src/project.coffee b/src/project.coffee index fe0cc0b8c..ca3c16e68 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -278,9 +278,15 @@ class Project # # * regex: # A RegExp to search with + # * options: + # - paths: an {Array} of path names to search within # * iterator: # A Function callback on each file found - scan: (regex, iterator) -> + scan: (regex, options={}, iterator) -> + if _.isFunction(options) + iterator = options + options = {} + bufferedData = "" state = 'readingPath' filePath = null @@ -333,6 +339,7 @@ class Project command = require.resolve('.bin/nak') args = ['--hidden', '--ackmate', regex.source, @getPath()] ignoredNames = config.get('core.ignoredNames') ? [] + args.unshift('-G', options.paths.join(',')) if options.paths and options.paths.length > 0 args.unshift('--ignore', ignoredNames.join(',')) if ignoredNames.length > 0 args.unshift('--ignoreCase') if regex.ignoreCase args.unshift('--addVCSIgnores') if config.get('core.excludeVcsIgnoredPaths') From cf88868bf0d2fb011831c3e8159923dcff3e2e95 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 16 Sep 2013 16:14:51 -0700 Subject: [PATCH 03/20] Use the full name of the -G option --- src/project.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/project.coffee b/src/project.coffee index ca3c16e68..2477e819e 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -339,7 +339,7 @@ class Project command = require.resolve('.bin/nak') args = ['--hidden', '--ackmate', regex.source, @getPath()] ignoredNames = config.get('core.ignoredNames') ? [] - args.unshift('-G', options.paths.join(',')) if options.paths and options.paths.length > 0 + args.unshift('--pathInclude', options.paths.join(',')) if options.paths and options.paths.length > 0 args.unshift('--ignore', ignoredNames.join(',')) if ignoredNames.length > 0 args.unshift('--ignoreCase') if regex.ignoreCase args.unshift('--addVCSIgnores') if config.get('core.excludeVcsIgnoredPaths') From 6dd08f85d34609ff668a387f93291dd0542b5fb9 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 16 Sep 2013 17:13:33 -0700 Subject: [PATCH 04/20] Return the lineText from project.scan Also change up match -> matchText for consistency. --- spec/project-spec.coffee | 25 +++++++++++++++---------- src/project.coffee | 4 ++-- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/spec/project-spec.coffee b/spec/project-spec.coffee index 017bb6a13..5067dd02c 100644 --- a/spec/project-spec.coffee +++ b/spec/project-spec.coffee @@ -240,12 +240,14 @@ describe "Project", -> runs -> expect(matches[0]).toEqual path: project.resolve('a') - match: 'aaa' + matchText: 'aaa' + lineText: 'aaa bbb' range: [[0, 0], [0, 3]] expect(matches[1]).toEqual path: project.resolve('a') - match: 'aa' + matchText: 'aa' + lineText: 'cc aa cc' range: [[1, 3], [1, 5]] it "works with with escaped literals (like $ and ^)", -> @@ -258,7 +260,8 @@ describe "Project", -> expect(matches[0]).toEqual path: project.resolve('a') - match: '$bill' + matchText: '$bill' + lineText: 'dollar$bill' range: [[2, 6], [2, 11]] it "works on evil filenames", -> @@ -268,7 +271,7 @@ describe "Project", -> waitsForPromise -> project.scan /evil/, (result) -> paths.push(result.path) - matches.push(result.match) + matches.push(result.matchText) runs -> expect(paths.length).toBe 5 @@ -299,12 +302,14 @@ describe "Project", -> expect(iterator.argsForCall[0][0]).toEqual path: project.resolve('a') - match: 'aaa' + matchText: 'aaa' + lineText: 'aaa bbb' range: [[0, 0], [0, 3]] expect(iterator.argsForCall[1][0]).toEqual path: project.resolve('a') - match: 'aa' + matchText: 'aa' + lineText: 'cc aa cc' range: [[1, 3], [1, 5]] describe "when the core.excludeVcsIgnoredPaths config is truthy", -> @@ -326,7 +331,7 @@ describe "Project", -> waitsForPromise -> project.scan /match/, (result) -> paths.push(result.path) - matches.push(result.match) + matches.push(result.matchText) runs -> expect(paths.length).toBe 0 @@ -343,7 +348,7 @@ describe "Project", -> waitsForPromise -> project.scan /aaa/, paths: ['a-dir/'], (result) -> paths.push(result.path) - matches.push(result.match) + matches.push(result.matchText) runs -> expect(paths.length).toBe 1 @@ -360,7 +365,7 @@ describe "Project", -> waitsForPromise -> project.scan /match this/, (result) -> paths.push(result.path) - matches.push(result.match) + matches.push(result.matchText) runs -> expect(paths.length).toBe 1 @@ -378,7 +383,7 @@ describe "Project", -> waitsForPromise -> project.scan /match/, (result) -> paths.push(result.path) - matches.push(result.match) + matches.push(result.matchText) runs -> expect(paths.length).toBe 0 diff --git a/src/project.coffee b/src/project.coffee index 2477e819e..16d42b948 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -316,8 +316,8 @@ class Project for [column, length] in matchPositions range = new Range([row, column], [row, column + length]) - match = lineText.substr(column, length) - iterator({path: filePath, range, match}) + matchText = lineText.substr(column, length) + iterator({path: filePath, range, matchText, lineText}) deferred = $.Deferred() errors = [] From 861adf669230a3f16a14909fd63c31ac67218164 Mon Sep 17 00:00:00 2001 From: probablycorey Date: Mon, 23 Sep 2013 15:46:57 -0700 Subject: [PATCH 05/20] Start using `scandal` and make the specs pass --- package.json | 3 +- spec/fixtures/git/working-dir/.gitignore | 3 +- spec/fixtures/git/working-dir/git.git/HEAD | 1 + spec/fixtures/git/working-dir/git.git/config | 6 ++ spec/fixtures/git/working-dir/git.git/index | Bin 0 -> 137 bytes .../65/a457425a679cbe9adf0d2741785d3ceabb44a7 | Bin 0 -> 50 bytes .../e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 | Bin 0 -> 15 bytes .../ef/046e9eecaa5255ea5e9817132d4001724d6ae1 | Bin 0 -> 132 bytes .../git/working-dir/git.git/refs/heads/master | 1 + spec/git-spec.coffee | 1 + spec/project-spec.coffee | 94 ++++++++---------- src/project.coffee | 73 +++----------- 12 files changed, 70 insertions(+), 112 deletions(-) create mode 100644 spec/fixtures/git/working-dir/git.git/HEAD create mode 100644 spec/fixtures/git/working-dir/git.git/config create mode 100644 spec/fixtures/git/working-dir/git.git/index create mode 100644 spec/fixtures/git/working-dir/git.git/objects/65/a457425a679cbe9adf0d2741785d3ceabb44a7 create mode 100644 spec/fixtures/git/working-dir/git.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 create mode 100644 spec/fixtures/git/working-dir/git.git/objects/ef/046e9eecaa5255ea5e9817132d4001724d6ae1 create mode 100644 spec/fixtures/git/working-dir/git.git/refs/heads/master diff --git a/package.json b/package.json index b0273a496..93a0f4d51 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,6 @@ "mkdirp": "0.3.5", "less": "git://github.com/nathansobo/less.js.git", "less-cache": "0.8.0", - "nak": "0.2.18", "nslog": "0.1.0", "oniguruma": "0.20.0", "optimist": "0.4.0", @@ -30,6 +29,7 @@ "pegjs": "0.7.0", "plist": "git://github.com/nathansobo/node-plist.git", "rimraf": "2.1.4", + "scandal": "0.1.0", "season": "0.13.0", "semver": "1.1.4", "space-pen": "1.2.0", @@ -117,6 +117,7 @@ }, "devDependencies": { "biscotto": "0.0.17", + "fstream": "0.1.24", "grunt": "~0.4.1", "grunt-cli": "~0.1.9", "grunt-coffeelint": "0.0.6", diff --git a/spec/fixtures/git/working-dir/.gitignore b/spec/fixtures/git/working-dir/.gitignore index 09f5ff762..23238eafc 100644 --- a/spec/fixtures/git/working-dir/.gitignore +++ b/spec/fixtures/git/working-dir/.gitignore @@ -1 +1,2 @@ -ignored.txt \ No newline at end of file +poop +ignored.txt diff --git a/spec/fixtures/git/working-dir/git.git/HEAD b/spec/fixtures/git/working-dir/git.git/HEAD new file mode 100644 index 000000000..cb089cd89 --- /dev/null +++ b/spec/fixtures/git/working-dir/git.git/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/spec/fixtures/git/working-dir/git.git/config b/spec/fixtures/git/working-dir/git.git/config new file mode 100644 index 000000000..af107929f --- /dev/null +++ b/spec/fixtures/git/working-dir/git.git/config @@ -0,0 +1,6 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true + ignorecase = true diff --git a/spec/fixtures/git/working-dir/git.git/index b/spec/fixtures/git/working-dir/git.git/index new file mode 100644 index 0000000000000000000000000000000000000000..bf35b18cd334b5611b86f4a8dc91bf08542daf34 GIT binary patch literal 137 zcmZ?q402{*U|<4b#(>UEnLwHWMl&)nurS0#rZX@!E&)n^1xks46HxQkR4~MWxT#H|svHx?@GG&8yum a%eN^dzV?cL@sl}bFS|j92$yAM$22rPLQ6n?I4({XK>N literal 0 HcmV?d00001 diff --git a/spec/fixtures/git/working-dir/git.git/refs/heads/master b/spec/fixtures/git/working-dir/git.git/refs/heads/master new file mode 100644 index 000000000..6134b5707 --- /dev/null +++ b/spec/fixtures/git/working-dir/git.git/refs/heads/master @@ -0,0 +1 @@ +ef046e9eecaa5255ea5e9817132d4001724d6ae1 diff --git a/spec/git-spec.coffee b/spec/git-spec.coffee index 2a972c4ca..26966b2a5 100644 --- a/spec/git-spec.coffee +++ b/spec/git-spec.coffee @@ -1,3 +1,4 @@ +temp = require 'temp' Git = require '../src/git' {fs} = require 'atom' path = require 'path' diff --git a/spec/project-spec.coffee b/spec/project-spec.coffee index 5067dd02c..63f5463f3 100644 --- a/spec/project-spec.coffee +++ b/spec/project-spec.coffee @@ -1,3 +1,5 @@ +temp = require 'temp' +fstream = require 'fstream' Project = require '../src/project' {_, fs} = require 'atom' path = require 'path' @@ -238,17 +240,13 @@ describe "Project", -> project.scan /(a)+/, (match) -> matches.push(match) runs -> - expect(matches[0]).toEqual - path: project.resolve('a') - matchText: 'aaa' - lineText: 'aaa bbb' - range: [[0, 0], [0, 3]] - - expect(matches[1]).toEqual - path: project.resolve('a') - matchText: 'aa' - lineText: 'cc aa cc' - range: [[1, 3], [1, 5]] + expect(matches).toHaveLength(3) + expect(matches[0].path).toBe project.resolve('a') + expect(matches[0].matches).toHaveLength(3) + expect(matches[0].matches[0]).toEqual + matchText: 'aaa' + lineText: 'aaa bbb' + range: [[0, 0], [0, 3]] it "works with with escaped literals (like $ and ^)", -> matches = [] @@ -258,8 +256,10 @@ describe "Project", -> runs -> expect(matches.length).toBe 1 + {path: resultPath, matches} = matches[0] + expect(resultPath).toBe project.resolve('a') + expect(matches).toHaveLength 1 expect(matches[0]).toEqual - path: project.resolve('a') matchText: '$bill' lineText: 'dollar$bill' range: [[2, 6], [2, 11]] @@ -271,11 +271,11 @@ describe "Project", -> waitsForPromise -> project.scan /evil/, (result) -> paths.push(result.path) - matches.push(result.matchText) + matches = matches.concat(result.matches) runs -> expect(paths.length).toBe 5 - matches.forEach (match) -> expect(match).toEqual 'evil' + matches.forEach (match) -> expect(match.matchText).toEqual 'evil' expect(paths[0]).toMatch /a_file_with_utf8.txt$/ expect(paths[1]).toMatch /file with spaces.txt$/ expect(paths[2]).toMatch /goddam\nnewlines$/m @@ -283,62 +283,49 @@ describe "Project", -> expect(path.basename(paths[4])).toBe "utfa\u0306.md" it "ignores case if the regex includes the `i` flag", -> - matches = [] + results = [] waitsForPromise -> - project.scan /DOLLAR/i, (match) -> matches.push(match) + project.scan /DOLLAR/i, (result) -> results.push(result) runs -> - expect(matches).toHaveLength 1 - - it "handles breaks in the search subprocess's output following the filename", -> - spyOn(BufferedProcess.prototype, 'bufferStream') - - iterator = jasmine.createSpy('iterator') - project.scan /a+/, iterator - - stdout = BufferedProcess.prototype.bufferStream.argsForCall[0][1] - stdout ":#{path.join(__dirname, 'fixtures', 'dir', 'a')}\n" - stdout "1;0 3:aaa bbb\n2;3 2:cc aa cc\n" - - expect(iterator.argsForCall[0][0]).toEqual - path: project.resolve('a') - matchText: 'aaa' - lineText: 'aaa bbb' - range: [[0, 0], [0, 3]] - - expect(iterator.argsForCall[1][0]).toEqual - path: project.resolve('a') - matchText: 'aa' - lineText: 'cc aa cc' - range: [[1, 3], [1, 5]] + expect(results).toHaveLength 1 describe "when the core.excludeVcsIgnoredPaths config is truthy", -> [projectPath, ignoredPath] = [] beforeEach -> - projectPath = path.join(__dirname, 'fixtures', 'git', 'working-dir') - ignoredPath = path.join(projectPath, 'ignored.txt') - fs.writeSync(ignoredPath, 'this match should not be included') + sourceProjectPath = path.join(__dirname, 'fixtures', 'git', 'working-dir') + projectPath = path.join(temp.mkdirSync("atom")) + + writerStream = fstream.Writer(projectPath) + fstream.Reader(sourceProjectPath).pipe(writerStream) + + waitsFor (done) -> + writerStream.on 'close', done + writerStream.on 'error', done + + runs -> + fs.rename(path.join(projectPath, 'git.git'), path.join(projectPath, '.git')) + ignoredPath = path.join(projectPath, 'ignored.txt') + fs.writeSync(ignoredPath, 'this match should not be included') afterEach -> - fs.remove(ignoredPath) if fs.exists(ignoredPath) + fs.remove(projectPath) if fs.exists(projectPath) it "excludes ignored files", -> project.setPath(projectPath) config.set('core.excludeVcsIgnoredPaths', true) - paths = [] - matches = [] + resultHandler = jasmine.createSpy("result found") waitsForPromise -> - project.scan /match/, (result) -> - paths.push(result.path) - matches.push(result.matchText) + project.scan /match/, (results) -> + console.log results + resultHandler() runs -> - expect(paths.length).toBe 0 - expect(matches.length).toBe 0 + expect(resultHandler).not.toHaveBeenCalled() it "includes only files when a directory filter is specified", -> - projectPath = fsUtils.resolveOnLoadPath('fixtures/dir') + projectPath = path.join(path.join(__dirname, 'fixtures', 'dir')) project.setPath(projectPath) filePath = path.join(projectPath, 'a-dir', 'oh-git') @@ -348,7 +335,8 @@ describe "Project", -> waitsForPromise -> project.scan /aaa/, paths: ['a-dir/'], (result) -> paths.push(result.path) - matches.push(result.matchText) + console.log result + matches = matches.concat(result.matches) runs -> expect(paths.length).toBe 1 @@ -365,7 +353,7 @@ describe "Project", -> waitsForPromise -> project.scan /match this/, (result) -> paths.push(result.path) - matches.push(result.matchText) + matches = matches.concat(result.matches) runs -> expect(paths.length).toBe 1 diff --git a/src/project.coffee b/src/project.coffee index 16d42b948..de2f1eb6c 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -1,6 +1,7 @@ fsUtils = require './fs-utils' path = require 'path' url = require 'url' +{PathSearcher, PathScanner, search} = require 'scandal' _ = require './underscore-extensions' $ = require './jquery-extensions' @@ -10,7 +11,6 @@ TextBuffer = require './text-buffer' EditSession = require './edit-session' EventEmitter = require './event-emitter' Directory = require './directory' -BufferedNodeProcess = require './buffered-node-process' Git = require './git' # Public: Represents a project that's opened in Atom. @@ -279,7 +279,7 @@ class Project # * regex: # A RegExp to search with # * options: - # - paths: an {Array} of path names to search within + # - paths: an {Array} of glob patterns to search within # * iterator: # A Function callback on each file found scan: (regex, options={}, iterator) -> @@ -287,63 +287,22 @@ class Project iterator = options options = {} - bufferedData = "" - state = 'readingPath' - filePath = null - - readPath = (line) -> - if /^[0-9,; ]+:/.test(line) - state = 'readingLines' - else if /^:/.test line - filePath = line.substr(1) - else - filePath += ('\n' + line) - - readLine = (line) -> - if line.length == 0 - state = 'readingPath' - filePath = null - else - colonIndex = line.indexOf(':') - matchInfo = line.substring(0, colonIndex) - lineText = line.substring(colonIndex + 1) - readMatches(matchInfo, lineText) - - readMatches = (matchInfo, lineText) -> - [lineNumber, matchPositionsText] = matchInfo.match(/(\d+);(.+)/)[1..] - row = parseInt(lineNumber) - 1 - matchPositions = matchPositionsText.split(',').map (positionText) -> positionText.split(' ').map (pos) -> parseInt(pos) - - for [column, length] in matchPositions - range = new Range([row, column], [row, column + length]) - matchText = lineText.substr(column, length) - iterator({path: filePath, range, matchText, lineText}) - deferred = $.Deferred() - errors = [] - stderr = (data) -> - errors.push(data) - stdout = (data) -> - lines = data.split('\n') - lines.pop() # the last segment is a spurious '' because data always ends in \n due to bufferLines: true - for line in lines - readPath(line) if state is 'readingPath' - readLine(line) if state is 'readingLines' - exit = (code) -> - if code is 0 - deferred.resolve() - else - console.error("Project scan failed: #{code}", errors.join('\n')) - deferred.reject({command, code}) + searchOptions = + inclusions: options.paths + includeHidden: true + excludeVcsIgnores: config.get('core.excludeVcsIgnoredPaths') + # args.unshift('--ignore', ignoredNames.join(',')) if ignoredNames.length > 0 + + searcher = new PathSearcher() + scanner = new PathScanner(@getPath(), searchOptions) + + searcher.on 'results-found', (result) -> + iterator(result) + + search regex, scanner, searcher, -> + deferred.resolve() - command = require.resolve('.bin/nak') - args = ['--hidden', '--ackmate', regex.source, @getPath()] - ignoredNames = config.get('core.ignoredNames') ? [] - args.unshift('--pathInclude', options.paths.join(',')) if options.paths and options.paths.length > 0 - args.unshift('--ignore', ignoredNames.join(',')) if ignoredNames.length > 0 - args.unshift('--ignoreCase') if regex.ignoreCase - args.unshift('--addVCSIgnores') if config.get('core.excludeVcsIgnoredPaths') - new BufferedNodeProcess({command, args, stdout, stderr, exit}) deferred # Private: From e26d7a032068f0d163754441cff5271ed01bcc9f Mon Sep 17 00:00:00 2001 From: probablycorey Date: Tue, 24 Sep 2013 11:43:58 -0700 Subject: [PATCH 06/20] wip --- src/project.coffee | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/project.coffee b/src/project.coffee index de2f1eb6c..f454f074b 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -300,7 +300,9 @@ class Project searcher.on 'results-found', (result) -> iterator(result) + console.time("search") search regex, scanner, searcher, -> + console.timeEnd("search") deferred.resolve() deferred From cd554a4f7bf2d60c42cbe955ba2dacf5679a68f2 Mon Sep 17 00:00:00 2001 From: probablycorey Date: Tue, 24 Sep 2013 13:21:12 -0700 Subject: [PATCH 07/20] Project::scan uses a task to do its work --- src/project.coffee | 17 +++++++---------- src/scan-handler.coffee | 15 +++++++++++++++ 2 files changed, 22 insertions(+), 10 deletions(-) create mode 100644 src/scan-handler.coffee diff --git a/src/project.coffee b/src/project.coffee index f454f074b..a059b2020 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -1,7 +1,6 @@ fsUtils = require './fs-utils' path = require 'path' url = require 'url' -{PathSearcher, PathScanner, search} = require 'scandal' _ = require './underscore-extensions' $ = require './jquery-extensions' @@ -11,6 +10,7 @@ TextBuffer = require './text-buffer' EditSession = require './edit-session' EventEmitter = require './event-emitter' Directory = require './directory' +Task = require './task' Git = require './git' # Public: Represents a project that's opened in Atom. @@ -288,23 +288,20 @@ class Project options = {} deferred = $.Deferred() + searchOptions = + ignoreCase: regex.ignoreCase inclusions: options.paths includeHidden: true excludeVcsIgnores: config.get('core.excludeVcsIgnoredPaths') # args.unshift('--ignore', ignoredNames.join(',')) if ignoredNames.length > 0 - searcher = new PathSearcher() - scanner = new PathScanner(@getPath(), searchOptions) - - searcher.on 'results-found', (result) -> - iterator(result) - - console.time("search") - search regex, scanner, searcher, -> - console.timeEnd("search") + task = Task.once require.resolve('./scan-handler'), @getPath(), regex.source, searchOptions, -> deferred.resolve() + task.on 'scan:result-found', (result) => + iterator(result) + deferred # Private: diff --git a/src/scan-handler.coffee b/src/scan-handler.coffee new file mode 100644 index 000000000..b284a7911 --- /dev/null +++ b/src/scan-handler.coffee @@ -0,0 +1,15 @@ +{PathSearcher, PathScanner, search} = require 'scandal' + +module.exports = (rootPath, regexSource, options) -> + callback = @async() + + searcher = new PathSearcher() + scanner = new PathScanner(rootPath, rootPath) + + searcher.on 'results-found', (result) -> + emit('scan:result-found', result) + + flags = "g" + flags += "i" if options.ignoreCase + regex = new RegExp(regexSource, flags) + search regex, scanner, searcher, callback From ba80ba458cdac9a506fcd2e9f421c5f8f3648305 Mon Sep 17 00:00:00 2001 From: probablycorey Date: Tue, 24 Sep 2013 13:22:25 -0700 Subject: [PATCH 08/20] Remove console.logs --- spec/project-spec.coffee | 2 -- 1 file changed, 2 deletions(-) diff --git a/spec/project-spec.coffee b/spec/project-spec.coffee index 63f5463f3..8a4c01daf 100644 --- a/spec/project-spec.coffee +++ b/spec/project-spec.coffee @@ -318,7 +318,6 @@ describe "Project", -> resultHandler = jasmine.createSpy("result found") waitsForPromise -> project.scan /match/, (results) -> - console.log results resultHandler() runs -> @@ -335,7 +334,6 @@ describe "Project", -> waitsForPromise -> project.scan /aaa/, paths: ['a-dir/'], (result) -> paths.push(result.path) - console.log result matches = matches.concat(result.matches) runs -> From 7856a8ce62769f1382a137d9b58a39491303c0fd Mon Sep 17 00:00:00 2001 From: probablycorey Date: Tue, 24 Sep 2013 13:36:00 -0700 Subject: [PATCH 09/20] Make the scan task actually work --- src/scan-handler.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scan-handler.coffee b/src/scan-handler.coffee index b284a7911..735fc2f00 100644 --- a/src/scan-handler.coffee +++ b/src/scan-handler.coffee @@ -4,7 +4,7 @@ module.exports = (rootPath, regexSource, options) -> callback = @async() searcher = new PathSearcher() - scanner = new PathScanner(rootPath, rootPath) + scanner = new PathScanner(rootPath, options) searcher.on 'results-found', (result) -> emit('scan:result-found', result) From f467746cba986d612e4f3bf619c2f843626f7122 Mon Sep 17 00:00:00 2001 From: probablycorey Date: Tue, 24 Sep 2013 13:36:52 -0700 Subject: [PATCH 10/20] Project::scan uses core.ignoredNames --- spec/project-spec.coffee | 24 +++++++++++------------- src/project.coffee | 2 +- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/spec/project-spec.coffee b/spec/project-spec.coffee index 8a4c01daf..0da5aeeef 100644 --- a/spec/project-spec.coffee +++ b/spec/project-spec.coffee @@ -358,19 +358,17 @@ describe "Project", -> expect(paths[0]).toBe filePath expect(matches.length).toBe 1 - xit "excludes values in core.ignoredNames", -> - # FIXME: this test doesnt make any sense. Why should it ignore the whole project dir? - projectPath = '/tmp/atom-tests/folder-with-dot-git/.git' - filePath = path.join(projectPath, 'test.txt') - fs.writeSync(filePath, 'match this') - project.setPath(projectPath) - paths = [] - matches = [] + it "excludes values in core.ignoredNames", -> + projectPath = path.join(__dirname, 'fixtures', 'git', 'working-dir') + ignoredNames = config.get("core.ignoredNames") + ignoredNames.push("a") + config.set("core.ignoredNames", ignoredNames) + + resultHandler = jasmine.createSpy("result found") waitsForPromise -> - project.scan /match/, (result) -> - paths.push(result.path) - matches.push(result.matchText) + project.scan /dollar/, (results) -> + console.log results + resultHandler() runs -> - expect(paths.length).toBe 0 - expect(matches.length).toBe 0 + expect(resultHandler).not.toHaveBeenCalled() diff --git a/src/project.coffee b/src/project.coffee index a059b2020..7ee3ac00a 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -294,7 +294,7 @@ class Project inclusions: options.paths includeHidden: true excludeVcsIgnores: config.get('core.excludeVcsIgnoredPaths') - # args.unshift('--ignore', ignoredNames.join(',')) if ignoredNames.length > 0 + exclusions: config.get('core.ignoredNames') task = Task.once require.resolve('./scan-handler'), @getPath(), regex.source, searchOptions, -> deferred.resolve() From cb11e2010097167923db0dce631eb6054759d5d5 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 24 Sep 2013 14:20:59 -0700 Subject: [PATCH 11/20] Upgrade to scandal 0.2.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 93a0f4d51..cb2910c09 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "pegjs": "0.7.0", "plist": "git://github.com/nathansobo/node-plist.git", "rimraf": "2.1.4", - "scandal": "0.1.0", + "scandal": "0.2.0", "season": "0.13.0", "semver": "1.1.4", "space-pen": "1.2.0", From 9c4d239696d2b8e0039e8f65029c0b1eb8e36d81 Mon Sep 17 00:00:00 2001 From: probablycorey Date: Tue, 24 Sep 2013 16:37:01 -0700 Subject: [PATCH 12/20] Fix Project::scan specs --- spec/project-spec.coffee | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/spec/project-spec.coffee b/spec/project-spec.coffee index 0da5aeeef..88d39fba2 100644 --- a/spec/project-spec.coffee +++ b/spec/project-spec.coffee @@ -234,34 +234,37 @@ describe "Project", -> 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 = [] + it "calls the callback with all regex results in all files in the project", -> + results = [] waitsForPromise -> - project.scan /(a)+/, (match) -> matches.push(match) + project.scan /(a)+/, (result) -> + results.push(result) runs -> - expect(matches).toHaveLength(3) - expect(matches[0].path).toBe project.resolve('a') - expect(matches[0].matches).toHaveLength(3) - expect(matches[0].matches[0]).toEqual + expect(results).toHaveLength(3) + expect(results[0].filePath).toBe project.resolve('a') + expect(results[0].matches).toHaveLength(3) + expect(results[0].matches[0]).toEqual matchText: 'aaa' lineText: 'aaa bbb' + lineTextOffset: 0 range: [[0, 0], [0, 3]] it "works with with escaped literals (like $ and ^)", -> - matches = [] + results = [] waitsForPromise -> - project.scan /\$\w+/, (match) -> matches.push(match) + project.scan /\$\w+/, (result) -> results.push(result) runs -> - expect(matches.length).toBe 1 + expect(results.length).toBe 1 - {path: resultPath, matches} = matches[0] - expect(resultPath).toBe project.resolve('a') + {filePath, matches} = results[0] + expect(filePath).toBe project.resolve('a') expect(matches).toHaveLength 1 expect(matches[0]).toEqual matchText: '$bill' lineText: 'dollar$bill' + lineTextOffset: 0 range: [[2, 6], [2, 11]] it "works on evil filenames", -> @@ -270,7 +273,7 @@ describe "Project", -> matches = [] waitsForPromise -> project.scan /evil/, (result) -> - paths.push(result.path) + paths.push(result.filePath) matches = matches.concat(result.matches) runs -> @@ -333,7 +336,7 @@ describe "Project", -> matches = [] waitsForPromise -> project.scan /aaa/, paths: ['a-dir/'], (result) -> - paths.push(result.path) + paths.push(result.filePath) matches = matches.concat(result.matches) runs -> @@ -350,7 +353,7 @@ describe "Project", -> matches = [] waitsForPromise -> project.scan /match this/, (result) -> - paths.push(result.path) + paths.push(result.filePath) matches = matches.concat(result.matches) runs -> From 00cdb3e31705709017024dae5d92f67d89ede112 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Tue, 24 Sep 2013 16:00:23 -0700 Subject: [PATCH 13/20] Add lineText and lineTextOffset to buffer.scan --- spec/text-buffer-spec.coffee | 11 +++++++++++ src/text-buffer.coffee | 9 +++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/spec/text-buffer-spec.coffee b/spec/text-buffer-spec.coffee index bb715a467..ec6efb63f 100644 --- a/spec/text-buffer-spec.coffee +++ b/spec/text-buffer-spec.coffee @@ -602,6 +602,17 @@ describe 'TextBuffer', -> it "clips the range to the end of the buffer", -> expect(buffer.getTextInRange([[12], [13, Infinity]])).toBe buffer.lineForRow(12) + describe ".scan(regex, fn)", -> + it "retunrns lineText and lineTextOffset", -> + matches = [] + buffer.scan /current/, (match) -> + matches.push(match) + expect(matches.length).toBe 1 + + expect(matches[0].matchText).toEqual 'current' + expect(matches[0].lineText).toEqual ' var pivot = items.shift(), current, left = [], right = [];' + expect(matches[0].lineTextOffset).toBe 0 + describe ".scanInRange(range, regex, fn)", -> describe "when given a regex with a ignore case flag", -> it "does a case-insensitive search", -> diff --git a/src/text-buffer.coffee b/src/text-buffer.coffee index cfad306c0..0b1431061 100644 --- a/src/text-buffer.coffee +++ b/src/text-buffer.coffee @@ -6,6 +6,7 @@ File = require './file' EventEmitter = require './event-emitter' Subscriber = require './subscriber' guid = require 'guid' +{P} = require 'scandal' # Private: Represents the contents of a file. # @@ -501,7 +502,10 @@ class TextBuffer # regex - A {RegExp} representing the text to find # iterator - A {Function} that's called on each match scan: (regex, iterator) -> - @scanInRange(regex, @getRange(), iterator) + @scanInRange regex, @getRange(), (result) => + result.lineText = @lineForRow(result.range.start.row) + result.lineTextOffset = 0 + iterator(result) # Scans for text in a given range, calling a function on each match. # @@ -538,7 +542,8 @@ class TextBuffer range = new Range(startPosition, endPosition) keepLooping = true replacementText = null - iterator({match, range, stop, replace }) + matchText = match[0] + iterator({ match, matchText, range, stop, replace }) if replacementText? @change(range, replacementText) From 238939e738a88783e411db7e5f7315bb641956e3 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 25 Sep 2013 11:01:15 -0700 Subject: [PATCH 14/20] Bubble contents-modified from buffer through editSession --- src/edit-session.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/src/edit-session.coffee b/src/edit-session.coffee index 7490f7ca3..d2bac5ac0 100644 --- a/src/edit-session.coffee +++ b/src/edit-session.coffee @@ -117,6 +117,7 @@ class EditSession project.setPath(path.dirname(@getPath())) unless project.getPath()? @trigger "title-changed" @trigger "path-changed" + @subscribe @buffer, "contents-modified", => @trigger "contents-modified" @subscribe @buffer, "contents-conflicted", => @trigger "contents-conflicted" @subscribe @buffer, "modified-status-changed", => @trigger "modified-status-changed" @preserveCursorPositionOnBufferReload() From 04f0bf02445d6274fb20c7957f26b085b36d8e45 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 25 Sep 2013 11:02:29 -0700 Subject: [PATCH 15/20] Provide scan() delegation in editSession --- src/edit-session.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/edit-session.coffee b/src/edit-session.coffee index d2bac5ac0..558d926d4 100644 --- a/src/edit-session.coffee +++ b/src/edit-session.coffee @@ -377,6 +377,9 @@ class EditSession # {Delegates to: TextBuffer.lineLengthForRow} lineLengthForBufferRow: (row) -> @buffer.lineLengthForRow(row) + # {Delegates to: TextBuffer.scan} + scan: (args...) -> @buffer.scan(args...) + # {Delegates to: TextBuffer.scanInRange} scanInBufferRange: (args...) -> @buffer.scanInRange(args...) From 865591a3da7e45250234e7bd5b1b3f6dd63c58ca Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 25 Sep 2013 15:03:50 -0700 Subject: [PATCH 16/20] Fix indentation --- spec/project-spec.coffee | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/project-spec.coffee b/spec/project-spec.coffee index 88d39fba2..5b37a9766 100644 --- a/spec/project-spec.coffee +++ b/spec/project-spec.coffee @@ -245,10 +245,10 @@ describe "Project", -> expect(results[0].filePath).toBe project.resolve('a') expect(results[0].matches).toHaveLength(3) expect(results[0].matches[0]).toEqual - matchText: 'aaa' - lineText: 'aaa bbb' - lineTextOffset: 0 - range: [[0, 0], [0, 3]] + matchText: 'aaa' + lineText: 'aaa bbb' + lineTextOffset: 0 + range: [[0, 0], [0, 3]] it "works with with escaped literals (like $ and ^)", -> results = [] From da6aff222b7516583abc6c263698de959a083d52 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 25 Sep 2013 15:09:00 -0700 Subject: [PATCH 17/20] upgrade themes for loading spinners --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index cb2910c09..639e983bb 100644 --- a/package.json +++ b/package.json @@ -38,9 +38,9 @@ "temp": "0.5.0", "underscore": "1.4.4", - "atom-light-ui": "0.2.1", + "atom-light-ui": "0.3.0", "atom-light-syntax": "0.2.0", - "atom-dark-ui": "0.2.0", + "atom-dark-ui": "0.3.0", "atom-dark-syntax": "0.2.0", "base16-tomorrow-dark-theme": "0.1.0", "solarized-dark-syntax": "0.1.0", From 824049e17a595cff6dd6e0849212ae6fb20dd49a Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 25 Sep 2013 15:59:10 -0700 Subject: [PATCH 18/20] Add escapeAttribute to underscore-extensions --- src/underscore-extensions.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/underscore-extensions.coffee b/src/underscore-extensions.coffee index 46ab466e4..fdfc0b845 100644 --- a/src/underscore-extensions.coffee +++ b/src/underscore-extensions.coffee @@ -28,6 +28,9 @@ _.mixin escapeRegExp: (string) -> string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + escapeAttribute: (string) -> + string.replace(/"/g, '"').replace(/\n/g, '') + humanizeEventName: (eventName, eventDoc) -> [namespace, event] = eventName.split(':') return _.undasherize(namespace) unless event? From b3fd4733047369daa5cca3f493dc73667689f3a0 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 25 Sep 2013 16:30:36 -0700 Subject: [PATCH 19/20] UPgrade to FNR v0.12.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 639e983bb..311f8e76f 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "command-palette": "0.3.0", "editor-stats": "0.2.0", "exception-reporting": "0.1.0", - "find-and-replace": "0.11.0", + "find-and-replace": "0.12.0", "fuzzy-finder": "0.5.0", "gfm": "0.4.0", "git-diff": "0.3.0", From 614ca3cb5f534f0a735806782bc1542a001b05a3 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Wed, 25 Sep 2013 16:40:55 -0700 Subject: [PATCH 20/20] Update to FNR v0.13.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 311f8e76f..49a366d60 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "command-palette": "0.3.0", "editor-stats": "0.2.0", "exception-reporting": "0.1.0", - "find-and-replace": "0.12.0", + "find-and-replace": "0.13.0", "fuzzy-finder": "0.5.0", "gfm": "0.4.0", "git-diff": "0.3.0",