Use the silver searcher to implement global search

Parsing uses a simple state machine in `Project.scan`.
This commit is contained in:
Nathan Sobo 2012-07-19 17:28:46 -06:00
parent f37330a218
commit 239cba25e4
3 changed files with 48 additions and 24 deletions

View File

@ -128,12 +128,12 @@ describe "Project", ->
runs ->
expect(matches[0]).toEqual
path: project.resolve('a')
match: ['aaa', 'a']
match: 'aaa'
range: [[0, 0], [0, 3]]
expect(matches[1]).toEqual
path: project.resolve('a')
match: ['aa', 'a']
match: 'aa'
range: [[1, 3], [1, 5]]
it "works on evil filenames", ->
@ -147,11 +147,9 @@ describe "Project", ->
runs ->
expect(paths.length).toBe 5
matches.forEach (match) -> expect(match).toEqual ['evil']
matches.forEach (match) -> expect(match).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
expect(paths[3]).toMatch /quote".txt$/m
expect(fs.base(paths[4])).toBe "utfa\u0306.md"

View File

@ -138,32 +138,58 @@ class Project
scan: (regex, iterator) ->
regex = new RegExp(regex.source, 'g')
command = "#{require.resolve('ack')} --all --match \"#{regex.source}\" \"#{@getPath()}\""
command = "#{require.resolve('ag')} --ackmate \"#{regex.source}\" \"#{@getPath()}\""
bufferedData = ""
console.log command
promise = ChildProcess.exec command , bufferLines: true, stdout: (data) ->
bufferedData += data
currentIndex = 0
while currentIndex < bufferedData.length
pathEndIndex = bufferedData.indexOf('\0', currentIndex)
break unless pathEndIndex >= 0
lineNumberEndIndex = bufferedData.indexOf('\0', pathEndIndex + 1)
lineEndIndex = bufferedData.indexOf('\n', lineNumberEndIndex + 1)
state = 'readingPath'
path = null
readPath = (line) ->
if /^[0-9,; ]+:/.test(line)
state = 'readingLines'
else if /^:/.test line
path = line.substr(1)
else
path += ('\n' + line)
readLine = (line) ->
if line.length == 0
state = 'readingPath'
path = 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])
match = lineText.substr(column, length)
iterator({path, range, match})
ChildProcess.exec command , bufferLines: true, stdout: (data) ->
lines = data.split('\n')
try
for line in lines
readPath(line) if state is 'readingPath'
readLine(line) if state is 'readingLines'
catch e
console.log e.stack
path = bufferedData.substring(currentIndex, pathEndIndex)
row = parseInt(bufferedData.substring(pathEndIndex + 1, lineNumberEndIndex)) - 1
line = bufferedData.substring(lineNumberEndIndex + 1, lineEndIndex)
while match = regex.exec(line)
range = new Range([row, match.index], [row, match.index + match[0].length])
iterator({path, match, range})
currentIndex = lineEndIndex + 1
bufferedData = bufferedData.substring(currentIndex)
promise.done -> console.log "DONE"
_.extend Project.prototype, EventEmitter

BIN
vendor/ag vendored Executable file

Binary file not shown.