After shift/arrow-key movement, merge overlapping selections

This commit is contained in:
Corey Johnson & Nathan Sobo 2012-03-27 11:09:35 -07:00
parent 6b96251174
commit 81869ebf59
6 changed files with 108 additions and 55 deletions

View File

@ -1013,46 +1013,24 @@ describe "Editor", ->
expect(cursor3.getBufferPosition()).toEqual [4, 0]
describe "selections", ->
it "adds an additional selection upon clicking and dragging with the meta-key held down", ->
editor.attachToDom()
editor.lines.trigger mousedownEvent(editor: editor, point: [4, 10])
editor.lines.trigger mousemoveEvent(editor: editor, point: [5, 27])
editor.lines.trigger 'mouseup'
describe "upon clicking and dragging with the meta-key held down", ->
it "adds an additional selection upon clicking and dragging with the meta-key held down", ->
editor.attachToDom()
editor.lines.trigger mousedownEvent(editor: editor, point: [4, 10])
editor.lines.trigger mousemoveEvent(editor: editor, point: [5, 27])
editor.lines.trigger 'mouseup'
editor.lines.trigger mousedownEvent(editor: editor, point: [6, 10], metaKey: true)
editor.lines.trigger mousemoveEvent(editor: editor, point: [8, 27], metaKey: true)
editor.lines.trigger 'mouseup'
editor.lines.trigger mousedownEvent(editor: editor, point: [6, 10], metaKey: true)
editor.lines.trigger mousemoveEvent(editor: editor, point: [8, 27], metaKey: true)
editor.lines.trigger 'mouseup'
selections = editor.compositeSelection.getSelections()
expect(selections.length).toBe 2
[selection1, selection2] = selections
expect(selection1.getScreenRange()).toEqual [[4, 10], [5, 27]]
expect(selection2.getScreenRange()).toEqual [[6, 10], [8, 27]]
selections = editor.compositeSelection.getSelections()
expect(selections.length).toBe 2
[selection1, selection2] = selections
expect(selection1.getScreenRange()).toEqual [[4, 10], [5, 27]]
expect(selection2.getScreenRange()).toEqual [[6, 10], [8, 27]]
it "adjusts all selections based on keyboard movement", ->
editor.setSelectionBufferRange [[0,9], [0,13]]
editor.addSelectionForBufferRange [[3,16], [3,21]]
[selection1, selection2] = editor.compositeSelection.getSelections()
editor.selectRight()
expect(selection1.getBufferRange()).toEqual [[0,9], [0,14]]
expect(selection2.getBufferRange()).toEqual [[3,16], [3,22]]
editor.selectLeft()
editor.selectLeft()
expect(selection1.getBufferRange()).toEqual [[0,9], [0,12]]
expect(selection2.getBufferRange()).toEqual [[3,16], [3,20]]
editor.selectDown()
expect(selection1.getBufferRange()).toEqual [[0,9], [1,12]]
expect(selection2.getBufferRange()).toEqual [[3,16], [4,20]]
editor.selectUp()
expect(selection1.getBufferRange()).toEqual [[0,9], [0,12]]
expect(selection2.getBufferRange()).toEqual [[3,16], [3,20]]
describe "when multiple selctions intersect", ->
it "merges a selection that is completely contained within another", ->
it "merges selections when they intersect", ->
editor.attachToDom()
editor.lines.trigger mousedownEvent(editor: editor, point: [4, 10])
editor.lines.trigger mousemoveEvent(editor: editor, point: [5, 27])
@ -1067,6 +1045,71 @@ describe "Editor", ->
[selection1] = selections
expect(selection1.getScreenRange()).toEqual [[3, 10], [6, 27]]
describe "upon moving the cursor with the arrow keys with the shift key held down", ->
it "resizes all selections", ->
editor.setSelectionBufferRange [[0,9], [0,13]]
editor.addSelectionForBufferRange [[3,16], [3,21]]
[selection1, selection2] = editor.compositeSelection.getSelections()
editor.selectRight()
expect(selection1.getBufferRange()).toEqual [[0,9], [0,14]]
expect(selection2.getBufferRange()).toEqual [[3,16], [3,22]]
editor.selectLeft()
editor.selectLeft()
expect(selection1.getBufferRange()).toEqual [[0,9], [0,12]]
expect(selection2.getBufferRange()).toEqual [[3,16], [3,20]]
editor.selectDown()
expect(selection1.getBufferRange()).toEqual [[0,9], [1,12]]
expect(selection2.getBufferRange()).toEqual [[3,16], [4,20]]
editor.selectUp()
expect(selection1.getBufferRange()).toEqual [[0,9], [0,12]]
expect(selection2.getBufferRange()).toEqual [[3,16], [3,20]]
it "merges selections when they intersect when moving down", ->
editor.setSelectionBufferRange [[0,9], [0,13]]
editor.addSelectionForBufferRange [[1,10], [1,20]]
editor.addSelectionForBufferRange [[2,15], [3,25]]
[selection1, selection2, selection3] = editor.compositeSelection.getSelections()
editor.selectDown()
expect(editor.compositeSelection.getSelections()).toEqual [selection1]
expect(selection1.getScreenRange()).toEqual([[0, 9], [4, 25]])
expect(selection2.parent()).not.toExist()
expect(selection3.parent()).not.toExist()
it "merges selections when they intersect when moving up", ->
editor.setSelectionBufferRange [[0,9], [0,13]], reverse: true
editor.addSelectionForBufferRange [[1,10], [1,20]], reverse: true
[selection1, selection2] = editor.compositeSelection.getSelections()
editor.selectUp()
expect(editor.compositeSelection.getSelections()).toEqual [selection1]
expect(selection1.getScreenRange()).toEqual([[0, 0], [1, 20]])
expect(selection2.parent()).not.toExist()
it "merges selections when they intersect when moving left", ->
editor.setSelectionBufferRange [[0,9], [0,13]], reverse: true
editor.addSelectionForBufferRange [[0,14], [1,20]], reverse: true
[selection1, selection2] = editor.compositeSelection.getSelections()
editor.selectLeft()
expect(editor.compositeSelection.getSelections()).toEqual [selection1]
expect(selection1.getScreenRange()).toEqual([[0, 8], [1, 20]])
expect(selection2.parent()).not.toExist()
it "merges selections when they intersect when moving right", ->
editor.setSelectionBufferRange [[0,9], [0,13]]
editor.addSelectionForBufferRange [[0,14], [1,20]]
[selection1, selection2] = editor.compositeSelection.getSelections()
editor.selectRight()
expect(editor.compositeSelection.getSelections()).toEqual [selection1]
expect(selection1.getScreenRange()).toEqual([[0, 9], [1, 21]])
expect(selection2.parent()).not.toExist()
describe "cursor merging", ->
it "merges cursors when they overlap due to a buffer change", ->
editor.setCursorScreenPosition([0, 0])

