mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-11-10 18:24:09 +03:00
0192c57f46
Fixes #688 The DisplayBuffer applies buffer and screen deltas to the row map as rows are inserted/removed from the buffer/screen. This can leave some of the regions in a weird state, such as mapping multiple screen rows to zero buffer rows. But next the DisplayBuffer applies any new mappings based on the replaced lines over the top of existing regions. These weirdly shaped regions should be overwritten by newly inserted regions, so at the end of the operation the row map makes sense again. This fixes a corner case where regions spanning 0 buffer rows at the very beginning of the row range were not being included in the set of regions to replace. This was in turn causing the RowMap to get into a bad state in certain situations involving soft-wrapped lines.
262 lines
12 KiB
CoffeeScript
262 lines
12 KiB
CoffeeScript
RowMap = require 'row-map'
|
|
|
|
describe "RowMap", ->
|
|
map = null
|
|
|
|
beforeEach ->
|
|
map = new RowMap
|
|
|
|
describe "when no mappings have been recorded", ->
|
|
it "maps buffer rows to screen rows 1:1", ->
|
|
expect(map.screenRowRangeForBufferRow(0)).toEqual [0, 1]
|
|
expect(map.screenRowRangeForBufferRow(100)).toEqual [100, 101]
|
|
|
|
describe ".mapBufferRowRange(startBufferRow, endBufferRow, screenRows)", ->
|
|
describe "when mapping to a single screen row (like a visible fold)", ->
|
|
beforeEach ->
|
|
map.mapBufferRowRange(5, 10, 1)
|
|
map.mapBufferRowRange(15, 20, 1)
|
|
map.mapBufferRowRange(25, 30, 1)
|
|
|
|
it "accounts for the mapping when translating buffer rows to screen row ranges", ->
|
|
expect(map.screenRowRangeForBufferRow(0)).toEqual [0, 1]
|
|
|
|
expect(map.screenRowRangeForBufferRow(4)).toEqual [4, 5]
|
|
expect(map.screenRowRangeForBufferRow(5)).toEqual [5, 6]
|
|
expect(map.screenRowRangeForBufferRow(9)).toEqual [5, 6]
|
|
expect(map.screenRowRangeForBufferRow(10)).toEqual [6, 7]
|
|
|
|
expect(map.screenRowRangeForBufferRow(14)).toEqual [10, 11]
|
|
expect(map.screenRowRangeForBufferRow(15)).toEqual [11, 12]
|
|
expect(map.screenRowRangeForBufferRow(19)).toEqual [11, 12]
|
|
expect(map.screenRowRangeForBufferRow(20)).toEqual [12, 13]
|
|
|
|
expect(map.screenRowRangeForBufferRow(24)).toEqual [16, 17]
|
|
expect(map.screenRowRangeForBufferRow(25)).toEqual [17, 18]
|
|
expect(map.screenRowRangeForBufferRow(29)).toEqual [17, 18]
|
|
expect(map.screenRowRangeForBufferRow(30)).toEqual [18, 19]
|
|
|
|
it "accounts for the mapping when translating screen rows to buffer row ranges", ->
|
|
expect(map.bufferRowRangeForScreenRow(0)).toEqual [0, 1]
|
|
|
|
expect(map.bufferRowRangeForScreenRow(4)).toEqual [4, 5]
|
|
expect(map.bufferRowRangeForScreenRow(5)).toEqual [5, 10]
|
|
expect(map.bufferRowRangeForScreenRow(6)).toEqual [10, 11]
|
|
|
|
expect(map.bufferRowRangeForScreenRow(10)).toEqual [14, 15]
|
|
expect(map.bufferRowRangeForScreenRow(11)).toEqual [15, 20]
|
|
expect(map.bufferRowRangeForScreenRow(12)).toEqual [20, 21]
|
|
|
|
expect(map.bufferRowRangeForScreenRow(16)).toEqual [24, 25]
|
|
expect(map.bufferRowRangeForScreenRow(17)).toEqual [25, 30]
|
|
expect(map.bufferRowRangeForScreenRow(18)).toEqual [30, 31]
|
|
|
|
describe "when mapping to zero screen rows (like an invisible fold)", ->
|
|
beforeEach ->
|
|
map.mapBufferRowRange(5, 10, 0)
|
|
map.mapBufferRowRange(15, 20, 0)
|
|
map.mapBufferRowRange(25, 30, 0)
|
|
|
|
it "accounts for the mapping when translating buffer rows to screen row ranges", ->
|
|
expect(map.screenRowRangeForBufferRow(0)).toEqual [0, 1]
|
|
|
|
expect(map.screenRowRangeForBufferRow(4)).toEqual [4, 5]
|
|
expect(map.screenRowRangeForBufferRow(5)).toEqual [5, 5]
|
|
expect(map.screenRowRangeForBufferRow(9)).toEqual [5, 5]
|
|
expect(map.screenRowRangeForBufferRow(10)).toEqual [5, 6]
|
|
|
|
expect(map.screenRowRangeForBufferRow(14)).toEqual [9, 10]
|
|
expect(map.screenRowRangeForBufferRow(15)).toEqual [10, 10]
|
|
expect(map.screenRowRangeForBufferRow(19)).toEqual [10, 10]
|
|
expect(map.screenRowRangeForBufferRow(20)).toEqual [10, 11]
|
|
|
|
expect(map.screenRowRangeForBufferRow(24)).toEqual [14, 15]
|
|
expect(map.screenRowRangeForBufferRow(25)).toEqual [15, 15]
|
|
expect(map.screenRowRangeForBufferRow(29)).toEqual [15, 15]
|
|
expect(map.screenRowRangeForBufferRow(30)).toEqual [15, 16]
|
|
|
|
it "accounts for the mapping when translating screen rows to buffer row ranges", ->
|
|
expect(map.bufferRowRangeForScreenRow(0)).toEqual [0, 1]
|
|
|
|
expect(map.bufferRowRangeForScreenRow(4)).toEqual [4, 5]
|
|
expect(map.bufferRowRangeForScreenRow(5)).toEqual [10, 11]
|
|
|
|
expect(map.bufferRowRangeForScreenRow(9)).toEqual [14, 15]
|
|
expect(map.bufferRowRangeForScreenRow(10)).toEqual [20, 21]
|
|
|
|
expect(map.bufferRowRangeForScreenRow(14)).toEqual [24, 25]
|
|
expect(map.bufferRowRangeForScreenRow(15)).toEqual [30, 31]
|
|
|
|
describe "when mapping a single buffer row to multiple screen rows (like a wrapped line)", ->
|
|
beforeEach ->
|
|
map.mapBufferRowRange(5, 6, 3)
|
|
map.mapBufferRowRange(10, 11, 2)
|
|
map.mapBufferRowRange(20, 21, 5)
|
|
|
|
it "accounts for the mapping when translating buffer rows to screen row ranges", ->
|
|
expect(map.screenRowRangeForBufferRow(0)).toEqual [0, 1]
|
|
|
|
expect(map.screenRowRangeForBufferRow(4)).toEqual [4, 5]
|
|
expect(map.screenRowRangeForBufferRow(5)).toEqual [5, 8]
|
|
expect(map.screenRowRangeForBufferRow(6)).toEqual [8, 9]
|
|
|
|
expect(map.screenRowRangeForBufferRow(9)).toEqual [11, 12]
|
|
expect(map.screenRowRangeForBufferRow(10)).toEqual [12, 14]
|
|
expect(map.screenRowRangeForBufferRow(11)).toEqual [14, 15]
|
|
|
|
expect(map.screenRowRangeForBufferRow(19)).toEqual [22, 23]
|
|
expect(map.screenRowRangeForBufferRow(20)).toEqual [23, 28]
|
|
expect(map.screenRowRangeForBufferRow(21)).toEqual [28, 29]
|
|
|
|
it "accounts for the mapping when translating screen rows to buffer row ranges", ->
|
|
expect(map.bufferRowRangeForScreenRow(0)).toEqual [0, 1]
|
|
|
|
expect(map.bufferRowRangeForScreenRow(4)).toEqual [4, 5]
|
|
expect(map.bufferRowRangeForScreenRow(5)).toEqual [5, 6]
|
|
expect(map.bufferRowRangeForScreenRow(7)).toEqual [5, 6]
|
|
expect(map.bufferRowRangeForScreenRow(8)).toEqual [6, 7]
|
|
|
|
expect(map.bufferRowRangeForScreenRow(11)).toEqual [9, 10]
|
|
expect(map.bufferRowRangeForScreenRow(12)).toEqual [10, 11]
|
|
expect(map.bufferRowRangeForScreenRow(13)).toEqual [10, 11]
|
|
expect(map.bufferRowRangeForScreenRow(14)).toEqual [11, 12]
|
|
|
|
expect(map.bufferRowRangeForScreenRow(22)).toEqual [19, 20]
|
|
expect(map.bufferRowRangeForScreenRow(23)).toEqual [20, 21]
|
|
expect(map.bufferRowRangeForScreenRow(27)).toEqual [20, 21]
|
|
expect(map.bufferRowRangeForScreenRow(28)).toEqual [21, 22]
|
|
|
|
describe "after re-mapping a row range to a new number of screen rows", ->
|
|
beforeEach ->
|
|
map.applyScreenDelta(12, 2) # simulate adding 2 more soft wraps
|
|
map.mapBufferRowRange(10, 11, 4)
|
|
|
|
it "updates translation accordingly", ->
|
|
expect(map.screenRowRangeForBufferRow(4)).toEqual [4, 5]
|
|
expect(map.screenRowRangeForBufferRow(5)).toEqual [5, 8]
|
|
expect(map.screenRowRangeForBufferRow(6)).toEqual [8, 9]
|
|
|
|
expect(map.screenRowRangeForBufferRow(9)).toEqual [11, 12]
|
|
expect(map.screenRowRangeForBufferRow(10)).toEqual [12, 16]
|
|
expect(map.screenRowRangeForBufferRow(11)).toEqual [16, 17]
|
|
|
|
expect(map.screenRowRangeForBufferRow(19)).toEqual [24, 25]
|
|
expect(map.screenRowRangeForBufferRow(20)).toEqual [25, 30]
|
|
expect(map.screenRowRangeForBufferRow(21)).toEqual [30, 31]
|
|
|
|
describe "when the row range is inside an existing 1:1 region", ->
|
|
it "preserves the starting screen row of subsequent 1:N regions", ->
|
|
map.mapBufferRowRange(5, 10, 1)
|
|
map.mapBufferRowRange(25, 30, 1)
|
|
|
|
expect(map.bufferRowRangeForScreenRow(5)).toEqual [5, 10]
|
|
expect(map.bufferRowRangeForScreenRow(21)).toEqual [25, 30]
|
|
|
|
map.mapBufferRowRange(15, 20, 1)
|
|
|
|
expect(map.bufferRowRangeForScreenRow(11)).toEqual [15, 20]
|
|
expect(map.bufferRowRangeForScreenRow(5)).toEqual [5, 10]
|
|
expect(map.bufferRowRangeForScreenRow(21)).toEqual [25, 30]
|
|
|
|
describe "when the row range surrounds existing regions", ->
|
|
it "replaces the regions inside the given buffer row range with a single region", ->
|
|
map.mapBufferRowRange(5, 10, 1) # inner fold 1
|
|
map.mapBufferRowRange(11, 13, 1) # inner fold 2
|
|
map.mapBufferRowRange(15, 20, 1) # inner fold 3
|
|
map.mapBufferRowRange(22, 27, 1) # following fold
|
|
|
|
map.mapBufferRowRange(5, 20, 1)
|
|
|
|
expect(map.bufferRowRangeForScreenRow(5)).toEqual [5, 20]
|
|
expect(map.bufferRowRangeForScreenRow(6)).toEqual [20, 21]
|
|
expect(map.bufferRowRangeForScreenRow(7)).toEqual [21, 22]
|
|
expect(map.bufferRowRangeForScreenRow(8)).toEqual [22, 27]
|
|
|
|
it "replaces regions that cover 0 buffer rows at the start or end of the buffer row range", ->
|
|
map.mapBufferRowRange(0, 0, 1)
|
|
map.mapBufferRowRange(0, 1, 1)
|
|
map.mapBufferRowRange(1, 1, 1)
|
|
map.mapBufferRowRange(0, 1, 3)
|
|
expect(map.screenRowRangeForBufferRow(0)).toEqual [0, 3]
|
|
|
|
describe "when the row range straddles existing regions", ->
|
|
it "splits the straddled regions and places the new region between them", ->
|
|
# filler region 0
|
|
map.mapBufferRowRange(4, 7, 1) # region 1
|
|
# filler region 2
|
|
map.mapBufferRowRange(13, 15, 1) # region 3
|
|
|
|
# create region straddling region 0 and region 2
|
|
map.mapBufferRowRange(2, 10, 1)
|
|
|
|
expect(map.regions[0]).toEqual(bufferRows: 2, screenRows: 2)
|
|
expect(map.regions[1]).toEqual(bufferRows: 8, screenRows: 1)
|
|
expect(map.regions[2]).toEqual(bufferRows: 3, screenRows: 8)
|
|
expect(map.regions[3]).toEqual(bufferRows: 2, screenRows: 1)
|
|
|
|
it "merges adjacent isomorphic mappings", ->
|
|
map.mapBufferRowRange(2, 4, 1)
|
|
map.mapBufferRowRange(4, 5, 2)
|
|
|
|
map.mapBufferRowRange(1, 4, 3)
|
|
expect(map.regions).toEqual [{bufferRows: 5, screenRows: 5}]
|
|
|
|
describe ".applyBufferDelta(startBufferRow, delta)", ->
|
|
describe "when applying a positive delta", ->
|
|
it "expands the region containing the given start row by the given delta", ->
|
|
map.mapBufferRowRange(4, 8, 1)
|
|
|
|
map.applyBufferDelta(5, 4)
|
|
|
|
expect(map.regions[0]).toEqual(bufferRows: 4, screenRows: 4)
|
|
expect(map.regions[1]).toEqual(bufferRows: 8, screenRows: 1)
|
|
|
|
describe "when applying a negative delta", ->
|
|
it "shrinks regions starting at the start row until the entire delta is consumed", ->
|
|
map.mapBufferRowRange(4, 8, 1)
|
|
map.mapBufferRowRange(10, 14, 1)
|
|
|
|
map.applyBufferDelta(3, -6)
|
|
|
|
expect(map.regions[0]).toEqual(bufferRows: 3, screenRows: 4)
|
|
expect(map.regions[1]).toEqual(bufferRows: 0, screenRows: 1)
|
|
expect(map.regions[2]).toEqual(bufferRows: 1, screenRows: 2)
|
|
expect(map.regions[3]).toEqual(bufferRows: 4, screenRows: 1)
|
|
|
|
describe ".applyScreenDelta(startScreenRow, delta)", ->
|
|
describe "when applying a positive delta", ->
|
|
it "can enlarge the screen side of existing regions", ->
|
|
map.mapBufferRowRange(5, 6, 3) # wrapped line
|
|
map.applyScreenDelta(5, 2) # wrap it twice more
|
|
expect(map.screenRowRangeForBufferRow(5)).toEqual [5, 10]
|
|
|
|
describe "when applying a negative delta", ->
|
|
it "can collapse the screen side of multiple regions to 0 until the entire delta has been applied", ->
|
|
map.mapBufferRowRange(5, 10, 1) # inner fold 1
|
|
map.mapBufferRowRange(11, 13, 1) # inner fold 2
|
|
map.mapBufferRowRange(15, 20, 1) # inner fold 3
|
|
map.mapBufferRowRange(22, 27, 1) # following fold
|
|
|
|
map.applyScreenDelta(6, -5)
|
|
|
|
expect(map.screenRowRangeForBufferRow(5)).toEqual [5, 6]
|
|
expect(map.screenRowRangeForBufferRow(9)).toEqual [5, 6]
|
|
expect(map.screenRowRangeForBufferRow(10)).toEqual [6, 6]
|
|
expect(map.screenRowRangeForBufferRow(19)).toEqual [6, 6]
|
|
expect(map.screenRowRangeForBufferRow(22)).toEqual [8, 9]
|
|
expect(map.screenRowRangeForBufferRow(26)).toEqual [8, 9]
|
|
|
|
it "starts collapsing the first region at the start row, not before", ->
|
|
map.mapBufferRowRange(5, 6, 4)
|
|
map.mapBufferRowRange(11, 13, 1)
|
|
|
|
map.applyScreenDelta(7, -5)
|
|
|
|
expect(map.regions[0]).toEqual(bufferRows: 5, screenRows: 5)
|
|
expect(map.regions[1]).toEqual(bufferRows: 1, screenRows: 2)
|
|
expect(map.regions[2]).toEqual(bufferRows: 5, screenRows: 2)
|
|
|
|
it "does not throw an exception when applying a delta beyond the last region", ->
|
|
map.mapBufferRowRange(5, 10, 1) # inner fold 1
|
|
map.applyScreenDelta(15, 10)
|