Skip to content

Commit

Permalink
Revert "Introduce atom.directory-searcher service v0.1.0."
Browse files Browse the repository at this point in the history
  • Loading branch information
Max Brunsfeld committed Jun 9, 2015
1 parent a3f6a9e commit 262d41c
Showing 5 changed files with 29 additions and 299 deletions.
26 changes: 0 additions & 26 deletions spec/task-spec.coffee
Original file line number Diff line number Diff line change
@@ -70,29 +70,3 @@ describe "Task", ->
task.terminate()
expect(stdout.listeners('data').length).toBe 0
expect(stderr.listeners('data').length).toBe 0

describe "::cancel()", ->
it "dispatches 'task:cancelled' when invoked on an active task", ->
task = new Task(require.resolve('./fixtures/task-spec-handler'))
cancelledEventSpy = jasmine.createSpy('eventSpy')
task.on('task:cancelled', cancelledEventSpy)
completedEventSpy = jasmine.createSpy('eventSpy')
task.on('task:completed', completedEventSpy)

expect(task.cancel()).toBe(true)
expect(cancelledEventSpy).toHaveBeenCalled()
expect(completedEventSpy).not.toHaveBeenCalled()

it "does not dispatch 'task:cancelled' when invoked on an inactive task", ->
handlerResult = null
task = Task.once require.resolve('./fixtures/task-spec-handler'), (result) ->
handlerResult = result

waitsFor ->
handlerResult?

runs ->
cancelledEventSpy = jasmine.createSpy('eventSpy')
task.on('task:cancelled', cancelledEventSpy)
expect(task.cancel()).toBe(false)
expect(cancelledEventSpy).not.toHaveBeenCalled()
84 changes: 0 additions & 84 deletions spec/workspace-spec.coffee
Original file line number Diff line number Diff line change
@@ -938,90 +938,6 @@ describe "Workspace", ->
.then ->
expect(resultPaths).toEqual([file2])

describe "when a custom directory searcher is registered", ->
fakeSearch = null
# Function that is invoked once all of the fields on fakeSearch are set.
onFakeSearchCreated = null

class FakeSearch
constructor: (@options) ->
# Note that hoisting resolve and reject in this way is generally frowned upon.
@promise = new Promise (resolve, reject) =>
@hoistedResolve = resolve
@hoistedReject = reject
onFakeSearchCreated?(this)
then: (args...) ->
@promise.then.apply(@promise, args)
cancel: ->
@cancelled = true
@hoistedReject()

beforeEach ->
fakeSearch = null
onFakeSearchCreated = null
atom.packages.serviceHub.provide('atom.directory-searcher', '0.1.0', {
canSearchDirectory: (directory) -> directory.getPath() is dir1
search: (directory, regex, options) -> fakeSearch = new FakeSearch(options)
})

it "can override the DefaultDirectorySearcher on a per-directory basis", ->
foreignFilePath = 'ssh://foreign-directory:8080/hello.txt'
numPathsSearchedInDir2 = 1
numPathsToPretendToSearchInCustomDirectorySearcher = 10
searchResult =
filePath: foreignFilePath,
matches: [
{
lineText: 'Hello world',
lineTextOffset: 0,
matchText: 'Hello',
range: [[0, 0], [0, 5]],
},
]
onFakeSearchCreated = (fakeSearch) ->
fakeSearch.options.didMatch(searchResult)
fakeSearch.options.didSearchPaths(numPathsToPretendToSearchInCustomDirectorySearcher)
fakeSearch.hoistedResolve()

resultPaths = []
onPathsSearched = jasmine.createSpy('onPathsSearched')
waitsForPromise ->
atom.workspace.scan /aaaa/, {onPathsSearched}, ({filePath}) ->
resultPaths.push(filePath)

runs ->
expect(resultPaths.sort()).toEqual([foreignFilePath, file2].sort())
# onPathsSearched should be called once by each DirectorySearcher. The order is not
# guaranteed, so we can only verify the total number of paths searched is correct
# after the second call.
expect(onPathsSearched.callCount).toBe(2)
expect(onPathsSearched.mostRecentCall.args[0]).toBe(
numPathsToPretendToSearchInCustomDirectorySearcher + numPathsSearchedInDir2)

it "can be cancelled when the object returned by scan() has its cancel() method invoked", ->
thenable = atom.workspace.scan /aaaa/, ->
expect(fakeSearch.cancelled).toBe(undefined)
thenable.cancel()
expect(fakeSearch.cancelled).toBe(true)

resultOfPromiseSearch = null
waitsForPromise ->
thenable.then (promiseResult) -> resultOfPromiseSearch = promiseResult

runs ->
expect(resultOfPromiseSearch).toBe('cancelled')

it "will have the side-effect of failing the overall search if it fails", ->
cancelableSearch = atom.workspace.scan /aaaa/, ->
fakeSearch.hoistedReject()

didReject = false
waitsForPromise ->
cancelableSearch.catch -> didReject = true

runs ->
expect(didReject).toBe(true)

describe "::replace(regex, replacementText, paths, iterator)", ->
[filePath, commentFilePath, sampleContent, sampleCommentContent] = []

95 changes: 0 additions & 95 deletions src/default-directory-searcher.coffee

This file was deleted.

10 changes: 2 additions & 8 deletions src/task.coffee
Original file line number Diff line number Diff line change
@@ -150,18 +150,12 @@ class Task
#
# No more events are emitted once this method is called.
terminate: ->
return false unless @childProcess?
return unless @childProcess?

@childProcess.removeAllListeners()
@childProcess.stdout.removeAllListeners()
@childProcess.stderr.removeAllListeners()
@childProcess.kill()
@childProcess = null

