mirror of
https://github.com/atom/atom.git
synced 2026-01-24 06:18:03 -05:00
Merge branch 'master' into chrome
This commit is contained in:
@@ -19,16 +19,16 @@ describe "Cursor", ->
|
||||
advanceClock(200)
|
||||
|
||||
expect(cursor).toHaveClass 'idle'
|
||||
cursor.setPosition([1, 2])
|
||||
cursor.setScreenPosition([1, 2])
|
||||
expect(cursor).not.toHaveClass 'idle'
|
||||
|
||||
window.advanceClock(200)
|
||||
expect(cursor).toHaveClass 'idle'
|
||||
|
||||
cursor.setPosition([1, 3])
|
||||
cursor.setScreenPosition([1, 3])
|
||||
advanceClock(100)
|
||||
|
||||
cursor.setPosition([1, 4])
|
||||
cursor.setScreenPosition([1, 4])
|
||||
advanceClock(100)
|
||||
expect(cursor).not.toHaveClass 'idle'
|
||||
|
||||
@@ -37,9 +37,9 @@ describe "Cursor", ->
|
||||
|
||||
describe ".isOnEOL()", ->
|
||||
it "only returns true when cursor is on the end of a line", ->
|
||||
cursor.setPosition([1,29])
|
||||
cursor.setScreenPosition([1,29])
|
||||
expect(cursor.isOnEOL()).toBeFalsy()
|
||||
|
||||
cursor.setPosition([1,30])
|
||||
cursor.setScreenPosition([1,30])
|
||||
expect(cursor.isOnEOL()).toBeTruthy()
|
||||
|
||||
|
||||
@@ -65,10 +65,10 @@ describe "Editor", ->
|
||||
expect(editor.lines.find('pre:eq(3)').text()).toBe " var pivot = items.shift(), current, left = [], "
|
||||
expect(editor.lines.find('pre:eq(4)').text()).toBe "right = [];"
|
||||
|
||||
editor.cursor.setPosition([3, 51])
|
||||
editor.cursor.setScreenPosition([3, 51])
|
||||
expect(editor.cursor.position()).toEqual(editor.lines.find('pre:eq(4)').position())
|
||||
|
||||
editor.cursor.setPosition([4, 0])
|
||||
editor.cursor.setScreenPosition([4, 0])
|
||||
expect(editor.cursor.position()).toEqual(editor.lines.find('pre:eq(5)').position())
|
||||
|
||||
editor.selection.setRange(new Range([6, 30], [6, 55]))
|
||||
@@ -99,10 +99,10 @@ describe "Editor", ->
|
||||
expect(editor.setMaxLineLength).not.toHaveBeenCalled()
|
||||
|
||||
describe "cursor movement", ->
|
||||
describe ".setCursorPosition({row, column})", ->
|
||||
describe ".setCursorScreenPosition({row, column})", ->
|
||||
beforeEach ->
|
||||
editor.attachToDom()
|
||||
editor.setCursorPosition(row: 2, column: 2)
|
||||
editor.setCursorScreenPosition(row: 2, column: 2)
|
||||
|
||||
it "moves the cursor to cover the character at the given row and column", ->
|
||||
expect(editor.getCursor().position().top).toBe(2 * editor.lineHeight)
|
||||
@@ -115,16 +115,16 @@ describe "Editor", ->
|
||||
describe "when the arrow keys are pressed", ->
|
||||
it "moves the cursor by a single row/column", ->
|
||||
editor.trigger keydownEvent('right')
|
||||
expect(editor.getCursorPosition()).toEqual(row: 0, column: 1)
|
||||
expect(editor.getCursorScreenPosition()).toEqual(row: 0, column: 1)
|
||||
|
||||
editor.trigger keydownEvent('down')
|
||||
expect(editor.getCursorPosition()).toEqual(row: 1, column: 1)
|
||||
expect(editor.getCursorScreenPosition()).toEqual(row: 1, column: 1)
|
||||
|
||||
editor.trigger keydownEvent('left')
|
||||
expect(editor.getCursorPosition()).toEqual(row: 1, column: 0)
|
||||
expect(editor.getCursorScreenPosition()).toEqual(row: 1, column: 0)
|
||||
|
||||
editor.trigger keydownEvent('up')
|
||||
expect(editor.getCursorPosition()).toEqual(row: 0, column: 0)
|
||||
expect(editor.getCursorScreenPosition()).toEqual(row: 0, column: 0)
|
||||
|
||||
describe "vertical movement", ->
|
||||
describe "auto-scrolling", ->
|
||||
@@ -173,50 +173,50 @@ describe "Editor", ->
|
||||
|
||||
it "retains the goal column when moving up", ->
|
||||
expect(lineLengths[6]).toBeGreaterThan(32)
|
||||
editor.setCursorPosition(row: 6, column: 32)
|
||||
editor.setCursorScreenPosition(row: 6, column: 32)
|
||||
|
||||
editor.moveCursorUp()
|
||||
expect(editor.getCursorPosition().column).toBe lineLengths[5]
|
||||
expect(editor.getCursorScreenPosition().column).toBe lineLengths[5]
|
||||
|
||||
editor.moveCursorUp()
|
||||
expect(editor.getCursorPosition().column).toBe lineLengths[4]
|
||||
expect(editor.getCursorScreenPosition().column).toBe lineLengths[4]
|
||||
|
||||
editor.moveCursorUp()
|
||||
expect(editor.getCursorPosition().column).toBe 32
|
||||
expect(editor.getCursorScreenPosition().column).toBe 32
|
||||
|
||||
it "retains the goal column when moving down", ->
|
||||
editor.setCursorPosition(row: 3, column: lineLengths[3])
|
||||
editor.setCursorScreenPosition(row: 3, column: lineLengths[3])
|
||||
|
||||
editor.moveCursorDown()
|
||||
expect(editor.getCursorPosition().column).toBe lineLengths[4]
|
||||
expect(editor.getCursorScreenPosition().column).toBe lineLengths[4]
|
||||
|
||||
editor.moveCursorDown()
|
||||
expect(editor.getCursorPosition().column).toBe lineLengths[5]
|
||||
expect(editor.getCursorScreenPosition().column).toBe lineLengths[5]
|
||||
|
||||
editor.moveCursorDown()
|
||||
expect(editor.getCursorPosition().column).toBe lineLengths[3]
|
||||
expect(editor.getCursorScreenPosition().column).toBe lineLengths[3]
|
||||
|
||||
it "clears the goal column when the cursor is set", ->
|
||||
# set a goal column by moving down
|
||||
editor.setCursorPosition(row: 3, column: lineLengths[3])
|
||||
editor.setCursorScreenPosition(row: 3, column: lineLengths[3])
|
||||
editor.moveCursorDown()
|
||||
expect(editor.getCursorPosition().column).not.toBe 6
|
||||
expect(editor.getCursorScreenPosition().column).not.toBe 6
|
||||
|
||||
# clear the goal column by explicitly setting the cursor position
|
||||
editor.setCursorColumn(6)
|
||||
expect(editor.getCursorPosition().column).toBe 6
|
||||
expect(editor.getCursorScreenPosition().column).toBe 6
|
||||
|
||||
editor.moveCursorDown()
|
||||
expect(editor.getCursorPosition().column).toBe 6
|
||||
expect(editor.getCursorScreenPosition().column).toBe 6
|
||||
|
||||
describe "when up is pressed on the first line", ->
|
||||
it "moves the cursor to the beginning of the line, but retains the goal column", ->
|
||||
editor.setCursorPosition(row: 0, column: 4)
|
||||
editor.setCursorScreenPosition(row: 0, column: 4)
|
||||
editor.moveCursorUp()
|
||||
expect(editor.getCursorPosition()).toEqual(row: 0, column: 0)
|
||||
expect(editor.getCursorScreenPosition()).toEqual(row: 0, column: 0)
|
||||
|
||||
editor.moveCursorDown()
|
||||
expect(editor.getCursorPosition()).toEqual(row: 1, column: 4)
|
||||
expect(editor.getCursorScreenPosition()).toEqual(row: 1, column: 4)
|
||||
|
||||
describe "when down is pressed on the last line", ->
|
||||
it "moves the cursor to the end of line, but retains the goal column", ->
|
||||
@@ -224,22 +224,22 @@ describe "Editor", ->
|
||||
lastLine = buffer.getLine(lastLineIndex)
|
||||
expect(lastLine.length).toBeGreaterThan(0)
|
||||
|
||||
editor.setCursorPosition(row: lastLineIndex, column: 1)
|
||||
editor.setCursorScreenPosition(row: lastLineIndex, column: 1)
|
||||
editor.moveCursorDown()
|
||||
expect(editor.getCursorPosition()).toEqual(row: lastLineIndex, column: lastLine.length)
|
||||
expect(editor.getCursorScreenPosition()).toEqual(row: lastLineIndex, column: lastLine.length)
|
||||
|
||||
editor.moveCursorUp()
|
||||
expect(editor.getCursorPosition().column).toBe 1
|
||||
expect(editor.getCursorScreenPosition().column).toBe 1
|
||||
|
||||
it "retains a goal column of 0", ->
|
||||
lastLineIndex = buffer.getLines().length - 1
|
||||
lastLine = buffer.getLine(lastLineIndex)
|
||||
expect(lastLine.length).toBeGreaterThan(0)
|
||||
|
||||
editor.setCursorPosition(row: lastLineIndex, column: 0)
|
||||
editor.setCursorScreenPosition(row: lastLineIndex, column: 0)
|
||||
editor.moveCursorDown()
|
||||
editor.moveCursorUp()
|
||||
expect(editor.getCursorPosition().column).toBe 0
|
||||
expect(editor.getCursorScreenPosition().column).toBe 0
|
||||
|
||||
describe "horizontal movement", ->
|
||||
describe "auto-scrolling", ->
|
||||
@@ -253,57 +253,57 @@ describe "Editor", ->
|
||||
editor.width(charWidth * 30)
|
||||
|
||||
# moving right
|
||||
editor.setCursorPosition([2, 24])
|
||||
editor.setCursorScreenPosition([2, 24])
|
||||
expect(editor.scrollLeft()).toBe 0
|
||||
|
||||
editor.setCursorPosition([2, 25])
|
||||
editor.setCursorScreenPosition([2, 25])
|
||||
expect(editor.scrollLeft()).toBe charWidth
|
||||
|
||||
editor.setCursorPosition([2, 28])
|
||||
editor.setCursorScreenPosition([2, 28])
|
||||
expect(editor.scrollLeft()).toBe charWidth * 4
|
||||
|
||||
# moving left
|
||||
editor.setCursorPosition([2, 9])
|
||||
editor.setCursorScreenPosition([2, 9])
|
||||
expect(editor.scrollLeft()).toBe charWidth * 4
|
||||
|
||||
editor.setCursorPosition([2, 8])
|
||||
editor.setCursorScreenPosition([2, 8])
|
||||
expect(editor.scrollLeft()).toBe charWidth * 3
|
||||
|
||||
editor.setCursorPosition([2, 5])
|
||||
editor.setCursorScreenPosition([2, 5])
|
||||
expect(editor.scrollLeft()).toBe 0
|
||||
|
||||
it "reduces scroll margins when there isn't enough width to maintain them and scroll smoothly", ->
|
||||
editor.hScrollMargin = 6
|
||||
editor.width(charWidth * 7)
|
||||
|
||||
editor.setCursorPosition([2, 3])
|
||||
editor.setCursorScreenPosition([2, 3])
|
||||
expect(editor.scrollLeft()).toBe(0)
|
||||
|
||||
editor.setCursorPosition([2, 4])
|
||||
editor.setCursorScreenPosition([2, 4])
|
||||
expect(editor.scrollLeft()).toBe(charWidth)
|
||||
|
||||
editor.setCursorPosition([2, 3])
|
||||
editor.setCursorScreenPosition([2, 3])
|
||||
expect(editor.scrollLeft()).toBe(0)
|
||||
|
||||
describe "when left is pressed on the first column", ->
|
||||
describe "when there is a previous line", ->
|
||||
it "wraps to the end of the previous line", ->
|
||||
editor.setCursorPosition(row: 1, column: 0)
|
||||
editor.setCursorScreenPosition(row: 1, column: 0)
|
||||
editor.moveCursorLeft()
|
||||
expect(editor.getCursorPosition()).toEqual(row: 0, column: buffer.getLine(0).length)
|
||||
expect(editor.getCursorScreenPosition()).toEqual(row: 0, column: buffer.getLine(0).length)
|
||||
|
||||
describe "when the cursor is on the first line", ->
|
||||
it "remains in the same position (0,0)", ->
|
||||
editor.setCursorPosition(row: 0, column: 0)
|
||||
editor.setCursorScreenPosition(row: 0, column: 0)
|
||||
editor.moveCursorLeft()
|
||||
expect(editor.getCursorPosition()).toEqual(row: 0, column: 0)
|
||||
expect(editor.getCursorScreenPosition()).toEqual(row: 0, column: 0)
|
||||
|
||||
describe "when right is pressed on the last column", ->
|
||||
describe "when there is a subsequent line", ->
|
||||
it "wraps to the beginning of the next line", ->
|
||||
editor.setCursorPosition(row: 0, column: buffer.getLine(0).length)
|
||||
editor.setCursorScreenPosition(row: 0, column: buffer.getLine(0).length)
|
||||
editor.moveCursorRight()
|
||||
expect(editor.getCursorPosition()).toEqual(row: 1, column: 0)
|
||||
expect(editor.getCursorScreenPosition()).toEqual(row: 1, column: 0)
|
||||
|
||||
describe "when the cursor is on the last line", ->
|
||||
it "remains in the same position", ->
|
||||
@@ -312,10 +312,10 @@ describe "Editor", ->
|
||||
expect(lastLine.length).toBeGreaterThan(0)
|
||||
|
||||
lastPosition = { row: lastLineIndex, column: lastLine.length }
|
||||
editor.setCursorPosition(lastPosition)
|
||||
editor.setCursorScreenPosition(lastPosition)
|
||||
editor.moveCursorRight()
|
||||
|
||||
expect(editor.getCursorPosition()).toEqual(lastPosition)
|
||||
expect(editor.getCursorScreenPosition()).toEqual(lastPosition)
|
||||
|
||||
describe "when a mousedown event occurs in the editor", ->
|
||||
beforeEach ->
|
||||
@@ -329,24 +329,24 @@ describe "Editor", ->
|
||||
|
||||
describe "when it is a single click", ->
|
||||
it "re-positions the cursor from the clicked screen position to the corresponding buffer position", ->
|
||||
expect(editor.getCursorPosition()).toEqual(row: 0, column: 0)
|
||||
expect(editor.getCursorScreenPosition()).toEqual(row: 0, column: 0)
|
||||
|
||||
[pageX, pageY] = window.pixelPositionForPoint(editor, [4, 7])
|
||||
editor.lines.trigger mousedownEvent({pageX, pageY})
|
||||
expect(editor.getCursorPosition()).toEqual(row: 3, column: 58)
|
||||
expect(editor.getCursorScreenPosition()).toEqual(row: 3, column: 58)
|
||||
|
||||
describe "when soft-wrap is disabled", ->
|
||||
describe "when it is a single click", ->
|
||||
it "re-positions the cursor to the clicked row / column", ->
|
||||
expect(editor.getCursorPosition()).toEqual(row: 0, column: 0)
|
||||
expect(editor.getCursorScreenPosition()).toEqual(row: 0, column: 0)
|
||||
|
||||
[pageX, pageY] = window.pixelPositionForPoint(editor, [3, 10])
|
||||
editor.lines.trigger mousedownEvent({pageX, pageY})
|
||||
expect(editor.getCursorPosition()).toEqual(row: 3, column: 10)
|
||||
expect(editor.getCursorScreenPosition()).toEqual(row: 3, column: 10)
|
||||
|
||||
describe "when it is a double click", ->
|
||||
it "selects the word under the cursor", ->
|
||||
expect(editor.getCursorPosition()).toEqual(row: 0, column: 0)
|
||||
expect(editor.getCursorScreenPosition()).toEqual(row: 0, column: 0)
|
||||
[pageX, pageY] = window.pixelPositionForPoint(editor, [0, 8])
|
||||
editor.lines.trigger mousedownEvent({pageX, pageY, originalEvent: {detail: 1}})
|
||||
$(document).trigger 'mouseup'
|
||||
@@ -355,7 +355,7 @@ describe "Editor", ->
|
||||
|
||||
describe "when it is clicked more then twice (tripple, quadruple, etc...)", ->
|
||||
it "selects the line under the cursor", ->
|
||||
expect(editor.getCursorPosition()).toEqual(row: 0, column: 0)
|
||||
expect(editor.getCursorScreenPosition()).toEqual(row: 0, column: 0)
|
||||
|
||||
# Triple click
|
||||
[pageX, pageY] = window.pixelPositionForPoint(editor, [1, 8])
|
||||
@@ -387,7 +387,7 @@ describe "Editor", ->
|
||||
|
||||
describe "when the arrow keys are pressed with the shift modifier", ->
|
||||
it "expands the selection up to the cursor's new location", ->
|
||||
editor.setCursorPosition(row: 1, column: 6)
|
||||
editor.setCursorScreenPosition(row: 1, column: 6)
|
||||
|
||||
expect(selection.isEmpty()).toBeTruthy()
|
||||
|
||||
@@ -456,7 +456,7 @@ describe "Editor", ->
|
||||
range = editor.selection.getRange()
|
||||
expect(range.start).toEqual({row: 4, column: 10})
|
||||
expect(range.end).toEqual({row: 5, column: 27})
|
||||
expect(editor.getCursorPosition()).toEqual(row: 5, column: 27)
|
||||
expect(editor.getCursorScreenPosition()).toEqual(row: 5, column: 27)
|
||||
|
||||
# mouse up may occur outside of editor, but still need to halt selection
|
||||
$(document).trigger 'mouseup'
|
||||
@@ -468,7 +468,7 @@ describe "Editor", ->
|
||||
range = editor.selection.getRange()
|
||||
expect(range.start).toEqual({row: 4, column: 10})
|
||||
expect(range.end).toEqual({row: 5, column: 27})
|
||||
expect(editor.getCursorPosition()).toEqual(row: 5, column: 27)
|
||||
expect(editor.getCursorScreenPosition()).toEqual(row: 5, column: 27)
|
||||
|
||||
it "creates a selection from word underneath double click to mouse cursor's location ", ->
|
||||
editor.attachToDom()
|
||||
@@ -487,7 +487,7 @@ describe "Editor", ->
|
||||
range = editor.selection.getRange()
|
||||
expect(range.start).toEqual({row: 4, column: 4})
|
||||
expect(range.end).toEqual({row: 5, column: 27})
|
||||
expect(editor.getCursorPosition()).toEqual(row: 5, column: 27)
|
||||
expect(editor.getCursorScreenPosition()).toEqual(row: 5, column: 27)
|
||||
|
||||
# mouse up may occur outside of editor, but still need to halt selection
|
||||
$(document).trigger 'mouseup'
|
||||
@@ -499,7 +499,7 @@ describe "Editor", ->
|
||||
range = editor.selection.getRange()
|
||||
expect(range.start).toEqual({row: 4, column: 4})
|
||||
expect(range.end).toEqual({row: 5, column: 27})
|
||||
expect(editor.getCursorPosition()).toEqual(row: 5, column: 27)
|
||||
expect(editor.getCursorScreenPosition()).toEqual(row: 5, column: 27)
|
||||
|
||||
|
||||
it "creates a selection from line underneath triple click to mouse cursor's location ", ->
|
||||
@@ -521,7 +521,7 @@ describe "Editor", ->
|
||||
range = editor.selection.getRange()
|
||||
expect(range.start).toEqual({row: 4, column: 0})
|
||||
expect(range.end).toEqual({row: 5, column: 27})
|
||||
expect(editor.getCursorPosition()).toEqual(row: 5, column: 27)
|
||||
expect(editor.getCursorScreenPosition()).toEqual(row: 5, column: 27)
|
||||
|
||||
# mouse up may occur outside of editor, but still need to halt selection
|
||||
$(document).trigger 'mouseup'
|
||||
@@ -533,20 +533,20 @@ describe "Editor", ->
|
||||
range = editor.selection.getRange()
|
||||
expect(range.start).toEqual({row: 4, column: 0})
|
||||
expect(range.end).toEqual({row: 5, column: 27})
|
||||
expect(editor.getCursorPosition()).toEqual(row: 5, column: 27)
|
||||
expect(editor.getCursorScreenPosition()).toEqual(row: 5, column: 27)
|
||||
|
||||
describe "buffer manipulation", ->
|
||||
describe "when text input events are triggered on the hidden input element", ->
|
||||
describe "when there is no selection", ->
|
||||
it "inserts the typed character at the cursor position, both in the buffer and the pre element", ->
|
||||
editor.setCursorPosition(row: 1, column: 6)
|
||||
editor.setCursorScreenPosition(row: 1, column: 6)
|
||||
|
||||
expect(editor.getCurrentLine().charAt(6)).not.toBe 'q'
|
||||
|
||||
editor.hiddenInput.textInput 'q'
|
||||
|
||||
expect(editor.getCurrentLine().charAt(6)).toBe 'q'
|
||||
expect(editor.getCursorPosition()).toEqual(row: 1, column: 7)
|
||||
expect(editor.getCursorScreenPosition()).toEqual(row: 1, column: 7)
|
||||
expect(editor.lines.find('pre:eq(1)')).toHaveText editor.getCurrentLine()
|
||||
|
||||
describe "when there is a selection", ->
|
||||
@@ -558,16 +558,16 @@ describe "Editor", ->
|
||||
describe "when return is pressed", ->
|
||||
describe "when the cursor is at the beginning of a line", ->
|
||||
it "inserts an empty line before it", ->
|
||||
editor.setCursorPosition(row: 1, column: 0)
|
||||
editor.setCursorScreenPosition(row: 1, column: 0)
|
||||
|
||||
editor.trigger keydownEvent('enter')
|
||||
|
||||
expect(editor.lines.find('pre:eq(1)')).toHaveHtml ' '
|
||||
expect(editor.getCursorPosition()).toEqual(row: 2, column: 0)
|
||||
expect(editor.getCursorScreenPosition()).toEqual(row: 2, column: 0)
|
||||
|
||||
describe "when the cursor is in the middle of a line", ->
|
||||
it "splits the current line to form a new line", ->
|
||||
editor.setCursorPosition(row: 1, column: 6)
|
||||
editor.setCursorScreenPosition(row: 1, column: 6)
|
||||
|
||||
originalLine = editor.lines.find('pre:eq(1)').text()
|
||||
lineBelowOriginalLine = editor.lines.find('pre:eq(2)').text()
|
||||
@@ -576,21 +576,21 @@ describe "Editor", ->
|
||||
expect(editor.lines.find('pre:eq(1)')).toHaveText originalLine[0...6]
|
||||
expect(editor.lines.find('pre:eq(2)')).toHaveText originalLine[6..]
|
||||
expect(editor.lines.find('pre:eq(3)')).toHaveText lineBelowOriginalLine
|
||||
expect(editor.getCursorPosition()).toEqual(row: 2, column: 0)
|
||||
expect(editor.getCursorScreenPosition()).toEqual(row: 2, column: 0)
|
||||
|
||||
describe "when the cursor is on the end of a line", ->
|
||||
it "inserts an empty line after it", ->
|
||||
editor.setCursorPosition(row: 1, column: buffer.getLine(1).length)
|
||||
editor.setCursorScreenPosition(row: 1, column: buffer.getLine(1).length)
|
||||
|
||||
editor.trigger keydownEvent('enter')
|
||||
|
||||
expect(editor.lines.find('pre:eq(2)')).toHaveHtml ' '
|
||||
expect(editor.getCursorPosition()).toEqual(row: 2, column: 0)
|
||||
expect(editor.getCursorScreenPosition()).toEqual(row: 2, column: 0)
|
||||
|
||||
describe "when backspace is pressed", ->
|
||||
describe "when the cursor is on the middle of the line", ->
|
||||
it "removes the character before the cursor", ->
|
||||
editor.setCursorPosition(row: 1, column: 7)
|
||||
editor.setCursorScreenPosition(row: 1, column: 7)
|
||||
expect(buffer.getLine(1)).toBe " var sort = function(items) {"
|
||||
|
||||
editor.trigger keydownEvent('backspace')
|
||||
@@ -598,7 +598,7 @@ describe "Editor", ->
|
||||
line = buffer.getLine(1)
|
||||
expect(line).toBe " var ort = function(items) {"
|
||||
expect(editor.lines.find('pre:eq(1)')).toHaveText line
|
||||
expect(editor.getCursorPosition()).toEqual {row: 1, column: 6}
|
||||
expect(editor.getCursorScreenPosition()).toEqual {row: 1, column: 6}
|
||||
|
||||
describe "when the cursor is at the beginning of a line", ->
|
||||
it "joins it with the line above", ->
|
||||
@@ -606,7 +606,7 @@ describe "Editor", ->
|
||||
expect(originalLine0).toBe "var quicksort = function () {"
|
||||
expect(buffer.getLine(1)).toBe " var sort = function(items) {"
|
||||
|
||||
editor.setCursorPosition(row: 1, column: 0)
|
||||
editor.setCursorScreenPosition(row: 1, column: 0)
|
||||
editor.trigger keydownEvent('backspace')
|
||||
|
||||
line0 = buffer.getLine(0)
|
||||
@@ -616,11 +616,11 @@ describe "Editor", ->
|
||||
|
||||
expect(editor.lines.find('pre:eq(0)')).toHaveText line0
|
||||
expect(editor.lines.find('pre:eq(1)')).toHaveText line1
|
||||
expect(editor.getCursorPosition()).toEqual {row: 0, column: originalLine0.length}
|
||||
expect(editor.getCursorScreenPosition()).toEqual {row: 0, column: originalLine0.length}
|
||||
|
||||
describe "when the cursor is at the first column of the first line", ->
|
||||
it "does nothing, but doesn't raise an error", ->
|
||||
editor.setCursorPosition(row: 0, column: 0)
|
||||
editor.setCursorScreenPosition(row: 0, column: 0)
|
||||
editor.trigger keydownEvent('backspace')
|
||||
|
||||
describe "when there is a selection", ->
|
||||
@@ -632,13 +632,13 @@ describe "Editor", ->
|
||||
describe "when delete is pressed", ->
|
||||
describe "when the cursor is on the middle of a line", ->
|
||||
it "deletes the character following the cursor", ->
|
||||
editor.setCursorPosition([1, 6])
|
||||
editor.setCursorScreenPosition([1, 6])
|
||||
editor.trigger keydownEvent('delete')
|
||||
expect(buffer.getLine(1)).toBe ' var ort = function(items) {'
|
||||
|
||||
describe "when the cursor is on the end of a line", ->
|
||||
it "joins the line with the following line", ->
|
||||
editor.setCursorPosition([1, buffer.getLine(1).length])
|
||||
editor.setCursorScreenPosition([1, buffer.getLine(1).length])
|
||||
editor.trigger keydownEvent('delete')
|
||||
expect(buffer.getLine(1)).toBe ' var sort = function(items) { if (items.length <= 1) return items;'
|
||||
|
||||
@@ -650,7 +650,7 @@ describe "Editor", ->
|
||||
|
||||
describe "when the cursor is on the last column of the last line", ->
|
||||
it "does nothing, but doesn't raise an error", ->
|
||||
editor.setCursorPosition([12, buffer.getLine(12).length])
|
||||
editor.setCursorScreenPosition([12, buffer.getLine(12).length])
|
||||
editor.trigger keydownEvent('delete')
|
||||
expect(buffer.getLine(12)).toBe '};'
|
||||
|
||||
@@ -673,7 +673,7 @@ describe "Editor", ->
|
||||
it "calculates line height and char width and updates the pixel position of the cursor", ->
|
||||
expect(editor.lineHeight).toBeNull()
|
||||
expect(editor.charWidth).toBeNull()
|
||||
editor.setCursorPosition(row: 2, column: 2)
|
||||
editor.setCursorScreenPosition(row: 2, column: 2)
|
||||
|
||||
editor.attachToDom()
|
||||
|
||||
@@ -695,7 +695,7 @@ describe "Editor", ->
|
||||
|
||||
describe ".setBuffer(buffer)", ->
|
||||
it "sets the cursor to the beginning of the file", ->
|
||||
expect(editor.getCursorPosition()).toEqual(row: 0, column: 0)
|
||||
expect(editor.getCursorScreenPosition()).toEqual(row: 0, column: 0)
|
||||
|
||||
describe ".clipPosition(point)", ->
|
||||
it "selects the nearest valid position to the given point", ->
|
||||
@@ -724,7 +724,7 @@ describe "Editor", ->
|
||||
|
||||
describe "when a paste event is triggered", ->
|
||||
it "pastes text into the buffer", ->
|
||||
editor.setCursorPosition [0, 4]
|
||||
editor.setCursorScreenPosition [0, 4]
|
||||
editor.trigger "paste"
|
||||
expect(editor.buffer.getLine(0)).toBe "var firstquicksort = function () {"
|
||||
|
||||
@@ -733,3 +733,10 @@ describe "Editor", ->
|
||||
editor.trigger "paste"
|
||||
expect(editor.buffer.getLine(1)).toBe " var first = function(items) {"
|
||||
|
||||
describe "folding", ->
|
||||
describe "when a fold-selection event is triggered", ->
|
||||
it "folds the selected text and renders a placeholder for it", ->
|
||||
editor.selection.setRange(new Range([4, 29], [7, 4]))
|
||||
editor.trigger 'fold-selection'
|
||||
expect(editor.lines.find('.line:eq(4)').text()).toBe ' while(items.length > 0) {...}'
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ describe "Highlighter", ->
|
||||
|
||||
describe "constructor", ->
|
||||
it "tokenizes all the lines in the buffer", ->
|
||||
expect(highlighter.screenLineForRow(0).tokens[0]).toEqual(type: 'keyword.definition', value: 'var')
|
||||
expect(highlighter.screenLineForRow(11).tokens[1]).toEqual(type: 'keyword', value: 'return')
|
||||
expect(highlighter.lineForScreenRow(0).tokens[0]).toEqual(type: 'keyword.definition', value: 'var')
|
||||
expect(highlighter.lineForScreenRow(11).tokens[1]).toEqual(type: 'keyword', value: 'return')
|
||||
|
||||
describe "when the buffer changes", ->
|
||||
changeHandler = null
|
||||
@@ -26,11 +26,11 @@ describe "Highlighter", ->
|
||||
range = new Range([0, 0], [2, 0])
|
||||
buffer.change(range, "foo()\nbar()\n")
|
||||
|
||||
expect(highlighter.screenLineForRow(0).tokens[0]).toEqual(type: 'identifier', value: 'foo')
|
||||
expect(highlighter.screenLineForRow(1).tokens[0]).toEqual(type: 'identifier', value: 'bar')
|
||||
expect(highlighter.lineForScreenRow(0).tokens[0]).toEqual(type: 'identifier', value: 'foo')
|
||||
expect(highlighter.lineForScreenRow(1).tokens[0]).toEqual(type: 'identifier', value: 'bar')
|
||||
|
||||
# line 2 is unchanged
|
||||
expect(highlighter.screenLineForRow(2).tokens[1]).toEqual(type: 'keyword', value: 'if')
|
||||
expect(highlighter.lineForScreenRow(2).tokens[1]).toEqual(type: 'keyword', value: 'if')
|
||||
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
[event] = changeHandler.argsForCall[0]
|
||||
@@ -43,9 +43,9 @@ describe "Highlighter", ->
|
||||
changeHandler.reset()
|
||||
|
||||
buffer.insert([2, 0], '/*')
|
||||
expect(highlighter.screenLineForRow(3).tokens[0].type).toBe 'comment'
|
||||
expect(highlighter.screenLineForRow(4).tokens[0].type).toBe 'comment'
|
||||
expect(highlighter.screenLineForRow(5).tokens[0].type).toBe 'comment'
|
||||
expect(highlighter.lineForScreenRow(3).tokens[0].type).toBe 'comment'
|
||||
expect(highlighter.lineForScreenRow(4).tokens[0].type).toBe 'comment'
|
||||
expect(highlighter.lineForScreenRow(5).tokens[0].type).toBe 'comment'
|
||||
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
[event] = changeHandler.argsForCall[0]
|
||||
@@ -57,7 +57,7 @@ describe "Highlighter", ->
|
||||
buffer.insert([5, 0], '*/')
|
||||
|
||||
buffer.insert([1, 0], 'var ')
|
||||
expect(highlighter.screenLineForRow(1).tokens[0].type).toBe 'comment'
|
||||
expect(highlighter.lineForScreenRow(1).tokens[0].type).toBe 'comment'
|
||||
|
||||
describe "when lines are both updated and removed", ->
|
||||
it "updates tokens to reflect the removed lines", ->
|
||||
@@ -65,16 +65,16 @@ describe "Highlighter", ->
|
||||
buffer.change(range, "foo()")
|
||||
|
||||
# previous line 0 remains
|
||||
expect(highlighter.screenLineForRow(0).tokens[0]).toEqual(type: 'keyword.definition', value: 'var')
|
||||
expect(highlighter.lineForScreenRow(0).tokens[0]).toEqual(type: 'keyword.definition', value: 'var')
|
||||
|
||||
# previous line 3 should be combined with input to form line 1
|
||||
expect(highlighter.screenLineForRow(1).tokens[0]).toEqual(type: 'identifier', value: 'foo')
|
||||
expect(highlighter.screenLineForRow(1).tokens[6]).toEqual(type: 'identifier', value: 'pivot')
|
||||
expect(highlighter.lineForScreenRow(1).tokens[0]).toEqual(type: 'identifier', value: 'foo')
|
||||
expect(highlighter.lineForScreenRow(1).tokens[6]).toEqual(type: 'identifier', value: 'pivot')
|
||||
|
||||
# lines below deleted regions should be shifted upward
|
||||
expect(highlighter.screenLineForRow(2).tokens[1]).toEqual(type: 'keyword', value: 'while')
|
||||
expect(highlighter.screenLineForRow(3).tokens[1]).toEqual(type: 'identifier', value: 'current')
|
||||
expect(highlighter.screenLineForRow(4).tokens[3]).toEqual(type: 'keyword.operator', value: '<')
|
||||
expect(highlighter.lineForScreenRow(2).tokens[1]).toEqual(type: 'keyword', value: 'while')
|
||||
expect(highlighter.lineForScreenRow(3).tokens[1]).toEqual(type: 'identifier', value: 'current')
|
||||
expect(highlighter.lineForScreenRow(4).tokens[3]).toEqual(type: 'keyword.operator', value: '<')
|
||||
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
[event] = changeHandler.argsForCall[0]
|
||||
@@ -86,9 +86,9 @@ describe "Highlighter", ->
|
||||
changeHandler.reset()
|
||||
|
||||
buffer.change(new Range([2, 0], [3, 0]), '/*')
|
||||
expect(highlighter.screenLineForRow(2).tokens[0].type).toBe 'comment'
|
||||
expect(highlighter.screenLineForRow(3).tokens[0].type).toBe 'comment'
|
||||
expect(highlighter.screenLineForRow(4).tokens[0].type).toBe 'comment'
|
||||
expect(highlighter.lineForScreenRow(2).tokens[0].type).toBe 'comment'
|
||||
expect(highlighter.lineForScreenRow(3).tokens[0].type).toBe 'comment'
|
||||
expect(highlighter.lineForScreenRow(4).tokens[0].type).toBe 'comment'
|
||||
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
[event] = changeHandler.argsForCall[0]
|
||||
@@ -101,19 +101,19 @@ describe "Highlighter", ->
|
||||
buffer.change(range, "foo()\nbar()\nbaz()\nquux()")
|
||||
|
||||
# previous line 0 remains
|
||||
expect(highlighter.screenLineForRow(0).tokens[0]).toEqual(type: 'keyword.definition', value: 'var')
|
||||
expect(highlighter.lineForScreenRow(0).tokens[0]).toEqual(type: 'keyword.definition', value: 'var')
|
||||
|
||||
# 3 new lines inserted
|
||||
expect(highlighter.screenLineForRow(1).tokens[0]).toEqual(type: 'identifier', value: 'foo')
|
||||
expect(highlighter.screenLineForRow(2).tokens[0]).toEqual(type: 'identifier', value: 'bar')
|
||||
expect(highlighter.screenLineForRow(3).tokens[0]).toEqual(type: 'identifier', value: 'baz')
|
||||
expect(highlighter.lineForScreenRow(1).tokens[0]).toEqual(type: 'identifier', value: 'foo')
|
||||
expect(highlighter.lineForScreenRow(2).tokens[0]).toEqual(type: 'identifier', value: 'bar')
|
||||
expect(highlighter.lineForScreenRow(3).tokens[0]).toEqual(type: 'identifier', value: 'baz')
|
||||
|
||||
# previous line 2 is joined with quux() on line 4
|
||||
expect(highlighter.screenLineForRow(4).tokens[0]).toEqual(type: 'identifier', value: 'quux')
|
||||
expect(highlighter.screenLineForRow(4).tokens[4]).toEqual(type: 'keyword', value: 'if')
|
||||
expect(highlighter.lineForScreenRow(4).tokens[0]).toEqual(type: 'identifier', value: 'quux')
|
||||
expect(highlighter.lineForScreenRow(4).tokens[4]).toEqual(type: 'keyword', value: 'if')
|
||||
|
||||
# previous line 3 is pushed down to become line 5
|
||||
expect(highlighter.screenLineForRow(5).tokens[3]).toEqual(type: 'identifier', value: 'pivot')
|
||||
expect(highlighter.lineForScreenRow(5).tokens[3]).toEqual(type: 'identifier', value: 'pivot')
|
||||
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
[event] = changeHandler.argsForCall[0]
|
||||
@@ -125,13 +125,13 @@ describe "Highlighter", ->
|
||||
changeHandler.reset()
|
||||
|
||||
buffer.insert([2, 0], '/*\nabcde\nabcder')
|
||||
expect(highlighter.screenLineForRow(2).tokens[0].type).toBe 'comment'
|
||||
expect(highlighter.screenLineForRow(3).tokens[0].type).toBe 'comment'
|
||||
expect(highlighter.screenLineForRow(4).tokens[0].type).toBe 'comment'
|
||||
expect(highlighter.screenLineForRow(5).tokens[0].type).toBe 'comment'
|
||||
expect(highlighter.screenLineForRow(6).tokens[0].type).toBe 'comment'
|
||||
expect(highlighter.screenLineForRow(7).tokens[0].type).toBe 'comment'
|
||||
expect(highlighter.screenLineForRow(8).tokens[0].type).not.toBe 'comment'
|
||||
expect(highlighter.lineForScreenRow(2).tokens[0].type).toBe 'comment'
|
||||
expect(highlighter.lineForScreenRow(3).tokens[0].type).toBe 'comment'
|
||||
expect(highlighter.lineForScreenRow(4).tokens[0].type).toBe 'comment'
|
||||
expect(highlighter.lineForScreenRow(5).tokens[0].type).toBe 'comment'
|
||||
expect(highlighter.lineForScreenRow(6).tokens[0].type).toBe 'comment'
|
||||
expect(highlighter.lineForScreenRow(7).tokens[0].type).toBe 'comment'
|
||||
expect(highlighter.lineForScreenRow(8).tokens[0].type).not.toBe 'comment'
|
||||
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
[event] = changeHandler.argsForCall[0]
|
||||
|
||||
@@ -4,34 +4,92 @@ LineFolder = require 'line-folder'
|
||||
Range = require 'range'
|
||||
|
||||
describe "LineFolder", ->
|
||||
[buffer, folder] = []
|
||||
[buffer, folder, changeHandler] = []
|
||||
|
||||
beforeEach ->
|
||||
buffer = new Buffer(require.resolve 'fixtures/sample.js')
|
||||
highlighter = new Higlighter(buffer)
|
||||
folder = new LineFolder(highlighter)
|
||||
changeHandler = jasmine.createSpy('changeHandler')
|
||||
folder.on 'change', changeHandler
|
||||
|
||||
describe "when folds are created and removed", ->
|
||||
it "emits 'fold' and 'unfold' events", ->
|
||||
foldHandler = jasmine.createSpy 'foldHandler'
|
||||
unfoldHandler = jasmine.createSpy 'unfoldHandler'
|
||||
folder.on 'fold', foldHandler
|
||||
folder.on 'unfold', unfoldHandler
|
||||
|
||||
foldRange = new Range([4, 29], [7, 4])
|
||||
fold = folder.createFold(foldRange)
|
||||
|
||||
expect(foldHandler).toHaveBeenCalled()
|
||||
[[range]] = foldHandler.argsForCall
|
||||
expect(range).toEqual foldRange
|
||||
|
||||
fold.destroy()
|
||||
expect(unfoldHandler).toHaveBeenCalled()
|
||||
[[range]] = unfoldHandler.argsForCall
|
||||
expect(range).toEqual foldRange
|
||||
|
||||
describe "screen line rendering", ->
|
||||
describe "when there is a single fold spanning multiple lines", ->
|
||||
it "renders a placeholder on the first line of a fold, and skips subsequent lines", ->
|
||||
folder.fold(new Range([4, 29], [7, 4]))
|
||||
[line4, line5] = fragments = folder.linesForScreenRows(4, 5)
|
||||
it "replaces folded lines with a single line containing a placeholder and emits a change event", ->
|
||||
[line4, line5] = folder.linesForScreenRows(4, 5)
|
||||
previousLine4Text = line4.text
|
||||
previousLine5Text = line5.text
|
||||
|
||||
fold = folder.createFold(new Range([4, 29], [7, 4]))
|
||||
[line4, line5] = folder.linesForScreenRows(4, 5)
|
||||
|
||||
expect(line4.text).toBe ' while(items.length > 0) {...}'
|
||||
expect(line5.text).toBe ' return sort(left).concat(pivot).concat(sort(right));'
|
||||
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
[event] = changeHandler.argsForCall[0]
|
||||
expect(event.oldRange).toEqual [[4, 0], [7, 5]]
|
||||
expect(event.newRange).toEqual [[4, 0], [4, 33]]
|
||||
changeHandler.reset()
|
||||
|
||||
fold.destroy()
|
||||
[line4, line5] = folder.linesForScreenRows(4, 5)
|
||||
expect(line4.text).toBe previousLine4Text
|
||||
expect(line5.text).toBe previousLine5Text
|
||||
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
[event] = changeHandler.argsForCall[0]
|
||||
expect(event.oldRange).toEqual [[4, 0], [4, 33]]
|
||||
expect(event.newRange).toEqual [[4, 0], [7, 5]]
|
||||
|
||||
describe "when there is a single fold contained on a single line", ->
|
||||
it "renders a placeholder for the folded region, but does not skip any lines", ->
|
||||
folder.fold(new Range([2, 8], [2, 25]))
|
||||
[line2, line3] = folder.linesForScreenRows(2, 3)
|
||||
fold = folder.createFold(new Range([2, 8], [2, 25]))
|
||||
|
||||
[line2, line3] = folder.linesForScreenRows(2, 3)
|
||||
expect(line2.text).toBe ' if (...) return items;'
|
||||
expect(line3.text).toBe ' var pivot = items.shift(), current, left = [], right = [];'
|
||||
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
[event] = changeHandler.argsForCall[0]
|
||||
expect(event.oldRange).toEqual [[2, 0], [2, 40]]
|
||||
expect(event.newRange).toEqual [[2, 0], [2, 26]]
|
||||
changeHandler.reset()
|
||||
|
||||
fold.destroy()
|
||||
|
||||
[line2, line3] = folder.linesForScreenRows(2, 3)
|
||||
expect(line2.text).toBe ' if (items.length <= 1) return items;'
|
||||
expect(line3.text).toBe ' var pivot = items.shift(), current, left = [], right = [];'
|
||||
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
[event] = changeHandler.argsForCall[0]
|
||||
expect(event.newRange).toEqual [[2, 0], [2, 40]]
|
||||
expect(event.oldRange).toEqual [[2, 0], [2, 26]]
|
||||
changeHandler.reset()
|
||||
|
||||
describe "when there is a nested fold on the last line of another fold", ->
|
||||
it "does not render a placeholder for the nested fold because it is inside of the other fold", ->
|
||||
folder.fold(new Range([8, 5], [8, 10]))
|
||||
folder.fold(new Range([4, 29], [8, 36]))
|
||||
folder.createFold(new Range([8, 5], [8, 10]))
|
||||
folder.createFold(new Range([4, 29], [8, 36]))
|
||||
[line4, line5] = folder.linesForScreenRows(4, 5)
|
||||
|
||||
expect(line4.text).toBe ' while(items.length > 0) {...concat(sort(right));'
|
||||
@@ -40,40 +98,237 @@ describe "LineFolder", ->
|
||||
describe "when another fold begins on the last line of a fold", ->
|
||||
describe "when the second fold is created before the first fold", ->
|
||||
it "renders a placeholder for both folds on the first line of the first fold", ->
|
||||
folder.fold(new Range([7, 5], [8, 36]))
|
||||
folder.fold(new Range([4, 29], [7, 4]))
|
||||
[line4, line5] = folder.linesForScreenRows(4, 5)
|
||||
fold1 = folder.createFold(new Range([7, 5], [8, 36]))
|
||||
fold2 = folder.createFold(new Range([4, 29], [7, 4]))
|
||||
|
||||
[line4, line5] = folder.linesForScreenRows(4, 5)
|
||||
expect(line4.text).toBe ' while(items.length > 0) {...}...concat(sort(right));'
|
||||
expect(line5.text).toBe ' };'
|
||||
|
||||
expect(changeHandler.callCount).toBe 2
|
||||
[[event1], [event2]] = changeHandler.argsForCall
|
||||
expect(event1.oldRange).toEqual [[7, 0], [8, 56]]
|
||||
expect(event1.newRange).toEqual [[7, 0], [7, 28]]
|
||||
expect(event2.oldRange).toEqual [[4, 0], [7, 28]]
|
||||
expect(event2.newRange).toEqual [[4, 0], [4, 56]]
|
||||
changeHandler.reset()
|
||||
|
||||
fold1.destroy()
|
||||
[line4, line5] = folder.linesForScreenRows(4, 5)
|
||||
expect(line4.text).toBe ' while(items.length > 0) {...}'
|
||||
expect(line5.text).toBe ' return sort(left).concat(pivot).concat(sort(right));'
|
||||
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
[event] = changeHandler.argsForCall[0]
|
||||
expect(event.oldRange).toEqual [[4, 0], [4, 56]]
|
||||
expect(event.newRange).toEqual [[4, 0], [5, 56]]
|
||||
changeHandler.reset()
|
||||
|
||||
fold2.destroy()
|
||||
[line4, line5] = folder.linesForScreenRows(4, 5)
|
||||
expect(line4.text).toBe ' while(items.length > 0) {'
|
||||
expect(line5.text).toBe ' current = items.shift();'
|
||||
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
[event] = changeHandler.argsForCall[0]
|
||||
expect(event.oldRange).toEqual [[4, 0], [4, 33]]
|
||||
expect(event.newRange).toEqual [[4, 0], [7, 5]]
|
||||
|
||||
describe "when the second fold is created after the first fold", ->
|
||||
it "renders a placeholder for both folds on the first line of the first fold", ->
|
||||
folder.fold(new Range([4, 29], [7, 4]))
|
||||
folder.fold(new Range([7, 5], [8, 36]))
|
||||
fold1 = folder.createFold(new Range([4, 29], [7, 4]))
|
||||
fold2 = folder.createFold(new Range([7, 5], [8, 36]))
|
||||
[line4, line5] = folder.linesForScreenRows(4, 5)
|
||||
expect(line4.text).toBe ' while(items.length > 0) {...}...concat(sort(right));'
|
||||
expect(line5.text).toBe ' };'
|
||||
|
||||
describe ".screenPositionForBufferPosition(bufferPosition)", ->
|
||||
expect(changeHandler.callCount).toBe 2
|
||||
[[event1], [event2]] = changeHandler.argsForCall
|
||||
expect(event1.oldRange).toEqual [[4, 0], [7, 5]]
|
||||
expect(event1.newRange).toEqual [[4, 0], [4, 33]]
|
||||
expect(event2.oldRange).toEqual [[4, 0], [5, 56]]
|
||||
expect(event2.newRange).toEqual [[4, 0], [4, 56]]
|
||||
changeHandler.reset()
|
||||
|
||||
fold1.destroy()
|
||||
[line4, line5] = folder.linesForScreenRows(4, 5)
|
||||
[line7] = folder.linesForScreenRows(7, 7)
|
||||
expect(line4.text).toBe ' while(items.length > 0) {'
|
||||
expect(line5.text).toBe ' current = items.shift();'
|
||||
expect(line7.text).toBe ' }...concat(sort(right));'
|
||||
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
[event] = changeHandler.argsForCall[0]
|
||||
expect(event.oldRange).toEqual [[4, 0], [4, 56]]
|
||||
expect(event.newRange).toEqual [[4, 0], [7, 28]]
|
||||
changeHandler.reset()
|
||||
|
||||
fold2.destroy()
|
||||
[line4, line5] = folder.linesForScreenRows(4, 5)
|
||||
expect(line4.text).toBe ' while(items.length > 0) {'
|
||||
expect(line5.text).toBe ' current = items.shift();'
|
||||
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
[event] = changeHandler.argsForCall[0]
|
||||
expect(event.oldRange).toEqual [[7, 0], [7, 28]]
|
||||
expect(event.newRange).toEqual [[7, 0], [8, 56]]
|
||||
|
||||
describe "when the buffer changes", ->
|
||||
[fold1, fold2] = []
|
||||
beforeEach ->
|
||||
fold1 = folder.createFold(new Range([4, 29], [7, 4]))
|
||||
fold2 = folder.createFold(new Range([7, 5], [8, 36]))
|
||||
changeHandler.reset()
|
||||
|
||||
describe "when the old range precedes lines with a fold", ->
|
||||
it "updates the buffer and re-positions subsequent folds", ->
|
||||
buffer.change(new Range([1, 5], [2, 10]), 'abc')
|
||||
|
||||
expect(folder.lineForScreenRow(1).text).toBe ' varabcems.length <= 1) return items;'
|
||||
expect(folder.lineForScreenRow(3).text).toBe ' while(items.length > 0) {...}...concat(sort(right));'
|
||||
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
[[event]] = changeHandler.argsForCall
|
||||
expect(event.oldRange).toEqual [[1, 0], [2, 40]]
|
||||
expect(event.newRange).toEqual [[1, 0], [1, 38]]
|
||||
changeHandler.reset()
|
||||
|
||||
fold1.destroy()
|
||||
expect(folder.lineForScreenRow(3).text).toBe ' while(items.length > 0) {'
|
||||
expect(folder.lineForScreenRow(6).text).toBe ' }...concat(sort(right));'
|
||||
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
[[event]] = changeHandler.argsForCall
|
||||
expect(event.oldRange).toEqual [[3, 0], [3, 56]]
|
||||
expect(event.newRange).toEqual [[3, 0], [6, 28]]
|
||||
|
||||
describe "when the old range follows lines with a fold", ->
|
||||
it "re-positions the screen ranges for the change event based on the preceding fold", ->
|
||||
buffer.change(new Range([9, 3], [10, 0]), 'abc')
|
||||
|
||||
expect(folder.lineForScreenRow(5).text).toBe ' }abc'
|
||||
expect(folder.lineForScreenRow(6).text).toBe ' return sort(Array.apply(this, arguments));'
|
||||
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
[[event]] = changeHandler.argsForCall
|
||||
expect(event.oldRange).toEqual [[5, 0], [6, 0]]
|
||||
expect(event.newRange).toEqual [[5, 0], [5, 6]]
|
||||
|
||||
describe "when the old range contains unfolded text on the first line of a fold, preceding the fold placeholder", ->
|
||||
it "re-renders the line with the placeholder and re-positions the fold", ->
|
||||
buffer.change(new Range([4, 4], [4, 9]), 'slongaz')
|
||||
|
||||
expect(folder.lineForScreenRow(4).text).toBe ' slongaz(items.length > 0) {...}...concat(sort(right));'
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
[[event]] = changeHandler.argsForCall
|
||||
expect(event.oldRange).toEqual [[4, 0], [4, 56]]
|
||||
expect(event.newRange).toEqual [[4, 0], [4, 58]]
|
||||
|
||||
fold1.destroy()
|
||||
expect(folder.lineForScreenRow(4).text).toBe ' slongaz(items.length > 0) {'
|
||||
|
||||
describe "when the old range is contained to a single line in-between two fold placeholders", ->
|
||||
it "re-renders the line with the placeholder and re-positions the second fold", ->
|
||||
buffer.insert([7, 4], 'abc')
|
||||
expect(folder.lineForScreenRow(4).text).toBe ' while(items.length > 0) {...abc}...concat(sort(right));'
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
[[event]] = changeHandler.argsForCall
|
||||
expect(event.oldRange).toEqual [[4, 0], [4, 56]]
|
||||
expect(event.newRange).toEqual [[4, 0], [4, 59]]
|
||||
|
||||
fold2.destroy()
|
||||
|
||||
expect(folder.lineForScreenRow(4).text).toBe ' while(items.length > 0) {...abc}'
|
||||
|
||||
describe "when the old range is inside a fold", ->
|
||||
it "does not trigger a change event, but updates the fold and ensures the change is present when the fold is destroyed", ->
|
||||
buffer.change(new Range([4, 29], [6, 0]), 'abc')
|
||||
|
||||
expect(folder.lineForScreenRow(4).text).toBe ' while(items.length > 0) {...}...concat(sort(right));'
|
||||
expect(changeHandler).not.toHaveBeenCalled()
|
||||
|
||||
fold1.destroy()
|
||||
expect(folder.lineForScreenRow(4).text).toBe ' while(items.length > 0) {abc current < pivot ? left.push(current) : right.push(current);'
|
||||
expect(folder.lineForScreenRow(5).text).toBe ' }...concat(sort(right));'
|
||||
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
[[event]] = changeHandler.argsForCall
|
||||
expect(event.oldRange).toEqual [[4, 0], [4, 56]]
|
||||
expect(event.newRange).toEqual [[4, 0], [5, 28]]
|
||||
|
||||
describe "when the old range surrounds a fold", ->
|
||||
it "removes the fold and replaces the fold placeholder with the new text", ->
|
||||
buffer.change(new Range([4, 29], [7, 4]), 'party()')
|
||||
|
||||
expect(folder.lineForScreenRow(4).text).toBe ' while(items.length > 0) {party()}...concat(sort(right));'
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
[[event]] = changeHandler.argsForCall
|
||||
expect(event.oldRange).toEqual [[4, 0], [4, 56]]
|
||||
expect(event.newRange).toEqual [[4, 0], [4, 60]]
|
||||
|
||||
describe "when the old range straddles the start of a fold", ->
|
||||
it "moves the start of the fold to the end of the new range", ->
|
||||
|
||||
describe "when the old region straddles the end of a fold", ->
|
||||
it "moves the start of the fold to the beginning of the new range", ->
|
||||
|
||||
describe "position translation", ->
|
||||
describe "when there is single fold spanning multiple lines", ->
|
||||
it "translates positions to account for folded lines and characters and the placeholder", ->
|
||||
folder.fold(new Range([4, 29], [7, 4]))
|
||||
folder.createFold(new Range([4, 29], [7, 4]))
|
||||
|
||||
# preceding fold: identity
|
||||
expect(folder.screenPositionForBufferPosition([3, 0])).toEqual [3, 0]
|
||||
expect(folder.screenPositionForBufferPosition([4, 0])).toEqual [4, 0]
|
||||
expect(folder.screenPositionForBufferPosition([4, 29])).toEqual [4, 29]
|
||||
|
||||
expect(folder.bufferPositionForScreenPosition([3, 0])).toEqual [3, 0]
|
||||
expect(folder.bufferPositionForScreenPosition([4, 0])).toEqual [4, 0]
|
||||
expect(folder.bufferPositionForScreenPosition([4, 29])).toEqual [4, 29]
|
||||
|
||||
# inside of fold: translate to the start of the fold
|
||||
# expect(folder.screenPositionForBufferPosition([4, 30])).toEqual [4, 29]
|
||||
# expect(folder.screenPositionForBufferPosition([5, 5])).toEqual [4, 29]
|
||||
expect(folder.screenPositionForBufferPosition([4, 35])).toEqual [4, 29]
|
||||
expect(folder.screenPositionForBufferPosition([5, 5])).toEqual [4, 29]
|
||||
|
||||
# following fold, on last line of fold
|
||||
expect(folder.screenPositionForBufferPosition([7, 4])).toEqual [4, 32]
|
||||
expect(folder.screenPositionForBufferPosition([7, 7])).toEqual [4, 35]
|
||||
expect(folder.bufferPositionForScreenPosition([4, 32])).toEqual [7, 4]
|
||||
|
||||
# # following fold, subsequent line
|
||||
expect(folder.screenPositionForBufferPosition([8, 0])).toEqual [5, 0]
|
||||
expect(folder.screenPositionForBufferPosition([13, 13])).toEqual [10, 13]
|
||||
expect(folder.screenPositionForBufferPosition([11, 13])).toEqual [8, 13]
|
||||
|
||||
expect(folder.bufferPositionForScreenPosition([5, 0])).toEqual [8, 0]
|
||||
expect(folder.bufferPositionForScreenPosition([10, 13])).toEqual [13, 13]
|
||||
|
||||
describe "when there is a single fold spanning a single line", ->
|
||||
it "translates positions to account for folded characters and the placeholder", ->
|
||||
folder.createFold(new Range([4, 10], [4, 15]))
|
||||
|
||||
expect(folder.screenPositionForBufferPosition([4, 5])).toEqual [4, 5]
|
||||
expect(folder.screenPositionForBufferPosition([4, 15])).toEqual [4, 13]
|
||||
expect(folder.screenPositionForBufferPosition([4, 20])).toEqual [4, 18]
|
||||
|
||||
expect(folder.bufferPositionForScreenPosition([4, 5])).toEqual [4, 5]
|
||||
expect(folder.bufferPositionForScreenPosition([4, 13])).toEqual [4, 15]
|
||||
expect(folder.bufferPositionForScreenPosition([4, 18])).toEqual [4, 20]
|
||||
describe ".clipScreenPosition(screenPosition)", ->
|
||||
beforeEach ->
|
||||
folder.createFold(new Range([4, 29], [7, 4]))
|
||||
|
||||
it "returns the nearest valid position based on the current screen lines", ->
|
||||
expect(folder.clipScreenPosition([-1, -1])).toEqual [0, 0]
|
||||
expect(folder.clipScreenPosition([0, -1])).toEqual [0, 0]
|
||||
expect(folder.clipScreenPosition([1, 10000])).toEqual [1, 30]
|
||||
expect(folder.clipScreenPosition([2, 15])).toEqual [2, 15]
|
||||
expect(folder.clipScreenPosition([4, 32])).toEqual [4, 32]
|
||||
expect(folder.clipScreenPosition([4, 1000])).toEqual [4, 33]
|
||||
expect(folder.clipScreenPosition([1000, 1000])).toEqual [10, 2]
|
||||
|
||||
it "clips positions inside a placeholder to the beginning of the placeholder", ->
|
||||
expect(folder.clipScreenPosition([4, 30])).toEqual [4, 29]
|
||||
expect(folder.clipScreenPosition([4, 31])).toEqual [4, 29]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ LineMap = require 'line-map'
|
||||
ScreenLineFragment = require 'screen-line-fragment'
|
||||
Buffer = require 'buffer'
|
||||
Highlighter = require 'highlighter'
|
||||
Delta = require 'delta'
|
||||
Point = require 'point'
|
||||
|
||||
describe "LineMap", ->
|
||||
[highlighter, map] = []
|
||||
@@ -12,9 +12,9 @@ describe "LineMap", ->
|
||||
buffer = new Buffer(require.resolve 'fixtures/sample.js')
|
||||
highlighter = new Highlighter(buffer)
|
||||
map = new LineMap
|
||||
[line0, line1, line2, line3, line4] = highlighter.lineFragmentsForRows(0, 4)
|
||||
[line0, line1, line2, line3, line4] = highlighter.linesForScreenRows(0, 4)
|
||||
|
||||
describe ".insertAtBufferRow(row, lineFragment(s))", ->
|
||||
describe ".insertAtBufferRow(row, screenLine(s))", ->
|
||||
describe "when passed a single, line fragment", ->
|
||||
it "inserts the line fragment before the specified buffer row", ->
|
||||
map.insertAtBufferRow(0, line1)
|
||||
@@ -22,10 +22,10 @@ describe "LineMap", ->
|
||||
map.insertAtBufferRow(2, line3)
|
||||
map.insertAtBufferRow(2, line2)
|
||||
|
||||
expect(map.lineFragmentsForScreenRow(0)).toEqual [line0]
|
||||
expect(map.lineFragmentsForScreenRow(1)).toEqual [line1]
|
||||
expect(map.lineFragmentsForScreenRow(2)).toEqual [line2]
|
||||
expect(map.lineFragmentsForScreenRow(3)).toEqual [line3]
|
||||
expect(map.lineForScreenRow(0)).toEqual line0
|
||||
expect(map.lineForScreenRow(1)).toEqual line1
|
||||
expect(map.lineForScreenRow(2)).toEqual line2
|
||||
expect(map.lineForScreenRow(3)).toEqual line3
|
||||
|
||||
describe "when passed an array of line fragments", ->
|
||||
it "inserts the given line fragments before the specified buffer row", ->
|
||||
@@ -33,23 +33,23 @@ describe "LineMap", ->
|
||||
map.insertAtBufferRow(0, [line0, line1])
|
||||
map.insertAtBufferRow(4, [line4])
|
||||
|
||||
expect(map.lineFragmentsForScreenRow(0)).toEqual [line0]
|
||||
expect(map.lineFragmentsForScreenRow(1)).toEqual [line1]
|
||||
expect(map.lineFragmentsForScreenRow(2)).toEqual [line2]
|
||||
expect(map.lineFragmentsForScreenRow(3)).toEqual [line3]
|
||||
expect(map.lineFragmentsForScreenRow(4)).toEqual [line4]
|
||||
expect(map.lineForScreenRow(0)).toEqual line0
|
||||
expect(map.lineForScreenRow(1)).toEqual line1
|
||||
expect(map.lineForScreenRow(2)).toEqual line2
|
||||
expect(map.lineForScreenRow(3)).toEqual line3
|
||||
expect(map.lineForScreenRow(4)).toEqual line4
|
||||
|
||||
describe ".spliceAtBufferRow(bufferRow, rowCount, lineFragments)", ->
|
||||
describe ".spliceAtBufferRow(bufferRow, rowCount, screenLines)", ->
|
||||
describe "when called with a row count of 0", ->
|
||||
it "inserts the given line fragments before the specified buffer row", ->
|
||||
map.insertAtBufferRow(0, [line0, line1, line2])
|
||||
map.spliceAtBufferRow(1, 0, [line3, line4])
|
||||
|
||||
expect(map.lineFragmentsForScreenRow(0)).toEqual [line0]
|
||||
expect(map.lineFragmentsForScreenRow(1)).toEqual [line3]
|
||||
expect(map.lineFragmentsForScreenRow(2)).toEqual [line4]
|
||||
expect(map.lineFragmentsForScreenRow(3)).toEqual [line1]
|
||||
expect(map.lineFragmentsForScreenRow(4)).toEqual [line2]
|
||||
expect(map.lineForScreenRow(0)).toEqual line0
|
||||
expect(map.lineForScreenRow(1)).toEqual line3
|
||||
expect(map.lineForScreenRow(2)).toEqual line4
|
||||
expect(map.lineForScreenRow(3)).toEqual line1
|
||||
expect(map.lineForScreenRow(4)).toEqual line2
|
||||
|
||||
describe "when called with a row count of 1", ->
|
||||
describe "when the specified buffer row is spanned by a single line fragment", ->
|
||||
@@ -58,10 +58,10 @@ describe "LineMap", ->
|
||||
map.spliceAtBufferRow(1, 1, [line3, line4])
|
||||
|
||||
expect(map.bufferLineCount()).toBe 4
|
||||
expect(map.lineFragmentsForScreenRow(0)).toEqual [line0]
|
||||
expect(map.lineFragmentsForScreenRow(1)).toEqual [line3]
|
||||
expect(map.lineFragmentsForScreenRow(2)).toEqual [line4]
|
||||
expect(map.lineFragmentsForScreenRow(3)).toEqual [line2]
|
||||
expect(map.lineForScreenRow(0)).toEqual line0
|
||||
expect(map.lineForScreenRow(1)).toEqual line3
|
||||
expect(map.lineForScreenRow(2)).toEqual line4
|
||||
expect(map.lineForScreenRow(3)).toEqual line2
|
||||
|
||||
describe "when the specified buffer row is spanned by multiple line fragments", ->
|
||||
it "replaces all spanning line fragments with the given line fragments", ->
|
||||
@@ -72,10 +72,10 @@ describe "LineMap", ->
|
||||
map.spliceAtBufferRow(1, 1, [line3a, line3b, line4])
|
||||
|
||||
expect(map.bufferLineCount()).toBe 4
|
||||
expect(map.lineFragmentsForScreenRow(0)).toEqual [line0]
|
||||
expect(map.lineFragmentsForScreenRow(1)).toEqual [line3a, line3b]
|
||||
expect(map.lineFragmentsForScreenRow(2)).toEqual [line4]
|
||||
expect(map.lineFragmentsForScreenRow(3)).toEqual [line2]
|
||||
expect(map.lineForScreenRow(0)).toEqual line0
|
||||
expect(map.lineForScreenRow(1)).toEqual line3a.concat(line3b)
|
||||
expect(map.lineForScreenRow(2)).toEqual line4
|
||||
expect(map.lineForScreenRow(3)).toEqual line2
|
||||
|
||||
describe "when called with a row count greater than 1", ->
|
||||
it "replaces all line fragments spanning the multiple buffer rows with the given line fragments", ->
|
||||
@@ -86,9 +86,9 @@ describe "LineMap", ->
|
||||
map.spliceAtBufferRow(1, 2, [line3a, line3b, line4])
|
||||
|
||||
expect(map.bufferLineCount()).toBe 3
|
||||
expect(map.lineFragmentsForScreenRow(0)).toEqual [line0]
|
||||
expect(map.lineFragmentsForScreenRow(1)).toEqual [line3a, line3b]
|
||||
expect(map.lineFragmentsForScreenRow(2)).toEqual [line4]
|
||||
expect(map.lineForScreenRow(0)).toEqual line0
|
||||
expect(map.lineForScreenRow(1)).toEqual line3a.concat(line3b)
|
||||
expect(map.lineForScreenRow(2)).toEqual line4
|
||||
|
||||
describe ".spliceAtScreenRow(startRow, rowCount, lineFragemnts)", ->
|
||||
describe "when called with a row count of 0", ->
|
||||
@@ -96,11 +96,11 @@ describe "LineMap", ->
|
||||
map.insertAtBufferRow(0, [line0, line1, line2])
|
||||
map.spliceAtScreenRow(1, 0, [line3, line4])
|
||||
|
||||
expect(map.lineFragmentsForScreenRow(0)).toEqual [line0]
|
||||
expect(map.lineFragmentsForScreenRow(1)).toEqual [line3]
|
||||
expect(map.lineFragmentsForScreenRow(2)).toEqual [line4]
|
||||
expect(map.lineFragmentsForScreenRow(3)).toEqual [line1]
|
||||
expect(map.lineFragmentsForScreenRow(4)).toEqual [line2]
|
||||
expect(map.lineForScreenRow(0)).toEqual line0
|
||||
expect(map.lineForScreenRow(1)).toEqual line3
|
||||
expect(map.lineForScreenRow(2)).toEqual line4
|
||||
expect(map.lineForScreenRow(3)).toEqual line1
|
||||
expect(map.lineForScreenRow(4)).toEqual line2
|
||||
|
||||
describe "when called with a row count of 1", ->
|
||||
describe "when the specified screen row is spanned by a single line fragment", ->
|
||||
@@ -109,10 +109,10 @@ describe "LineMap", ->
|
||||
map.spliceAtScreenRow(1, 1, [line3, line4])
|
||||
|
||||
expect(map.bufferLineCount()).toBe 4
|
||||
expect(map.lineFragmentsForScreenRow(0)).toEqual [line0]
|
||||
expect(map.lineFragmentsForScreenRow(1)).toEqual [line3]
|
||||
expect(map.lineFragmentsForScreenRow(2)).toEqual [line4]
|
||||
expect(map.lineFragmentsForScreenRow(3)).toEqual [line2]
|
||||
expect(map.lineForScreenRow(0)).toEqual line0
|
||||
expect(map.lineForScreenRow(1)).toEqual line3
|
||||
expect(map.lineForScreenRow(2)).toEqual line4
|
||||
expect(map.lineForScreenRow(3)).toEqual line2
|
||||
|
||||
describe "when the specified screen row is spanned by multiple line fragments", ->
|
||||
it "replaces all spanning line fragments with the given line fragments", ->
|
||||
@@ -123,10 +123,10 @@ describe "LineMap", ->
|
||||
map.spliceAtScreenRow(1, 1, [line3a, line3b, line4])
|
||||
|
||||
expect(map.bufferLineCount()).toBe 4
|
||||
expect(map.lineFragmentsForScreenRow(0)).toEqual [line0]
|
||||
expect(map.lineFragmentsForScreenRow(1)).toEqual [line3a, line3b]
|
||||
expect(map.lineFragmentsForScreenRow(2)).toEqual [line4]
|
||||
expect(map.lineFragmentsForScreenRow(3)).toEqual [line2]
|
||||
expect(map.lineForScreenRow(0)).toEqual line0
|
||||
expect(map.lineForScreenRow(1)).toEqual line3a.concat(line3b)
|
||||
expect(map.lineForScreenRow(2)).toEqual line4
|
||||
expect(map.lineForScreenRow(3)).toEqual line2
|
||||
|
||||
describe "when called with a row count greater than 1", ->
|
||||
it "replaces all line fragments spanning the multiple buffer rows with the given line fragments", ->
|
||||
@@ -137,13 +137,12 @@ describe "LineMap", ->
|
||||
map.spliceAtScreenRow(1, 2, [line3a, line3b, line4])
|
||||
|
||||
expect(map.bufferLineCount()).toBe 3
|
||||
expect(map.lineFragmentsForScreenRow(0)).toEqual [line0]
|
||||
expect(map.lineFragmentsForScreenRow(1)).toEqual [line3a, line3b]
|
||||
expect(map.lineFragmentsForScreenRow(2)).toEqual [line4]
|
||||
expect(map.lineForScreenRow(0)).toEqual line0
|
||||
expect(map.lineForScreenRow(1)).toEqual line3a.concat(line3b)
|
||||
expect(map.lineForScreenRow(2)).toEqual line4
|
||||
|
||||
describe ".linesForScreenRows(startRow, endRow)", ->
|
||||
it "returns lines for the given row range, concatenating fragments that belong on a single screen line", ->
|
||||
line1Text = line1.text
|
||||
[line1a, line1b] = line1.splitAt(11)
|
||||
[line3a, line3b] = line3.splitAt(16)
|
||||
map.insertAtBufferRow(0, [line0, line1a, line1b, line2, line3a, line3b, line4])
|
||||
@@ -151,17 +150,28 @@ describe "LineMap", ->
|
||||
# repeating assertion to cover a regression where this method mutated lines
|
||||
expect(map.linesForScreenRows(1, 3)).toEqual [line1, line2, line3]
|
||||
|
||||
describe ".screenPositionForBufferPosition(bufferPosition, allowEOL=true)", ->
|
||||
describe ".lineForBufferRow(bufferRow)", ->
|
||||
it "returns the concatenated screen line fragments that comprise the given buffer row", ->
|
||||
line1Text = line1.text
|
||||
[line1a, line1b] = line1.splitAt(11)
|
||||
line1a.screenDelta = new Point(1, 0)
|
||||
|
||||
map.insertAtBufferRow(0, [line0, line1a, line1b, line2])
|
||||
|
||||
expect(map.lineForBufferRow(0).text).toBe line0.text
|
||||
expect(map.lineForBufferRow(1).text).toBe line1Text
|
||||
|
||||
describe ".screenPositionForBufferPosition(bufferPosition, eagerWrap=true)", ->
|
||||
beforeEach ->
|
||||
# line1a-line3b describes a fold
|
||||
[line1a, line1b] = line1.splitAt(10)
|
||||
[line3a, line3b] = line3.splitAt(20)
|
||||
line1a.bufferDelta.rows = 2
|
||||
line1a.bufferDelta.columns = 20
|
||||
line1a.bufferDelta.row = 2
|
||||
line1a.bufferDelta.column = 20
|
||||
|
||||
# line4a-line4b describes a wrapped line
|
||||
[line4a, line4b] = line4.splitAt(20)
|
||||
line4a.screenDelta = new Delta(1, 0)
|
||||
line4a.screenDelta = new Point(1, 0)
|
||||
|
||||
map.insertAtBufferRow(0, [line0, line1a, line3b, line4a, line4b])
|
||||
|
||||
@@ -176,6 +186,7 @@ describe "LineMap", ->
|
||||
describe "when eagerWrap is false", ->
|
||||
it "does not wrap buffer positions at the end of a screen line to the beginning of the next screen line", ->
|
||||
expect(map.screenPositionForBufferPosition([4, 20], false)).toEqual [2, 20]
|
||||
expect(map.screenPositionForBufferPosition([4, 29], false)).toEqual [3, 9]
|
||||
|
||||
describe "when eagerWrap is true", ->
|
||||
it "wraps buffer positions at the end of a screen line to the end end of the next screen line", ->
|
||||
@@ -185,8 +196,8 @@ describe "LineMap", ->
|
||||
it "returns the total of all inserted screen row deltas", ->
|
||||
[line1a, line1b] = line1.splitAt(10)
|
||||
[line3a, line3b] = line3.splitAt(10)
|
||||
line1a.screenDelta = new Delta(1, 0)
|
||||
line3a.screenDelta = new Delta(1, 0)
|
||||
line1a.screenDelta = new Point(1, 0)
|
||||
line3a.screenDelta = new Point(1, 0)
|
||||
|
||||
map.insertAtBufferRow(0, [line0, line1a, line1b, line2])
|
||||
|
||||
|
||||
@@ -1,37 +1,40 @@
|
||||
Buffer = require 'buffer'
|
||||
LineWrapper = require 'line-wrapper'
|
||||
Buffer = require 'buffer'
|
||||
Highlighter = require 'highlighter'
|
||||
LineFolder = require 'line-folder'
|
||||
Range = require 'range'
|
||||
ScreenLineFragment = require 'screen-line-fragment'
|
||||
_ = require 'underscore'
|
||||
|
||||
describe "LineWrapper", ->
|
||||
[wrapper, buffer, changeHandler] = []
|
||||
[wrapper, folder, buffer, changeHandler] = []
|
||||
|
||||
beforeEach ->
|
||||
buffer = new Buffer(require.resolve('fixtures/sample.js'))
|
||||
wrapper = new LineWrapper(50, new Highlighter(buffer))
|
||||
highlighter = new Highlighter(buffer)
|
||||
folder = new LineFolder(highlighter)
|
||||
wrapper = new LineWrapper(50, folder)
|
||||
changeHandler = jasmine.createSpy('changeHandler')
|
||||
wrapper.on 'change', changeHandler
|
||||
|
||||
describe ".tokensForScreenRow(row)", ->
|
||||
describe ".lineForScreenRow(row)", ->
|
||||
it "returns tokens for the line fragment corresponding to the given screen row", ->
|
||||
expect(tokensText wrapper.screenLineForRow(3).tokens).toEqual(' var pivot = items.shift(), current, left = [], ')
|
||||
expect(tokensText wrapper.screenLineForRow(4).tokens).toEqual('right = [];')
|
||||
expect(tokensText wrapper.screenLineForRow(5).tokens).toEqual(' while(items.length > 0) {')
|
||||
expect(tokensText wrapper.lineForScreenRow(3).tokens).toEqual(' var pivot = items.shift(), current, left = [], ')
|
||||
expect(tokensText wrapper.lineForScreenRow(4).tokens).toEqual('right = [];')
|
||||
expect(tokensText wrapper.lineForScreenRow(5).tokens).toEqual(' while(items.length > 0) {')
|
||||
|
||||
describe ".screenLineCount()", ->
|
||||
describe ".lineCount()", ->
|
||||
it "returns the total number of screen lines", ->
|
||||
expect(wrapper.screenLineCount()).toBe 16
|
||||
expect(wrapper.lineCount()).toBe 16
|
||||
|
||||
describe "when the buffer changes", ->
|
||||
describe "when a buffer line is updated", ->
|
||||
describe "when the number of screen lines remains the same for the changed buffer line", ->
|
||||
it "re-wraps the existing lines and emits a change event for all its screen lines", ->
|
||||
buffer.insert([6, 28], '1234567')
|
||||
expect(wrapper.screenLineForRow(7).text).toBe ' current < pivot ? left1234567.push(current) '
|
||||
expect(wrapper.screenLineForRow(8).text).toBe ': right.push(current);'
|
||||
expect(wrapper.screenLineForRow(9).text).toBe ' }'
|
||||
expect(wrapper.lineForScreenRow(7).text).toBe ' current < pivot ? left1234567.push(current) '
|
||||
expect(wrapper.lineForScreenRow(8).text).toBe ': right.push(current);'
|
||||
expect(wrapper.lineForScreenRow(9).text).toBe ' }'
|
||||
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
[event] = changeHandler.argsForCall[0]
|
||||
@@ -41,10 +44,10 @@ describe "LineWrapper", ->
|
||||
describe "when the number of screen lines increases for the changed buffer line", ->
|
||||
it "re-wraps and adds an additional screen line and emits a change event for all screen lines", ->
|
||||
buffer.insert([6, 28], '1234567890')
|
||||
expect(wrapper.screenLineForRow(7).text).toBe ' current < pivot ? '
|
||||
expect(wrapper.screenLineForRow(8).text).toBe 'left1234567890.push(current) : '
|
||||
expect(wrapper.screenLineForRow(9).text).toBe 'right.push(current);'
|
||||
expect(wrapper.screenLineForRow(10).text).toBe ' }'
|
||||
expect(wrapper.lineForScreenRow(7).text).toBe ' current < pivot ? '
|
||||
expect(wrapper.lineForScreenRow(8).text).toBe 'left1234567890.push(current) : '
|
||||
expect(wrapper.lineForScreenRow(9).text).toBe 'right.push(current);'
|
||||
expect(wrapper.lineForScreenRow(10).text).toBe ' }'
|
||||
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
[event] = changeHandler.argsForCall[0]
|
||||
@@ -54,8 +57,8 @@ describe "LineWrapper", ->
|
||||
describe "when the number of screen lines decreases for the changed buffer line", ->
|
||||
it "re-wraps and removes a screen line and emits a change event for all screen lines", ->
|
||||
buffer.change(new Range([6, 24], [6, 42]), '')
|
||||
expect(wrapper.screenLineForRow(7).text).toBe ' current < pivot ? : right.push(current);'
|
||||
expect(wrapper.screenLineForRow(8).text).toBe ' }'
|
||||
expect(wrapper.lineForScreenRow(7).text).toBe ' current < pivot ? : right.push(current);'
|
||||
expect(wrapper.lineForScreenRow(8).text).toBe ' }'
|
||||
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
[event] = changeHandler.argsForCall[0]
|
||||
@@ -65,10 +68,10 @@ describe "LineWrapper", ->
|
||||
describe "when buffer lines are inserted", ->
|
||||
it "re-wraps existing and new screen lines and emits a change event", ->
|
||||
buffer.insert([6, 21], '1234567890 abcdefghij 1234567890\nabcdefghij')
|
||||
expect(wrapper.screenLineForRow(7).text).toBe ' current < pivot1234567890 abcdefghij '
|
||||
expect(wrapper.screenLineForRow(8).text).toBe '1234567890'
|
||||
expect(wrapper.screenLineForRow(9).text).toBe 'abcdefghij ? left.push(current) : '
|
||||
expect(wrapper.screenLineForRow(10).text).toBe 'right.push(current);'
|
||||
expect(wrapper.lineForScreenRow(7).text).toBe ' current < pivot1234567890 abcdefghij '
|
||||
expect(wrapper.lineForScreenRow(8).text).toBe '1234567890'
|
||||
expect(wrapper.lineForScreenRow(9).text).toBe 'abcdefghij ? left.push(current) : '
|
||||
expect(wrapper.lineForScreenRow(10).text).toBe 'right.push(current);'
|
||||
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
[event] = changeHandler.argsForCall[0]
|
||||
@@ -78,10 +81,10 @@ describe "LineWrapper", ->
|
||||
describe "when buffer lines are removed", ->
|
||||
it "removes screen lines and emits a change event", ->
|
||||
buffer.change(new Range([3, 21], [7, 5]), ';')
|
||||
expect(wrapper.screenLineForRow(3).text).toBe ' var pivot = items;'
|
||||
expect(wrapper.screenLineForRow(4).text).toBe ' return '
|
||||
expect(wrapper.screenLineForRow(5).text).toBe 'sort(left).concat(pivot).concat(sort(right));'
|
||||
expect(wrapper.screenLineForRow(6).text).toBe ' };'
|
||||
expect(wrapper.lineForScreenRow(3).text).toBe ' var pivot = items;'
|
||||
expect(wrapper.lineForScreenRow(4).text).toBe ' return '
|
||||
expect(wrapper.lineForScreenRow(5).text).toBe 'sort(left).concat(pivot).concat(sort(right));'
|
||||
expect(wrapper.lineForScreenRow(6).text).toBe ' };'
|
||||
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
[event] = changeHandler.argsForCall[0]
|
||||
@@ -91,9 +94,9 @@ describe "LineWrapper", ->
|
||||
describe ".setMaxLength(length)", ->
|
||||
it "changes the length at which lines are wrapped and emits a change event for all screen lines", ->
|
||||
wrapper.setMaxLength(40)
|
||||
expect(tokensText wrapper.screenLineForRow(4).tokens).toBe 'left = [], right = [];'
|
||||
expect(tokensText wrapper.screenLineForRow(5).tokens).toBe ' while(items.length > 0) {'
|
||||
expect(tokensText wrapper.screenLineForRow(12).tokens).toBe 'sort(left).concat(pivot).concat(sort(rig'
|
||||
expect(tokensText wrapper.lineForScreenRow(4).tokens).toBe 'left = [], right = [];'
|
||||
expect(tokensText wrapper.lineForScreenRow(5).tokens).toBe ' while(items.length > 0) {'
|
||||
expect(tokensText wrapper.lineForScreenRow(12).tokens).toBe 'sort(left).concat(pivot).concat(sort(rig'
|
||||
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
[event] = changeHandler.argsForCall[0]
|
||||
@@ -122,6 +125,11 @@ describe "LineWrapper", ->
|
||||
it "translates a position at the end of a wrapped screen line to the begining of the next screen line", ->
|
||||
expect(wrapper.screenPositionForBufferPosition([3, 51], true)).toEqual([4, 0])
|
||||
|
||||
describe "when the position follows a fold", ->
|
||||
it "adjusts the position to account for the fold", ->
|
||||
fold = folder.createFold(new Range([4, 29], [7, 4]))
|
||||
expect(wrapper.screenPositionForBufferPosition([7, 4])).toEqual [5, 32]
|
||||
|
||||
describe ".bufferPositionForScreenPosition(point)", ->
|
||||
it "translates the given screen position to a buffer position, account for wrapped lines", ->
|
||||
# before any wrapped lines
|
||||
@@ -135,6 +143,11 @@ describe "LineWrapper", ->
|
||||
# following a wrapped line
|
||||
expect(wrapper.bufferPositionForScreenPosition([5, 5])).toEqual([4, 5])
|
||||
|
||||
describe "when the position follows a fold placeholder", ->
|
||||
it "adjusts the position to account for the fold", ->
|
||||
fold = folder.createFold(new Range([4, 29], [7, 4]))
|
||||
expect(wrapper.bufferPositionForScreenPosition([5, 32])).toEqual [7, 4]
|
||||
|
||||
describe ".wrapScreenLine(screenLine)", ->
|
||||
makeTokens = (tokenValues...) ->
|
||||
tokenValues.map (value) -> { value, type: 'foo' }
|
||||
|
||||
@@ -3,16 +3,16 @@ Buffer = require 'buffer'
|
||||
Highlighter = require 'highlighter'
|
||||
|
||||
describe "screenLineFragment", ->
|
||||
[lineFragment, highlighter] = []
|
||||
[screenLine, highlighter] = []
|
||||
|
||||
beforeEach ->
|
||||
buffer = new Buffer(require.resolve 'fixtures/sample.js')
|
||||
highlighter = new Highlighter(buffer)
|
||||
lineFragment = highlighter.lineFragmentForRow(3)
|
||||
screenLine = highlighter.lineForScreenRow(3)
|
||||
|
||||
describe ".splitAt(column)", ->
|
||||
it "breaks the line fragment into two fragments", ->
|
||||
[left, right] = lineFragment.splitAt(31)
|
||||
[left, right] = screenLine.splitAt(31)
|
||||
expect(left.text).toBe ' var pivot = items.shift(), '
|
||||
expect(tokensText left.tokens).toBe left.text
|
||||
|
||||
@@ -20,7 +20,7 @@ describe "screenLineFragment", ->
|
||||
expect(tokensText right.tokens).toBe right.text
|
||||
|
||||
it "splits tokens if they straddle the split boundary", ->
|
||||
[left, right] = lineFragment.splitAt(34)
|
||||
[left, right] = screenLine.splitAt(34)
|
||||
expect(left.text).toBe ' var pivot = items.shift(), cur'
|
||||
expect(tokensText left.tokens).toBe left.text
|
||||
|
||||
@@ -30,7 +30,7 @@ describe "screenLineFragment", ->
|
||||
expect(_.last(left.tokens).type).toBe right.tokens[0].type
|
||||
|
||||
it "ensures the returned fragments cover the span of the original line", ->
|
||||
[left, right] = lineFragment.splitAt(15)
|
||||
[left, right] = screenLine.splitAt(15)
|
||||
expect(left.bufferDelta).toEqual [0, 15]
|
||||
expect(left.screenDelta).toEqual [0, 15]
|
||||
|
||||
@@ -46,15 +46,15 @@ describe "screenLineFragment", ->
|
||||
|
||||
describe "if splitting at 0", ->
|
||||
it "returns undefined for the left half", ->
|
||||
expect(lineFragment.splitAt(0)).toEqual [undefined, lineFragment]
|
||||
expect(screenLine.splitAt(0)).toEqual [undefined, screenLine]
|
||||
|
||||
describe "if splitting at a column equal to the line length", ->
|
||||
it "returns an empty line fragment that spans a row for the right half", ->
|
||||
[left, right] = lineFragment.splitAt(lineFragment.text.length)
|
||||
[left, right] = screenLine.splitAt(screenLine.text.length)
|
||||
|
||||
expect(left.text).toBe lineFragment.text
|
||||
expect(left.screenDelta).toEqual [0, lineFragment.text.length]
|
||||
expect(left.bufferDelta).toEqual [0, lineFragment.text.length]
|
||||
expect(left.text).toBe screenLine.text
|
||||
expect(left.screenDelta).toEqual [0, screenLine.text.length]
|
||||
expect(left.bufferDelta).toEqual [0, screenLine.text.length]
|
||||
|
||||
expect(right.text).toBe ''
|
||||
expect(right.screenDelta).toEqual [1, 0]
|
||||
@@ -62,10 +62,10 @@ describe "screenLineFragment", ->
|
||||
|
||||
describe ".concat(otherFragment)", ->
|
||||
it "returns the concatenation of the receiver and the given fragment", ->
|
||||
[left, right] = lineFragment.splitAt(14)
|
||||
expect(left.concat(right)).toEqual lineFragment
|
||||
[left, right] = screenLine.splitAt(14)
|
||||
expect(left.concat(right)).toEqual screenLine
|
||||
|
||||
concatenated = lineFragment.concat(highlighter.lineFragmentForRow(4))
|
||||
concatenated = screenLine.concat(highlighter.lineForScreenRow(4))
|
||||
expect(concatenated.text).toBe ' var pivot = items.shift(), current, left = [], right = []; while(items.length > 0) {'
|
||||
expect(tokensText concatenated.tokens).toBe concatenated.text
|
||||
expect(concatenated.screenDelta).toEqual [2, 0]
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
_ = require 'underscore'
|
||||
Buffer = require 'buffer'
|
||||
Highlighter = require 'highlighter'
|
||||
|
||||
describe "ScreenLine", ->
|
||||
[screenLine, highlighter] = []
|
||||
|
||||
beforeEach ->
|
||||
buffer = new Buffer(require.resolve 'fixtures/sample.js')
|
||||
highlighter = new Highlighter(buffer)
|
||||
screenLine = highlighter.screenLineForRow(3)
|
||||
|
||||
describe ".pushToken(token)", ->
|
||||
it "appends the given token to the screen line", ->
|
||||
screenLine.pushToken(value: "foo", type: "bar")
|
||||
expect(_.last(screenLine.tokens)).toEqual(value: "foo", type: "bar")
|
||||
expect(screenLine.text).toBe ' var pivot = items.shift(), current, left = [], right = [];foo'
|
||||
|
||||
describe ".concat(screenLine)", ->
|
||||
it "returns a new screen line combining the contents of the receiver and the given screen line", ->
|
||||
otherLine = highlighter.screenLineForRow(4)
|
||||
concatenated = screenLine.concat(otherLine)
|
||||
expect(concatenated.text).toBe screenLine.text + otherLine.text
|
||||
expect(concatenated.tokens).toEqual screenLine.tokens.concat(otherLine.tokens)
|
||||
|
||||
describe ".splitAt(splitColumn)", ->
|
||||
describe "when the split column is less than the line length", ->
|
||||
describe "when the split column is at the start of a token", ->
|
||||
it "returns two screen lines", ->
|
||||
[left, right] = screenLine.splitAt(31)
|
||||
expect(left.text).toBe ' var pivot = items.shift(), '
|
||||
expect(tokensText left.tokens).toBe left.text
|
||||
|
||||
expect(right.text).toBe 'current, left = [], right = [];'
|
||||
expect(tokensText right.tokens).toBe right.text
|
||||
|
||||
describe "when the split column is in the middle of a token", ->
|
||||
it "it returns two screen lines, with the token split in half", ->
|
||||
[left, right] = screenLine.splitAt(34)
|
||||
expect(left.text).toBe ' var pivot = items.shift(), cur'
|
||||
expect(tokensText left.tokens).toBe left.text
|
||||
|
||||
expect(right.text).toBe 'rent, left = [], right = [];'
|
||||
expect(tokensText right.tokens).toBe right.text
|
||||
|
||||
describe "when the split column is 0 or equals the line length", ->
|
||||
it "returns a singleton array of the screen line (doesn't split it)", ->
|
||||
expect(screenLine.splitAt(0)).toEqual([screenLine])
|
||||
expect(screenLine.splitAt(screenLine.text.length)).toEqual([screenLine])
|
||||
|
||||
@@ -16,8 +16,8 @@ describe "Selection", ->
|
||||
it "places the anchor at the start of the range and the cursor at the end", ->
|
||||
range = new Range({row: 2, column: 7}, {row: 3, column: 18})
|
||||
selection.setRange(range)
|
||||
expect(selection.anchor.getPosition()).toEqual range.start
|
||||
expect(selection.cursor.getPosition()).toEqual range.end
|
||||
expect(selection.anchor.getScreenPosition()).toEqual range.start
|
||||
expect(selection.cursor.getScreenPosition()).toEqual range.end
|
||||
|
||||
describe ".delete()", ->
|
||||
describe "when nothing is selected", ->
|
||||
@@ -162,30 +162,30 @@ describe "Selection", ->
|
||||
describe ".selectWord()", ->
|
||||
describe "when the cursor is inside a word", ->
|
||||
it "selects the entire word", ->
|
||||
editor.setCursorPosition [0,8]
|
||||
editor.setCursorScreenPosition [0,8]
|
||||
selection.selectWord()
|
||||
expect(selection.getText()).toBe 'quicksort'
|
||||
|
||||
describe "when the cursor is on beginning of a word", ->
|
||||
it "selects the entire word", ->
|
||||
editor.setCursorPosition [0,4]
|
||||
editor.setCursorScreenPosition [0,4]
|
||||
selection.selectWord()
|
||||
expect(selection.getText()).toBe 'quicksort'
|
||||
|
||||
describe "when the cursor is at the end of a word", ->
|
||||
it "selects the entire word", ->
|
||||
editor.setCursorPosition [0,13]
|
||||
editor.setCursorScreenPosition [0,13]
|
||||
selection.selectWord()
|
||||
expect(selection.getText()).toBe 'quicksort'
|
||||
|
||||
describe "when the cursor is not on a word", ->
|
||||
it "selects nothing", ->
|
||||
editor.setCursorPosition [5,2]
|
||||
editor.setCursorScreenPosition [5,2]
|
||||
selection.selectWord()
|
||||
expect(selection.getText()).toBe ''
|
||||
|
||||
describe ".selectLine(row)", ->
|
||||
it "selects the entire line at given row", ->
|
||||
editor.setCursorPosition [0,2]
|
||||
editor.setCursorScreenPosition [0,2]
|
||||
selection.selectLine(1)
|
||||
expect(selection.getText()).toBe " var sort = function(items) {"
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
SpanIndex = require 'span-index'
|
||||
|
||||
describe "SpanIndex", ->
|
||||
index = null
|
||||
beforeEach ->
|
||||
index = new SpanIndex
|
||||
|
||||
describe ".insert(index, span(s), values)", ->
|
||||
describe "when called with an array of spans", ->
|
||||
it "assigns each span in the array to the corresponding entry", ->
|
||||
index.insert(0, [2, 1], ['a', 'b'])
|
||||
expect(index.indexForSpan(1).index).toBe 0
|
||||
expect(index.indexForSpan(2).index).toBe 1
|
||||
|
||||
describe "when called with a single number as the span", ->
|
||||
it "assigns that span to all entries", ->
|
||||
index.insert(0, 1, ['a', 'b'])
|
||||
expect(index.indexForSpan(0).index).toBe 0
|
||||
expect(index.indexForSpan(1).index).toBe 1
|
||||
|
||||
describe ".updateSpans(start, end, spans)", ->
|
||||
it "updates the spans of a range of entries indicated by the given index to the given value", ->
|
||||
index.insert(0, [3, 2, 3, 1, 2], ['a', 'b', 'c', 'd', 'e'])
|
||||
index.updateSpans(1, 3, 1)
|
||||
expect(index.spanForIndex(0)).toBe 3
|
||||
expect(index.spanForIndex(1)).toBe 4
|
||||
expect(index.spanForIndex(2)).toBe 5
|
||||
expect(index.spanForIndex(3)).toBe 6
|
||||
expect(index.spanForIndex(4)).toBe 8
|
||||
|
||||
describe ".sliceBySpan(start, end)", ->
|
||||
describe "when the index contains values that start and end evenly on the given start/end span indices", ->
|
||||
it "returns the spanning values with a start and end offset of 0", ->
|
||||
index.insert(0, [1, 2, 3, 1, 2], ['a', 'b', 'c', 'd', 'e'])
|
||||
{ values, startOffset, endOffset } = index.sliceBySpan(1, 6)
|
||||
|
||||
expect(values).toEqual ['b', 'c', 'd']
|
||||
expect(startOffset).toBe 0
|
||||
expect(endOffset).toBe 0
|
||||
|
||||
describe "when the index contains values that overlap the given start/end span indices", ->
|
||||
it "includes the overlapping values, assigning the start and end offsets to indicate where they overlap the desired span indices", ->
|
||||
index.insert(0, [3, 1, 1, 3, 1], ['a', 'b', 'c', 'd', 'e'])
|
||||
{ values, startOffset, endOffset } = index.sliceBySpan(1, 7)
|
||||
|
||||
expect(values).toEqual ['a', 'b', 'c', 'd']
|
||||
expect(startOffset).toBe 1
|
||||
expect(endOffset).toBe 2
|
||||
|
||||
index.clear()
|
||||
index.insert(0, [1, 4, 1], ['a', 'b', 'c'])
|
||||
{ values, startOffset, endOffset } = index.sliceBySpan(3, 4)
|
||||
|
||||
expect(values).toEqual ['b']
|
||||
expect(startOffset).toBe 2
|
||||
expect(endOffset).toBe 3
|
||||
|
||||
describe "when the index contains values with a span of 0", ->
|
||||
it "treats 0-spanning values as having no width", ->
|
||||
index.insert(0, [0, 0, 3, 2, 3, 1], ['a', 'b', 'c', 'd', 'e', 'f'])
|
||||
{ values, startOffset, endOffset } = index.sliceBySpan(1, 7)
|
||||
expect(values).toEqual ['c', 'd', 'e']
|
||||
expect(startOffset).toBe 1
|
||||
expect(endOffset).toBe 2
|
||||
|
||||
it "does not include 0-spanning values in the returned slice", ->
|
||||
index.insert(0, [3, 0, 2, 0, 3, 1], ['a', 'b', 'c', 'd', 'e', 'f'])
|
||||
{ values, startOffset, endOffset } = index.sliceBySpan(1, 7)
|
||||
expect(values).toEqual ['a', 'c', 'e']
|
||||
expect(startOffset).toBe 1
|
||||
expect(endOffset).toBe 2
|
||||
|
||||
describe ".lengthBySpan()", ->
|
||||
it "returns the sum the spans of all entries in the index", ->
|
||||
index.insert(0, [3, 0, 2, 0, 3, 1], ['a', 'b', 'c', 'd', 'e', 'f'])
|
||||
expect(index.lengthBySpan()).toBe 9
|
||||
|
||||
describe ".indexForSpan(span)", ->
|
||||
it "returns the index of the entry whose aggregated span meets or exceeds the given span, plus an offset", ->
|
||||
index.insert(0, [3, 0, 2, 1], ['a', 'b', 'c', 'd'])
|
||||
expect(index.indexForSpan(0)).toEqual(index: 0, offset: 0)
|
||||
expect(index.indexForSpan(2)).toEqual(index: 0, offset: 2)
|
||||
expect(index.indexForSpan(3)).toEqual(index: 2, offset: 0)
|
||||
expect(index.indexForSpan(4)).toEqual(index: 2, offset: 1)
|
||||
expect(index.indexForSpan(5)).toEqual(index: 3, offset: 0)
|
||||
|
||||
describe ".spanForIndex(index)", ->
|
||||
it "returns the aggregate of spans for all elements up to and including the given index", ->
|
||||
index.insert(0, [3, 0, 2, 0, 3, 1], ['a', 'b', 'c', 'd', 'e', 'f'])
|
||||
expect(index.spanForIndex(0)).toBe 3
|
||||
expect(index.spanForIndex(1)).toBe 3
|
||||
expect(index.spanForIndex(2)).toBe 5
|
||||
expect(index.spanForIndex(3)).toBe 5
|
||||
expect(index.spanForIndex(4)).toBe 8
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -27,14 +27,14 @@ describe "VimMode", ->
|
||||
|
||||
it "does not allow the cursor to be placed on the \n character, unless the line is empty", ->
|
||||
editor.buffer.setText("012345\n\nabcdef")
|
||||
editor.setCursorPosition([0, 5])
|
||||
expect(editor.getCursorPosition()).toEqual [0,5]
|
||||
editor.setCursorScreenPosition([0, 5])
|
||||
expect(editor.getCursorScreenPosition()).toEqual [0,5]
|
||||
|
||||
editor.setCursorPosition([0, 6])
|
||||
expect(editor.getCursorPosition()).toEqual [0,5]
|
||||
editor.setCursorScreenPosition([0, 6])
|
||||
expect(editor.getCursorScreenPosition()).toEqual [0,5]
|
||||
|
||||
editor.setCursorPosition([1, 0])
|
||||
expect(editor.getCursorPosition()).toEqual [1,0]
|
||||
editor.setCursorScreenPosition([1, 0])
|
||||
expect(editor.getCursorScreenPosition()).toEqual [1,0]
|
||||
|
||||
it "clears the operator stack when commands can't be composed", ->
|
||||
editor.trigger keydownEvent('d')
|
||||
@@ -67,23 +67,23 @@ describe "VimMode", ->
|
||||
describe "the x keybinding", ->
|
||||
it "deletes a charachter", ->
|
||||
editor.buffer.setText("012345")
|
||||
editor.setCursorPosition([0, 4])
|
||||
editor.setCursorScreenPosition([0, 4])
|
||||
|
||||
editor.trigger keydownEvent('x')
|
||||
expect(editor.buffer.getText()).toBe '01235'
|
||||
expect(editor.getCursorPosition()).toEqual([0, 4])
|
||||
expect(editor.getCursorScreenPosition()).toEqual([0, 4])
|
||||
|
||||
editor.trigger keydownEvent('x')
|
||||
expect(editor.buffer.getText()).toBe '0123'
|
||||
expect(editor.getCursorPosition()).toEqual([0, 3])
|
||||
expect(editor.getCursorScreenPosition()).toEqual([0, 3])
|
||||
|
||||
editor.trigger keydownEvent('x')
|
||||
expect(editor.buffer.getText()).toBe '012'
|
||||
expect(editor.getCursorPosition()).toEqual([0, 2])
|
||||
expect(editor.getCursorScreenPosition()).toEqual([0, 2])
|
||||
|
||||
it "deletes nothing when cursor is on empty line", ->
|
||||
editor.buffer.setText "012345\n\nabcdef"
|
||||
editor.setCursorPosition [1, 0]
|
||||
editor.setCursorScreenPosition [1, 0]
|
||||
|
||||
editor.trigger keydownEvent 'x'
|
||||
expect(editor.buffer.getText()).toBe "012345\n\nabcdef"
|
||||
@@ -92,202 +92,202 @@ describe "VimMode", ->
|
||||
describe "when followed by a d", ->
|
||||
it "deletes the current line", ->
|
||||
editor.buffer.setText("12345\nabcde\nABCDE")
|
||||
editor.setCursorPosition([1,1])
|
||||
editor.setCursorScreenPosition([1,1])
|
||||
|
||||
editor.trigger keydownEvent('d')
|
||||
editor.trigger keydownEvent('d')
|
||||
expect(editor.buffer.getText()).toBe "12345\nABCDE"
|
||||
expect(editor.getCursorPosition()).toEqual([1,0])
|
||||
expect(editor.getCursorScreenPosition()).toEqual([1,0])
|
||||
|
||||
it "deletes the last line", ->
|
||||
editor.buffer.setText("12345\nabcde\nABCDE")
|
||||
editor.setCursorPosition([2,1])
|
||||
editor.setCursorScreenPosition([2,1])
|
||||
editor.trigger keydownEvent('d')
|
||||
editor.trigger keydownEvent('d')
|
||||
expect(editor.buffer.getText()).toBe "12345\nabcde"
|
||||
expect(editor.getCursorPosition()).toEqual([1,0])
|
||||
expect(editor.getCursorScreenPosition()).toEqual([1,0])
|
||||
|
||||
xdescribe "when the second d is prefixed by a count", ->
|
||||
it "deletes n lines, starting from the current", ->
|
||||
editor.buffer.setText("12345\nabcde\nABCDE\nQWERT")
|
||||
editor.setCursorPosition([1,1])
|
||||
editor.setCursorScreenPosition([1,1])
|
||||
|
||||
editor.trigger keydownEvent('d')
|
||||
editor.trigger keydownEvent('2')
|
||||
editor.trigger keydownEvent('d')
|
||||
|
||||
expect(editor.buffer.getText()).toBe "12345\nQWERT"
|
||||
expect(editor.getCursorPosition()).toEqual([1,0])
|
||||
expect(editor.getCursorScreenPosition()).toEqual([1,0])
|
||||
|
||||
describe "when followed by an h", ->
|
||||
it "deletes the previous letter on the current line", ->
|
||||
editor.buffer.setText("abcd\n01234")
|
||||
editor.setCursorPosition([1,1])
|
||||
editor.setCursorScreenPosition([1,1])
|
||||
|
||||
editor.trigger keydownEvent 'd'
|
||||
editor.trigger keydownEvent 'h'
|
||||
|
||||
expect(editor.buffer.getText()).toBe "abcd\n1234"
|
||||
expect(editor.getCursorPosition()).toEqual([1,0])
|
||||
expect(editor.getCursorScreenPosition()).toEqual([1,0])
|
||||
|
||||
editor.trigger keydownEvent 'd'
|
||||
editor.trigger keydownEvent 'h'
|
||||
|
||||
expect(editor.buffer.getText()).toBe "abcd\n1234"
|
||||
expect(editor.getCursorPosition()).toEqual([1,0])
|
||||
expect(editor.getCursorScreenPosition()).toEqual([1,0])
|
||||
|
||||
describe "when followed by a w", ->
|
||||
it "deletes to the beginning of the next word", ->
|
||||
editor.buffer.setText("abcd efg")
|
||||
editor.setCursorPosition([0,2])
|
||||
editor.setCursorScreenPosition([0,2])
|
||||
|
||||
editor.trigger keydownEvent('d')
|
||||
editor.trigger keydownEvent('w')
|
||||
|
||||
expect(editor.buffer.getText()).toBe "abefg"
|
||||
expect(editor.getCursorPosition()).toEqual([0,2])
|
||||
expect(editor.getCursorScreenPosition()).toEqual([0,2])
|
||||
|
||||
editor.buffer.setText("one two three four")
|
||||
editor.setCursorPosition([0,0])
|
||||
editor.setCursorScreenPosition([0,0])
|
||||
|
||||
editor.trigger keydownEvent('d')
|
||||
editor.trigger keydownEvent('3')
|
||||
editor.trigger keydownEvent('w')
|
||||
|
||||
expect(editor.buffer.getText()).toBe "four"
|
||||
expect(editor.getCursorPosition()).toEqual([0,0])
|
||||
expect(editor.getCursorScreenPosition()).toEqual([0,0])
|
||||
|
||||
describe "when followed by a b", ->
|
||||
it "deletes to the beginning of the previous word", ->
|
||||
editor.buffer.setText("abcd efg")
|
||||
editor.setCursorPosition([0,2])
|
||||
editor.setCursorScreenPosition([0,2])
|
||||
|
||||
editor.trigger keydownEvent('d')
|
||||
editor.trigger keydownEvent('b')
|
||||
|
||||
expect(editor.buffer.getText()).toBe "cd efg"
|
||||
expect(editor.getCursorPosition()).toEqual([0,0])
|
||||
expect(editor.getCursorScreenPosition()).toEqual([0,0])
|
||||
|
||||
editor.buffer.setText("one two three four")
|
||||
editor.setCursorPosition([0,11])
|
||||
editor.setCursorScreenPosition([0,11])
|
||||
|
||||
editor.trigger keydownEvent('d')
|
||||
editor.trigger keydownEvent('3')
|
||||
editor.trigger keydownEvent('b')
|
||||
|
||||
expect(editor.buffer.getText()).toBe "ee four"
|
||||
expect(editor.getCursorPosition()).toEqual([0,0])
|
||||
expect(editor.getCursorScreenPosition()).toEqual([0,0])
|
||||
|
||||
describe "basic motion bindings", ->
|
||||
beforeEach ->
|
||||
editor.buffer.setText("12345\nabcde\nABCDE")
|
||||
editor.setCursorPosition([1,1])
|
||||
editor.setCursorScreenPosition([1,1])
|
||||
|
||||
describe "the h keybinding", ->
|
||||
it "moves the cursor left, but not to the previous line", ->
|
||||
editor.trigger keydownEvent('h')
|
||||
expect(editor.getCursorPosition()).toEqual([1,0])
|
||||
expect(editor.getCursorScreenPosition()).toEqual([1,0])
|
||||
editor.trigger keydownEvent('h')
|
||||
expect(editor.getCursorPosition()).toEqual([1,0])
|
||||
expect(editor.getCursorScreenPosition()).toEqual([1,0])
|
||||
|
||||
describe "the j keybinding", ->
|
||||
it "moves the cursor down, but not to the end of the last line", ->
|
||||
editor.trigger keydownEvent 'j'
|
||||
expect(editor.getCursorPosition()).toEqual([2,1])
|
||||
expect(editor.getCursorScreenPosition()).toEqual([2,1])
|
||||
editor.trigger keydownEvent 'j'
|
||||
expect(editor.getCursorPosition()).toEqual([2,1])
|
||||
expect(editor.getCursorScreenPosition()).toEqual([2,1])
|
||||
|
||||
describe "the k keybinding", ->
|
||||
it "moves the cursor up, but not to the beginning of the first line", ->
|
||||
editor.trigger keydownEvent('k')
|
||||
expect(editor.getCursorPosition()).toEqual([0,1])
|
||||
expect(editor.getCursorScreenPosition()).toEqual([0,1])
|
||||
editor.trigger keydownEvent('k')
|
||||
expect(editor.getCursorPosition()).toEqual([0,1])
|
||||
expect(editor.getCursorScreenPosition()).toEqual([0,1])
|
||||
|
||||
describe "the l keybinding", ->
|
||||
it "moves the cursor right, but not to the next line", ->
|
||||
editor.setCursorPosition([1,3])
|
||||
editor.setCursorScreenPosition([1,3])
|
||||
editor.trigger keydownEvent('l')
|
||||
expect(editor.getCursorPosition()).toEqual([1,4])
|
||||
expect(editor.getCursorScreenPosition()).toEqual([1,4])
|
||||
editor.trigger keydownEvent('l')
|
||||
expect(editor.getCursorPosition()).toEqual([1,4])
|
||||
expect(editor.getCursorScreenPosition()).toEqual([1,4])
|
||||
|
||||
describe "the w keybinding", ->
|
||||
it "moves the cursor to the beginning of the next word", ->
|
||||
editor.buffer.setText("ab cde1+- \n xyz\n\nzip")
|
||||
editor.setCursorPosition([0,0])
|
||||
editor.setCursorScreenPosition([0,0])
|
||||
|
||||
editor.trigger keydownEvent('w')
|
||||
expect(editor.getCursorPosition()).toEqual([0,3])
|
||||
expect(editor.getCursorScreenPosition()).toEqual([0,3])
|
||||
|
||||
editor.trigger keydownEvent('w')
|
||||
expect(editor.getCursorPosition()).toEqual([0,7])
|
||||
expect(editor.getCursorScreenPosition()).toEqual([0,7])
|
||||
|
||||
editor.trigger keydownEvent('w')
|
||||
expect(editor.getCursorPosition()).toEqual([1,1])
|
||||
expect(editor.getCursorScreenPosition()).toEqual([1,1])
|
||||
|
||||
editor.trigger keydownEvent('w')
|
||||
expect(editor.getCursorPosition()).toEqual([2,0])
|
||||
expect(editor.getCursorScreenPosition()).toEqual([2,0])
|
||||
|
||||
editor.trigger keydownEvent('w')
|
||||
expect(editor.getCursorPosition()).toEqual([3,0])
|
||||
expect(editor.getCursorScreenPosition()).toEqual([3,0])
|
||||
|
||||
editor.trigger keydownEvent('w')
|
||||
expect(editor.getCursorPosition()).toEqual([3,2])
|
||||
expect(editor.getCursorScreenPosition()).toEqual([3,2])
|
||||
|
||||
describe "the { keybinding", ->
|
||||
it "moves the cursor to the beginning of the paragraph", ->
|
||||
editor.buffer.setText("abcde\n\nfghij\nhijk\n xyz \n\nzip\n\n \nthe end")
|
||||
editor.setCursorPosition([0,0])
|
||||
editor.setCursorScreenPosition([0,0])
|
||||
|
||||
editor.trigger keydownEvent('}')
|
||||
expect(editor.getCursorPosition()).toEqual [1,0]
|
||||
expect(editor.getCursorScreenPosition()).toEqual [1,0]
|
||||
|
||||
editor.trigger keydownEvent('}')
|
||||
expect(editor.getCursorPosition()).toEqual [5,0]
|
||||
expect(editor.getCursorScreenPosition()).toEqual [5,0]
|
||||
|
||||
editor.trigger keydownEvent('}')
|
||||
expect(editor.getCursorPosition()).toEqual [7,0]
|
||||
expect(editor.getCursorScreenPosition()).toEqual [7,0]
|
||||
|
||||
editor.trigger keydownEvent('}')
|
||||
expect(editor.getCursorPosition()).toEqual [9,6]
|
||||
expect(editor.getCursorScreenPosition()).toEqual [9,6]
|
||||
|
||||
describe "the b keybinding", ->
|
||||
it "moves the cursor to the beginning of the previous word", ->
|
||||
editor.buffer.setText(" ab cde1+- \n xyz\n\nzip }\n last")
|
||||
editor.setCursorPosition [4,1]
|
||||
editor.setCursorScreenPosition [4,1]
|
||||
|
||||
editor.trigger keydownEvent('b')
|
||||
expect(editor.getCursorPosition()).toEqual [3,4]
|
||||
expect(editor.getCursorScreenPosition()).toEqual [3,4]
|
||||
|
||||
editor.trigger keydownEvent('b')
|
||||
expect(editor.getCursorPosition()).toEqual [3,0]
|
||||
expect(editor.getCursorScreenPosition()).toEqual [3,0]
|
||||
|
||||
editor.trigger keydownEvent('b')
|
||||
expect(editor.getCursorPosition()).toEqual [2,0]
|
||||
expect(editor.getCursorScreenPosition()).toEqual [2,0]
|
||||
|
||||
editor.trigger keydownEvent('b')
|
||||
expect(editor.getCursorPosition()).toEqual [1,1]
|
||||
expect(editor.getCursorScreenPosition()).toEqual [1,1]
|
||||
|
||||
editor.trigger keydownEvent('b')
|
||||
expect(editor.getCursorPosition()).toEqual [0,8]
|
||||
expect(editor.getCursorScreenPosition()).toEqual [0,8]
|
||||
|
||||
editor.trigger keydownEvent('b')
|
||||
expect(editor.getCursorPosition()).toEqual [0,4]
|
||||
expect(editor.getCursorScreenPosition()).toEqual [0,4]
|
||||
|
||||
editor.trigger keydownEvent('b')
|
||||
expect(editor.getCursorPosition()).toEqual [0,1]
|
||||
expect(editor.getCursorScreenPosition()).toEqual [0,1]
|
||||
|
||||
editor.trigger keydownEvent('b')
|
||||
expect(editor.getCursorPosition()).toEqual [0,0]
|
||||
expect(editor.getCursorScreenPosition()).toEqual [0,0]
|
||||
|
||||
editor.trigger keydownEvent('b')
|
||||
expect(editor.getCursorPosition()).toEqual [0,0]
|
||||
expect(editor.getCursorScreenPosition()).toEqual [0,0]
|
||||
|
||||
describe "numeric prefix bindings", ->
|
||||
it "repeats the following operation N times", ->
|
||||
editor.buffer.setText("12345")
|
||||
editor.setCursorPosition([0,1])
|
||||
editor.setCursorScreenPosition([0,1])
|
||||
|
||||
editor.trigger keydownEvent('3')
|
||||
editor.trigger keydownEvent('x')
|
||||
@@ -295,7 +295,7 @@ describe "VimMode", ->
|
||||
expect(editor.buffer.getText()).toBe '15'
|
||||
|
||||
editor.buffer.setText("123456789abc")
|
||||
editor.setCursorPosition([0,0])
|
||||
editor.setCursorScreenPosition([0,0])
|
||||
editor.trigger keydownEvent('1')
|
||||
editor.trigger keydownEvent('0')
|
||||
editor.trigger keydownEvent('x')
|
||||
@@ -308,11 +308,11 @@ describe "VimMode", ->
|
||||
|
||||
it "allows the cursor to reach the end of the line", ->
|
||||
editor.buffer.setText("012345\n\nabcdef")
|
||||
editor.setCursorPosition([0, 5])
|
||||
expect(editor.getCursorPosition()).toEqual [0,5]
|
||||
editor.setCursorScreenPosition([0, 5])
|
||||
expect(editor.getCursorScreenPosition()).toEqual [0,5]
|
||||
|
||||
editor.setCursorPosition([0, 6])
|
||||
expect(editor.getCursorPosition()).toEqual [0,6]
|
||||
editor.setCursorScreenPosition([0, 6])
|
||||
expect(editor.getCursorScreenPosition()).toEqual [0,6]
|
||||
|
||||
it "puts the editor into command mode when <escape> is pressed", ->
|
||||
expect(editor).not.toHaveClass 'command-mode'
|
||||
|
||||
@@ -13,11 +13,11 @@ class Cursor extends View
|
||||
@one 'attach', => @updateAppearance()
|
||||
|
||||
bufferChanged: (e) ->
|
||||
@setPosition(e.newRange.end)
|
||||
@setScreenPosition(e.newRange.end)
|
||||
|
||||
setPosition: (point) ->
|
||||
setScreenPosition: (point) ->
|
||||
point = Point.fromObject(point)
|
||||
@point = @editor.clipPosition(point)
|
||||
@$position = @editor.clipPosition(point)
|
||||
@goalColumn = null
|
||||
@updateAppearance()
|
||||
@trigger 'cursor:position-changed'
|
||||
@@ -26,67 +26,67 @@ class Cursor extends View
|
||||
window.clearTimeout(@idleTimeout) if @idleTimeout
|
||||
@idleTimeout = window.setTimeout (=> @addClass 'idle'), 200
|
||||
|
||||
getPosition: -> _.clone(@point)
|
||||
getScreenPosition: -> _.clone(@$position)
|
||||
|
||||
getColumn: ->
|
||||
@getPosition().column
|
||||
@getScreenPosition().column
|
||||
|
||||
setColumn: (column) ->
|
||||
{ row } = @getPosition()
|
||||
@setPosition {row, column}
|
||||
{ row } = @getScreenPosition()
|
||||
@setScreenPosition {row, column}
|
||||
|
||||
getRow: ->
|
||||
@getPosition().row
|
||||
@getScreenPosition().row
|
||||
|
||||
isOnEOL: ->
|
||||
@getColumn() == @editor.getCurrentLine().length
|
||||
|
||||
moveUp: ->
|
||||
{ row, column } = @getPosition()
|
||||
{ row, column } = @getScreenPosition()
|
||||
column = @goalColumn if @goalColumn?
|
||||
if row > 0
|
||||
@setPosition({row: row - 1, column: column})
|
||||
@setScreenPosition({row: row - 1, column: column})
|
||||
else
|
||||
@moveToLineStart()
|
||||
|
||||
@goalColumn = column
|
||||
|
||||
moveDown: ->
|
||||
{ row, column } = @getPosition()
|
||||
{ row, column } = @getScreenPosition()
|
||||
column = @goalColumn if @goalColumn?
|
||||
if row < @editor.buffer.numLines() - 1
|
||||
@setPosition({row: row + 1, column: column})
|
||||
@setScreenPosition({row: row + 1, column: column})
|
||||
else
|
||||
@moveToLineEnd()
|
||||
|
||||
@goalColumn = column
|
||||
|
||||
moveToLineEnd: ->
|
||||
{ row } = @getPosition()
|
||||
@setPosition({ row, column: @editor.buffer.getLine(row).length })
|
||||
{ row } = @getScreenPosition()
|
||||
@setScreenPosition({ row, column: @editor.buffer.getLine(row).length })
|
||||
|
||||
moveToLineStart: ->
|
||||
{ row } = @getPosition()
|
||||
@setPosition({ row, column: 0 })
|
||||
{ row } = @getScreenPosition()
|
||||
@setScreenPosition({ row, column: 0 })
|
||||
|
||||
moveRight: ->
|
||||
{ row, column } = @getPosition()
|
||||
{ row, column } = @getScreenPosition()
|
||||
if column < @editor.buffer.getLine(row).length
|
||||
column++
|
||||
else if row < @editor.buffer.numLines() - 1
|
||||
row++
|
||||
column = 0
|
||||
@setPosition({row, column})
|
||||
@setScreenPosition({row, column})
|
||||
|
||||
moveLeft: ->
|
||||
{ row, column } = @getPosition()
|
||||
{ row, column } = @getScreenPosition()
|
||||
if column > 0
|
||||
column--
|
||||
else if row > 0
|
||||
row--
|
||||
column = @editor.buffer.getLine(row).length
|
||||
|
||||
@setPosition({row, column})
|
||||
@setScreenPosition({row, column})
|
||||
|
||||
moveLeftUntilMatch: (regex) ->
|
||||
row = @getRow()
|
||||
@@ -108,10 +108,10 @@ class Cursor extends View
|
||||
|
||||
offset = match and -match[0].length or 0
|
||||
|
||||
@setPosition [row, column + offset]
|
||||
@setScreenPosition [row, column + offset]
|
||||
|
||||
updateAppearance: ->
|
||||
position = @editor.pixelPositionFromPoint(@point)
|
||||
position = @editor.pixelPositionFromPoint(@getScreenPosition())
|
||||
@css(position)
|
||||
@autoScrollVertically(position)
|
||||
@autoScrollHorizontally(position)
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
Point = require 'point'
|
||||
|
||||
module.exports =
|
||||
class Delta
|
||||
@fromObject: (object) ->
|
||||
if object instanceof Delta
|
||||
object
|
||||
else
|
||||
new Delta(object[0], object[1])
|
||||
|
||||
constructor: (@rows=0, @columns=0) ->
|
||||
|
||||
add: (other) ->
|
||||
debugger unless other
|
||||
rows = @rows + other.rows
|
||||
if other.rows == 0
|
||||
columns = @columns + other.columns
|
||||
else
|
||||
columns = other.columns
|
||||
|
||||
new Delta(rows, columns)
|
||||
|
||||
splitAt: (column) ->
|
||||
if @rows == 0
|
||||
rightColumns = @columns - column
|
||||
else
|
||||
rightColumns = @columns
|
||||
|
||||
[new Delta(0, column), new Delta(@rows, rightColumns)]
|
||||
|
||||
inspect: ->
|
||||
"(#{@rows}, #{@columns})"
|
||||
|
||||
isEqual: (other) ->
|
||||
other = Delta.fromObject(other)
|
||||
@rows == other.rows and @columns == other.columns
|
||||
|
||||
toPoint: ->
|
||||
new Point(@rows, @columns)
|
||||
@@ -4,6 +4,7 @@ Point = require 'point'
|
||||
Cursor = require 'cursor'
|
||||
Selection = require 'selection'
|
||||
Highlighter = require 'highlighter'
|
||||
LineFolder = require 'line-folder'
|
||||
LineWrapper = require 'line-wrapper'
|
||||
UndoManager = require 'undo-manager'
|
||||
Range = require 'range'
|
||||
@@ -57,6 +58,7 @@ class Editor extends View
|
||||
'meta-z': 'undo'
|
||||
'meta-Z': 'redo'
|
||||
'alt-meta-w': 'toggle-soft-wrap'
|
||||
'alt-meta-f': 'fold-selection'
|
||||
|
||||
@on 'move-right', => @moveCursorRight()
|
||||
@on 'move-left', => @moveCursorLeft()
|
||||
@@ -75,6 +77,7 @@ class Editor extends View
|
||||
@on 'undo', => @undo()
|
||||
@on 'redo', => @redo()
|
||||
@on 'toggle-soft-wrap', => @toggleSoftWrap()
|
||||
@on 'fold-selection', => @foldSelection()
|
||||
|
||||
buildCursorAndSelection: ->
|
||||
@cursor = new Cursor(this)
|
||||
@@ -92,7 +95,7 @@ class Editor extends View
|
||||
clickCount = e.originalEvent.detail
|
||||
|
||||
if clickCount == 1
|
||||
@setCursorPosition @pointFromMouseEvent(e)
|
||||
@setCursorScreenPosition @pointFromMouseEvent(e)
|
||||
else if clickCount == 2
|
||||
@selection.selectWord()
|
||||
else if clickCount >= 3
|
||||
@@ -104,7 +107,7 @@ class Editor extends View
|
||||
@insertText(e.originalEvent.data)
|
||||
|
||||
@on 'cursor:position-changed', =>
|
||||
@hiddenInput.css(@pixelPositionFromPoint(@cursor.getPosition()))
|
||||
@hiddenInput.css(@pixelPositionFromPoint(@cursor.getScreenPosition()))
|
||||
|
||||
@one 'attach', =>
|
||||
@calculateDimensions()
|
||||
@@ -129,22 +132,23 @@ class Editor extends View
|
||||
|
||||
renderLines: ->
|
||||
@lines.empty()
|
||||
for screenLine in @lineWrapper.screenLines()
|
||||
for screenLine in @lineWrapper.getLines()
|
||||
@lines.append @buildLineElement(screenLine)
|
||||
|
||||
setBuffer: (@buffer) ->
|
||||
@highlighter = new Highlighter(@buffer)
|
||||
@lineWrapper = new LineWrapper(Infinity, @highlighter)
|
||||
@lineFolder = new LineFolder(@highlighter)
|
||||
@lineWrapper = new LineWrapper(Infinity, @lineFolder)
|
||||
@undoManager = new UndoManager(@buffer)
|
||||
@renderLines()
|
||||
@setCursorPosition(row: 0, column: 0)
|
||||
@setCursorScreenPosition(row: 0, column: 0)
|
||||
|
||||
@buffer.on 'change', (e) =>
|
||||
@cursor.bufferChanged(e)
|
||||
|
||||
@lineWrapper.on 'change', (e) =>
|
||||
{ oldRange, newRange } = e
|
||||
screenLines = @lineWrapper.screenLinesForRows(newRange.start.row, newRange.end.row)
|
||||
screenLines = @lineWrapper.linesForScreenRows(newRange.start.row, newRange.end.row)
|
||||
if newRange.end.row > oldRange.end.row
|
||||
# update, then insert elements
|
||||
for row in [newRange.start.row..newRange.end.row]
|
||||
@@ -250,8 +254,8 @@ class Editor extends View
|
||||
moveCursorDown: -> @cursor.moveDown()
|
||||
moveCursorRight: -> @cursor.moveRight()
|
||||
moveCursorLeft: -> @cursor.moveLeft()
|
||||
setCursorPosition: (point) -> @cursor.setPosition(point)
|
||||
getCursorPosition: -> @cursor.getPosition()
|
||||
setCursorScreenPosition: (point) -> @cursor.setScreenPosition(point)
|
||||
getCursorScreenPosition: -> @cursor.getScreenPosition()
|
||||
setCursorRow: (row) -> @cursor.setRow(row)
|
||||
getCursorRow: -> @cursor.getRow()
|
||||
setCursorColumn: (column) -> @cursor.setColumn(column)
|
||||
@@ -271,6 +275,8 @@ class Editor extends View
|
||||
copySelection: -> @selection.copy()
|
||||
paste: -> @selection.insertText(atom.native.readFromPasteboard())
|
||||
|
||||
foldSelection: -> @selection.fold()
|
||||
|
||||
backspace: ->
|
||||
@selectLeft() if @selection.isEmpty()
|
||||
@selection.delete()
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
_ = require 'underscore'
|
||||
ScreenLineFragment = require 'screen-line-fragment'
|
||||
ScreenLine = require 'screen-line'
|
||||
EventEmitter = require 'event-emitter'
|
||||
|
||||
module.exports =
|
||||
@@ -11,7 +10,7 @@ class Highlighter
|
||||
|
||||
constructor: (@buffer) ->
|
||||
@buildTokenizer()
|
||||
@screenLines = @buildScreenLinesForRows('start', 0, @buffer.lastRow())
|
||||
@screenLines = @buildLinesForScreenRows('start', 0, @buffer.lastRow())
|
||||
@buffer.on 'change', (e) => @handleBufferChange(e)
|
||||
|
||||
buildTokenizer: ->
|
||||
@@ -25,7 +24,7 @@ class Highlighter
|
||||
|
||||
startState = @screenLines[newRange.start.row - 1]?.state or 'start'
|
||||
@screenLines[oldRange.start.row..oldRange.end.row] =
|
||||
@buildScreenLinesForRows(startState, newRange.start.row, newRange.end.row)
|
||||
@buildLinesForScreenRows(startState, newRange.start.row, newRange.end.row)
|
||||
|
||||
# spill detection
|
||||
# compare scanner state of last re-highlighted line with its previous state.
|
||||
@@ -36,7 +35,7 @@ class Highlighter
|
||||
break if @screenLines[row].state == previousState
|
||||
nextRow = row + 1
|
||||
previousState = @screenLines[nextRow].state
|
||||
@screenLines[nextRow] = @buildScreenLineForRow(@screenLines[row].state, nextRow)
|
||||
@screenLines[nextRow] = @buildLineForScreenRow(@screenLines[row].state, nextRow)
|
||||
|
||||
# if highlighting spilled beyond the bounds of the textual change, update
|
||||
# the pre and post range to reflect area of highlight changes
|
||||
@@ -49,30 +48,25 @@ class Highlighter
|
||||
|
||||
@trigger("change", {oldRange, newRange})
|
||||
|
||||
buildScreenLinesForRows: (startState, startRow, endRow) ->
|
||||
buildLinesForScreenRows: (startState, startRow, endRow) ->
|
||||
state = startState
|
||||
for row in [startRow..endRow]
|
||||
screenLine = @buildScreenLineForRow(state, row)
|
||||
screenLine = @buildLineForScreenRow(state, row)
|
||||
state = screenLine.state
|
||||
screenLine
|
||||
|
||||
buildScreenLineForRow: (state, row) ->
|
||||
buildLineForScreenRow: (state, row) ->
|
||||
line = @buffer.getLine(row)
|
||||
{tokens, state} = @tokenizer.getLineTokens(line, state)
|
||||
new ScreenLine(tokens, line, state)
|
||||
new ScreenLineFragment(tokens, line, [1, 0], [1, 0], { state })
|
||||
|
||||
screenLineForRow: (row) ->
|
||||
lineForScreenRow: (row) ->
|
||||
@screenLines[row]
|
||||
|
||||
lineFragments: ->
|
||||
@lineFragmentsForRows(0, @buffer.lastRow())
|
||||
linesForScreenRows: (startRow, endRow) ->
|
||||
@screenLines[startRow..endRow]
|
||||
|
||||
lineFragmentsForRows: (startRow, endRow) ->
|
||||
for row in [startRow..endRow]
|
||||
@lineFragmentForRow(row)
|
||||
|
||||
lineFragmentForRow: (row) ->
|
||||
{ tokens, text } = @screenLines[row]
|
||||
new ScreenLineFragment(tokens, text, [1, 0], [1, 0])
|
||||
lastRow: ->
|
||||
@screenLines.length - 1
|
||||
|
||||
_.extend(Highlighter.prototype, EventEmitter)
|
||||
|
||||
@@ -1,50 +1,110 @@
|
||||
_ = require 'underscore'
|
||||
Point = require 'point'
|
||||
Range = require 'range'
|
||||
LineMap = require 'line-map'
|
||||
ScreenLineFragment = require 'screen-line-fragment'
|
||||
_ = require 'underscore'
|
||||
EventEmitter = require 'event-emitter'
|
||||
|
||||
module.exports =
|
||||
class LineFolder
|
||||
lineMap: null
|
||||
lastHighlighterChangeEvent: null
|
||||
|
||||
constructor: (@highlighter) ->
|
||||
@activeFolds = {}
|
||||
@buildLineMap()
|
||||
@highlighter.buffer.on 'change', (e) => @handleBufferChange(e)
|
||||
@highlighter.on 'change', (e) => @lastHighlighterChangeEvent = e
|
||||
|
||||
buildLineMap: ->
|
||||
@lineMap = new LineMap
|
||||
@lineMap.insertAtBufferRow(0, @highlighter.lineFragments())
|
||||
@lineMap.insertAtBufferRow(0, @highlighter.screenLines)
|
||||
|
||||
fold: (bufferRange) ->
|
||||
@activeFolds[bufferRange.start.row] ?= []
|
||||
@activeFolds[bufferRange.start.row].push(new Fold(this, bufferRange))
|
||||
screenRange = @screenRangeForBufferRange(bufferRange)
|
||||
@lineMap.replaceScreenRows(screenRange.start.row, screenRange.end.row, @renderScreenLine(screenRange.start.row))
|
||||
logLines: (start=0, end=@lastRow())->
|
||||
for row in [start..end]
|
||||
line = @lineForScreenRow(row).text
|
||||
console.log row, line, line.length
|
||||
|
||||
renderScreenLine: (screenRow) ->
|
||||
@renderScreenLineForBufferRow(@bufferRowForScreenRow(screenRow))
|
||||
createFold: (bufferRange) ->
|
||||
fold = new Fold(this, bufferRange)
|
||||
@registerFold(bufferRange.start.row, fold)
|
||||
oldScreenRange = @expandScreenRangeToLineEnds(@screenRangeForBufferRange(bufferRange))
|
||||
|
||||
renderScreenLineForBufferRow: (bufferRow, startColumn=0) ->
|
||||
screenLine = @highlighter.lineFragmentForRow(bufferRow).splitAt(startColumn)[1]
|
||||
lineWithFold = @buildLine(oldScreenRange.start.row)
|
||||
@lineMap.replaceScreenRows(oldScreenRange.start.row, oldScreenRange.end.row, lineWithFold)
|
||||
|
||||
newScreenRange = oldScreenRange.copy()
|
||||
newScreenRange.end = _.clone(newScreenRange.start)
|
||||
for fragment in lineWithFold
|
||||
newScreenRange.end.column += fragment.text.length
|
||||
|
||||
@trigger 'change', oldRange: oldScreenRange, newRange: newScreenRange
|
||||
@trigger 'fold', bufferRange
|
||||
fold
|
||||
|
||||
destroyFold: (fold) ->
|
||||
bufferRange = fold.getRange()
|
||||
@unregisterFold(bufferRange.start.row, fold)
|
||||
startScreenRow = @screenRowForBufferRow(bufferRange.start.row)
|
||||
|
||||
oldScreenRange = new Range()
|
||||
oldScreenRange.start.row = startScreenRow
|
||||
oldScreenRange.end.row = startScreenRow
|
||||
oldScreenRange.end.column = @lineMap.lineForScreenRow(startScreenRow).text.length
|
||||
|
||||
@lineMap.replaceScreenRow(startScreenRow, @buildLinesForBufferRows(bufferRange.start.row, bufferRange.end.row))
|
||||
|
||||
newScreenRange = @expandScreenRangeToLineEnds(@screenRangeForBufferRange(bufferRange))
|
||||
|
||||
@trigger 'change', oldRange: oldScreenRange, newRange: newScreenRange
|
||||
@trigger 'unfold', fold.getRange()
|
||||
|
||||
registerFold: (bufferRow, fold) ->
|
||||
@activeFolds[bufferRow] ?= []
|
||||
@activeFolds[bufferRow].push(fold)
|
||||
|
||||
unregisterFold: (bufferRow, fold) ->
|
||||
folds = @activeFolds[bufferRow]
|
||||
folds.splice(folds.indexOf(fold), 1)
|
||||
|
||||
handleBufferChange: (e) ->
|
||||
for row, folds of @activeFolds
|
||||
fold.handleBufferChange(e) for fold in folds
|
||||
@handleHighlighterChange(@lastHighlighterChangeEvent)
|
||||
|
||||
handleHighlighterChange: (e) ->
|
||||
oldScreenRange = @screenRangeForBufferRange(e.oldRange)
|
||||
expandedOldScreenRange = @expandScreenRangeToLineEnds(oldScreenRange)
|
||||
lines = @buildLinesForBufferRows(e.newRange.start.row, e.newRange.end.row)
|
||||
@lineMap.replaceScreenRows(oldScreenRange.start.row, oldScreenRange.end.row, lines)
|
||||
newScreenRange = @screenRangeForBufferRange(e.newRange)
|
||||
expandedNewScreenRange = @expandScreenRangeToLineEnds(newScreenRange)
|
||||
|
||||
unless oldScreenRange.isEmpty() and newScreenRange.isEmpty()
|
||||
@trigger 'change', oldRange: expandedOldScreenRange, newRange: expandedNewScreenRange
|
||||
|
||||
buildLinesForBufferRows: (start, end) ->
|
||||
lines = [@buildLine(@screenRowForBufferRow(start))]
|
||||
if end > start
|
||||
for row in [start + 1..end]
|
||||
lines.push @buildLineForBufferRow(row)
|
||||
_.flatten(lines)
|
||||
|
||||
buildLine: (screenRow) ->
|
||||
@buildLineForBufferRow(@bufferRowForScreenRow(screenRow))
|
||||
|
||||
buildLineForBufferRow: (bufferRow, startColumn=0) ->
|
||||
screenLine = @highlighter.lineForScreenRow(bufferRow).splitAt(startColumn)[1]
|
||||
for fold in @foldsForBufferRow(bufferRow)
|
||||
{ start, end } = fold.range
|
||||
{ start, end } = fold.getRange()
|
||||
if start.column > startColumn
|
||||
prefix = screenLine.splitAt(start.column - startColumn)[0]
|
||||
suffix = @buildScreenLineForBufferRow(end.row, end.column)
|
||||
suffix = @buildLineForBufferRow(end.row, end.column)
|
||||
return _.flatten([prefix, @buildFoldPlaceholder(fold), suffix])
|
||||
screenLine
|
||||
|
||||
buildScreenLineForBufferRow: (bufferRow, startColumn=0) ->
|
||||
screenLine = @highlighter.lineFragmentForRow(bufferRow).splitAt(startColumn)[1]
|
||||
for fold in @foldsForBufferRow(bufferRow)
|
||||
{ start, end } = fold.range
|
||||
if start.column > startColumn
|
||||
prefix = screenLine.splitAt(start.column - startColumn)[0]
|
||||
suffix = @buildScreenLineForBufferRow(end.row, end.column)
|
||||
screenLine = _.flatten([prefix, @buildFoldPlaceholder(fold), suffix])
|
||||
return screenLine
|
||||
screenLine
|
||||
|
||||
buildFoldPlaceholder: (fold) ->
|
||||
new ScreenLineFragment([{value: '...', type: 'fold-placeholder'}], '...', [0, 3], fold.range.toDelta())
|
||||
new ScreenLineFragment([{value: '...', type: 'fold-placeholder'}], '...', [0, 3], fold.getRange().toDelta(), isAtomic: true)
|
||||
|
||||
foldsForBufferRow: (bufferRow) ->
|
||||
@activeFolds[bufferRow] or []
|
||||
@@ -52,6 +112,18 @@ class LineFolder
|
||||
linesForScreenRows: (startRow, endRow) ->
|
||||
@lineMap.linesForScreenRows(startRow, endRow)
|
||||
|
||||
lineForScreenRow: (screenRow) ->
|
||||
@lineMap.lineForScreenRow(screenRow)
|
||||
|
||||
getLines: ->
|
||||
@lineMap.getScreenLines()
|
||||
|
||||
lineCount: ->
|
||||
@lineMap.screenLineCount()
|
||||
|
||||
lastRow: ->
|
||||
@lineCount() - 1
|
||||
|
||||
screenRowForBufferRow: (bufferRow) ->
|
||||
@screenPositionForBufferPosition([bufferRow, 0]).row
|
||||
|
||||
@@ -64,8 +136,48 @@ class LineFolder
|
||||
bufferPositionForScreenPosition: (screenPosition) ->
|
||||
@lineMap.bufferPositionForScreenPosition(screenPosition)
|
||||
|
||||
clipScreenPosition: (screenPosition) ->
|
||||
@lineMap.clipScreenPosition(screenPosition)
|
||||
|
||||
screenRangeForBufferRange: (bufferRange) ->
|
||||
@lineMap.screenRangeForBufferRange(bufferRange)
|
||||
|
||||
expandScreenRangeToLineEnds: (screenRange) ->
|
||||
{ start, end } = screenRange
|
||||
new Range([start.row, 0], [end.row, @lineMap.lineForScreenRow(end.row).text.length])
|
||||
|
||||
_.extend LineFolder.prototype, EventEmitter
|
||||
|
||||
class Fold
|
||||
constructor: (@lineFolder, @range) ->
|
||||
constructor: (@lineFolder, {@start, @end}) ->
|
||||
|
||||
destroy: ->
|
||||
@lineFolder.destroyFold(this)
|
||||
|
||||
getRange: ->
|
||||
new Range(@start, @end)
|
||||
|
||||
handleBufferChange: (event) ->
|
||||
oldStartRow = @start.row
|
||||
|
||||
{ oldRange } = event
|
||||
if oldRange.start.isLessThanOrEqual(@start) and oldRange.end.isGreaterThanOrEqual(@end)
|
||||
@lineFolder.unregisterFold(oldStartRow, this)
|
||||
return
|
||||
|
||||
@start = @updateAnchorPoint(@start, event)
|
||||
@end = @updateAnchorPoint(@end, event, false)
|
||||
|
||||
if @start.row != oldStartRow
|
||||
@lineFolder.unregisterFold(oldStartRow, this)
|
||||
@lineFolder.registerFold(@start.row, this)
|
||||
|
||||
updateAnchorPoint: (point, event, inclusive=true) ->
|
||||
{ newRange, oldRange } = event
|
||||
if inclusive
|
||||
return point if oldRange.end.isGreaterThan(point)
|
||||
else
|
||||
return point if oldRange.end.isGreaterThanOrEqual(point)
|
||||
|
||||
newRange.end.add(point.subtract(oldRange.end))
|
||||
|
||||
|
||||
@@ -1,129 +1,152 @@
|
||||
_ = require 'underscore'
|
||||
Delta = require 'delta'
|
||||
Point = require 'point'
|
||||
Range = require 'range'
|
||||
|
||||
module.exports =
|
||||
class LineMap
|
||||
constructor: ->
|
||||
@lineFragments = []
|
||||
@screenLines = []
|
||||
|
||||
insertAtBufferRow: (bufferRow, lineFragments) ->
|
||||
lineFragments = [lineFragments] unless _.isArray(lineFragments)
|
||||
delta = new Delta
|
||||
insertAtBufferRow: (bufferRow, screenLines) ->
|
||||
screenLines = [screenLines] unless _.isArray(screenLines)
|
||||
delta = new Point
|
||||
insertIndex = 0
|
||||
|
||||
for lineFragment in @lineFragments
|
||||
nextDelta = delta.add(lineFragment.bufferDelta)
|
||||
break if nextDelta.rows > bufferRow
|
||||
for screenLine in @screenLines
|
||||
nextDelta = delta.add(screenLine.bufferDelta)
|
||||
break if nextDelta.row > bufferRow
|
||||
delta = nextDelta
|
||||
insertIndex++
|
||||
|
||||
@lineFragments[insertIndex...insertIndex] = lineFragments
|
||||
@screenLines[insertIndex...insertIndex] = screenLines
|
||||
|
||||
spliceAtBufferRow: (startRow, rowCount, lineFragments) ->
|
||||
@spliceByDelta('bufferDelta', startRow, rowCount, lineFragments)
|
||||
spliceAtBufferRow: (startRow, rowCount, screenLines) ->
|
||||
@spliceByDelta('bufferDelta', startRow, rowCount, screenLines)
|
||||
|
||||
spliceAtScreenRow: (startRow, rowCount, lineFragments) ->
|
||||
@spliceByDelta('screenDelta', startRow, rowCount, lineFragments)
|
||||
spliceAtScreenRow: (startRow, rowCount, screenLines) ->
|
||||
@spliceByDelta('screenDelta', startRow, rowCount, screenLines)
|
||||
|
||||
spliceByDelta: (deltaType, startRow, rowCount, lineFragments) ->
|
||||
spliceByDelta: (deltaType, startRow, rowCount, screenLines) ->
|
||||
stopRow = startRow + rowCount
|
||||
startIndex = undefined
|
||||
stopIndex = 0
|
||||
delta = new Delta
|
||||
delta = new Point
|
||||
|
||||
for lineFragment, i in @lineFragments
|
||||
startIndex = i if delta.rows == startRow and not startIndex
|
||||
nextDelta = delta.add(lineFragment[deltaType])
|
||||
break if nextDelta.rows > stopRow
|
||||
for screenLine, i in @screenLines
|
||||
startIndex = i if delta.row == startRow and not startIndex
|
||||
nextDelta = delta.add(screenLine[deltaType])
|
||||
break if nextDelta.row > stopRow
|
||||
delta = nextDelta
|
||||
stopIndex++
|
||||
|
||||
@lineFragments[startIndex...stopIndex] = lineFragments
|
||||
@screenLines[startIndex...stopIndex] = screenLines
|
||||
|
||||
replaceBufferRows: (start, end, lineFragments) ->
|
||||
@spliceAtBufferRow(start, end - start + 1, lineFragments)
|
||||
replaceBufferRows: (start, end, screenLines) ->
|
||||
@spliceAtBufferRow(start, end - start + 1, screenLines)
|
||||
|
||||
replaceScreenRows: (start, end, lineFragments) ->
|
||||
@spliceAtScreenRow(start, end - start + 1, lineFragments)
|
||||
replaceScreenRow: (row, screenLines) ->
|
||||
@replaceScreenRows(row, row, screenLines)
|
||||
|
||||
lineFragmentsForScreenRow: (screenRow) ->
|
||||
@lineFragmentsForScreenRows(screenRow, screenRow)
|
||||
replaceScreenRows: (start, end, screenLines) ->
|
||||
@spliceAtScreenRow(start, end - start + 1, screenLines)
|
||||
|
||||
lineFragmentsForScreenRows: (startRow, endRow) ->
|
||||
lineFragments = []
|
||||
delta = new Delta
|
||||
getScreenLines: ->
|
||||
return @screenLines
|
||||
|
||||
for lineFragment in @lineFragments
|
||||
break if delta.rows > endRow
|
||||
lineFragments.push(lineFragment) if delta.rows >= startRow
|
||||
delta = delta.add(lineFragment.screenDelta)
|
||||
|
||||
lineFragments
|
||||
lineForScreenRow: (row) ->
|
||||
@linesForScreenRows(row, row)[0]
|
||||
|
||||
linesForScreenRows: (startRow, endRow) ->
|
||||
lastLine = null
|
||||
lines = []
|
||||
delta = new Delta
|
||||
delta = new Point
|
||||
|
||||
for fragment in @lineFragments
|
||||
break if delta.rows > endRow
|
||||
if delta.rows >= startRow
|
||||
for fragment in @screenLines
|
||||
break if delta.row > endRow
|
||||
if delta.row >= startRow
|
||||
if pendingFragment
|
||||
pendingFragment = pendingFragment.concat(fragment)
|
||||
else
|
||||
pendingFragment = fragment
|
||||
if pendingFragment.screenDelta.rows > 0
|
||||
if pendingFragment.screenDelta.row > 0
|
||||
lines.push pendingFragment
|
||||
pendingFragment = null
|
||||
delta = delta.add(fragment.screenDelta)
|
||||
lines
|
||||
|
||||
lineForBufferRow: (row) ->
|
||||
line = null
|
||||
delta = new Point
|
||||
for fragment in @screenLines
|
||||
break if delta.row > row
|
||||
if delta.row == row
|
||||
if line
|
||||
line = line.concat(fragment)
|
||||
else
|
||||
line = fragment
|
||||
delta = delta.add(fragment.bufferDelta)
|
||||
line
|
||||
|
||||
bufferLineCount: ->
|
||||
delta = new Delta
|
||||
for lineFragment in @lineFragments
|
||||
delta = delta.add(lineFragment.bufferDelta)
|
||||
delta.rows
|
||||
delta = new Point
|
||||
for screenLine in @screenLines
|
||||
delta = delta.add(screenLine.bufferDelta)
|
||||
delta.row
|
||||
|
||||
screenLineCount: ->
|
||||
delta = new Delta
|
||||
for lineFragment in @lineFragments
|
||||
delta = delta.add(lineFragment.screenDelta)
|
||||
delta.rows
|
||||
delta = new Point
|
||||
for screenLine in @screenLines
|
||||
delta = delta.add(screenLine.screenDelta)
|
||||
delta.row
|
||||
|
||||
screenPositionForBufferPosition: (bufferPosition, eagerWrap=true) ->
|
||||
bufferPosition = Point.fromObject(bufferPosition)
|
||||
bufferDelta = new Delta
|
||||
screenDelta = new Delta
|
||||
|
||||
for lineFragment in @lineFragments
|
||||
nextDelta = bufferDelta.add(lineFragment.bufferDelta)
|
||||
break if nextDelta.toPoint().greaterThan(bufferPosition)
|
||||
break if nextDelta.toPoint().isEqual(bufferPosition) and not eagerWrap
|
||||
bufferDelta = new Point
|
||||
screenDelta = new Point
|
||||
|
||||
for screenLine in @screenLines
|
||||
nextDelta = bufferDelta.add(screenLine.bufferDelta)
|
||||
break if nextDelta.isGreaterThan(bufferPosition)
|
||||
break if nextDelta.isEqual(bufferPosition) and not eagerWrap
|
||||
bufferDelta = nextDelta
|
||||
screenDelta = screenDelta.add(lineFragment.screenDelta)
|
||||
screenDelta = screenDelta.add(screenLine.screenDelta)
|
||||
|
||||
columns = screenDelta.columns + (bufferPosition.column - bufferDelta.columns)
|
||||
new Point(screenDelta.rows, columns)
|
||||
remainingBufferColumn = bufferPosition.column - bufferDelta.column
|
||||
additionalScreenColumn = Math.max(0, Math.min(remainingBufferColumn, screenLine.lengthForClipping()))
|
||||
|
||||
new Point(screenDelta.row, screenDelta.column + additionalScreenColumn)
|
||||
|
||||
bufferPositionForScreenPosition: (screenPosition) ->
|
||||
screenPosition = Point.fromObject(screenPosition)
|
||||
bufferDelta = new Delta
|
||||
screenDelta = new Delta
|
||||
bufferDelta = new Point
|
||||
screenDelta = new Point
|
||||
|
||||
for lineFragment in @lineFragments
|
||||
nextDelta = screenDelta.add(lineFragment.screenDelta)
|
||||
break if nextDelta.toPoint().greaterThan(screenPosition)
|
||||
for screenLine in @screenLines
|
||||
nextDelta = screenDelta.add(screenLine.screenDelta)
|
||||
break if nextDelta.isGreaterThan(screenPosition)
|
||||
screenDelta = nextDelta
|
||||
bufferDelta = bufferDelta.add(lineFragment.bufferDelta)
|
||||
bufferDelta = bufferDelta.add(screenLine.bufferDelta)
|
||||
|
||||
columns = bufferDelta.columns + (screenPosition.column - screenDelta.columns)
|
||||
new Point(bufferDelta.rows, columns)
|
||||
column = bufferDelta.column + (screenPosition.column - screenDelta.column)
|
||||
new Point(bufferDelta.row, column)
|
||||
|
||||
screenRangeForBufferRange: (bufferRange) ->
|
||||
start = @screenPositionForBufferPosition(bufferRange.start)
|
||||
end = @screenPositionForBufferPosition(bufferRange.end)
|
||||
new Range(start, end)
|
||||
|
||||
clipScreenPosition: (screenPosition) ->
|
||||
screenPosition = Point.fromObject(screenPosition)
|
||||
screenPosition = new Point(Math.max(0, screenPosition.row), Math.max(0, screenPosition.column))
|
||||
|
||||
screenDelta = new Point
|
||||
for screenLine in @screenLines
|
||||
nextDelta = screenDelta.add(screenLine.screenDelta)
|
||||
break if nextDelta.isGreaterThan(screenPosition)
|
||||
screenDelta = nextDelta
|
||||
|
||||
maxColumn = screenDelta.column + screenLine.lengthForClipping()
|
||||
screenDelta.column = Math.min(maxColumn, screenPosition.column)
|
||||
|
||||
screenDelta
|
||||
|
||||
|
||||
@@ -1,73 +1,49 @@
|
||||
_ = require 'underscore'
|
||||
EventEmitter = require 'event-emitter'
|
||||
SpanIndex = require 'span-index'
|
||||
LineMap = require 'line-map'
|
||||
Point = require 'point'
|
||||
Range = require 'range'
|
||||
Delta = require 'delta'
|
||||
|
||||
module.exports =
|
||||
class LineWrapper
|
||||
constructor: (@maxLength, @highlighter) ->
|
||||
@buffer = @highlighter.buffer
|
||||
@buildWrappedLines()
|
||||
@highlighter.on 'change', (e) => @handleChange(e)
|
||||
constructor: (@maxLength, @lineFolder) ->
|
||||
@buildLineMap()
|
||||
@lineFolder.on 'change', (e) => @handleChange(e)
|
||||
|
||||
setMaxLength: (@maxLength) ->
|
||||
oldRange = new Range
|
||||
oldRange.end.row = @screenLineCount() - 1
|
||||
oldRange.end.column = _.last(@index.last().screenLines).text.length
|
||||
@buildWrappedLines()
|
||||
newRange = new Range
|
||||
newRange.end.row = @screenLineCount() - 1
|
||||
newRange.end.column = _.last(@index.last().screenLines).text.length
|
||||
oldRange = @rangeForAllLines()
|
||||
@buildLineMap()
|
||||
newRange = @rangeForAllLines()
|
||||
@trigger 'change', { oldRange, newRange }
|
||||
|
||||
getSpans: (wrappedLines) ->
|
||||
wrappedLines.map (line) -> line.screenLines.length
|
||||
|
||||
unpackWrappedLines: (wrappedLines) ->
|
||||
_.flatten(_.pluck(wrappedLines, 'screenLines'))
|
||||
|
||||
buildWrappedLines: ->
|
||||
@index = new SpanIndex
|
||||
buildLineMap: ->
|
||||
@lineMap = new LineMap
|
||||
wrappedLines = @buildWrappedLinesForBufferRows(0, @buffer.lastRow())
|
||||
@index.insert 0, @getSpans(wrappedLines), wrappedLines
|
||||
@lineMap.insertAtBufferRow 0, @unpackWrappedLines(wrappedLines)
|
||||
@lineMap.insertAtBufferRow 0, @buildScreenLinesForBufferRows(0, @lineFolder.lastRow())
|
||||
|
||||
handleChange: (e) ->
|
||||
oldRange = new Range
|
||||
oldBufferRange = e.oldRange
|
||||
newBufferRange = e.newRange
|
||||
|
||||
bufferRow = e.oldRange.start.row
|
||||
oldRange.start.row = @firstScreenRowForBufferRow(e.oldRange.start.row)
|
||||
oldRange.end.row = @lastScreenRowForBufferRow(e.oldRange.end.row)
|
||||
oldRange.end.column = _.last(@index.at(e.oldRange.end.row).screenLines).text.length
|
||||
oldScreenRange = @lineMap.screenRangeForBufferRange(@expandBufferRangeToLineEnds(oldBufferRange))
|
||||
newScreenLines = @buildScreenLinesForBufferRows(newBufferRange.start.row, newBufferRange.end.row)
|
||||
@lineMap.replaceBufferRows oldBufferRange.start.row, oldBufferRange.end.row, newScreenLines
|
||||
newScreenRange = @lineMap.screenRangeForBufferRange(@expandBufferRangeToLineEnds(newBufferRange))
|
||||
|
||||
{ start, end } = e.oldRange
|
||||
wrappedLines = @buildWrappedLinesForBufferRows(e.newRange.start.row, e.newRange.end.row)
|
||||
@index.splice start.row, end.row, @getSpans(wrappedLines), wrappedLines
|
||||
@lineMap.replaceBufferRows start.row, end.row, @unpackWrappedLines(wrappedLines)
|
||||
@trigger 'change', { oldRange: oldScreenRange, newRange: newScreenRange }
|
||||
|
||||
newRange = oldRange.copy()
|
||||
newRange.end.row = @lastScreenRowForBufferRow(e.newRange.end.row)
|
||||
newRange.end.column = _.last(@index.at(e.newRange.end.row).screenLines).text.length
|
||||
expandBufferRangeToLineEnds: (bufferRange) ->
|
||||
{ start, end } = bufferRange
|
||||
new Range([start.row, 0], [end.row, @lineMap.lineForBufferRow(end.row).text.length])
|
||||
|
||||
@trigger 'change', { oldRange, newRange }
|
||||
rangeForAllLines: ->
|
||||
endRow = @lineCount() - 1
|
||||
endColumn = @lineMap.lineForScreenRow(endRow).text.length
|
||||
new Range([0, 0], [endRow, endColumn])
|
||||
|
||||
firstScreenRowForBufferRow: (bufferRow) ->
|
||||
@screenPositionForBufferPosition([bufferRow, 0]).row
|
||||
|
||||
lastScreenRowForBufferRow: (bufferRow) ->
|
||||
startRow = @screenPositionForBufferPosition([bufferRow, 0]).row
|
||||
startRow + (@index.at(bufferRow).screenLines.length - 1)
|
||||
|
||||
buildWrappedLinesForBufferRows: (start, end) ->
|
||||
for row in [start..end]
|
||||
@buildWrappedLineForBufferRow(row)
|
||||
|
||||
buildWrappedLineForBufferRow: (bufferRow) ->
|
||||
{ screenLines: @wrapScreenLine(@highlighter.lineFragmentForRow(bufferRow)) }
|
||||
buildScreenLinesForBufferRows: (start, end) ->
|
||||
_(@lineFolder
|
||||
.linesForScreenRows(start, end)
|
||||
.map((screenLine) => @wrapScreenLine(screenLine))).flatten()
|
||||
|
||||
wrapScreenLine: (screenLine, startColumn=0) ->
|
||||
screenLines = []
|
||||
@@ -78,7 +54,7 @@ class LineWrapper
|
||||
endColumn = startColumn + screenLine.text.length
|
||||
else
|
||||
[leftHalf, rightHalf] = screenLine.splitAt(splitColumn)
|
||||
leftHalf.screenDelta = new Delta(1, 0)
|
||||
leftHalf.screenDelta = new Point(1, 0)
|
||||
screenLines.push leftHalf
|
||||
endColumn = startColumn + leftHalf.text.length
|
||||
screenLines.push @wrapScreenLine(rightHalf, endColumn)...
|
||||
@@ -100,35 +76,28 @@ class LineWrapper
|
||||
return column + 1 if /\s/.test(line[column])
|
||||
return @maxLength
|
||||
|
||||
screenRangeFromBufferRange: (bufferRange) ->
|
||||
start = @screenPositionForBufferPosition(bufferRange.start, false)
|
||||
end = @screenPositionForBufferPosition(bufferRange.end, false)
|
||||
new Range(start,end)
|
||||
screenRangeForBufferRange: (bufferRange) ->
|
||||
@lineMap.screenRangeForBufferRange(bufferRange)
|
||||
|
||||
screenPositionForBufferPosition: (bufferPosition, eagerWrap=true) ->
|
||||
@lineMap.screenPositionForBufferPosition(bufferPosition, eagerWrap)
|
||||
@lineMap.screenPositionForBufferPosition(
|
||||
@lineFolder.screenPositionForBufferPosition(bufferPosition),
|
||||
eagerWrap)
|
||||
|
||||
bufferPositionForScreenPosition: (screenPosition) ->
|
||||
@lineMap.bufferPositionForScreenPosition(screenPosition)
|
||||
@lineFolder.bufferPositionForScreenPosition(
|
||||
@lineMap.bufferPositionForScreenPosition(screenPosition))
|
||||
|
||||
screenLineForRow: (screenRow) ->
|
||||
@screenLinesForRows(screenRow, screenRow)[0]
|
||||
lineForScreenRow: (screenRow) ->
|
||||
@linesForScreenRows(screenRow, screenRow)[0]
|
||||
|
||||
screenLinesForRows: (startRow, endRow) ->
|
||||
screenLines = []
|
||||
linesForScreenRows: (startRow, endRow) ->
|
||||
@lineMap.linesForScreenRows(startRow, endRow)
|
||||
|
||||
{ values, startOffset, endOffset } = @index.sliceBySpan(startRow, endRow)
|
||||
getLines: ->
|
||||
@linesForScreenRows(0, @lineCount() - 1)
|
||||
|
||||
screenLines.push(values[0].screenLines[startOffset..-1]...)
|
||||
for wrappedLine in values[1...-1]
|
||||
screenLines.push(wrappedLine.screenLines...)
|
||||
screenLines.push(_.last(values).screenLines[0..endOffset]...)
|
||||
screenLines
|
||||
|
||||
screenLines: ->
|
||||
@screenLinesForRows(0, @screenLineCount() - 1)
|
||||
|
||||
screenLineCount: ->
|
||||
lineCount: ->
|
||||
@lineMap.screenLineCount()
|
||||
|
||||
_.extend(LineWrapper.prototype, EventEmitter)
|
||||
|
||||
@@ -11,16 +11,33 @@ class Point
|
||||
|
||||
new Point(row, column)
|
||||
|
||||
constructor: (@row, @column) ->
|
||||
constructor: (@row=0, @column=0) ->
|
||||
|
||||
isEqual: (other) ->
|
||||
if other instanceof Array
|
||||
@row == other[0] and @column == other[1]
|
||||
add: (other) ->
|
||||
row = @row + other.row
|
||||
if other.row == 0
|
||||
column = @column + other.column
|
||||
else
|
||||
@row == other.row and @column == other.column
|
||||
column = other.column
|
||||
|
||||
inspect: ->
|
||||
"(#{@row}, #{@column})"
|
||||
new Point(row, column)
|
||||
|
||||
subtract: (other) ->
|
||||
row = @row - other.row
|
||||
if @row == other.row
|
||||
column = @column - other.column
|
||||
else
|
||||
column = @column
|
||||
|
||||
new Point(row, column)
|
||||
|
||||
splitAt: (column) ->
|
||||
if @row == 0
|
||||
rightColumn = @column - column
|
||||
else
|
||||
rightColumn = @column
|
||||
|
||||
[new Point(0, column), new Point(@row, rightColumn)]
|
||||
|
||||
compare: (other) ->
|
||||
if @row > other.row
|
||||
@@ -35,5 +52,22 @@ class Point
|
||||
else
|
||||
0
|
||||
|
||||
greaterThan: (other) ->
|
||||
isEqual: (other) ->
|
||||
other = Point.fromObject(other)
|
||||
@compare(other) == 0
|
||||
|
||||
isLessThan: (other) ->
|
||||
@compare(other) < 0
|
||||
|
||||
isLessThanOrEqual: (other) ->
|
||||
@compare(other) <= 0
|
||||
|
||||
isGreaterThan: (other) ->
|
||||
@compare(other) > 0
|
||||
|
||||
isGreaterThanOrEqual: (other) ->
|
||||
@compare(other) >= 0
|
||||
|
||||
inspect: ->
|
||||
"(#{@row}, #{@column})"
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
Point = require 'point'
|
||||
Delta = require 'delta'
|
||||
_ = require 'underscore'
|
||||
|
||||
|
||||
@@ -37,5 +36,5 @@ class Range
|
||||
columns = @end.column - @start.column
|
||||
else
|
||||
columns = @end.column
|
||||
new Delta(rows, columns)
|
||||
new Point(rows, columns)
|
||||
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
_ = require 'underscore'
|
||||
Delta = require 'delta'
|
||||
Point = require 'point'
|
||||
|
||||
module.exports =
|
||||
class ScreenLineFragment
|
||||
constructor: (@tokens, @text, screenDelta, bufferDelta) ->
|
||||
@screenDelta = Delta.fromObject(screenDelta)
|
||||
@bufferDelta = Delta.fromObject(bufferDelta)
|
||||
isAtomic: false
|
||||
|
||||
constructor: (@tokens, @text, screenDelta, bufferDelta, extraFields) ->
|
||||
@screenDelta = Point.fromObject(screenDelta)
|
||||
@bufferDelta = Point.fromObject(bufferDelta)
|
||||
_.extend(this, extraFields)
|
||||
|
||||
splitAt: (column) ->
|
||||
return [undefined, this] if column == 0
|
||||
@@ -43,5 +46,11 @@ class ScreenLineFragment
|
||||
bufferDelta = @bufferDelta.add(other.bufferDelta)
|
||||
new ScreenLineFragment(tokens, text, screenDelta, bufferDelta)
|
||||
|
||||
lengthForClipping: ->
|
||||
if @isAtomic
|
||||
0
|
||||
else
|
||||
@text.length
|
||||
|
||||
isEqual: (other) ->
|
||||
_.isEqual(@tokens, other.tokens) and @screenDelta.isEqual(other.screenDelta) and @bufferDelta.isEqual(other.bufferDelta)
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
_ = require 'underscore'
|
||||
|
||||
module.exports =
|
||||
class ScreenLine
|
||||
tokens: null
|
||||
text: null
|
||||
state: null
|
||||
|
||||
constructor: (@tokens, @text, @state) ->
|
||||
|
||||
pushToken: (token) ->
|
||||
@tokens.push(token)
|
||||
@text += token.value
|
||||
|
||||
concat: (otherLine) ->
|
||||
new ScreenLine(@tokens.concat(otherLine.tokens), @text + otherLine.text)
|
||||
|
||||
splitAt: (column) ->
|
||||
return [this] if column == 0 or column >= @text.length
|
||||
|
||||
rightTokens = _.clone(@tokens)
|
||||
leftTokens = []
|
||||
leftTextLength = 0
|
||||
while leftTextLength < column
|
||||
if leftTextLength + rightTokens[0].value.length > column
|
||||
rightTokens[0..0] = @splitTokenAt(rightTokens[0], column - leftTextLength)
|
||||
nextToken = rightTokens.shift()
|
||||
leftTextLength += nextToken.value.length
|
||||
leftTokens.push nextToken
|
||||
|
||||
leftLine = new ScreenLine(leftTokens, @text.substring(0, column))
|
||||
rightLine = new ScreenLine(rightTokens, @text.substring(column))
|
||||
[leftLine, rightLine]
|
||||
|
||||
splitTokenAt: (token, splitIndex) ->
|
||||
{ type, value } = token
|
||||
value1 = value.substring(0, splitIndex)
|
||||
value2 = value.substring(splitIndex)
|
||||
[{value: value1, type }, {value: value2, type}]
|
||||
@@ -1,4 +1,5 @@
|
||||
Cursor = require 'cursor'
|
||||
|
||||
Range = require 'range'
|
||||
{View, $$} = require 'space-pen'
|
||||
|
||||
@@ -61,17 +62,17 @@ class Selection extends View
|
||||
|
||||
getRange: ->
|
||||
if @anchor
|
||||
new Range(@anchor.getPosition(), @cursor.getPosition())
|
||||
new Range(@anchor.getScreenPosition(), @cursor.getScreenPosition())
|
||||
else
|
||||
new Range(@cursor.getPosition(), @cursor.getPosition())
|
||||
new Range(@cursor.getScreenPosition(), @cursor.getScreenPosition())
|
||||
|
||||
setRange: (range) ->
|
||||
@cursor.setPosition(range.start)
|
||||
@cursor.setScreenPosition(range.start)
|
||||
@modifySelection =>
|
||||
@cursor.setPosition(range.end)
|
||||
@cursor.setScreenPosition(range.end)
|
||||
|
||||
getScreenRange: ->
|
||||
@editor.lineWrapper.screenRangeFromBufferRange(@getRange())
|
||||
@editor.lineWrapper.screenRangeForBufferRange(@getRange())
|
||||
|
||||
getText: ->
|
||||
@editor.buffer.getTextInRange @getRange()
|
||||
@@ -97,8 +98,8 @@ class Selection extends View
|
||||
|
||||
placeAnchor: ->
|
||||
return if @anchor
|
||||
cursorPosition = @cursor.getPosition()
|
||||
@anchor = { getPosition: -> cursorPosition }
|
||||
cursorPosition = @cursor.getScreenPosition()
|
||||
@anchor = { getScreenPosition: -> cursorPosition }
|
||||
|
||||
selectWord: ->
|
||||
row = @cursor.getRow()
|
||||
@@ -141,7 +142,7 @@ class Selection extends View
|
||||
|
||||
selectToPosition: (position) ->
|
||||
@modifySelection =>
|
||||
@cursor.setPosition(position)
|
||||
@cursor.setScreenPosition(position)
|
||||
|
||||
moveCursorToLineEnd: ->
|
||||
@cursor.moveToLineEnd()
|
||||
@@ -157,3 +158,6 @@ class Selection extends View
|
||||
return if @isEmpty()
|
||||
text = @editor.buffer.getTextInRange @getRange()
|
||||
atom.native.writeToPasteboard text
|
||||
|
||||
fold: ->
|
||||
@editor.lineFolder.createFold(@getRange())
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
_ = require 'underscore'
|
||||
|
||||
module.exports =
|
||||
class SpanIndex
|
||||
constructor: ->
|
||||
@entries = []
|
||||
|
||||
insert: (index, spans, values) ->
|
||||
@entries[index..index] = @buildIndexEntries(spans, values)
|
||||
|
||||
replace: (index, span, value) ->
|
||||
@splice(index, index, span, [value])
|
||||
|
||||
splice: (start, end, spans, values) ->
|
||||
@entries[start..end] = @buildIndexEntries(spans, values)
|
||||
|
||||
updateSpans: (start, end, span) ->
|
||||
for i in [start..end]
|
||||
@entries[i].span = span
|
||||
|
||||
at: (index) ->
|
||||
@entries[index].value
|
||||
|
||||
last: ->
|
||||
_.last(@entries).value
|
||||
|
||||
clear: ->
|
||||
@entries = []
|
||||
|
||||
lengthBySpan: ->
|
||||
length = 0
|
||||
for entry in @entries
|
||||
length += entry.span
|
||||
length
|
||||
|
||||
sliceBySpan: (start, end) ->
|
||||
currentSpan = 0
|
||||
values = []
|
||||
|
||||
for entry in @entries
|
||||
continue if entry.span is 0
|
||||
nextSpan = currentSpan + entry.span
|
||||
if nextSpan > start
|
||||
startOffset = start - currentSpan if currentSpan <= start
|
||||
if currentSpan <= end
|
||||
values.push entry.value
|
||||
endOffset = end - currentSpan if nextSpan >= end
|
||||
else
|
||||
break
|
||||
currentSpan = nextSpan
|
||||
|
||||
{ values, startOffset, endOffset }
|
||||
|
||||
|
||||
indexForSpan: (targetSpan) ->
|
||||
currentSpan = 0
|
||||
index = 0
|
||||
offset = 0
|
||||
for entry in @entries
|
||||
nextSpan = currentSpan + entry.span
|
||||
if nextSpan > targetSpan
|
||||
offset = targetSpan - currentSpan
|
||||
return { index, offset}
|
||||
currentSpan = nextSpan
|
||||
index++
|
||||
|
||||
spanForIndex: (index) ->
|
||||
span = 0
|
||||
for i in [0..index]
|
||||
span += @entries[i].span
|
||||
span
|
||||
|
||||
buildIndexEntries: (spans, values) ->
|
||||
if _.isArray(spans)
|
||||
_.zip(spans, values).map ([span, value]) -> new SpanIndexEntry(span, value)
|
||||
else
|
||||
values.map (value) -> new SpanIndexEntry(spans, value)
|
||||
|
||||
class SpanIndexEntry
|
||||
constructor: (@span, @value) ->
|
||||
|
||||
@@ -7,27 +7,27 @@ class Motion
|
||||
|
||||
class MoveLeft extends Motion
|
||||
execute: ->
|
||||
{column, row} = @editor.getCursorPosition()
|
||||
{column, row} = @editor.getCursorScreenPosition()
|
||||
@editor.moveCursorLeft() if column > 0
|
||||
|
||||
select: ->
|
||||
position = @editor.getCursorPosition()
|
||||
position = @editor.getCursorScreenPosition()
|
||||
position.column-- if position.column > 0
|
||||
@editor.selectToPosition position
|
||||
|
||||
class MoveRight extends Motion
|
||||
execute: ->
|
||||
{column, row} = @editor.getCursorPosition()
|
||||
{column, row} = @editor.getCursorScreenPosition()
|
||||
@editor.moveCursorRight()
|
||||
|
||||
class MoveUp extends Motion
|
||||
execute: ->
|
||||
{column, row} = @editor.getCursorPosition()
|
||||
{column, row} = @editor.getCursorScreenPosition()
|
||||
@editor.moveCursorUp() if row > 0
|
||||
|
||||
class MoveDown extends Motion
|
||||
execute: ->
|
||||
{column, row} = @editor.getCursorPosition()
|
||||
{column, row} = @editor.getCursorScreenPosition()
|
||||
@editor.moveCursorDown() if row < (@editor.buffer.numLines() - 1)
|
||||
|
||||
class MoveToPreviousWord extends Motion
|
||||
@@ -39,14 +39,14 @@ class MoveToPreviousWord extends Motion
|
||||
|
||||
class MoveToNextWord extends Motion
|
||||
execute: ->
|
||||
@editor.setCursorPosition(@nextWordPosition())
|
||||
@editor.setCursorScreenPosition(@nextWordPosition())
|
||||
|
||||
select: ->
|
||||
@editor.selectToPosition(@nextWordPosition())
|
||||
|
||||
nextWordPosition: ->
|
||||
regex = getWordRegex()
|
||||
{ row, column } = @editor.getCursorPosition()
|
||||
{ row, column } = @editor.getCursorScreenPosition()
|
||||
rightOfCursor = @editor.buffer.getLine(row).substring(column)
|
||||
|
||||
match = regex.exec(rightOfCursor)
|
||||
@@ -64,7 +64,7 @@ class MoveToNextWord extends Motion
|
||||
|
||||
class MoveToNextParagraph extends Motion
|
||||
execute: ->
|
||||
@editor.setCursorPosition(@nextPosition())
|
||||
@editor.setCursorScreenPosition(@nextPosition())
|
||||
|
||||
select: ->
|
||||
@editor.selectToPosition(@nextPosition())
|
||||
|
||||
@@ -44,7 +44,7 @@ class Delete
|
||||
@editor.getSelection().delete()
|
||||
else
|
||||
@editor.buffer.deleteRow(@editor.getCursorRow())
|
||||
@editor.setCursorPosition([@editor.getCursorRow(), 0])
|
||||
@editor.setCursorScreenPosition([@editor.getCursorRow(), 0])
|
||||
|
||||
compose: (motion) ->
|
||||
if not motion.select
|
||||
|
||||
Reference in New Issue
Block a user