From 03ae0bbbb6c99da919d5b43cbf466b85bacc4ecf Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 18 May 2012 19:22:56 -0600 Subject: [PATCH] Guts on the floor, but 2 line-wise fold specs are passing and the renderer is getting there --- spec/app/editor-spec.coffee | 4 +- spec/app/renderer-spec.coffee | 43 ++++++++++++-------- src/app/fold.coffee | 4 ++ src/app/renderer.coffee | 62 ++++++++++++++--------------- src/app/screen-line-fragment.coffee | 3 ++ 5 files changed, 65 insertions(+), 51 deletions(-) diff --git a/spec/app/editor-spec.coffee b/spec/app/editor-spec.coffee index 6c75ff020..662ad4cd3 100644 --- a/spec/app/editor-spec.coffee +++ b/spec/app/editor-spec.coffee @@ -2426,11 +2426,11 @@ describe "Editor", -> editor.attachToDom() describe "when a fold-selection event is triggered", -> - fit "folds the lines covered by the selection into a single line with a fold class", -> + it "folds the lines covered by the selection into a single line with a fold class", -> editor.getSelection().setBufferRange(new Range([4, 29], [7, 4])) editor.trigger 'fold-selection' - expect(editor.visibleLines.find('.line:eq(4)').toHaveClass('fold') + expect(editor.visibleLines.find('.line:eq(4)')).toHaveClass('fold') expect(editor.visibleLines.find('.line:eq(5)').text()).toBe '8' expect(editor.getSelection().isEmpty()).toBeTruthy() diff --git a/spec/app/renderer-spec.coffee b/spec/app/renderer-spec.coffee index 4d245b9d8..b943dbe45 100644 --- a/spec/app/renderer-spec.coffee +++ b/spec/app/renderer-spec.coffee @@ -223,16 +223,20 @@ describe "Renderer", -> describe "folding", -> beforeEach -> - buffer = new Buffer(require.resolve 'fixtures/two-hundred.js') + buffer = new Buffer(require.resolve 'fixtures/two-hundred.txt') renderer = new Renderer(buffer, {tabText}) + renderer.on 'change', changeHandler describe "when folds are created and destroyed", -> describe "when a fold spans multiple lines", -> fit "replaces the lines spanned by the fold with a single line with a html class of 'fold'", -> fold = renderer.createFold(4, 7) - expect(renderer.lineForRow(4).text).toHaveClass('fold') - expect(renderer.lineForRow(4).text).toMatch /^4-+/ + foldPlaceholder = renderer.lineForRow(4) + expect(foldPlaceholder.fold).toBe fold + expect(foldPlaceholder.text).toMatch /^4-+/ + expect(foldPlaceholder.bufferDelta).toEqual [4, 0] + expect(foldPlaceholder.screenDelta).toEqual [1, 0] expect(renderer.lineForRow(5).text).toBe '8' expect(changeHandler).toHaveBeenCalled() @@ -242,8 +246,10 @@ describe "Renderer", -> changeHandler.reset() fold.destroy() - expect(renderer.lineForRow(4).text).not.toHaveClass('fold') + expect(renderer.lineForRow(4).fold).toBeUndefined() expect(renderer.lineForRow(4).text).toMatch /^4-+/ + expect(renderer.lineForRow(4).bufferDelta).toEqual [1, 0] + expect(renderer.lineForRow(4).screenDelta).toEqual [1, 0] expect(renderer.lineForRow(5).text).toBe '5' expect(changeHandler).toHaveBeenCalled() @@ -252,29 +258,34 @@ describe "Renderer", -> expect(event.newRange).toEqual [[4, 0], [7, 1]] describe "when a fold spans a single line", -> - it "renders a placeholder for the folded region, but does not skip any lines", -> - fold = renderer.createFold([[2, 8], [2, 25]]) + fit "renders a fold placeholder for the folded line but does not skip any lines", -> + fold = renderer.createFold(4, 4) - [line2, line3] = renderer.linesForRows(2, 3) - expect(line2.text).toBe ' if (...) return items;' - expect(line3.text).toBe ' var pivot = items.shift(), current, left = [], right = [];' + foldPlaceholder = renderer.lineForRow(4) + expect(foldPlaceholder.fold).toBe fold + expect(foldPlaceholder.text).toMatch /^4-+/ + expect(foldPlaceholder.bufferDelta).toEqual [1, 0] + expect(foldPlaceholder.screenDelta).toEqual [1, 0] + expect(renderer.lineForRow(5).text).toBe '5' expect(changeHandler).toHaveBeenCalled() [[event]] = changeHandler.argsForCall - expect(event.oldRange).toEqual [[2, 0], [2, 40]] - expect(event.newRange).toEqual [[2, 0], [2, 26]] + expect(event.oldRange).toEqual [[4, 0], [4, 101]] + expect(event.newRange).toEqual [[4, 0], [4, 101]] changeHandler.reset() fold.destroy() - [line2, line3] = renderer.linesForRows(2, 3) - expect(line2.text).toBe ' if (items.length <= 1) return items;' - expect(line3.text).toBe ' var pivot = items.shift(), current, left = [], right = [];' + expect(renderer.lineForRow(4).fold).toBeUndefined() + expect(renderer.lineForRow(4).text).toMatch /^4-+/ + expect(renderer.lineForRow(4).bufferDelta).toEqual [1, 0] + expect(renderer.lineForRow(4).screenDelta).toEqual [1, 0] + expect(renderer.lineForRow(5).text).toBe '5' expect(changeHandler).toHaveBeenCalled() [[event]] = changeHandler.argsForCall - expect(event.newRange).toEqual [[2, 0], [2, 40]] - expect(event.oldRange).toEqual [[2, 0], [2, 26]] + expect(event.oldRange).toEqual [[4, 0], [4, 101]] + expect(event.newRange).toEqual [[4, 0], [4, 101]] changeHandler.reset() describe "when a fold is nested within another fold", -> diff --git a/src/app/fold.coffee b/src/app/fold.coffee index 535ad762b..d094cb26a 100644 --- a/src/app/fold.coffee +++ b/src/app/fold.coffee @@ -1,4 +1,5 @@ Range = require 'range' +Point = require 'point' module.exports = class Fold @@ -18,6 +19,9 @@ class Fold # new Range([@startRow, 0], @endRow) throw "Don't worry about this yet -- sobo" + getBufferDelta: -> + new Point(@endRow - @startRow + 1, 0) + handleBufferChange: (event) -> # oldStartRow = @start.row diff --git a/src/app/renderer.coffee b/src/app/renderer.coffee index 957566386..c1a942165 100644 --- a/src/app/renderer.coffee +++ b/src/app/renderer.coffee @@ -55,8 +55,9 @@ class Renderer fold = new Fold(this, startRow, endRow) @registerFold(startRow, fold) - bufferRange = new Range([[startRow, 0], [endRow, @buffer.lineLengthForRow(endRow)]]) + bufferRange = new Range([startRow, 0], [endRow, @buffer.lineLengthForRow(endRow)]) oldScreenRange = @screenLineRangeForBufferRange(bufferRange) + lines = @buildLineForBufferRow(startRow) @lineMap.replaceScreenRows(oldScreenRange.start.row, oldScreenRange.end.row, lines) newScreenRange = @screenLineRangeForBufferRange(bufferRange) @@ -66,22 +67,17 @@ class Renderer fold destroyFold: (fold) -> - bufferRange = fold.getRange().copy() - @unregisterFold(bufferRange.start.row, fold) - - bufferRange.start.row = @bufferRowForScreenRow(@screenRowForBufferRow(bufferRange.start.row)) - startScreenRow = @screenRowForBufferRow(bufferRange.start.row) + @unregisterFold(fold.startRow, fold) + { startRow, endRow } = fold + bufferRange = new Range([startRow, 0], [endRow, @buffer.lineLengthForRow(endRow)]) oldScreenRange = @screenLineRangeForBufferRange(bufferRange) - lines = @buildLinesForBufferRows(bufferRange.start.row, bufferRange.end.row) - @lineMap.replaceScreenRows( - oldScreenRange.start.row, - oldScreenRange.end.row - lines) + lines = @buildLinesForBufferRows(startRow, endRow) + @lineMap.replaceScreenRows(oldScreenRange.start.row, oldScreenRange.end.row, lines) newScreenRange = @screenLineRangeForBufferRange(bufferRange) @trigger 'change', oldRange: oldScreenRange, newRange: newScreenRange - @trigger 'unfold', fold.getRange() + @trigger 'unfold', bufferRange screenRowForBufferRow: (bufferRow) -> @lineMap.screenPositionForBufferPosition([bufferRow, 0]).row @@ -137,31 +133,30 @@ class Renderer startBufferColumn = null currentScreenLineLength = 0 + startBufferColumn = 0 while startBufferRow <= endBufferRow - break if - startBufferColumn ?= 0 - line = @highlighter.lineForRow(startBufferRow) - line = line.splitAt(startBufferColumn)[1] - wrapScreenColumn = @findWrapColumn(line.text, @maxLineLength - currentScreenLineLength) + screenLine = @highlighter.lineForRow(startBufferRow) if fold = @foldForBufferRow(startBufferRow) - placeholder = @buildFoldPlaceholder(fold) - lineFragments.push(placeholder) - startBufferRow = fold.end.row + 1 - startBufferColumn = 0 - currentScreenLineLength = 0 + screenLine = screenLine.copy() + screenLine.fold = fold + screenLine.bufferDelta = fold.getBufferDelta() + lineFragments.push(screenLine) + startBufferRow = fold.endRow + 1 continue + startBufferColumn ?= 0 + screenLine = screenLine.splitAt(startBufferColumn)[1] if startBufferColumn > 0 + wrapScreenColumn = @findWrapColumn(screenLine.text, @maxLineLength) if wrapScreenColumn? - line = line.splitAt(wrapScreenColumn)[0] - line.screenDelta = new Point(1, 0) + screenLine = screenLine.splitAt(wrapScreenColumn)[0] + screenLine.screenDelta = new Point(1, 0) startBufferColumn += wrapScreenColumn else startBufferRow++ - startBufferColumn = null + startBufferColumn = 0 - lineFragments.push(line) - currentScreenLineLength = 0 + lineFragments.push(screenLine) lineFragments @@ -186,16 +181,17 @@ class Renderer unregisterFold: (bufferRow, fold) -> folds = @activeFolds[bufferRow] - folds.splice(folds.indexOf(fold), 1) + _.remove(folds, fold) delete @foldsById[fold.id] - foldsForBufferRow: (bufferRow) -> - folds = @activeFolds[bufferRow] or [] - folds.sort (a, b) -> a.compare(b) + foldForBufferRow: (bufferRow) -> + @activeFolds[bufferRow]?[0] buildFoldPlaceholder: (fold) -> - token = new Token(value: '...', type: 'fold-placeholder', fold: fold, isAtomic: true) - new ScreenLineFragment([token], token.value, [0, token.value.length], fold.getRange().toDelta()) + + # token = new Token(value: '...', type: 'fold-placeholder', fold: fold, isAtomic: true) + # delta = new Point(fold.endRow - fold.startRow + 1, 0) + # new ScreenLineFragment([token], token.value, [0, token.value.length], delta) screenLineRangeForBufferRange: (bufferRange) -> @expandScreenRangeToLineEnds( diff --git a/src/app/screen-line-fragment.coffee b/src/app/screen-line-fragment.coffee index e16391d80..3b9a1d0df 100644 --- a/src/app/screen-line-fragment.coffee +++ b/src/app/screen-line-fragment.coffee @@ -14,6 +14,9 @@ class ScreenLineFragment @bufferDelta = Point.fromObject(bufferDelta) _.extend(this, extraFields) + copy: -> + new ScreenLineFragment(@tokens, @text, @screenDelta, @bufferDelta, { @state }) + splitAt: (column) -> return [new ScreenLineFragment([], '', [0, 0], [0, 0]), this] if column == 0