true

cancel: ->
didForcefullyTerminate = @terminate()
if didForcefullyTerminate
@emit('task:cancelled')
didForcefullyTerminate
undefined
113 changes: 27 additions & 86 deletions src/workspace.coffee
Original file line number Diff line number Diff line change
@@ -7,7 +7,6 @@ Serializable = require 'serializable'
{Emitter, Disposable, CompositeDisposable} = require 'event-kit'
Grim = require 'grim'
fs = require 'fs-plus'
DefaultDirectorySearcher = require './default-directory-searcher'
Model = require './model'
TextEditor = require './text-editor'
PaneContainer = require './pane-container'
@@ -47,13 +46,6 @@ class Workspace extends Model
@paneContainer ?= new PaneContainer()
@paneContainer.onDidDestroyPaneItem(@didDestroyPaneItem)

@directorySearchers = []
@defaultDirectorySearcher = new DefaultDirectorySearcher()
atom.packages.serviceHub.consume(
'atom.directory-searcher',
'^0.1.0',
(provider) => @directorySearchers.unshift(provider))

@panelContainers =
top: new PanelContainer({location: 'top'})
left: new PanelContainer({location: 'left'})
@@ -799,65 +791,36 @@ class Workspace extends Model
# * `regex` {RegExp} to search with.
# * `options` (optional) {Object} (default: {})
# * `paths` An {Array} of glob patterns to search within
# * `onPathsSearched` (optional) {Function}
# * `iterator` {Function} callback on each file found
#
# Returns a `Promise` with a `cancel()` method that will cancel all
# of the underlying searches that were started as part of this scan.
# Returns a `Promise`.
scan: (regex, options={}, iterator) ->
if _.isFunction(options)
iterator = options
options = {}

# Find a searcher for every Directory in the project. Each searcher that is matched
# will be associated with an Array of Directory objects in the Map.
directoriesForSearcher = new Map()
for directory in atom.project.getDirectories()
searcher = @defaultDirectorySearcher
for directorySearcher in @directorySearchers
if directorySearcher.canSearchDirectory(directory)
searcher = directorySearcher
break
directories = directoriesForSearcher.get(searcher)
unless directories
directories = []
directoriesForSearcher.set(searcher, directories)
directories.push(directory)

# Define the onPathsSearched callback.
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')

task = Task.once require.resolve('./scan-handler'), atom.project.getPaths(), 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)
# Maintain a map of directories to the number of search results. When notified of a new count,
# replace the entry in the map and update the total.
onPathsSearchedOption = options.onPathsSearched
totalNumberOfPathsSearched = 0
numberOfPathsSearchedForSearcher = new Map()
onPathsSearched = (searcher, numberOfPathsSearched) ->
oldValue = numberOfPathsSearchedForSearcher.get(searcher)
if oldValue
totalNumberOfPathsSearched -= oldValue
numberOfPathsSearchedForSearcher.set(searcher, numberOfPathsSearched)
totalNumberOfPathsSearched += numberOfPathsSearched
onPathsSearchedOption(totalNumberOfPathsSearched)
else
onPathsSearched = ->

# Kick off all of the searches and unify them into one Promise.
allSearches = []
directoriesForSearcher.forEach (directories, searcher) ->
searchOptions =
inclusions: options.paths or []
includeHidden: true
excludeVcsIgnores: atom.config.get('core.excludeVcsIgnoredPaths')
exclusions: atom.config.get('core.ignoredNames')
follow: atom.config.get('core.followSymlinks')
didMatch: (result) ->
iterator(result) unless atom.project.isPathModified(result.filePath)
didError: (error) ->
iterator(null, error)
didSearchPaths: (count) -> onPathsSearched(searcher, count)
directorySearcher = searcher.search(directories, regex, searchOptions)
allSearches.push(directorySearcher)
searchPromise = Promise.all(allSearches)
task.on 'scan:paths-searched', (numberOfPathsSearched) ->
options.onPathsSearched(numberOfPathsSearched)

for buffer in atom.project.getBuffers() when buffer.isModified()
filePath = buffer.getPath()
@@ -866,33 +829,11 @@ class Workspace extends Model
buffer.scan regex, (match) -> matches.push match
iterator {filePath, matches} if matches.length > 0

# Make sure the Promise that is returned to the client is cancelable. To be consistent
# with the existing behavior, instead of cancel() rejecting the promise, it should
# resolve it with the special value 'cancelled'. At least the built-in find-and-replace
# package relies on this behavior.
isCancelled = false
cancellablePromise = new Promise (resolve, reject) ->
onSuccess = ->
resolve(null)
onFailure = ->
if isCancelled
resolve('cancelled')
else
reject()
searchPromise.then(onSuccess, onFailure)
cancellablePromise.cancel = ->
isCancelled = true
# Note that cancelling all (or actually, any) of the members of allSearches
# will cause searchPromise to reject, which will cause cancellablePromise to resolve
# in the desired way.
promise.cancel() for promise in allSearches

# Although this method claims to return a `Promise`, the `ResultsPaneView.onSearch()`
# method in the find-and-replace package expects the object returned by this method to have a
# `done()` method. Include a done() method until find-and-replace can be updated.
cancellablePromise.done = (onSuccessOrFailure) ->
cancellablePromise.then(onSuccessOrFailure, onSuccessOrFailure)
cancellablePromise
promise = deferred.promise
promise.cancel = ->
task.terminate()
deferred.resolve('cancelled')
promise

# Public: Performs a replace across all the specified files in the project.
#

0 comments on commit 262d41c

Please sign in to comment.