Skip to content
This repository has been archived by the owner on Dec 15, 2022. It is now read-only.

Commit

Permalink
Refactor iterator helper objects in scanInRange
Browse files Browse the repository at this point in the history
  • Loading branch information
maxbrunsfeld committed Dec 16, 2016
1 parent 187dcd2 commit 7ad08bc
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 62 deletions.
71 changes: 58 additions & 13 deletions src/match-iterator.coffee
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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}
54 changes: 5 additions & 49 deletions src/text-buffer.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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"
Expand All @@ -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.
Expand Down

0 comments on commit 7ad08bc

Please sign in to comment.