diff --git a/src/match-iterator.coffee b/src/match-iterator.coffee index 711962da39..78a13853b1 100644 --- a/src/match-iterator.coffee +++ b/src/match-iterator.coffee @@ -1,7 +1,53 @@ +Point = require './point' +Range = require './range' + +class SearchCallbackArgument + Object.defineProperty @::, "range", + get: -> + return @computedRange if @computedRange? + + matchStartIndex = @match.index + matchEndIndex = matchStartIndex + @matchText.length + + startPosition = @buffer.positionForCharacterIndex(matchStartIndex + @lengthDelta) + endPosition = @buffer.positionForCharacterIndex(matchEndIndex + @lengthDelta) + + @computedRange = new Range(startPosition, endPosition) + + set: (range) -> + @computedRange = range + + constructor: (@buffer, @match, @lengthDelta) -> + @stopped = false + @replacementText = null + @matchText = @match[0] + + getReplacementDelta: -> + return 0 unless @replacementText? + @replacementText.length - @matchText.length + + replace: (text) => + @replacementText = text + @buffer.setTextInRange(@range, @replacementText) + + stop: => + @stopped = true + class Forwards - constructor: (@text, @regex, @startIndex, @endIndex) -> + constructor: (@buffer, @regex, @startIndex, @endIndex) -> + @text = @buffer.getText() @regex.lastIndex = @startIndex + iterate: (callback, global) -> + lengthDelta = 0 + while match = @next() + argument = new SearchCallbackArgument(@buffer, match, lengthDelta) + callback(argument) + if argument.replacementText? + lengthDelta += argument.replacementText.length - argument.matchText.length + break unless global and not arg.stopped + return + next: -> if match = @regex.exec(@text) matchLength = match[0].length @@ -18,19 +64,22 @@ class Forwards else matchEndIndex++ if matchLength is 0 @regex.lastIndex = matchEndIndex - - if match - {value: match, done: false} - else - {value: null, done: true} + match class Backwards - constructor: (@text, @regex, @startIndex, endIndex, @chunkSize) -> + constructor: (@buffer, @regex, @startIndex, endIndex, @chunkSize) -> + @text = @buffer.getText() @bufferedMatches = [] - @doneScanning = false @chunkStartIndex = @chunkEndIndex = endIndex @lastMatchIndex = Infinity + iterate: (callback, global) -> + while match = @next() + argument = new SearchCallbackArgument(@buffer, match, 0) + callback(argument) + break unless global and not argument.stopped + return + scanNextChunk: -> # If results were found in the last chunk, then scan to the beginning # of the previous result. Otherwise, continue to scan to the same position @@ -68,10 +117,6 @@ class Backwards next: -> until @chunkStartIndex is @startIndex or @bufferedMatches.length > 0 @scanNextChunk() - - if match = @bufferedMatches.pop() - {value: match, done: false} - else - {value: null, done: true} + @bufferedMatches.pop() module.exports = {Forwards, Backwards} diff --git a/src/text-buffer.coffee b/src/text-buffer.coffee index 444f42c6a8..979c52ea1a 100644 --- a/src/text-buffer.coffee +++ b/src/text-buffer.coffee @@ -15,42 +15,6 @@ MatchIterator = require './match-iterator' DisplayLayer = require './display-layer' {spliceArray, newlineRegex, normalizePatchChanges} = require './helpers' -class SearchCallbackArgument - Object.defineProperty @::, "range", - get: -> - return @computedRange if @computedRange? - - matchStartIndex = @match.index - matchEndIndex = matchStartIndex + @matchText.length - - startPosition = @buffer.positionForCharacterIndex(matchStartIndex + @lengthDelta) - endPosition = @buffer.positionForCharacterIndex(matchEndIndex + @lengthDelta) - - @computedRange = new Range(startPosition, endPosition) - - set: (range) -> - @computedRange = range - - constructor: (@buffer, @match, @lengthDelta) -> - @stopped = false - @replacementText = null - @matchText = @match[0] - - getReplacementDelta: -> - return 0 unless @replacementText? - - @replacementText.length - @matchText.length - - replace: (text) => - @replacementText = text - @buffer.setTextInRange(@range, @replacementText) - - stop: => - @stopped = true - - keepLooping: -> - @stopped is false - class TransactionAbortedError extends Error constructor: -> super @@ -1150,14 +1114,14 @@ class TextBuffer # # * `regex` A {RegExp} to search for. # * `range` A {Range} in which to search. - # * `iterator` A {Function} that's called on each match with an {Object} + # * `callback` A {Function} that's called on each match with an {Object} # containing the following keys: # * `match` The current regular expression match. # * `matchText` A {String} with the text of the match. # * `range` The {Range} of the match. # * `stop` Call this {Function} to terminate the scan. # * `replace` Call this {Function} with a {String} to replace the match. - scanInRange: (regex, range, iterator, reverse=false) -> + scanInRange: (regex, range, callback, reverse=false) -> range = @clipRange(range) global = regex.global flags = "gm" @@ -1168,19 +1132,11 @@ class TextBuffer endIndex = @characterIndexForPosition(range.end) if reverse - matches = new MatchIterator.Backwards(@getText(), regex, startIndex, endIndex, @backwardsScanChunkSize) + iterator = new MatchIterator.Backwards(this, regex, startIndex, endIndex, @backwardsScanChunkSize) else - matches = new MatchIterator.Forwards(@getText(), regex, startIndex, endIndex) - - lengthDelta = 0 - until (next = matches.next()).done - match = next.value - callbackArgument = new SearchCallbackArgument(this, match, lengthDelta) - iterator(callbackArgument) - lengthDelta += callbackArgument.getReplacementDelta() unless reverse + iterator = new MatchIterator.Forwards(this, regex, startIndex, endIndex) - break unless global and callbackArgument.keepLooping() - return + iterator.iterate(callback, global) # Public: Scan regular expression matches in a given range in reverse order, # calling the given iterator function on each match.