forked from atom/atom
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdefault-directory-searcher.coffee
94 lines (89 loc) · 4.29 KB
/
default-directory-searcher.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
Task = require './task'
# Searches local files for lines matching a specified regex. Implements `.then()`
# so that it can be used with `Promise.all()`.
class DirectorySearch
constructor: (rootPaths, regex, options) ->
scanHandlerOptions =
ignoreCase: regex.ignoreCase
inclusions: options.inclusions
includeHidden: options.includeHidden
excludeVcsIgnores: options.excludeVcsIgnores
globalExclusions: options.exclusions
follow: options.follow
searchOptions =
leadingContextLineCount: options.leadingContextLineCount
trailingContextLineCount: options.trailingContextLineCount
@task = new Task(require.resolve('./scan-handler'))
@task.on 'scan:result-found', options.didMatch
@task.on 'scan:file-error', options.didError
@task.on 'scan:paths-searched', options.didSearchPaths
@promise = new Promise (resolve, reject) =>
@task.on('task:cancelled', reject)
@task.start rootPaths, regex.source, scanHandlerOptions, searchOptions, =>
@task.terminate()
resolve()
then: (args...) ->
@promise.then.apply(@promise, args)
cancel: ->
# This will cause @promise to reject.
@task.cancel()
null
# Default provider for the `atom.directory-searcher` service.
module.exports =
class DefaultDirectorySearcher
# Determines whether this object supports search for a `Directory`.
#
# * `directory` {Directory} whose search needs might be supported by this object.
#
# Returns a `boolean` indicating whether this object can search this `Directory`.
canSearchDirectory: (directory) -> true
# Performs a text search for files in the specified `Directory`, subject to the
# specified parameters.
#
# Results are streamed back to the caller by invoking methods on the specified `options`,
# such as `didMatch` and `didError`.
#
# * `directories` {Array} of {Directory} objects to search, all of which have been accepted by
# this searcher's `canSearchDirectory()` predicate.
# * `regex` {RegExp} to search with.
# * `options` {Object} with the following properties:
# * `didMatch` {Function} call with a search result structured as follows:
# * `searchResult` {Object} with the following keys:
# * `filePath` {String} absolute path to the matching file.
# * `matches` {Array} with object elements with the following keys:
# * `lineText` {String} The full text of the matching line (without a line terminator character).
# * `lineTextOffset` {Number} (This always seems to be 0?)
# * `matchText` {String} The text that matched the `regex` used for the search.
# * `range` {Range} Identifies the matching region in the file. (Likely as an array of numeric arrays.)
# * `didError` {Function} call with an Error if there is a problem during the search.
# * `didSearchPaths` {Function} periodically call with the number of paths searched thus far.
# * `inclusions` {Array} of glob patterns (as strings) to search within. Note that this
# array may be empty, indicating that all files should be searched.
#
# Each item in the array is a file/directory pattern, e.g., `src` to search in the "src"
# directory or `*.js` to search all JavaScript files. In practice, this often comes from the
# comma-delimited list of patterns in the bottom text input of the ProjectFindView dialog.
# * `ignoreHidden` {boolean} whether to ignore hidden files.
# * `excludeVcsIgnores` {boolean} whether to exclude VCS ignored paths.
# * `exclusions` {Array} similar to inclusions
# * `follow` {boolean} whether symlinks should be followed.
#
# Returns a *thenable* `DirectorySearch` that includes a `cancel()` method. If `cancel()` is
# invoked before the `DirectorySearch` is determined, it will resolve the `DirectorySearch`.
search: (directories, regex, options) ->
rootPaths = directories.map (directory) -> directory.getPath()
isCancelled = false
directorySearch = new DirectorySearch(rootPaths, regex, options)
promise = new Promise (resolve, reject) ->
directorySearch.then resolve, ->
if isCancelled
resolve()
else
reject()
return {
then: promise.then.bind(promise)
catch: promise.catch.bind(promise)
cancel: ->
isCancelled = true
directorySearch.cancel()
}