View File

@ -16,11 +16,13 @@ describe "Range", ->
expect(new Range(new Point(1, 1), new Point(1, 2)).isEmpty()).toBeFalsy()
describe ".intersectsWith(otherRange)", ->
it "returns true if the ranges intersect", ->
it "returns true if the ranges intersect or share an endpoint", ->
expect(new Range([1, 1], [2, 10]).intersectsWith(new Range([2, 1], [3, 10]))).toBeTruthy()
expect(new Range([2, 1], [3, 10]).intersectsWith(new Range([1, 1], [2, 10]))).toBeTruthy()
expect(new Range([2, 1], [3, 10]).intersectsWith(new Range([2, 5], [3, 1]))).toBeTruthy()
expect(new Range([2, 5], [3, 1]).intersectsWith(new Range([2, 1], [3, 10]))).toBeTruthy()
expect(new Range([2, 5], [3, 1]).intersectsWith(new Range([3, 1], [3, 10]))).toBeTruthy()
expect(new Range([3, 1], [3, 10]).intersectsWith(new Range([2, 5], [3, 1]))).toBeTruthy()
expect(new Range([2, 5], [3, 1]).intersectsWith(new Range([3, 2], [3, 10]))).toBeFalsy()
expect(new Range([3, 2], [3, 10]).intersectsWith(new Range([2, 5], [3, 1]))).toBeFalsy()

View File

