pulsar/spec/app/command-interpreter-spec.coffee
Nathan Sobo 8d05802290 Redesign commands around multiple selections
Every command returns an array of buffer ranges to select from its execute method. The composite command loops through each current selection with each command, then sets the new selection to the aggregated buffer ranges returned by all commands at that step.
2012-04-04 12:09:33 -06:00

255 lines
12 KiB
CoffeeScript

CommandInterpreter = require 'command-interpreter'
Buffer = require 'buffer'
Editor = require 'editor'
describe "CommandInterpreter", ->
[interpreter, editor, buffer] = []
beforeEach ->
buffer = new Buffer(require.resolve 'fixtures/sample.js')
editor = new Editor({buffer})
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 ".", ->
describe "when a single selection", ->
it 'maintains the current selection', ->
editor.clearSelections()
editor.setSelectionBufferRange([[1,1], [2,2]])
interpreter.eval(editor, '.')
expect(editor.getSelection().getBufferRange()).toEqual [[1,1], [2,2]]
editor.setSelectionBufferRange([[1,1], [2,2]])
interpreter.eval(editor, '.,')
expect(editor.getSelection().getBufferRange()).toEqual [[1,1], [12,2]]
editor.setSelectionBufferRange([[1,1], [2,2]])
interpreter.eval(editor, ',.')
expect(editor.getSelection().getBufferRange()).toEqual [[0,0], [2,2]]
describe "with multiple selections", ->
it "maintains the current selections", ->
preSelections = editor.getSelections()
expect(preSelections.length).toBe 3
[preRange1, preRange2, preRange3] = preSelections.map (s) -> s.getScreenRange()
interpreter.eval(editor, '.')
selections = editor.getSelections()
expect(selections.length).toBe 3
[selection1, selection2, selection3] = selections
expect(selection1.getScreenRange()).toEqual preRange1
expect(selection2.getScreenRange()).toEqual preRange2
expect(selection3.getScreenRange()).toEqual preRange3
describe "/regex/", ->
beforeEach ->
editor.clearSelections()
it 'selects text matching regex after current selection', ->
editor.setSelectionBufferRange([[4,16], [4,20]])
interpreter.eval(editor, '/pivot/')
expect(editor.getSelection().getBufferRange()).toEqual [[6,16], [6,21]]
it 'does not require the trailing slash', ->
editor.setSelectionBufferRange([[4,16], [4,20]])
interpreter.eval(editor, '/pivot')
expect(editor.getSelection().getBufferRange()).toEqual [[6,16], [6,21]]
it "searches from the end of each selection in the buffer", ->
editor.clearSelections()
editor.setSelectionBufferRange([[4,16], [4,20]])
editor.addSelectionForBufferRange([[1,16], [2,20]])
expect(editor.getSelections().length).toBe 2
interpreter.eval(editor, '/pivot')
selections = editor.getSelections()
expect(selections.length).toBe 2
expect(selections[0].getBufferRange()).toEqual [[3,8], [3,13]]
expect(selections[1].getBufferRange()).toEqual [[6,16], [6,21]]
it "wraps around to the beginning of the buffer, but doesn't infinitely loop if no matches are found", ->
editor.setSelectionBufferRange([[10, 0], [10,3]])
interpreter.eval(editor, '/pivot')
expect(editor.getSelection().getBufferRange()).toEqual [[3,8], [3,13]]
interpreter.eval(editor, '/mike tyson')
expect(editor.getSelection().getBufferRange()).toEqual [[3,8], [3,13]]
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/", ->
it "sets the current selection to every match of the regex in the current selection", ->
interpreter.eval(editor, '6,7 x/current/')
selections = editor.getSelections()
expect(selections.length).toBe 4
expect(selections[0].getBufferRange()).toEqual [[5,6], [5,13]]
expect(selections[1].getBufferRange()).toEqual [[6,6], [6,13]]
expect(selections[2].getBufferRange()).toEqual [[6,34], [6,41]]
expect(selections[3].getBufferRange()).toEqual [[6,56], [6,63]]
describe "when matching /$/", ->
it "matches the end of each line in the selected region", ->
interpreter.eval(editor, '6,8 x/$/')
cursors = editor.getCursors()
expect(cursors.length).toBe 3
expect(cursors[0].getBufferPosition()).toEqual [5, 30]
expect(cursors[1].getBufferPosition()).toEqual [6, 65]
expect(cursors[2].getBufferPosition()).toEqual [7, 5]
it "loops through current selections and selects text matching the regex", ->
editor.setSelectionBufferRange [[3,0], [3,62]]
editor.addSelectionForBufferRange [[6,0], [6,65]]
interpreter.eval(editor, 'x/current')
selections = editor.getSelections()
expect(selections.length).toBe 4
expect(selections[0].getBufferRange()).toEqual [[3,31], [3,38]]
expect(selections[1].getBufferRange()).toEqual [[6,6], [6,13]]
expect(selections[2].getBufferRange()).toEqual [[6,34], [6,41]]
expect(selections[3].getBufferRange()).toEqual [[6,56], [6,63]]
describe "substitution", ->
it "does nothing if there are no matches", ->
editor.setSelectionBufferRange([[6, 0], [6, 44]])
interpreter.eval(editor, 's/not-in-text/foo/')
expect(buffer.lineForRow(6)).toBe ' current < pivot ? left.push(current) : right.push(current);'
describe "when not global", ->
describe "when there is a single selection", ->
it "performs a single substitution within the current selection", ->
editor.setSelectionBufferRange([[6, 0], [6, 44]])
interpreter.eval(editor, 's/current/foo/')
expect(buffer.lineForRow(6)).toBe ' foo < pivot ? left.push(current) : right.push(current);'
describe "when there are multiple selections", ->
it "performs a single substitutions within each of the selections", ->
editor.setSelectionBufferRange([[5, 0], [5, 20]])
editor.addSelectionForBufferRange([[6, 0], [6, 44]])
interpreter.eval(editor, 's/current/foo/')
expect(buffer.lineForRow(5)).toBe ' foo = items.shift();'
expect(buffer.lineForRow(6)).toBe ' foo < pivot ? left.push(current) : right.push(current);'
describe "when global", ->
it "performs a multiple substitutions within the current selection", ->
editor.setSelectionBufferRange([[6, 0], [6, 44]])
interpreter.eval(editor, 's/current/foo/g')
expect(buffer.lineForRow(6)).toBe ' foo < pivot ? left.push(foo) : right.push(current);'
describe "when prefixed with an address", ->
it "only makes substitutions within given lines", ->
interpreter.eval(editor, '4,6s/ /!/g')
expect(buffer.lineForRow(2)).toBe ' if (items.length <= 1) return items;'
expect(buffer.lineForRow(3)).toBe '!!!!var!pivot!=!items.shift(),!current,!left!=![],!right!=![];'
expect(buffer.lineForRow(4)).toBe '!!!!while(items.length!>!0)!{'
expect(buffer.lineForRow(5)).toBe '!!!!!!current!=!items.shift();'
expect(buffer.lineForRow(6)).toBe ' current < pivot ? left.push(current) : right.push(current);'
describe "when matching $", ->
it "matches the end of each line and avoids infinitely looping on a zero-width 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 "when matching ^", ->
it "matches the beginning of each line and avoids infinitely looping on a zero-width 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 "when there are multiple selections", ->
it "performs a multiple substitutions within each of the selections", ->
editor.setSelectionBufferRange([[5, 0], [5, 20]])
editor.addSelectionForBufferRange([[6, 0], [6, 44]])
interpreter.eval(editor, 's/current/foo/g')
expect(buffer.lineForRow(5)).toBe ' foo = items.shift();'
expect(buffer.lineForRow(6)).toBe ' foo < pivot ? left.push(foo) : right.push(current);'
describe ".repeatRelativeAddress()", ->
it "repeats the last search command if there is one", ->
interpreter.repeatRelativeAddress(editor) # don't raise an exception
editor.setCursorScreenPosition([4, 0])
interpreter.eval(editor, '/current')
expect(editor.getSelection().getBufferRange()).toEqual [[5,6], [5,13]]
interpreter.repeatRelativeAddress(editor)
expect(editor.getSelection().getBufferRange()).toEqual [[6,6], [6,13]]
interpreter.eval(editor, 's/r/R/g')
interpreter.repeatRelativeAddress(editor)
expect(editor.getSelection().getBufferRange()).toEqual [[6,34], [6,41]]
interpreter.eval(editor, '0')
interpreter.eval(editor, '/sort/ s/r/R/') # this contains a substitution... won't be repeated
interpreter.repeatRelativeAddress(editor)
expect(editor.getSelection().getBufferRange()).toEqual [[3,31], [3,38]]