WIP: Handle buffer change events correctly with respect to folded lines

We're handling changes that straddle the start row and are in the middle of the fold, but we're still screwing up when the old range straddles the end row.
This commit is contained in:
Corey Johnson & Nathan Sobo
2012-05-22 19:02:13 -07:00
parent 13416bd6f2
commit 04f4a9a765
3 changed files with 98 additions and 28 deletions

View File

@@ -1,7 +1,7 @@
Renderer = require 'renderer'
Buffer = require 'buffer'
describe "Renderer", ->
fdescribe "Renderer", ->
[renderer, buffer, changeHandler, tabText] = []
beforeEach ->
tabText = ' '
@@ -303,23 +303,52 @@ describe "Renderer", ->
expect(event.newRange).toEqual [[3, 0], [4, 1]]
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.insert([2, 0], '\n')
expect(fold1.startRow).toBe 2
expect(fold1.endRow).toBe 5
describe "when the end of the new range precedes the end of the fold", ->
it "updates the fold and ensures the change is present when the fold is destroyed", ->
buffer.insert([3, 0], '\n')
expect(fold1.startRow).toBe 2
expect(fold1.endRow).toBe 5
buffer.logLines(0, 10)
renderer.logLines(0, 10)
expect(renderer.lineForRow(1).text).toBe "1"
expect(renderer.lineForRow(2).text).toBe "2"
expect(renderer.lineForRow(2).fold).toBe fold1
expect(renderer.lineForRow(2).bufferDelta).toEqual [4, 0]
expect(renderer.lineForRow(3).text).toMatch "5"
expect(renderer.lineForRow(4).fold).toBe fold2
expect(renderer.lineForRow(5).text).toMatch /^9-+/
expect(changeHandler).toHaveBeenCalled()
[[event]] = changeHandler.argsForCall
expect(event.oldRange).toEqual [[2, 0], [2, 1]]
expect(event.newRange).toEqual [[2, 0], [2, 1]]
describe "when the end of the new range exceeds the end of the fold", ->
ffit "expands the fold to contain all the inserted lines", ->
buffer.change([[3, 0], [4, 0]], 'a\nb\nc\nd\n')
expect(fold1.startRow).toBe 2
expect(fold1.endRow).toBe 7
# buffer.logLines(0, 10)
# renderer.logLines(0, 10)
# expect(renderer.lineForRow(1).text).toBe "1"
# expect(renderer.lineForRow(2).text).toBe "2"
# expect(renderer.lineForRow(2).fold).toBe fold1
# expect(renderer.lineForRow(2).bufferDelta).toEqual [4, 0]
# expect(renderer.lineForRow(3).text).toMatch "5"
# expect(renderer.lineForRow(4).fold).toBe fold2
# expect(renderer.lineForRow(5).text).toMatch /^9-+/
# expect(changeHandler).toHaveBeenCalled()
# [[event]] = changeHandler.argsForCall
# expect(event.oldRange).toEqual [[2, 0], [2, 1]]
# expect(event.newRange).toEqual [[2, 0], [2, 1]]
expect(renderer.lineForRow(1).text).toBe "1"
expect(renderer.lineForRow(2).text).toBe ""
expect(renderer.lineForRow(2).fold).toBe fold1
expect(renderer.lineForRow(2).bufferDelta).toEqual [4, 0]
expect(renderer.lineForRow(3).text).toMatch "5"
expect(renderer.lineForRow(4).fold).toBe fold2
expect(renderer.lineForRow(5).text).toMatch /^9-+/
expect(changeHandler).toHaveBeenCalled()
[[event]] = changeHandler.argsForCall
expect(event.oldRange).toEqual [[2, 0], [2, 1]]
expect(event.newRange).toEqual [[2, 0], [2, 0]]
describe "when the old range surrounds a fold", ->
it "removes the fold and replaces the fold placeholder with the new text", ->
@@ -351,6 +380,26 @@ describe "Renderer", ->
expect(event.oldRange).toEqual [[1, 0], [3, 2]]
expect(event.newRange).toEqual [[1, 0], [1, 9]]
describe "when the old range straddles the beginning of a fold", ->
describe "when lines are added to the buffer", ->
it "replaces lines in the portion of the range that precedes the fold and adjusts the end of the fold to encompass additional lines", ->
buffer.change([[1, 1], [3, 0]], "a\nb\nc\nd\n")
expect(fold1.startRow).toBe 2
expect(fold1.endRow).toBe 6
buffer.logLines(0, 10)
console.log "================================================"
renderer.logLines(0, 10)
expect(renderer.lineForRow(1).text).toBe '1a'
expect(renderer.lineForRow(2).text).toBe 'b'
expect(renderer.lineForRow(2).fold).toBe fold1
describe "when lines are removed from the buffer", ->
describe "position translation", ->
it "translates positions to account for folded lines and characters and the placeholder", ->
renderer.createFold(4, 7)

