mirror of
https://github.com/atom/atom.git
synced 2026-01-24 22:38:20 -05:00
Refer to "buffer" and "screen" coordinate spaces as "input" and "output"
Since we compose the line wrapper and the line folder together, the line map is not always translating between screen and buffer coordinate spaces. It's translating one step in the chain, with output closer to the screen and input closer to the buffer.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
LineMap = require 'line-map'
|
||||
ScreenLineFragment = require 'screen-line-fragment'
|
||||
Buffer = require 'buffer'
|
||||
Input = require 'buffer'
|
||||
Highlighter = require 'highlighter'
|
||||
Point = require 'point'
|
||||
|
||||
@@ -9,190 +9,189 @@ describe "LineMap", ->
|
||||
[line0, line1, line2, line3, line4] = []
|
||||
|
||||
beforeEach ->
|
||||
buffer = new Buffer(require.resolve 'fixtures/sample.js')
|
||||
buffer = new Input(require.resolve 'fixtures/sample.js')
|
||||
highlighter = new Highlighter(buffer)
|
||||
map = new LineMap
|
||||
[line0, line1, line2, line3, line4] = highlighter.linesForScreenRows(0, 4)
|
||||
|
||||
describe ".insertAtBufferRow(row, screenLine(s))", ->
|
||||
describe ".insertAtInputRow(row, lineFragments)", ->
|
||||
it "inserts the given line fragments before the specified buffer row", ->
|
||||
map.insertAtBufferRow(0, [line2, line3])
|
||||
map.insertAtBufferRow(0, [line0, line1])
|
||||
map.insertAtBufferRow(4, [line4])
|
||||
map.insertAtInputRow(0, [line2, line3])
|
||||
map.insertAtInputRow(0, [line0, line1])
|
||||
map.insertAtInputRow(4, [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
|
||||
expect(map.lineForOutputRow(0)).toEqual line0
|
||||
expect(map.lineForOutputRow(1)).toEqual line1
|
||||
expect(map.lineForOutputRow(2)).toEqual line2
|
||||
expect(map.lineForOutputRow(3)).toEqual line3
|
||||
expect(map.lineForOutputRow(4)).toEqual line4
|
||||
|
||||
it "allows for partial line fragments on the row following the insertion", ->
|
||||
[line0a, line0b] = line0.splitAt(10)
|
||||
map.insertAtBufferRow(0, [line0a, line0b])
|
||||
map.insertAtBufferRow(0, [line1])
|
||||
map.insertAtInputRow(0, [line0a, line0b])
|
||||
map.insertAtInputRow(0, [line1])
|
||||
|
||||
expect(map.lineForScreenRow(0)).toEqual line1
|
||||
expect(map.lineForScreenRow(1)).toEqual line0a.concat(line0b)
|
||||
expect(map.lineForOutputRow(0)).toEqual line1
|
||||
expect(map.lineForOutputRow(1)).toEqual line0a.concat(line0b)
|
||||
|
||||
|
||||
describe ".spliceAtBufferRow(bufferRow, rowCount, screenLines)", ->
|
||||
describe ".spliceAtInputRow(bufferRow, rowCount, lineFragments)", ->
|
||||
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])
|
||||
map.spliceAtBufferRow(1, 0, [line3, line4])
|
||||
map.insertAtInputRow(0, [line0, line1])
|
||||
map.spliceAtInputRow(1, 0, [line3, line4])
|
||||
|
||||
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.lineForOutputRow(0)).toEqual line0
|
||||
expect(map.lineForOutputRow(1)).toEqual line3
|
||||
expect(map.lineForOutputRow(2)).toEqual line4
|
||||
expect(map.lineForOutputRow(3)).toEqual line1
|
||||
|
||||
map.spliceAtBufferRow(0, 0, [line2])
|
||||
expect(map.lineForScreenRow(0)).toEqual line2
|
||||
map.spliceAtInputRow(0, 0, [line2])
|
||||
expect(map.lineForOutputRow(0)).toEqual line2
|
||||
|
||||
describe "when called with a row count of 1", ->
|
||||
describe "when the specified buffer row is spanned by a single line fragment", ->
|
||||
it "replaces the spanning line fragment with the given line fragments", ->
|
||||
map.insertAtBufferRow(0, [line0, line1, line2])
|
||||
map.spliceAtBufferRow(1, 1, [line3, line4])
|
||||
map.insertAtInputRow(0, [line0, line1, line2])
|
||||
map.spliceAtInputRow(1, 1, [line3, line4])
|
||||
|
||||
expect(map.bufferLineCount()).toBe 4
|
||||
expect(map.lineForScreenRow(0)).toEqual line0
|
||||
expect(map.lineForScreenRow(1)).toEqual line3
|
||||
expect(map.lineForScreenRow(2)).toEqual line4
|
||||
expect(map.lineForScreenRow(3)).toEqual line2
|
||||
expect(map.inputLineCount()).toBe 4
|
||||
expect(map.lineForOutputRow(0)).toEqual line0
|
||||
expect(map.lineForOutputRow(1)).toEqual line3
|
||||
expect(map.lineForOutputRow(2)).toEqual line4
|
||||
expect(map.lineForOutputRow(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", ->
|
||||
[line1a, line1b] = line1.splitAt(10)
|
||||
[line3a, line3b] = line3.splitAt(10)
|
||||
|
||||
map.insertAtBufferRow(0, [line0, line1a, line1b, line2])
|
||||
map.spliceAtBufferRow(1, 1, [line3a, line3b, line4])
|
||||
map.insertAtInputRow(0, [line0, line1a, line1b, line2])
|
||||
map.spliceAtInputRow(1, 1, [line3a, line3b, line4])
|
||||
|
||||
expect(map.bufferLineCount()).toBe 4
|
||||
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
|
||||
expect(map.inputLineCount()).toBe 4
|
||||
expect(map.lineForOutputRow(0)).toEqual line0
|
||||
expect(map.lineForOutputRow(1)).toEqual line3a.concat(line3b)
|
||||
expect(map.lineForOutputRow(2)).toEqual line4
|
||||
expect(map.lineForOutputRow(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", ->
|
||||
[line1a, line1b] = line1.splitAt(10)
|
||||
[line3a, line3b] = line3.splitAt(10)
|
||||
|
||||
map.insertAtBufferRow(0, [line0, line1a, line1b, line2])
|
||||
map.spliceAtBufferRow(1, 2, [line3a, line3b, line4])
|
||||
map.insertAtInputRow(0, [line0, line1a, line1b, line2])
|
||||
map.spliceAtInputRow(1, 2, [line3a, line3b, line4])
|
||||
|
||||
expect(map.bufferLineCount()).toBe 3
|
||||
expect(map.lineForScreenRow(0)).toEqual line0
|
||||
expect(map.lineForScreenRow(1)).toEqual line3a.concat(line3b)
|
||||
expect(map.lineForScreenRow(2)).toEqual line4
|
||||
expect(map.inputLineCount()).toBe 3
|
||||
expect(map.lineForOutputRow(0)).toEqual line0
|
||||
expect(map.lineForOutputRow(1)).toEqual line3a.concat(line3b)
|
||||
expect(map.lineForOutputRow(2)).toEqual line4
|
||||
|
||||
describe ".spliceAtScreenRow(startRow, rowCount, lineFragemnts)", ->
|
||||
describe ".spliceAtOutputRow(startRow, rowCount, lineFragemnts)", ->
|
||||
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.spliceAtScreenRow(1, 0, [line3, line4])
|
||||
map.insertAtInputRow(0, [line0, line1, line2])
|
||||
map.spliceAtOutputRow(1, 0, [line3, line4])
|
||||
|
||||
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
|
||||
expect(map.lineForOutputRow(0)).toEqual line0
|
||||
expect(map.lineForOutputRow(1)).toEqual line3
|
||||
expect(map.lineForOutputRow(2)).toEqual line4
|
||||
expect(map.lineForOutputRow(3)).toEqual line1
|
||||
expect(map.lineForOutputRow(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", ->
|
||||
describe "when the specified output row is spanned by a single line fragment", ->
|
||||
it "replaces the spanning line fragment with the given line fragments", ->
|
||||
map.insertAtBufferRow(0, [line0, line1, line2])
|
||||
map.spliceAtScreenRow(1, 1, [line3, line4])
|
||||
map.insertAtInputRow(0, [line0, line1, line2])
|
||||
map.spliceAtOutputRow(1, 1, [line3, line4])
|
||||
|
||||
expect(map.bufferLineCount()).toBe 4
|
||||
expect(map.lineForScreenRow(0)).toEqual line0
|
||||
expect(map.lineForScreenRow(1)).toEqual line3
|
||||
expect(map.lineForScreenRow(2)).toEqual line4
|
||||
expect(map.lineForScreenRow(3)).toEqual line2
|
||||
expect(map.inputLineCount()).toBe 4
|
||||
expect(map.lineForOutputRow(0)).toEqual line0
|
||||
expect(map.lineForOutputRow(1)).toEqual line3
|
||||
expect(map.lineForOutputRow(2)).toEqual line4
|
||||
expect(map.lineForOutputRow(3)).toEqual line2
|
||||
|
||||
describe "when the specified screen row is spanned by multiple line fragments", ->
|
||||
describe "when the specified output row is spanned by multiple line fragments", ->
|
||||
it "replaces all spanning line fragments with the given line fragments", ->
|
||||
[line0a, line0b] = line0.splitAt(10)
|
||||
[line3a, line3b] = line3.splitAt(10)
|
||||
|
||||
map.insertAtBufferRow(0, [line0a, line0b, line1, line2])
|
||||
map.spliceAtScreenRow(0, 1, [line3a, line3b, line4])
|
||||
map.insertAtInputRow(0, [line0a, line0b, line1, line2])
|
||||
map.spliceAtOutputRow(0, 1, [line3a, line3b, line4])
|
||||
|
||||
expect(map.bufferLineCount()).toBe 4
|
||||
expect(map.lineForScreenRow(0)).toEqual line3a.concat(line3b)
|
||||
expect(map.lineForScreenRow(1)).toEqual line4
|
||||
expect(map.lineForScreenRow(2)).toEqual line1
|
||||
expect(map.lineForScreenRow(3)).toEqual line2
|
||||
expect(map.inputLineCount()).toBe 4
|
||||
expect(map.lineForOutputRow(0)).toEqual line3a.concat(line3b)
|
||||
expect(map.lineForOutputRow(1)).toEqual line4
|
||||
expect(map.lineForOutputRow(2)).toEqual line1
|
||||
expect(map.lineForOutputRow(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", ->
|
||||
[line1a, line1b] = line1.splitAt(10)
|
||||
[line3a, line3b] = line3.splitAt(10)
|
||||
|
||||
map.insertAtBufferRow(0, [line0, line1a, line1b, line2])
|
||||
map.spliceAtScreenRow(1, 2, [line3a, line3b, line4])
|
||||
map.insertAtInputRow(0, [line0, line1a, line1b, line2])
|
||||
map.spliceAtOutputRow(1, 2, [line3a, line3b, line4])
|
||||
|
||||
expect(map.bufferLineCount()).toBe 3
|
||||
expect(map.lineForScreenRow(0)).toEqual line0
|
||||
expect(map.lineForScreenRow(1)).toEqual line3a.concat(line3b)
|
||||
expect(map.lineForScreenRow(2)).toEqual line4
|
||||
expect(map.inputLineCount()).toBe 3
|
||||
expect(map.lineForOutputRow(0)).toEqual line0
|
||||
expect(map.lineForOutputRow(1)).toEqual line3a.concat(line3b)
|
||||
expect(map.lineForOutputRow(2)).toEqual line4
|
||||
|
||||
describe ".linesForScreenRows(startRow, endRow)", ->
|
||||
it "returns lines for the given row range, concatenating fragments that belong on a single screen line", ->
|
||||
describe ".linesForOutputRows(startRow, endRow)", ->
|
||||
it "returns lines for the given row range, concatenating fragments that belong on a single output line", ->
|
||||
[line1a, line1b] = line1.splitAt(11)
|
||||
[line3a, line3b] = line3.splitAt(16)
|
||||
map.insertAtBufferRow(0, [line0, line1a, line1b, line2, line3a, line3b, line4])
|
||||
expect(map.linesForScreenRows(1, 3)).toEqual [line1, line2, line3]
|
||||
map.insertAtInputRow(0, [line0, line1a, line1b, line2, line3a, line3b, line4])
|
||||
expect(map.linesForOutputRows(1, 3)).toEqual [line1, line2, line3]
|
||||
# repeating assertion to cover a regression where this method mutated lines
|
||||
expect(map.linesForScreenRows(1, 3)).toEqual [line1, line2, line3]
|
||||
expect(map.linesForOutputRows(1, 3)).toEqual [line1, line2, line3]
|
||||
|
||||
describe ".lineForBufferRow(bufferRow)", ->
|
||||
it "returns the concatenated screen line fragments that comprise the given buffer row", ->
|
||||
describe ".lineForInputRow(bufferRow)", ->
|
||||
it "returns the concatenated output line fragments that comprise the given buffer row", ->
|
||||
line1Text = line1.text
|
||||
[line1a, line1b] = line1.splitAt(11)
|
||||
line1a.screenDelta = new Point(1, 0)
|
||||
line1a.outputDelta = new Point(1, 0)
|
||||
|
||||
map.insertAtBufferRow(0, [line0, line1a, line1b, line2])
|
||||
map.insertAtInputRow(0, [line0, line1a, line1b, line2])
|
||||
|
||||
expect(map.lineForBufferRow(0).text).toBe line0.text
|
||||
expect(map.lineForBufferRow(1).text).toBe line1Text
|
||||
expect(map.lineForInputRow(0).text).toBe line0.text
|
||||
expect(map.lineForInputRow(1).text).toBe line1Text
|
||||
|
||||
describe ".screenPositionForBufferPosition(bufferPosition)", ->
|
||||
describe ".outputPositionForInputPosition(bufferPosition)", ->
|
||||
beforeEach ->
|
||||
# line1a-line3b describes a fold
|
||||
[line1a, line1b] = line1.splitAt(10)
|
||||
[line3a, line3b] = line3.splitAt(20)
|
||||
line1a.bufferDelta.row = 2
|
||||
line1a.bufferDelta.column = 20
|
||||
line1a.inputDelta.row = 2
|
||||
line1a.inputDelta.column = 20
|
||||
|
||||
# line4a-line4b describes a wrapped line
|
||||
[line4a, line4b] = line4.splitAt(20)
|
||||
line4a.screenDelta = new Point(1, 0)
|
||||
line4a.outputDelta = new Point(1, 0)
|
||||
|
||||
map.insertAtBufferRow(0, [line0, line1a, line3b, line4a, line4b])
|
||||
map.insertAtInputRow(0, [line0, line1a, line3b, line4a, line4b])
|
||||
|
||||
it "translates the given buffer position based on buffer and screen deltas of the line fragments in the map", ->
|
||||
expect(map.screenPositionForBufferPosition([0, 0])).toEqual [0, 0]
|
||||
expect(map.screenPositionForBufferPosition([0, 5])).toEqual [0, 5]
|
||||
expect(map.screenPositionForBufferPosition([1, 5])).toEqual [1, 5]
|
||||
expect(map.screenPositionForBufferPosition([3, 20])).toEqual [1, 10]
|
||||
expect(map.screenPositionForBufferPosition([3, 30])).toEqual [1, 20]
|
||||
expect(map.screenPositionForBufferPosition([4, 5])).toEqual [2, 5]
|
||||
it "translates the given buffer position based on buffer and output deltas of the line fragments in the map", ->
|
||||
expect(map.outputPositionForInputPosition([0, 0])).toEqual [0, 0]
|
||||
expect(map.outputPositionForInputPosition([0, 5])).toEqual [0, 5]
|
||||
expect(map.outputPositionForInputPosition([1, 5])).toEqual [1, 5]
|
||||
expect(map.outputPositionForInputPosition([3, 20])).toEqual [1, 10]
|
||||
expect(map.outputPositionForInputPosition([3, 30])).toEqual [1, 20]
|
||||
expect(map.outputPositionForInputPosition([4, 5])).toEqual [2, 5]
|
||||
|
||||
it "wraps buffer positions at the end of a screen line to the end end of the next screen line", ->
|
||||
expect(map.screenPositionForBufferPosition([4, 20])).toEqual [3, 0]
|
||||
it "wraps buffer positions at the end of a output line to the end end of the next output line", ->
|
||||
expect(map.outputPositionForInputPosition([4, 20])).toEqual [3, 0]
|
||||
|
||||
describe ".screenLineCount()", ->
|
||||
it "returns the total of all inserted screen row deltas", ->
|
||||
describe ".outputLineCount()", ->
|
||||
it "returns the total of all inserted output row deltas", ->
|
||||
[line1a, line1b] = line1.splitAt(10)
|
||||
[line3a, line3b] = line3.splitAt(10)
|
||||
line1a.screenDelta = new Point(1, 0)
|
||||
line3a.screenDelta = new Point(1, 0)
|
||||
line1a.outputDelta = new Point(1, 0)
|
||||
line3a.outputDelta = new Point(1, 0)
|
||||
|
||||
map.insertAtBufferRow(0, [line0, line1a, line1b, line2])
|
||||
|
||||
expect(map.screenLineCount()).toBe 4
|
||||
map.insertAtInputRow(0, [line0, line1a, line1b, line2])
|
||||
|
||||
expect(map.outputLineCount()).toBe 4
|
||||
|
||||
|
||||
@@ -167,8 +167,8 @@ describe "LineWrapper", ->
|
||||
expect(line1.startColumn).toBe 0
|
||||
expect(line1.endColumn).toBe 6
|
||||
expect(line1.text.length).toBe 6
|
||||
expect(line1.screenDelta).toEqual [1, 0]
|
||||
expect(line1.bufferDelta).toEqual [1, 0]
|
||||
expect(line1.outputDelta).toEqual [1, 0]
|
||||
expect(line1.inputDelta).toEqual [1, 0]
|
||||
|
||||
describe "when the buffer line is empty", ->
|
||||
it "returns a single empty screen line", ->
|
||||
@@ -176,8 +176,8 @@ describe "LineWrapper", ->
|
||||
expect(screenLines.length).toBe 1
|
||||
[screenLine] = screenLines
|
||||
expect(screenLine.tokens).toEqual []
|
||||
expect(screenLine.screenDelta).toEqual [1, 0]
|
||||
expect(screenLine.bufferDelta).toEqual [1, 0]
|
||||
expect(screenLine.outputDelta).toEqual [1, 0]
|
||||
expect(screenLine.inputDelta).toEqual [1, 0]
|
||||
|
||||
describe "when there is a non-whitespace character at the max-length boundary", ->
|
||||
describe "when there is whitespace before the max-length boundary", ->
|
||||
@@ -191,14 +191,14 @@ describe "LineWrapper", ->
|
||||
expect(line1.startColumn).toBe 0
|
||||
expect(line1.endColumn).toBe 7
|
||||
expect(line1.text.length).toBe 7
|
||||
expect(line1.screenDelta).toEqual [1, 0]
|
||||
expect(line1.bufferDelta).toEqual [0, 7]
|
||||
expect(line1.outputDelta).toEqual [1, 0]
|
||||
expect(line1.inputDelta).toEqual [0, 7]
|
||||
|
||||
expect(line2.startColumn).toBe 7
|
||||
expect(line2.endColumn).toBe 12
|
||||
expect(line2.text.length).toBe 5
|
||||
expect(line2.screenDelta).toEqual [1, 0]
|
||||
expect(line2.bufferDelta).toEqual [1, 0]
|
||||
expect(line2.outputDelta).toEqual [1, 0]
|
||||
expect(line2.inputDelta).toEqual [1, 0]
|
||||
|
||||
describe "when there is no whitespace before the max-length boundary", ->
|
||||
it "splits the line at the boundary, because there's no 'good' place to split it", ->
|
||||
|
||||
@@ -31,18 +31,18 @@ describe "screenLineFragment", ->
|
||||
|
||||
it "ensures the returned fragments cover the span of the original line", ->
|
||||
[left, right] = screenLine.splitAt(15)
|
||||
expect(left.bufferDelta).toEqual [0, 15]
|
||||
expect(left.screenDelta).toEqual [0, 15]
|
||||
expect(left.inputDelta).toEqual [0, 15]
|
||||
expect(left.outputDelta).toEqual [0, 15]
|
||||
|
||||
expect(right.bufferDelta).toEqual [1, 0]
|
||||
expect(right.screenDelta).toEqual [1, 0]
|
||||
expect(right.inputDelta).toEqual [1, 0]
|
||||
expect(right.outputDelta).toEqual [1, 0]
|
||||
|
||||
[left2, right2] = left.splitAt(5)
|
||||
expect(left2.bufferDelta).toEqual [0, 5]
|
||||
expect(left2.screenDelta).toEqual [0, 5]
|
||||
expect(left2.inputDelta).toEqual [0, 5]
|
||||
expect(left2.outputDelta).toEqual [0, 5]
|
||||
|
||||
expect(right2.bufferDelta).toEqual [0, 10]
|
||||
expect(right2.screenDelta).toEqual [0, 10]
|
||||
expect(right2.inputDelta).toEqual [0, 10]
|
||||
expect(right2.outputDelta).toEqual [0, 10]
|
||||
|
||||
describe "if splitting at 0", ->
|
||||
it "returns undefined for the left half", ->
|
||||
@@ -53,12 +53,12 @@ describe "screenLineFragment", ->
|
||||
[left, right] = screenLine.splitAt(screenLine.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(left.outputDelta).toEqual [0, screenLine.text.length]
|
||||
expect(left.inputDelta).toEqual [0, screenLine.text.length]
|
||||
|
||||
expect(right.text).toBe ''
|
||||
expect(right.screenDelta).toEqual [1, 0]
|
||||
expect(right.bufferDelta).toEqual [1, 0]
|
||||
expect(right.outputDelta).toEqual [1, 0]
|
||||
expect(right.inputDelta).toEqual [1, 0]
|
||||
|
||||
describe ".concat(otherFragment)", ->
|
||||
it "returns the concatenation of the receiver and the given fragment", ->
|
||||
@@ -68,8 +68,8 @@ describe "screenLineFragment", ->
|
||||
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]
|
||||
expect(concatenated.bufferDelta).toEqual [2, 0]
|
||||
expect(concatenated.outputDelta).toEqual [2, 0]
|
||||
expect(concatenated.inputDelta).toEqual [2, 0]
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ class LineFolder
|
||||
|
||||
buildLineMap: ->
|
||||
@lineMap = new LineMap
|
||||
@lineMap.insertAtBufferRow(0, @highlighter.screenLines)
|
||||
@lineMap.insertAtInputRow(0, @highlighter.screenLines)
|
||||
|
||||
logLines: (start=0, end=@lastRow())->
|
||||
@lineMap.logLines(start, end)
|
||||
@@ -32,7 +32,7 @@ class LineFolder
|
||||
oldScreenRange = @expandScreenRangeToLineEnds(@screenRangeForBufferRange(bufferRange))
|
||||
|
||||
lineWithFold = @buildLineForBufferRow(bufferRange.start.row)
|
||||
@lineMap.replaceScreenRows(oldScreenRange.start.row, oldScreenRange.end.row, lineWithFold)
|
||||
@lineMap.replaceOutputRows(oldScreenRange.start.row, oldScreenRange.end.row, lineWithFold)
|
||||
|
||||
newScreenRange = oldScreenRange.copy()
|
||||
newScreenRange.end = _.clone(newScreenRange.start)
|
||||
@@ -51,9 +51,9 @@ class LineFolder
|
||||
oldScreenRange = new Range()
|
||||
oldScreenRange.start.row = startScreenRow
|
||||
oldScreenRange.end.row = startScreenRow
|
||||
oldScreenRange.end.column = @lineMap.lineForScreenRow(startScreenRow).text.length
|
||||
oldScreenRange.end.column = @lineMap.lineForOutputRow(startScreenRow).text.length
|
||||
|
||||
@lineMap.replaceScreenRow(startScreenRow, @buildLinesForBufferRows(bufferRange.start.row, bufferRange.end.row))
|
||||
@lineMap.replaceOutputRow(startScreenRow, @buildLinesForBufferRows(bufferRange.start.row, bufferRange.end.row))
|
||||
|
||||
newScreenRange = @expandScreenRangeToLineEnds(@screenRangeForBufferRange(bufferRange))
|
||||
|
||||
@@ -79,7 +79,7 @@ class LineFolder
|
||||
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)
|
||||
@lineMap.replaceOutputRows(oldScreenRange.start.row, oldScreenRange.end.row, lines)
|
||||
newScreenRange = @screenRangeForBufferRange(e.newRange)
|
||||
expandedNewScreenRange = @expandScreenRangeToLineEnds(newScreenRange)
|
||||
|
||||
@@ -118,16 +118,16 @@ class LineFolder
|
||||
folds.sort (a, b) -> a.compare(b)
|
||||
|
||||
linesForScreenRows: (startRow, endRow) ->
|
||||
@lineMap.linesForScreenRows(startRow, endRow)
|
||||
@lineMap.linesForOutputRows(startRow, endRow)
|
||||
|
||||
lineForScreenRow: (screenRow) ->
|
||||
@lineMap.lineForScreenRow(screenRow)
|
||||
@lineMap.lineForOutputRow(screenRow)
|
||||
|
||||
getLines: ->
|
||||
@lineMap.screenLinesForRows(0, @lastRow())
|
||||
@lineMap.linesForOutputRows(0, @lastRow())
|
||||
|
||||
lineCount: ->
|
||||
@lineMap.screenLineCount()
|
||||
@lineMap.outputLineCount()
|
||||
|
||||
lastRow: ->
|
||||
@lineCount() - 1
|
||||
@@ -139,23 +139,23 @@ class LineFolder
|
||||
@bufferPositionForScreenPosition([screenRow, 0]).row
|
||||
|
||||
screenPositionForBufferPosition: (bufferPosition) ->
|
||||
@lineMap.screenPositionForBufferPosition(bufferPosition)
|
||||
@lineMap.outputPositionForInputPosition(bufferPosition)
|
||||
|
||||
bufferPositionForScreenPosition: (screenPosition) ->
|
||||
@lineMap.bufferPositionForScreenPosition(screenPosition)
|
||||
@lineMap.inputPositionForOutputPosition(screenPosition)
|
||||
|
||||
clipScreenPosition: (screenPosition, options={}) ->
|
||||
@lineMap.clipScreenPosition(screenPosition, options)
|
||||
@lineMap.clipOutputPosition(screenPosition, options)
|
||||
|
||||
screenRangeForBufferRange: (bufferRange) ->
|
||||
@lineMap.screenRangeForBufferRange(bufferRange)
|
||||
@lineMap.outputRangeForInputRange(bufferRange)
|
||||
|
||||
bufferRangeForScreenRange: (screenRange) ->
|
||||
@lineMap.bufferRangeForScreenRange(screenRange)
|
||||
@lineMap.inputRangeForOutputRange(screenRange)
|
||||
|
||||
expandScreenRangeToLineEnds: (screenRange) ->
|
||||
{ start, end } = screenRange
|
||||
new Range([start.row, 0], [end.row, @lineMap.lineForScreenRow(end.row).text.length])
|
||||
new Range([start.row, 0], [end.row, @lineMap.lineForOutputRow(end.row).text.length])
|
||||
|
||||
_.extend LineFolder.prototype, EventEmitter
|
||||
|
||||
|
||||
@@ -7,66 +7,66 @@ class LineMap
|
||||
constructor: ->
|
||||
@lineFragments = []
|
||||
|
||||
insertAtBufferRow: (bufferRow, lineFragments) ->
|
||||
@spliceAtBufferRow(bufferRow, 0, lineFragments)
|
||||
insertAtInputRow: (inputRow, lineFragments) ->
|
||||
@spliceAtInputRow(inputRow, 0, lineFragments)
|
||||
|
||||
spliceAtBufferRow: (startRow, rowCount, lineFragments) ->
|
||||
@spliceByDelta('bufferDelta', startRow, rowCount, lineFragments)
|
||||
spliceAtInputRow: (startRow, rowCount, lineFragments) ->
|
||||
@spliceByDelta('inputDelta', startRow, rowCount, lineFragments)
|
||||
|
||||
spliceAtScreenRow: (startRow, rowCount, lineFragments) ->
|
||||
@spliceByDelta('screenDelta', startRow, rowCount, lineFragments)
|
||||
spliceAtOutputRow: (startRow, rowCount, lineFragments) ->
|
||||
@spliceByDelta('outputDelta', startRow, rowCount, lineFragments)
|
||||
|
||||
replaceBufferRows: (start, end, lineFragments) ->
|
||||
@spliceAtBufferRow(start, end - start + 1, lineFragments)
|
||||
replaceInputRows: (start, end, lineFragments) ->
|
||||
@spliceAtInputRow(start, end - start + 1, lineFragments)
|
||||
|
||||
replaceScreenRow: (row, lineFragments) ->
|
||||
@replaceScreenRows(row, row, lineFragments)
|
||||
replaceOutputRow: (row, lineFragments) ->
|
||||
@replaceOutputRows(row, row, lineFragments)
|
||||
|
||||
replaceScreenRows: (start, end, lineFragments) ->
|
||||
@spliceAtScreenRow(start, end - start + 1, lineFragments)
|
||||
replaceOutputRows: (start, end, lineFragments) ->
|
||||
@spliceAtOutputRow(start, end - start + 1, lineFragments)
|
||||
|
||||
lineForScreenRow: (row) ->
|
||||
@linesForScreenRows(row, row)[0]
|
||||
lineForOutputRow: (row) ->
|
||||
@linesForOutputRows(row, row)[0]
|
||||
|
||||
linesForScreenRows: (startRow, endRow) ->
|
||||
@linesByDelta('screenDelta', startRow, endRow)
|
||||
linesForOutputRows: (startRow, endRow) ->
|
||||
@linesByDelta('outputDelta', startRow, endRow)
|
||||
|
||||
lineForBufferRow: (row) ->
|
||||
@linesForBufferRows(row, row)[0]
|
||||
lineForInputRow: (row) ->
|
||||
@linesForInputRows(row, row)[0]
|
||||
|
||||
linesForBufferRows: (startRow, endRow) ->
|
||||
@linesByDelta('bufferDelta', startRow, endRow)
|
||||
linesForInputRows: (startRow, endRow) ->
|
||||
@linesByDelta('inputDelta', startRow, endRow)
|
||||
|
||||
bufferLineCount: ->
|
||||
@lineCountByDelta('bufferDelta')
|
||||
inputLineCount: ->
|
||||
@lineCountByDelta('inputDelta')
|
||||
|
||||
screenLineCount: ->
|
||||
@lineCountByDelta('screenDelta')
|
||||
outputLineCount: ->
|
||||
@lineCountByDelta('outputDelta')
|
||||
|
||||
lineCountByDelta: (deltaType) ->
|
||||
@traverseByDelta(deltaType, new Point(Infinity, 0))[deltaType].row
|
||||
|
||||
lastScreenRow: ->
|
||||
@screenLineCount() - 1
|
||||
lastOutputRow: ->
|
||||
@outputLineCount() - 1
|
||||
|
||||
screenPositionForBufferPosition: (bufferPosition) ->
|
||||
@translatePosition('bufferDelta', 'screenDelta', bufferPosition)
|
||||
outputPositionForInputPosition: (inputPosition) ->
|
||||
@translatePosition('inputDelta', 'outputDelta', inputPosition)
|
||||
|
||||
bufferPositionForScreenPosition: (screenPosition) ->
|
||||
@translatePosition('screenDelta', 'bufferDelta', screenPosition)
|
||||
inputPositionForOutputPosition: (outputPosition) ->
|
||||
@translatePosition('outputDelta', 'inputDelta', outputPosition)
|
||||
|
||||
screenRangeForBufferRange: (bufferRange) ->
|
||||
start = @screenPositionForBufferPosition(bufferRange.start)
|
||||
end = @screenPositionForBufferPosition(bufferRange.end)
|
||||
outputRangeForInputRange: (inputRange) ->
|
||||
start = @outputPositionForInputPosition(inputRange.start)
|
||||
end = @outputPositionForInputPosition(inputRange.end)
|
||||
new Range(start, end)
|
||||
|
||||
bufferRangeForScreenRange: (screenRange) ->
|
||||
start = @bufferPositionForScreenPosition(screenRange.start)
|
||||
end = @bufferPositionForScreenPosition(screenRange.end)
|
||||
inputRangeForOutputRange: (outputRange) ->
|
||||
start = @inputPositionForOutputPosition(outputRange.start)
|
||||
end = @inputPositionForOutputPosition(outputRange.end)
|
||||
new Range(start, end)
|
||||
|
||||
clipScreenPosition: (screenPosition, options) ->
|
||||
@translatePosition('screenDelta', 'screenDelta', screenPosition, options)
|
||||
clipOutputPosition: (outputPosition, options) ->
|
||||
@translatePosition('outputDelta', 'outputDelta', outputPosition, options)
|
||||
|
||||
spliceByDelta: (deltaType, startRow, rowCount, lineFragments) ->
|
||||
stopRow = startRow + rowCount
|
||||
@@ -93,7 +93,7 @@ class LineMap
|
||||
else
|
||||
pendingFragment = _.clone(lineFragment)
|
||||
if pendingFragment[deltaType].row > 0
|
||||
pendingFragment.bufferDelta = new Point(1, 0)
|
||||
pendingFragment.inputDelta = new Point(1, 0)
|
||||
lines.push pendingFragment
|
||||
pendingFragment = null
|
||||
lines
|
||||
@@ -145,20 +145,20 @@ class LineMap
|
||||
|
||||
traverseByDelta: (deltaType, startPosition, endPosition=startPosition, iterator=null) ->
|
||||
traversalDelta = new Point
|
||||
screenDelta = new Point
|
||||
bufferDelta = new Point
|
||||
outputDelta = new Point
|
||||
inputDelta = new Point
|
||||
|
||||
for lineFragment in @lineFragments
|
||||
iterator(lineFragment) if traversalDelta.isGreaterThanOrEqual(startPosition) and iterator?
|
||||
traversalDelta = traversalDelta.add(lineFragment[deltaType])
|
||||
break if traversalDelta.isGreaterThan(endPosition)
|
||||
screenDelta = screenDelta.add(lineFragment.screenDelta)
|
||||
bufferDelta = bufferDelta.add(lineFragment.bufferDelta)
|
||||
outputDelta = outputDelta.add(lineFragment.outputDelta)
|
||||
inputDelta = inputDelta.add(lineFragment.inputDelta)
|
||||
|
||||
{ screenDelta, bufferDelta, lastLineFragment: lineFragment }
|
||||
{ outputDelta, inputDelta, lastLineFragment: lineFragment }
|
||||
|
||||
logLines: (start=0, end=@screenLineCount() - 1)->
|
||||
logLines: (start=0, end=@outputLineCount() - 1)->
|
||||
for row in [start..end]
|
||||
line = @lineForScreenRow(row).text
|
||||
line = @lineForOutputRow(row).text
|
||||
console.log row, line, line.length
|
||||
|
||||
|
||||
@@ -18,26 +18,26 @@ class LineWrapper
|
||||
|
||||
buildLineMap: ->
|
||||
@lineMap = new LineMap
|
||||
@lineMap.insertAtBufferRow 0, @buildScreenLinesForBufferRows(0, @lineFolder.lastRow())
|
||||
@lineMap.insertAtInputRow 0, @buildScreenLinesForBufferRows(0, @lineFolder.lastRow())
|
||||
|
||||
handleChange: (e) ->
|
||||
oldBufferRange = e.oldRange
|
||||
newBufferRange = e.newRange
|
||||
|
||||
oldScreenRange = @lineMap.screenRangeForBufferRange(@expandBufferRangeToLineEnds(oldBufferRange))
|
||||
oldScreenRange = @lineMap.outputRangeForInputRange(@expandBufferRangeToLineEnds(oldBufferRange))
|
||||
newScreenLines = @buildScreenLinesForBufferRows(newBufferRange.start.row, newBufferRange.end.row)
|
||||
@lineMap.replaceBufferRows oldBufferRange.start.row, oldBufferRange.end.row, newScreenLines
|
||||
newScreenRange = @lineMap.screenRangeForBufferRange(@expandBufferRangeToLineEnds(newBufferRange))
|
||||
@lineMap.replaceInputRows oldBufferRange.start.row, oldBufferRange.end.row, newScreenLines
|
||||
newScreenRange = @lineMap.outputRangeForInputRange(@expandBufferRangeToLineEnds(newBufferRange))
|
||||
|
||||
@trigger 'change', { oldRange: oldScreenRange, newRange: newScreenRange }
|
||||
|
||||
expandBufferRangeToLineEnds: (bufferRange) ->
|
||||
{ start, end } = bufferRange
|
||||
new Range([start.row, 0], [end.row, @lineMap.lineForBufferRow(end.row).text.length])
|
||||
new Range([start.row, 0], [end.row, @lineMap.lineForInputRow(end.row).text.length])
|
||||
|
||||
rangeForAllLines: ->
|
||||
endRow = @lineCount() - 1
|
||||
endColumn = @lineMap.lineForScreenRow(endRow).text.length
|
||||
endColumn = @lineMap.lineForOutputRow(endRow).text.length
|
||||
new Range([0, 0], [endRow, endColumn])
|
||||
|
||||
buildScreenLinesForBufferRows: (start, end) ->
|
||||
@@ -54,7 +54,7 @@ class LineWrapper
|
||||
endColumn = startColumn + screenLine.text.length
|
||||
else
|
||||
[leftHalf, rightHalf] = screenLine.splitAt(splitColumn)
|
||||
leftHalf.screenDelta = new Point(1, 0)
|
||||
leftHalf.outputDelta = new Point(1, 0)
|
||||
screenLines.push leftHalf
|
||||
endColumn = startColumn + leftHalf.text.length
|
||||
screenLines.push @wrapScreenLine(rightHalf, endColumn)...
|
||||
@@ -77,25 +77,25 @@ class LineWrapper
|
||||
return @maxLength
|
||||
|
||||
screenPositionForBufferPosition: (bufferPosition) ->
|
||||
@lineMap.screenPositionForBufferPosition(
|
||||
@lineMap.outputPositionForInputPosition(
|
||||
@lineFolder.screenPositionForBufferPosition(bufferPosition))
|
||||
|
||||
bufferPositionForScreenPosition: (screenPosition) ->
|
||||
@lineFolder.bufferPositionForScreenPosition(
|
||||
@lineMap.bufferPositionForScreenPosition(screenPosition))
|
||||
@lineMap.inputPositionForOutputPosition(screenPosition))
|
||||
|
||||
screenRangeForBufferRange: (bufferRange) ->
|
||||
@lineMap.screenRangeForBufferRange(
|
||||
@lineMap.outputRangeForInputRange(
|
||||
@lineFolder.screenRangeForBufferRange(bufferRange))
|
||||
|
||||
bufferRangeForScreenRange: (screenRange) ->
|
||||
@lineFolder.bufferRangeForScreenRange(
|
||||
@lineMap.bufferRangeForScreenRange(screenRange))
|
||||
@lineMap.inputRangeForOutputRange(screenRange))
|
||||
|
||||
clipScreenPosition: (screenPosition, options={}) ->
|
||||
@lineMap.screenPositionForBufferPosition(
|
||||
@lineMap.outputPositionForInputPosition(
|
||||
@lineFolder.clipScreenPosition(
|
||||
@lineMap.bufferPositionForScreenPosition(@lineMap.clipScreenPosition(screenPosition, options)),
|
||||
@lineMap.inputPositionForOutputPosition(@lineMap.clipOutputPosition(screenPosition, options)),
|
||||
options
|
||||
)
|
||||
)
|
||||
@@ -104,13 +104,13 @@ class LineWrapper
|
||||
@linesForScreenRows(screenRow, screenRow)[0]
|
||||
|
||||
linesForScreenRows: (startRow, endRow) ->
|
||||
@lineMap.linesForScreenRows(startRow, endRow)
|
||||
@lineMap.linesForOutputRows(startRow, endRow)
|
||||
|
||||
getLines: ->
|
||||
@linesForScreenRows(0, @lastRow())
|
||||
|
||||
lineCount: ->
|
||||
@lineMap.screenLineCount()
|
||||
@lineMap.outputLineCount()
|
||||
|
||||
lastRow: ->
|
||||
@lineCount() - 1
|
||||
|
||||
@@ -5,9 +5,9 @@ module.exports =
|
||||
class ScreenLineFragment
|
||||
isAtomic: false
|
||||
|
||||
constructor: (@tokens, @text, screenDelta, bufferDelta, extraFields) ->
|
||||
@screenDelta = Point.fromObject(screenDelta)
|
||||
@bufferDelta = Point.fromObject(bufferDelta)
|
||||
constructor: (@tokens, @text, outputDelta, inputDelta, extraFields) ->
|
||||
@outputDelta = Point.fromObject(outputDelta)
|
||||
@inputDelta = Point.fromObject(inputDelta)
|
||||
_.extend(this, extraFields)
|
||||
|
||||
splitAt: (column) ->
|
||||
@@ -26,8 +26,8 @@ class ScreenLineFragment
|
||||
leftText = @text.substring(0, column)
|
||||
rightText = @text.substring(column)
|
||||
|
||||
[leftScreenDelta, rightScreenDelta] = @screenDelta.splitAt(column)
|
||||
[leftBufferDelta, rightBufferDelta] = @bufferDelta.splitAt(column)
|
||||
[leftScreenDelta, rightScreenDelta] = @outputDelta.splitAt(column)
|
||||
[leftBufferDelta, rightBufferDelta] = @inputDelta.splitAt(column)
|
||||
|
||||
leftFragment = new ScreenLineFragment(leftTokens, leftText, leftScreenDelta, leftBufferDelta)
|
||||
rightFragment = new ScreenLineFragment(rightTokens, rightText, rightScreenDelta, rightBufferDelta)
|
||||
@@ -42,9 +42,9 @@ class ScreenLineFragment
|
||||
concat: (other) ->
|
||||
tokens = @tokens.concat(other.tokens)
|
||||
text = @text + other.text
|
||||
screenDelta = @screenDelta.add(other.screenDelta)
|
||||
bufferDelta = @bufferDelta.add(other.bufferDelta)
|
||||
new ScreenLineFragment(tokens, text, screenDelta, bufferDelta)
|
||||
outputDelta = @outputDelta.add(other.outputDelta)
|
||||
inputDelta = @inputDelta.add(other.inputDelta)
|
||||
new ScreenLineFragment(tokens, text, outputDelta, inputDelta)
|
||||
|
||||
lengthForClipping: ->
|
||||
if @isAtomic
|
||||
@@ -53,7 +53,7 @@ class ScreenLineFragment
|
||||
@text.length
|
||||
|
||||
isSoftWrapped: ->
|
||||
@screenDelta.row == 1 and @bufferDelta.row == 0
|
||||
@outputDelta.row == 1 and @inputDelta.row == 0
|
||||
|
||||
isEqual: (other) ->
|
||||
_.isEqual(@tokens, other.tokens) and @screenDelta.isEqual(other.screenDelta) and @bufferDelta.isEqual(other.bufferDelta)
|
||||
_.isEqual(@tokens, other.tokens) and @outputDelta.isEqual(other.outputDelta) and @inputDelta.isEqual(other.inputDelta)
|
||||
|
||||
Reference in New Issue
Block a user