mirror of
https://github.com/atom/atom.git
synced 2026-01-24 06:18:03 -05:00
WIP: can destroy folds. emits change events.
This commit is contained in:
@@ -4,22 +4,44 @@ LineFolder = require 'line-folder'
|
||||
Range = require 'range'
|
||||
|
||||
describe "LineFolder", ->
|
||||
[buffer, folder] = []
|
||||
[buffer, folder, changeHandler] = []
|
||||
|
||||
beforeEach ->
|
||||
buffer = new Buffer(require.resolve 'fixtures/sample.js')
|
||||
highlighter = new Higlighter(buffer)
|
||||
folder = new LineFolder(highlighter)
|
||||
changeHandler = jasmine.createSpy('changeHandler')
|
||||
folder.on 'change', changeHandler
|
||||
|
||||
describe "screen line rendering", ->
|
||||
describe "when folds are created and removed", ->
|
||||
describe "when there is a single fold spanning multiple lines", ->
|
||||
it "renders a placeholder on the first line of a fold, and skips subsequent lines", ->
|
||||
folder.fold(new Range([4, 29], [7, 4]))
|
||||
[line4, line5] = fragments = folder.linesForScreenRows(4, 5)
|
||||
it "replaces folded lines with a single line containing a placeholder and emits a change event", ->
|
||||
[line4, line5] = folder.linesForScreenRows(4, 5)
|
||||
previousLine4Text = line4.text
|
||||
previousLine5Text = line5.text
|
||||
|
||||
fold = folder.fold(new Range([4, 29], [7, 4]))
|
||||
[line4, line5] = folder.linesForScreenRows(4, 5)
|
||||
|
||||
expect(line4.text).toBe ' while(items.length > 0) {...}'
|
||||
expect(line5.text).toBe ' return sort(left).concat(pivot).concat(sort(right));'
|
||||
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
[event] = changeHandler.argsForCall[0]
|
||||
expect(event.oldRange).toEqual [[4, 0], [7, 5]]
|
||||
expect(event.newRange).toEqual [[4, 0], [4, 33]]
|
||||
changeHandler.reset()
|
||||
|
||||
fold.destroy()
|
||||
[line4, line5] = folder.linesForScreenRows(4, 5)
|
||||
expect(line4.text).toBe previousLine4Text
|
||||
expect(line5.text).toBe previousLine5Text
|
||||
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
[event] = changeHandler.argsForCall[0]
|
||||
expect(event.oldRange).toEqual [[4, 0], [4, 33]]
|
||||
expect(event.newRange).toEqual [[4, 0], [7, 5]]
|
||||
|
||||
describe "when there is a single fold contained on a single line", ->
|
||||
it "renders a placeholder for the folded region, but does not skip any lines", ->
|
||||
folder.fold(new Range([2, 8], [2, 25]))
|
||||
@@ -28,6 +50,7 @@ describe "LineFolder", ->
|
||||
expect(line2.text).toBe ' if (...) return items;'
|
||||
expect(line3.text).toBe ' var pivot = items.shift(), current, left = [], right = [];'
|
||||
|
||||
describe "screen line rendering", ->
|
||||
describe "when there is a nested fold on the last line of another fold", ->
|
||||
it "does not render a placeholder for the nested fold because it is inside of the other fold", ->
|
||||
folder.fold(new Range([8, 5], [8, 10]))
|
||||
@@ -55,6 +78,37 @@ describe "LineFolder", ->
|
||||
expect(line4.text).toBe ' while(items.length > 0) {...}...concat(sort(right));'
|
||||
expect(line5.text).toBe ' };'
|
||||
|
||||
describe "change events", ->
|
||||
changeHandler = null
|
||||
|
||||
beforeEach ->
|
||||
|
||||
describe "when folds are created or destroyed", ->
|
||||
it "emits a change event for the lines that are folded / unfolded", ->
|
||||
fold1 = folder.fold(new Range([4, 29], [7, 4]))
|
||||
changeHandler.reset()
|
||||
|
||||
fold2 = folder.fold(new Range([7, 5], [8, 34]))
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
[event] = changeHandler.argsForCall[0]
|
||||
expect(event.oldRange).toEqual [[4, 0], [5, 56]]
|
||||
expect(event.newRange).toEqual [[4, 0], [4, 58]]
|
||||
changeHandler.reset()
|
||||
|
||||
# fold1.destroy()
|
||||
# expect(changeHandler).toHaveBeenCalled()
|
||||
# [event] = changeHandler.argsForCall[0]
|
||||
# expect(event.oldRange).toEqual [[4, 0], [4, 33]]
|
||||
# expect(event.newRange).toEqual [[4, 0], [7, 5]]
|
||||
# changeHandler.reset()
|
||||
|
||||
describe "when the buffer changes", ->
|
||||
describe "when the change precedes any folds", ->
|
||||
|
||||
describe "when the change follows a fold", ->
|
||||
|
||||
describe "when the change is inside of a fold", ->
|
||||
|
||||
describe "position translation", ->
|
||||
describe "when there is single fold spanning multiple lines", ->
|
||||
it "translates positions to account for folded lines and characters and the placeholder", ->
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
_ = require 'underscore'
|
||||
Point = require 'point'
|
||||
Range = require 'range'
|
||||
LineMap = require 'line-map'
|
||||
ScreenLineFragment = require 'screen-line-fragment'
|
||||
_ = require 'underscore'
|
||||
EventEmitter = require 'event-emitter'
|
||||
|
||||
module.exports =
|
||||
class LineFolder
|
||||
@@ -14,10 +16,44 @@ class LineFolder
|
||||
@lineMap.insertAtBufferRow(0, @highlighter.screenLines)
|
||||
|
||||
fold: (bufferRange) ->
|
||||
fold = new Fold(this, bufferRange)
|
||||
@activeFolds[bufferRange.start.row] ?= []
|
||||
@activeFolds[bufferRange.start.row].push(new Fold(this, bufferRange))
|
||||
screenRange = @screenRangeForBufferRange(bufferRange)
|
||||
@lineMap.replaceScreenRows(screenRange.start.row, screenRange.end.row, @renderScreenLine(screenRange.start.row))
|
||||
@activeFolds[bufferRange.start.row].push(fold)
|
||||
oldScreenRange = @expandScreenRangeToLineEnds(@screenRangeForBufferRange(bufferRange))
|
||||
|
||||
lineWithFold = @renderScreenLine(oldScreenRange.start.row)
|
||||
@lineMap.replaceScreenRows(oldScreenRange.start.row, oldScreenRange.end.row, lineWithFold)
|
||||
|
||||
newScreenRange = oldScreenRange.copy()
|
||||
newScreenRange.end = _.clone(newScreenRange.start)
|
||||
for fragment in lineWithFold
|
||||
newScreenRange.end.column += fragment.text.length
|
||||
|
||||
@trigger 'change', oldRange: oldScreenRange, newRange: newScreenRange
|
||||
fold
|
||||
|
||||
destroyFold: (fold) ->
|
||||
bufferRange = fold.range
|
||||
folds = @activeFolds[bufferRange.start.row]
|
||||
foldIndex = folds.indexOf(fold)
|
||||
folds[foldIndex..foldIndex] = []
|
||||
|
||||
startScreenRow = @screenRowForBufferRow(bufferRange.start.row)
|
||||
|
||||
oldScreenRange = new Range()
|
||||
oldScreenRange.start.row = startScreenRow
|
||||
oldScreenRange.end.row = startScreenRow
|
||||
oldScreenRange.end.column = @lineMap.lineForScreenRow(startScreenRow).text.length
|
||||
|
||||
@lineMap.replaceScreenRow(startScreenRow, @renderScreenLinesForBufferRows(bufferRange.start.row, bufferRange.end.row))
|
||||
|
||||
newScreenRange = @expandScreenRangeToLineEnds(@screenRangeForBufferRange(bufferRange))
|
||||
|
||||
@trigger 'change', oldRange: oldScreenRange, newRange: newScreenRange
|
||||
|
||||
renderScreenLinesForBufferRows: (start, end) ->
|
||||
for row in [start..end]
|
||||
@renderScreenLineForBufferRow(row)
|
||||
|
||||
renderScreenLine: (screenRow) ->
|
||||
@renderScreenLineForBufferRow(@bufferRowForScreenRow(screenRow))
|
||||
@@ -56,5 +92,15 @@ class LineFolder
|
||||
screenRangeForBufferRange: (bufferRange) ->
|
||||
@lineMap.screenRangeForBufferRange(bufferRange)
|
||||
|
||||
expandScreenRangeToLineEnds: (screenRange) ->
|
||||
{ start, end } = screenRange
|
||||
new Range([start.row, 0], [end.row, @lineMap.lineForScreenRow(end.row).text.length])
|
||||
|
||||
_.extend LineFolder.prototype, EventEmitter
|
||||
|
||||
class Fold
|
||||
constructor: (@lineFolder, @range) ->
|
||||
|
||||
destroy: ->
|
||||
@lineFolder.destroyFold(this)
|
||||
|
||||
|
||||
@@ -45,6 +45,10 @@ class LineMap
|
||||
replaceBufferRows: (start, end, screenLines) ->
|
||||
@spliceAtBufferRow(start, end - start + 1, screenLines)
|
||||
|
||||
|
||||
replaceScreenRow: (row, screenLines) ->
|
||||
@replaceScreenRows(row, row, screenLines)
|
||||
|
||||
replaceScreenRows: (start, end, screenLines) ->
|
||||
@spliceAtScreenRow(start, end - start + 1, screenLines)
|
||||
|
||||
|
||||
@@ -25,14 +25,14 @@ class LineWrapper
|
||||
oldBufferRange = e.oldRange
|
||||
newBufferRange = e.newRange
|
||||
|
||||
oldScreenRange = @lineMap.screenRangeForBufferRange(@expandRangeToLineEnds(oldBufferRange))
|
||||
oldScreenRange = @lineMap.screenRangeForBufferRange(@expandBufferRangeToLineEnds(oldBufferRange))
|
||||
newScreenLines = @buildScreenLinesForBufferRows(newBufferRange.start.row, newBufferRange.end.row)
|
||||
@lineMap.replaceBufferRows oldBufferRange.start.row, oldBufferRange.end.row, newScreenLines
|
||||
newScreenRange = @lineMap.screenRangeForBufferRange(@expandRangeToLineEnds(newBufferRange))
|
||||
newScreenRange = @lineMap.screenRangeForBufferRange(@expandBufferRangeToLineEnds(newBufferRange))
|
||||
|
||||
@trigger 'change', { oldRange: oldScreenRange, newRange: newScreenRange }
|
||||
|
||||
expandRangeToLineEnds: (bufferRange) ->
|
||||
expandBufferRangeToLineEnds: (bufferRange) ->
|
||||
{ start, end } = bufferRange
|
||||
new Range([start.row, 0], [end.row, @lineMap.lineForBufferRow(end.row).text.length])
|
||||
|
||||
|
||||
Reference in New Issue
Block a user