View File

@@ -15,18 +15,19 @@ class Fold
destroy: ->
@renderer.destroyFold(this)
inspect: ->
"Fold(#{@startRow}, #{@endRow})"
getBufferDelta: ->
new Point(@endRow - @startRow + 1, 0)
handleBufferChange: (event) ->
oldStartRow = @startRow
{ oldRange } = event
if oldRange.start.row <= @startRow and oldRange.end.row >= @endRow
@renderer.unregisterFold(oldStartRow, this)
if @isContainedByRange(event.oldRange)
@renderer.unregisterFold(@startRow, this)
return
changeInsideFold = @startRow <= oldRange.start.row and @endRow >= oldRange.end.row
@updateStartRow(event)
@updateEndRow(event)
@@ -34,18 +35,34 @@ class Fold
@renderer.unregisterFold(oldStartRow, this)
@renderer.registerFold(@startRow, this)
changeInsideFold
isContainedByRange: (range) ->
range.start.row <= @startRow and @endRow <= range.end.row
updateStartRow: (event) ->
{ newRange, oldRange } = event
return if oldRange.start.row >= @startRow
deltaFromOldRangeEndRow = @startRow - oldRange.end.row
@startRow = newRange.end.row + deltaFromOldRangeEndRow
if oldRange.end.row < @startRow
delta = newRange.end.row - oldRange.end.row
else if newRange.end.row < @startRow
delta = newRange.end.row - @startRow
else
delta = 0
console.log "start row delta", delta
@startRow += delta
updateEndRow: (event) ->
{ newRange, oldRange } = event
return if oldRange.start.row > @endRow
deltaFromOldRangeEndRow = @endRow - oldRange.end.row
@endRow = newRange.end.row + deltaFromOldRangeEndRow
if oldRange.end.row <= @endRow
delta = newRange.end.row - oldRange.end.row
else if newRange.end.row <= @endRow
console.log "newRange.end.row", newRange.end.row, " - @endRow", @endRow
delta = newRange.end.row - @endRow
else
delta = 0
console.log "end row delta", delta
@endRow += delta

View File

@@ -111,12 +111,15 @@ class Renderer
@handleHighlighterChange(@lastHighlighterChangeEvent)
handleHighlighterChange: (e) ->
{ oldRange, newRange } = e
oldRange = @bufferRangeForScreenRange(@screenRangeForBufferRange(e.oldRange.copy()))
newRange = @bufferRangeForScreenRange(@screenRangeForBufferRange(e.newRange.copy()))
oldScreenRange = @screenLineRangeForBufferRange(oldRange)
newScreenLines = @buildLinesForBufferRows(newRange.start.row, newRange.end.row)
@lineMap.replaceScreenRows oldScreenRange.start.row, oldScreenRange.end.row, newScreenLines
newScreenRange = @screenLineRangeForBufferRange(newRange)
console.log "New Screen Range", newScreenRange.inspect()
@trigger 'change', { oldRange: oldScreenRange, newRange: newScreenRange, bufferChanged: true }
@@ -176,6 +179,7 @@ class Renderer
@foldsById[fold.id] = fold
unregisterFold: (bufferRow, fold) ->
console.log "unregistering fold", fold.id
folds = @activeFolds[bufferRow]
_.remove(folds, fold)
delete @foldsById[fold.id]