mirror of
https://github.com/atom/atom.git
synced 2026-01-23 13:58:08 -05:00
Move Project::scan to Workspace
This commit is contained in:
@@ -4,7 +4,6 @@ Project = require '../src/project'
|
||||
_ = require 'underscore-plus'
|
||||
fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
platform = require './spec-helper-platform'
|
||||
BufferedProcess = require '../src/buffered-process'
|
||||
|
||||
describe "Project", ->
|
||||
@@ -295,190 +294,6 @@ describe "Project", ->
|
||||
|
||||
expect(editor.isModified()).toBeTruthy()
|
||||
|
||||
describe ".scan(options, callback)", ->
|
||||
describe "when called with a regex", ->
|
||||
it "calls the callback with all regex results in all files in the project", ->
|
||||
results = []
|
||||
waitsForPromise ->
|
||||
atom.project.scan /(a)+/, (result) ->
|
||||
results.push(result)
|
||||
|
||||
runs ->
|
||||
expect(results).toHaveLength(3)
|
||||
expect(results[0].filePath).toBe atom.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 ^)", ->
|
||||
results = []
|
||||
waitsForPromise ->
|
||||
atom.project.scan /\$\w+/, (result) -> results.push(result)
|
||||
|
||||
runs ->
|
||||
expect(results.length).toBe 1
|
||||
|
||||
{filePath, matches} = results[0]
|
||||
expect(filePath).toBe atom.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", ->
|
||||
platform.generateEvilFiles()
|
||||
atom.project.setPaths([path.join(__dirname, 'fixtures', 'evil-files')])
|
||||
paths = []
|
||||
matches = []
|
||||
waitsForPromise ->
|
||||
atom.project.scan /evil/, (result) ->
|
||||
paths.push(result.filePath)
|
||||
matches = matches.concat(result.matches)
|
||||
|
||||
runs ->
|
||||
_.each(matches, (m) -> expect(m.matchText).toEqual 'evil')
|
||||
|
||||
if platform.isWindows()
|
||||
expect(paths.length).toBe 3
|
||||
expect(paths[0]).toMatch /a_file_with_utf8.txt$/
|
||||
expect(paths[1]).toMatch /file with spaces.txt$/
|
||||
expect(path.basename(paths[2])).toBe "utfa\u0306.md"
|
||||
else
|
||||
expect(paths.length).toBe 5
|
||||
expect(paths[0]).toMatch /a_file_with_utf8.txt$/
|
||||
expect(paths[1]).toMatch /file with spaces.txt$/
|
||||
expect(paths[2]).toMatch /goddam\nnewlines$/m
|
||||
expect(paths[3]).toMatch /quote".txt$/m
|
||||
expect(path.basename(paths[4])).toBe "utfa\u0306.md"
|
||||
|
||||
it "ignores case if the regex includes the `i` flag", ->
|
||||
results = []
|
||||
waitsForPromise ->
|
||||
atom.project.scan /DOLLAR/i, (result) -> results.push(result)
|
||||
|
||||
runs ->
|
||||
expect(results).toHaveLength 1
|
||||
|
||||
describe "when the core.excludeVcsIgnoredPaths config is truthy", ->
|
||||
[projectPath, ignoredPath] = []
|
||||
|
||||
beforeEach ->
|
||||
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.writeFileSync(ignoredPath, 'this match should not be included')
|
||||
|
||||
afterEach ->
|
||||
fs.removeSync(projectPath) if fs.existsSync(projectPath)
|
||||
|
||||
it "excludes ignored files", ->
|
||||
atom.project.setPaths([projectPath])
|
||||
atom.config.set('core.excludeVcsIgnoredPaths', true)
|
||||
resultHandler = jasmine.createSpy("result found")
|
||||
waitsForPromise ->
|
||||
atom.project.scan /match/, (results) ->
|
||||
resultHandler()
|
||||
|
||||
runs ->
|
||||
expect(resultHandler).not.toHaveBeenCalled()
|
||||
|
||||
it "includes only files when a directory filter is specified", ->
|
||||
projectPath = path.join(path.join(__dirname, 'fixtures', 'dir'))
|
||||
atom.project.setPaths([projectPath])
|
||||
|
||||
filePath = path.join(projectPath, 'a-dir', 'oh-git')
|
||||
|
||||
paths = []
|
||||
matches = []
|
||||
waitsForPromise ->
|
||||
atom.project.scan /aaa/, paths: ["a-dir#{path.sep}"], (result) ->
|
||||
paths.push(result.filePath)
|
||||
matches = matches.concat(result.matches)
|
||||
|
||||
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 = temp.mkdirSync()
|
||||
filePath = path.join(projectPath, '.text')
|
||||
fs.writeFileSync(filePath, 'match this')
|
||||
atom.project.setPaths([projectPath])
|
||||
paths = []
|
||||
matches = []
|
||||
waitsForPromise ->
|
||||
atom.project.scan /match this/, (result) ->
|
||||
paths.push(result.filePath)
|
||||
matches = matches.concat(result.matches)
|
||||
|
||||
runs ->
|
||||
expect(paths.length).toBe 1
|
||||
expect(paths[0]).toBe filePath
|
||||
expect(matches.length).toBe 1
|
||||
|
||||
it "excludes values in core.ignoredNames", ->
|
||||
projectPath = path.join(__dirname, 'fixtures', 'git', 'working-dir')
|
||||
ignoredNames = atom.config.get("core.ignoredNames")
|
||||
ignoredNames.push("a")
|
||||
atom.config.set("core.ignoredNames", ignoredNames)
|
||||
|
||||
resultHandler = jasmine.createSpy("result found")
|
||||
waitsForPromise ->
|
||||
atom.project.scan /dollar/, (results) ->
|
||||
resultHandler()
|
||||
|
||||
runs ->
|
||||
expect(resultHandler).not.toHaveBeenCalled()
|
||||
|
||||
it "scans buffer contents if the buffer is modified", ->
|
||||
editor = null
|
||||
results = []
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('a').then (o) ->
|
||||
editor = o
|
||||
editor.setText("Elephant")
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.scan /a|Elephant/, (result) -> results.push result
|
||||
|
||||
runs ->
|
||||
expect(results).toHaveLength 3
|
||||
resultForA = _.find results, ({filePath}) -> path.basename(filePath) == 'a'
|
||||
expect(resultForA.matches).toHaveLength 1
|
||||
expect(resultForA.matches[0].matchText).toBe 'Elephant'
|
||||
|
||||
it "ignores buffers outside the project", ->
|
||||
editor = null
|
||||
results = []
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open(temp.openSync().path).then (o) ->
|
||||
editor = o
|
||||
editor.setText("Elephant")
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.scan /Elephant/, (result) -> results.push result
|
||||
|
||||
runs ->
|
||||
expect(results).toHaveLength 0
|
||||
|
||||
describe ".eachBuffer(callback)", ->
|
||||
beforeEach ->
|
||||
atom.project.bufferForPathSync('a')
|
||||
|
||||
@@ -2,6 +2,10 @@ path = require 'path'
|
||||
temp = require 'temp'
|
||||
Workspace = require '../src/workspace'
|
||||
{View} = require '../src/space-pen-extensions'
|
||||
platform = require './spec-helper-platform'
|
||||
_ = require 'underscore-plus'
|
||||
fstream = require 'fstream'
|
||||
fs = require 'fs-plus'
|
||||
|
||||
describe "Workspace", ->
|
||||
workspace = null
|
||||
@@ -553,3 +557,187 @@ describe "Workspace", ->
|
||||
|
||||
expect(atom.workspace.panelForItem(item)).toBe panel
|
||||
expect(atom.workspace.panelForItem(itemWithNoPanel)).toBe null
|
||||
|
||||
describe "::scan(options, callback)", ->
|
||||
describe "when called with a regex", ->
|
||||
it "calls the callback with all regex results in all files in the project", ->
|
||||
results = []
|
||||
waitsForPromise ->
|
||||
atom.workspace.scan /(a)+/, (result) ->
|
||||
results.push(result)
|
||||
|
||||
runs ->
|
||||
expect(results).toHaveLength(3)
|
||||
expect(results[0].filePath).toBe atom.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 ^)", ->
|
||||
results = []
|
||||
waitsForPromise ->
|
||||
atom.workspace.scan /\$\w+/, (result) -> results.push(result)
|
||||
|
||||
runs ->
|
||||
expect(results.length).toBe 1
|
||||
|
||||
{filePath, matches} = results[0]
|
||||
expect(filePath).toBe atom.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", ->
|
||||
platform.generateEvilFiles()
|
||||
atom.project.setPaths([path.join(__dirname, 'fixtures', 'evil-files')])
|
||||
paths = []
|
||||
matches = []
|
||||
waitsForPromise ->
|
||||
atom.workspace.scan /evil/, (result) ->
|
||||
paths.push(result.filePath)
|
||||
matches = matches.concat(result.matches)
|
||||
|
||||
runs ->
|
||||
_.each(matches, (m) -> expect(m.matchText).toEqual 'evil')
|
||||
|
||||
if platform.isWindows()
|
||||
expect(paths.length).toBe 3
|
||||
expect(paths[0]).toMatch /a_file_with_utf8.txt$/
|
||||
expect(paths[1]).toMatch /file with spaces.txt$/
|
||||
expect(path.basename(paths[2])).toBe "utfa\u0306.md"
|
||||
else
|
||||
expect(paths.length).toBe 5
|
||||
expect(paths[0]).toMatch /a_file_with_utf8.txt$/
|
||||
expect(paths[1]).toMatch /file with spaces.txt$/
|
||||
expect(paths[2]).toMatch /goddam\nnewlines$/m
|
||||
expect(paths[3]).toMatch /quote".txt$/m
|
||||
expect(path.basename(paths[4])).toBe "utfa\u0306.md"
|
||||
|
||||
it "ignores case if the regex includes the `i` flag", ->
|
||||
results = []
|
||||
waitsForPromise ->
|
||||
atom.workspace.scan /DOLLAR/i, (result) -> results.push(result)
|
||||
|
||||
runs ->
|
||||
expect(results).toHaveLength 1
|
||||
|
||||
describe "when the core.excludeVcsIgnoredPaths config is truthy", ->
|
||||
[projectPath, ignoredPath] = []
|
||||
|
||||
beforeEach ->
|
||||
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.writeFileSync(ignoredPath, 'this match should not be included')
|
||||
|
||||
afterEach ->
|
||||
fs.removeSync(projectPath) if fs.existsSync(projectPath)
|
||||
|
||||
it "excludes ignored files", ->
|
||||
atom.project.setPaths([projectPath])
|
||||
atom.config.set('core.excludeVcsIgnoredPaths', true)
|
||||
resultHandler = jasmine.createSpy("result found")
|
||||
waitsForPromise ->
|
||||
atom.workspace.scan /match/, (results) ->
|
||||
resultHandler()
|
||||
|
||||
runs ->
|
||||
expect(resultHandler).not.toHaveBeenCalled()
|
||||
|
||||
it "includes only files when a directory filter is specified", ->
|
||||
projectPath = path.join(path.join(__dirname, 'fixtures', 'dir'))
|
||||
atom.project.setPaths([projectPath])
|
||||
|
||||
filePath = path.join(projectPath, 'a-dir', 'oh-git')
|
||||
|
||||
paths = []
|
||||
matches = []
|
||||
waitsForPromise ->
|
||||
atom.workspace.scan /aaa/, paths: ["a-dir#{path.sep}"], (result) ->
|
||||
paths.push(result.filePath)
|
||||
matches = matches.concat(result.matches)
|
||||
|
||||
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 = temp.mkdirSync()
|
||||
filePath = path.join(projectPath, '.text')
|
||||
fs.writeFileSync(filePath, 'match this')
|
||||
atom.project.setPaths([projectPath])
|
||||
paths = []
|
||||
matches = []
|
||||
waitsForPromise ->
|
||||
atom.workspace.scan /match this/, (result) ->
|
||||
paths.push(result.filePath)
|
||||
matches = matches.concat(result.matches)
|
||||
|
||||
runs ->
|
||||
expect(paths.length).toBe 1
|
||||
expect(paths[0]).toBe filePath
|
||||
expect(matches.length).toBe 1
|
||||
|
||||
it "excludes values in core.ignoredNames", ->
|
||||
projectPath = path.join(__dirname, 'fixtures', 'git', 'working-dir')
|
||||
ignoredNames = atom.config.get("core.ignoredNames")
|
||||
ignoredNames.push("a")
|
||||
atom.config.set("core.ignoredNames", ignoredNames)
|
||||
|
||||
resultHandler = jasmine.createSpy("result found")
|
||||
waitsForPromise ->
|
||||
atom.workspace.scan /dollar/, (results) ->
|
||||
resultHandler()
|
||||
|
||||
runs ->
|
||||
expect(resultHandler).not.toHaveBeenCalled()
|
||||
|
||||
it "scans buffer contents if the buffer is modified", ->
|
||||
editor = null
|
||||
results = []
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open('a').then (o) ->
|
||||
editor = o
|
||||
editor.setText("Elephant")
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.scan /a|Elephant/, (result) -> results.push result
|
||||
|
||||
runs ->
|
||||
expect(results).toHaveLength 3
|
||||
resultForA = _.find results, ({filePath}) -> path.basename(filePath) == 'a'
|
||||
expect(resultForA.matches).toHaveLength 1
|
||||
expect(resultForA.matches[0].matchText).toBe 'Elephant'
|
||||
|
||||
it "ignores buffers outside the project", ->
|
||||
editor = null
|
||||
results = []
|
||||
|
||||
waitsForPromise ->
|
||||
atom.project.open(temp.openSync().path).then (o) ->
|
||||
editor = o
|
||||
editor.setText("Elephant")
|
||||
|
||||
waitsForPromise ->
|
||||
atom.workspace.scan /Elephant/, (result) -> results.push result
|
||||
|
||||
runs ->
|
||||
expect(results).toHaveLength 0
|
||||
|
||||
@@ -176,53 +176,9 @@ class Project extends Model
|
||||
Section: Searching and Replacing
|
||||
###
|
||||
|
||||
# Public: Performs a search across all the files in the project.
|
||||
#
|
||||
# * `regex` {RegExp} to search with.
|
||||
# * `options` (optional) {Object} (default: {})
|
||||
# * `paths` An {Array} of glob patterns to search within
|
||||
# * `iterator` {Function} callback on each file found
|
||||
scan: (regex, options={}, iterator) ->
|
||||
if _.isFunction(options)
|
||||
iterator = options
|
||||
options = {}
|
||||
|
||||
deferred = Q.defer()
|
||||
|
||||
searchOptions =
|
||||
ignoreCase: regex.ignoreCase
|
||||
inclusions: options.paths
|
||||
includeHidden: true
|
||||
excludeVcsIgnores: atom.config.get('core.excludeVcsIgnoredPaths')
|
||||
exclusions: atom.config.get('core.ignoredNames')
|
||||
follow: atom.config.get('core.followSymlinks')
|
||||
|
||||
# TODO: need to support all paths in @getPaths()
|
||||
task = Task.once require.resolve('./scan-handler'), @getPaths()[0], regex.source, searchOptions, ->
|
||||
deferred.resolve()
|
||||
|
||||
task.on 'scan:result-found', (result) =>
|
||||
iterator(result) unless @isPathModified(result.filePath)
|
||||
|
||||
task.on 'scan:file-error', (error) ->
|
||||
iterator(null, error)
|
||||
|
||||
if _.isFunction(options.onPathsSearched)
|
||||
task.on 'scan:paths-searched', (numberOfPathsSearched) ->
|
||||
options.onPathsSearched(numberOfPathsSearched)
|
||||
|
||||
for buffer in @getBuffers() when buffer.isModified()
|
||||
filePath = buffer.getPath()
|
||||
continue unless @contains(filePath)
|
||||
matches = []
|
||||
buffer.scan regex, (match) -> matches.push match
|
||||
iterator {filePath, matches} if matches.length > 0
|
||||
|
||||
promise = deferred.promise
|
||||
promise.cancel = ->
|
||||
task.terminate()
|
||||
deferred.resolve('cancelled')
|
||||
promise
|
||||
Grim.deprecate("Use atom.workspace.scan instead of atom.project.scan")
|
||||
atom.workspace.scan(regex, options, iterator)
|
||||
|
||||
# Public: Performs a replace across all the specified files in the project.
|
||||
#
|
||||
|
||||
@@ -14,6 +14,7 @@ PanelElement = require './panel-element'
|
||||
PanelContainer = require './panel-container'
|
||||
PanelContainerElement = require './panel-container-element'
|
||||
WorkspaceElement = require './workspace-element'
|
||||
Task = require './task'
|
||||
|
||||
# Essential: Represents the state of the user interface for the entire window.
|
||||
# An instance of this class is available via the `atom.workspace` global.
|
||||
@@ -780,3 +781,57 @@ class Workspace extends Model
|
||||
addPanel: (location, options) ->
|
||||
options ?= {}
|
||||
@panelContainers[location].addPanel(new Panel(options))
|
||||
|
||||
###
|
||||
Section: Searching and Replacing
|
||||
###
|
||||
|
||||
# Public: Performs a search across all the files in the workspace.
|
||||
#
|
||||
# * `regex` {RegExp} to search with.
|
||||
# * `options` (optional) {Object} (default: {})
|
||||
# * `paths` An {Array} of glob patterns to search within
|
||||
# * `iterator` {Function} callback on each file found
|
||||
#
|
||||
# Returns a `Promise`.
|
||||
scan: (regex, options={}, iterator) ->
|
||||
if _.isFunction(options)
|
||||
iterator = options
|
||||
options = {}
|
||||
|
||||
deferred = Q.defer()
|
||||
|
||||
searchOptions =
|
||||
ignoreCase: regex.ignoreCase
|
||||
inclusions: options.paths
|
||||
includeHidden: true
|
||||
excludeVcsIgnores: atom.config.get('core.excludeVcsIgnoredPaths')
|
||||
exclusions: atom.config.get('core.ignoredNames')
|
||||
follow: atom.config.get('core.followSymlinks')
|
||||
|
||||
# TODO: need to support all paths in @getPaths()
|
||||
task = Task.once require.resolve('./scan-handler'), atom.project.getPaths()[0], regex.source, searchOptions, ->
|
||||
deferred.resolve()
|
||||
|
||||
task.on 'scan:result-found', (result) =>
|
||||
iterator(result) unless atom.project.isPathModified(result.filePath)
|
||||
|
||||
task.on 'scan:file-error', (error) ->
|
||||
iterator(null, error)
|
||||
|
||||
if _.isFunction(options.onPathsSearched)
|
||||
task.on 'scan:paths-searched', (numberOfPathsSearched) ->
|
||||
options.onPathsSearched(numberOfPathsSearched)
|
||||
|
||||
for buffer in atom.project.getBuffers() when buffer.isModified()
|
||||
filePath = buffer.getPath()
|
||||
continue unless atom.project.contains(filePath)
|
||||
matches = []
|
||||
buffer.scan regex, (match) -> matches.push match
|
||||
iterator {filePath, matches} if matches.length > 0
|
||||
|
||||
promise = deferred.promise
|
||||
promise.cancel = ->
|
||||
task.terminate()
|
||||
deferred.resolve('cancelled')
|
||||
promise
|
||||
|
||||
Reference in New Issue
Block a user