Match $ in command regexes as end of line. Don't infinitely loop on substituting zero-width matches

This commit is contained in:
Corey Johnson & Nathan Sobo 2012-03-27 15:39:07 -07:00
parent 7d969e145a
commit 5e89c44477
6 changed files with 37 additions and 6 deletions

View File

@ -11,25 +11,34 @@ describe "CommandInterpreter", ->
interpreter = new CommandInterpreter()
describe "addresses", ->
beforeEach ->
editor.addSelectionForBufferRange([[7,0], [7,11]])
editor.addSelectionForBufferRange([[8,0], [8,11]])
describe "a line address", ->
it "selects the specified line", ->
interpreter.eval(editor, '4')
expect(editor.getSelections().length).toBe 1
expect(editor.getSelection().getBufferRange()).toEqual [[3, 0], [4, 0]]
describe "0", ->
it "selects the zero-length string at the start of the file", ->
interpreter.eval(editor, '0')
expect(editor.getSelections().length).toBe 1
expect(editor.getSelection().getBufferRange()).toEqual [[0,0], [0,0]]
interpreter.eval(editor, '0,1')
expect(editor.getSelections().length).toBe 1
expect(editor.getSelection().getBufferRange()).toEqual [[0,0], [1,0]]
describe "$", ->
it "selects EOF", ->
interpreter.eval(editor, '$')
expect(editor.getSelections().length).toBe 1
expect(editor.getSelection().getBufferRange()).toEqual [[12,2], [12,2]]
interpreter.eval(editor, '1,$')
expect(editor.getSelections().length).toBe 1
expect(editor.getSelection().getBufferRange()).toEqual [[0,0], [12,2]]
describe ".", ->
@ -50,32 +59,38 @@ describe "CommandInterpreter", ->
it 'selects text matching regex after current selection', ->
editor.getSelection().setBufferRange([[4,16], [4,20]])
interpreter.eval(editor, '/pivot/')
expect(editor.getSelections().length).toBe 1
expect(editor.getSelection().getBufferRange()).toEqual [[6,16], [6,21]]
it 'does not require the trailing slash', ->
editor.getSelection().setBufferRange([[4,16], [4,20]])
interpreter.eval(editor, '/pivot')
expect(editor.getSelections().length).toBe 1
expect(editor.getSelection().getBufferRange()).toEqual [[6,16], [6,21]]
describe "address range", ->
describe "when two addresses are specified", ->
it "selects from the begining of the left address to the end of the right address", ->
interpreter.eval(editor, '4,7')
expect(editor.getSelections().length).toBe 1
expect(editor.getSelection().getBufferRange()).toEqual [[3, 0], [7, 0]]
describe "when the left address is unspecified", ->
it "selects from the begining of buffer to the end of the right address", ->
interpreter.eval(editor, ',7')
expect(editor.getSelections().length).toBe 1
expect(editor.getSelection().getBufferRange()).toEqual [[0, 0], [7, 0]]
describe "when the right address is unspecified", ->
it "selects from the begining of left address to the end file", ->
interpreter.eval(editor, '4,')
expect(editor.getSelections().length).toBe 1
expect(editor.getSelection().getBufferRange()).toEqual [[3, 0], [12, 2]]
describe "when the neither address is specified", ->
it "selects the entire file", ->
interpreter.eval(editor, ',')
expect(editor.getSelections().length).toBe 1
expect(editor.getSelection().getBufferRange()).toEqual [[0, 0], [12, 2]]
describe "x/regex/", ->
@ -130,6 +145,14 @@ describe "CommandInterpreter", ->
expect(buffer.lineForRow(5)).toBe '!!!!!!current!=!items.shift();'
expect(buffer.lineForRow(6)).toBe ' current < pivot ? left.push(current) : right.push(current);'
describe "when the regex matches a zero-width string", ->
it "does not infinitely loop when looking for the next match", ->
interpreter.eval(editor, ',s/$/!!!/g')
expect(buffer.lineForRow(0)).toBe 'var quicksort = function () {!!!'
expect(buffer.lineForRow(2)).toBe ' if (items.length <= 1) return items;!!!'
expect(buffer.lineForRow(6)).toBe ' current < pivot ? left.push(current) : right.push(current);!!!'
expect(buffer.lineForRow(12)).toBe '};!!!'
describe ".repeatRelativeAddress()", ->
it "repeats the last search command if there is one", ->
interpreter.repeatRelativeAddress(editor) # don't raise an exception

View File

@ -3,6 +3,8 @@ Command = require 'command-interpreter/command'
module.exports =
class Address extends Command
execute: (editor) ->
editor.getSelection().setBufferRange(@getRange(editor))
range = @getRange(editor)
editor.clearSelections()
editor.setSelectionBufferRange(range)
isAddress: -> true

View File

@ -3,3 +3,6 @@ _ = require 'underscore'
module.exports =
class Command
isAddress: -> false
regexForPattern: (pattern) ->
new RegExp(pattern, 'm')

View File

@ -6,7 +6,7 @@ class RegexAddress extends Address
regex: null
constructor: (pattern) ->
@regex = new RegExp(pattern)
@regex = @regexForPattern(pattern)
getRange: (editor) ->
selectedRange = editor.getSelection().getBufferRange()

View File

@ -6,7 +6,7 @@ class SelectAllMatches extends Command
@regex: null
constructor: (pattern) ->
@regex = new RegExp(pattern)
@regex = @regexForPattern(pattern)
execute: (editor) ->
rangesToSelect = []

View File

@ -5,7 +5,7 @@ class Substitution extends Command
global: false
constructor: (@findText, @replaceText, @options) ->
@findRegex = new RegExp(@findText)
@findRegex = @regexForPattern(@findText)
@global = 'g' in @options
execute: (editor) ->
@ -27,7 +27,10 @@ class Substitution extends Command
buffer.change([startPosition, endPosition], @replaceText)
if @global
text = text[(match.index + match[0].length)..]
startIndex = matchStartIndex + @replaceText.length
offset = if match[0].length then 0 else 1
startNextStringFragmentAt = match.index + match[0].length + offset
return if startNextStringFragmentAt >= text.length
text = text[startNextStringFragmentAt..]
startIndex = matchStartIndex + offset + @replaceText.length
@replace(editor, text, startIndex)