pulsar/spec/app/line-map-spec.coffee
Nathan Sobo 3516dea210 Introduce LanguageMode wrapper for Ace modes as a foundation of our own modes
LanguageMode is the central point for all language-specific behavior associated with an EditSession. There is one LanguageMode instance per EditSession. LanguageMode has access to the EditSession and its TokenizedBuffer, and in reverse the EditSession, DisplayBuffer, and TokenizedBuffer also make use of LanguageMode. This is a bit incestuous, but I think it's okay because you can think of LanguageMode as a swappable strategy object that governs language-specific aspects of that constellation of objects.
2012-07-27 12:30:06 -06:00

216 lines
9.6 KiB
CoffeeScript

LineMap = require 'line-map'
ScreenLine = require 'screen-line'
Buffer = require 'buffer'
TokenizedBuffer = require 'tokenized-buffer'
Point = require 'point'
describe "LineMap", ->
[editSession, tokenizedBuffer, map] = []
[line0, line1, line2, line3, line4] = []
beforeEach ->
editSession = fixturesProject.buildEditSessionForPath('sample.js')
{ buffer, tokenizedBuffer } = editSession
map = new LineMap
[line0, line1, line2, line3, line4] = tokenizedBuffer.linesForScreenRows(0, 4)
afterEach ->
editSession.destroy()
describe ".insertAtBufferRow(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])
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
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])
expect(map.lineForScreenRow(0)).toEqual line1
expect(map.lineForScreenRow(1)).toEqual line0a.concat(line0b)
describe ".spliceAtBufferRow(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])
expect(map.lineForScreenRow(0)).toEqual line0
expect(map.lineForScreenRow(1)).toEqual line3
expect(map.lineForScreenRow(2)).toEqual line4
expect(map.lineForScreenRow(3)).toEqual line1
map.spliceAtBufferRow(0, 0, [line2])
expect(map.lineForScreenRow(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])
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
map.spliceAtBufferRow(2, 1, [line0])
expect(map.lineForScreenRow(2)).toEqual line0
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", ->
[line1a, line1b] = line1.splitAt(10)
[line3a, line3b] = line3.splitAt(10)
map.insertAtBufferRow(0, [line0, line1a, line1b, line2])
map.spliceAtBufferRow(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
describe "when the row following the specified buffer row is spanned by multiple line fragments", ->
it "replaces the specified row, but no portion of the following row", ->
[line3a, line3b] = line3.splitAt(10)
map.insertAtBufferRow(0, [line0, line1, line2, line3a, line3b])
map.spliceAtBufferRow(2, 1, [line4])
expect(map.lineForScreenRow(0)).toEqual line0
expect(map.lineForScreenRow(1)).toEqual line1
expect(map.lineForScreenRow(2)).toEqual line4
expect(map.lineForScreenRow(3)).toEqual line3a.concat(line3b)
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])
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
describe ".spliceAtScreenRow(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])
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", ->
it "replaces the spanning line fragment with the given line fragments", ->
map.insertAtBufferRow(0, [line0, line1, line2])
map.spliceAtScreenRow(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
describe "when the specified screen 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])
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
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])
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
describe ".linesForScreenRows(startRow, endRow)", ->
it "returns lines for the given row range, concatenating fragments that belong on a single screen 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]
# repeating assertion to cover a regression where this method mutated lines
expect(map.linesForScreenRows(1, 3)).toEqual [line1, line2, line3]
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)", ->
beforeEach ->
# line1a-line3b describes a fold
[line1a, line1b] = line1.splitAt(10)
[line3a, line3b] = line3.splitAt(20)
line1a.bufferDelta.row = 2
line1a.bufferDelta.column = 20
# line4a-line4b describes a wrapped line
[line4a, line4b] = line4.splitAt(20)
line4a.screenDelta = new Point(1, 0)
map.insertAtBufferRow(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 "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]
describe ".screenLineCount()", ->
it "returns the total of all inserted screen row deltas", ->
[line1a, line1b] = line1.splitAt(10)
[line3a, line3b] = line3.splitAt(10)
line1a.screenDelta = new Point(1, 0)
line3a.screenDelta = new Point(1, 0)
map.insertAtBufferRow(0, [line0, line1a, line1b, line2])
expect(map.screenLineCount()).toBe 4