mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-11-13 08:44:12 +03:00
3516dea210
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.
216 lines
9.6 KiB
CoffeeScript
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
|
|
|