From 847e3d16e5a01f255e1ea4ebafaf402f13b49f73 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 27 Mar 2012 17:41:53 -0700 Subject: [PATCH] Add Buffer.traverseRegexMatchesInRange --- spec/atom/buffer-spec.coffee | 53 ++++++++++++++++++++++++++++++++++++ src/atom/buffer.coffee | 35 ++++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/spec/atom/buffer-spec.coffee b/spec/atom/buffer-spec.coffee index c8d07e0de..e3f0c0715 100644 --- a/spec/atom/buffer-spec.coffee +++ b/spec/atom/buffer-spec.coffee @@ -204,6 +204,59 @@ describe 'Buffer', -> range = [[2,10], [4,10]] expect(buffer.getTextInRange(range)).toBe "ems.length <= 1) return items;\n var pivot = items.shift(), current, left = [], right = [];\n while(" + describe ".traverseRegexMatchesInRange(range, regexSource, fn)", -> + describe "when given a regex with no global flag", -> + it "calls the iterator with the first match for the given regex in the given range", -> + matches = [] + ranges = [] + buffer.traverseRegexMatchesInRange /cu(rr)ent/, [[4,0], [6,44]], (match, range) -> + matches.push(match) + ranges.push(range) + + expect(matches.length).toBe 1 + expect(ranges.length).toBe 1 + + expect(matches[0][0]).toBe 'current' + expect(matches[0][1]).toBe 'rr' + expect(ranges[0]).toEqual [[5,6], [5,13]] + + describe "when given a regex with a global flag", -> + it "calls the iterator with each match for the given regex in the given range", -> + matches = [] + ranges = [] + buffer.traverseRegexMatchesInRange /cu(rr)ent/g, [[4,0], [6,59]], (match, range) -> + matches.push(match) + ranges.push(range) + + expect(matches.length).toBe 3 + expect(ranges.length).toBe 3 + + expect(matches[0][0]).toBe 'current' + expect(matches[0][1]).toBe 'rr' + expect(ranges[0]).toEqual [[5,6], [5,13]] + + expect(matches[1][0]).toBe 'current' + expect(matches[1][1]).toBe 'rr' + expect(ranges[1]).toEqual [[6,6], [6,13]] + + expect(matches[2][0]).toBe 'current' + expect(matches[2][1]).toBe 'rr' + expect(ranges[2]).toEqual [[6,34], [6,41]] + + describe "when the iterator returns a replacement string", -> + it "replaces each occurrence of the regex match with the string", -> + ranges = [] + buffer.traverseRegexMatchesInRange /cu(rr)ent/g, [[4,0], [6,59]], (match, range) -> + ranges.push(range) + "foo" + + expect(ranges[0]).toEqual [[5,6], [5,13]] + expect(ranges[1]).toEqual [[6,6], [6,13]] + expect(ranges[2]).toEqual [[6,30], [6,37]] + + expect(buffer.lineForRow(5)).toBe ' foo = items.shift();' + expect(buffer.lineForRow(6)).toBe ' foo < pivot ? left.push(foo) : right.push(current);' + describe ".characterIndexForPosition(position)", -> it "returns the total number of charachters that precede the given position", -> expect(buffer.characterIndexForPosition([0, 0])).toBe 0 diff --git a/src/atom/buffer.coffee b/src/atom/buffer.coffee index d0e6eaa40..c168e1878 100644 --- a/src/atom/buffer.coffee +++ b/src/atom/buffer.coffee @@ -140,4 +140,39 @@ class Buffer @mode = new (require("ace/mode/#{modeName}").Mode) + traverseRegexMatchesInRange: (regex, range, iterator) -> + range = Range.fromObject(range) + global = regex.global + regex = new RegExp(regex.source, 'gm') + + traverseRecursively = (text, startIndex, endIndex, lengthDelta) => + regex.lastIndex = startIndex + return unless match = regex.exec(text) + + matchLength = match[0].length + matchStartIndex = match.index + matchEndIndex = match.index + matchLength + + return if matchEndIndex > endIndex + + startPosition = @positionForCharacterIndex(matchStartIndex + lengthDelta) + endPosition = @positionForCharacterIndex(matchEndIndex + lengthDelta) + range = new Range(startPosition, endPosition) + replacementText = iterator(match, range) + + if _.isString(replacementText) + @change(range, replacementText) + lengthDelta += replacementText.length - matchLength + + if matchLength is 0 + matchStartIndex++ + matchEndIndex++ + + if global + traverseRecursively(text, matchEndIndex, endIndex, lengthDelta) + + startIndex = @characterIndexForPosition(range.start) + endIndex = @characterIndexForPosition(range.end) + traverseRecursively(@getText(), startIndex, endIndex, 0) + _.extend(Buffer.prototype, EventEmitter)