@ -17,9 +17,9 @@ class CompositeSeleciton
@selections.push(selection)
@editor.lines.append(selection)
addSelectionForBufferRange: (bufferRange) ->
addSelectionForBufferRange: (bufferRange, options) ->
cursor = @editor.compositeCursor.addCursor()
@selectionForCursor(cursor).setBufferRange(bufferRange)
@selectionForCursor(cursor).setBufferRange(bufferRange, options)
removeSelectionForCursor: (cursor) ->
_.remove(@selections, @selectionForCursor(cursor))
@ -31,32 +31,36 @@ class CompositeSeleciton
selection.handleBufferChange(e) for selection in @getSelections()
insertText: (text) ->
@modifySelections (selection) ->
@modifySelectedText (selection) ->
selection.insertText(text)
backspace: ->
@modifySelections (selection) -> selection.backspace()
@modifySelectedText (selection) -> selection.backspace()
delete: ->
@modifySelections (selection) -> selection.delete()
@modifySelectedText (selection) -> selection.delete()
selectToScreenPosition: (position) ->
@lastSelection().selectToScreenPosition(position)
selectRight: ->
selection.selectRight() for selection in @getSelections()
@mergeIntersectingSelections()
selectLeft: ->
selection.selectLeft() for selection in @getSelections()
@mergeIntersectingSelections()
selectUp: ->
selection.selectUp() for selection in @getSelections()
@mergeIntersectingSelections()
selectDown: ->
selection.selectDown() for selection in @getSelections()
@mergeIntersectingSelections()
setBufferRange: (bufferRange) ->
@lastSelection().setBufferRange(bufferRange)
setBufferRange: (bufferRange, options) ->
@lastSelection().setBufferRange(bufferRange, options)
getBufferRange: (bufferRange) ->
@lastSelection().getBufferRange()
@ -77,7 +81,7 @@ class CompositeSeleciton
@mergeIntersectingSelections()
return
modifySelections: (fn) ->
modifySelectedText: (fn) ->
selection.retainSelection = true for selection in @getSelections()
for selection in @getSelections()
selection.retainSelection = false
@ -85,7 +89,7 @@ class CompositeSeleciton
cut: ->
maintainPasteboard = false
@modifySelections (selection) ->
@modifySelectedText (selection) ->
selection.cut(maintainPasteboard)
maintainPasteboard = true

View File

@ -356,8 +356,8 @@ class Editor extends View
getSelection: (index) -> @compositeSelection.getSelection(index)
getSelectedText: -> @compositeSelection.getSelection().getText()
setSelectionBufferRange: (bufferRange) -> @compositeSelection.setBufferRange(bufferRange)
addSelectionForBufferRange: (bufferRange) -> @compositeSelection.addSelectionForBufferRange(bufferRange)
setSelectionBufferRange: (bufferRange, options) -> @compositeSelection.setBufferRange(bufferRange, options)
addSelectionForBufferRange: (bufferRange, options) -> @compositeSelection.addSelectionForBufferRange(bufferRange, options)
selectRight: -> @compositeSelection.selectRight()
selectLeft: -> @compositeSelection.selectLeft()
selectUp: -> @compositeSelection.selectUp()

View File

@ -42,7 +42,7 @@ class Range
intersectsWith: (otherRange) ->
if @start.isLessThanOrEqual(otherRange.start)
@end.isGreaterThan(otherRange.start)
@end.isGreaterThanOrEqual(otherRange.start)
else
otherRange.intersectsWith(this)

View File

@ -81,16 +81,20 @@ class Selection extends View
else
new Range(@cursor.getScreenPosition(), @cursor.getScreenPosition())
setScreenRange: (range) ->
@cursor.setScreenPosition(range.start)
setScreenRange: (range, options={}) ->
{ reverse } = options
{ start, end } = range
[start, end] = [end, start] if reverse
@cursor.setScreenPosition(start)
@modifySelection =>
@cursor.setScreenPosition(range.end)
@cursor.setScreenPosition(end)
getBufferRange: ->
@editor.bufferRangeForScreenRange(@getScreenRange())
setBufferRange: (bufferRange) ->
@setScreenRange(@editor.screenRangeForBufferRange(bufferRange))
setBufferRange: (bufferRange, options) ->
@setScreenRange(@editor.screenRangeForBufferRange(bufferRange), options)
getText: ->
@editor.buffer.getTextInRange @getBufferRange()