Merge pull request #1102 from atom/bo-add-replace

Add replace() to project and buffer
This commit is contained in:
Ben Ogle 2013-11-08 16:57:38 -08:00
commit 5f8e757f57
5 changed files with 130 additions and 1 deletions

View File

@ -31,7 +31,7 @@
"pathwatcher": "0.9.0",
"pegjs": "0.7.0",
"q": "0.9.7",
"scandal": "0.6.4",
"scandal": "0.7.0",
"season": "0.14.0",
"semver": "1.1.4",
"space-pen": "2.0.0",

View File

@ -296,6 +296,67 @@ describe "Project", ->
expect(project.getPath()?).toBeFalsy()
expect(project.getRootDirectory()?).toBeFalsy()
describe ".replace()", ->
[filePath, commentFilePath, sampleContent, sampleCommentContent] = []
beforeEach ->
project.setPath(project.resolve('../'))
filePath = project.resolve('sample.js')
commentFilePath = project.resolve('sample-with-comments.js')
sampleContent = fs.readFileSync(filePath).toString()
sampleCommentContent = fs.readFileSync(commentFilePath).toString()
afterEach ->
fs.writeFileSync(filePath, sampleContent)
fs.writeFileSync(commentFilePath, sampleCommentContent)
describe "when called with unopened files", ->
it "replaces properly", ->
results = []
waitsForPromise ->
project.replace /items/gi, 'items', [filePath], (result) ->
results.push(result)
runs ->
expect(results).toHaveLength 1
expect(results[0].filePath).toBe filePath
expect(results[0].replacements).toBe 6
describe "when a buffer is already open", ->
it "replaces properly and saves when not modified", ->
editSession = project.openSync('sample.js')
expect(editSession.isModified()).toBeFalsy()
results = []
waitsForPromise ->
project.replace /items/gi, 'items', [filePath], (result) ->
results.push(result)
runs ->
expect(results).toHaveLength 1
expect(results[0].filePath).toBe filePath
expect(results[0].replacements).toBe 6
expect(editSession.isModified()).toBeFalsy()
it "does NOT save when modified", ->
editSession = project.openSync('sample.js')
editSession.buffer.change([[0,0],[0,0]], 'omg')
expect(editSession.isModified()).toBeTruthy()
results = []
waitsForPromise ->
project.replace /items/gi, 'okthen', [filePath], (result) ->
results.push(result)
runs ->
expect(results).toHaveLength 1
expect(results[0].filePath).toBe filePath
expect(results[0].replacements).toBe 6
expect(editSession.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", ->

View File

@ -336,6 +336,42 @@ class Project
deferred.promise
# Public: Performs a replace across all the specified files in the project.
#
# * regex: A RegExp to search with
# * replacementText: Text to replace all matches of regex with
# * filePaths: List of file path strings to run the replace on.
# * iterator: A Function callback on each file with replacements. ({filePath, replacements}) ->
replace: (regex, replacementText, filePaths, iterator) ->
deferred = Q.defer()
openPaths = (buffer.getPath() for buffer in @buffers)
outOfProcessPaths = _.difference(filePaths, openPaths)
inProcessFinished = !openPaths.length
outOfProcessFinished = !outOfProcessPaths.length
checkFinished = ->
deferred.resolve() if outOfProcessFinished and inProcessFinished
unless outOfProcessFinished.length
flags = 'g'
flags += 'i' if regex.ignoreCase
task = Task.once require.resolve('./replace-handler'), outOfProcessPaths, regex.source, flags, replacementText, ->
outOfProcessFinished = true
checkFinished()
task.on 'replace:path-replaced', iterator
for buffer in @buffers
replacements = buffer.replace(regex, replacementText, iterator)
iterator({filePath: buffer.getPath(), replacements}) if replacements
inProcessFinished = true
checkFinished()
deferred.promise
# Private:
buildEditSessionForBuffer: (buffer, editSessionOptions) ->
editSession = new EditSession(_.extend({buffer}, editSessionOptions))

View File

@ -0,0 +1,13 @@
{PathReplacer} = require 'scandal'
module.exports = (filePaths, regexSource, regexFlags, replacementText) ->
callback = @async()
replacer = new PathReplacer()
regex = new RegExp(regexSource, regexFlags)
replacer.on 'path-replaced', (result) ->
emit('replace:path-replaced', result)
replacer.replacePaths regex, replacementText, filePaths, ->
callback()

View File

@ -538,6 +538,25 @@ class TextBuffer
result.lineTextOffset = 0
iterator(result)
# Replace all matches of regex with replacementText
#
# regex: A {RegExp} representing the text to find
# replacementText: A {String} representing the text to replace
#
# Returns the number of replacements made
replace: (regex, replacementText) ->
doSave = !@isModified()
replacements = 0
@transact =>
@scan regex, ({matchText, replace}) ->
replace(matchText.replace(regex, replacementText))
replacements++
@save() if doSave
replacements
# Scans for text in a given range, calling a function on each match.
#
# regex - A {RegExp} representing the text to find