From 1d46da55da43af32c5f5d3480d4fdb321b57273d Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 9 Nov 2012 07:31:30 -0700 Subject: [PATCH] WIP: Borrowing from code mirror to update lines. Scrolling / resizing work, but not much else --- spec/app/editor-spec.coffee | 7 ++- src/app/editor.coffee | 93 ++++++++++++++++++++++++++++--------- src/app/line-map.coffee | 2 +- 3 files changed, 77 insertions(+), 25 deletions(-) diff --git a/spec/app/editor-spec.coffee b/spec/app/editor-spec.coffee index 50a83e468..248ccd6fe 100644 --- a/spec/app/editor-spec.coffee +++ b/spec/app/editor-spec.coffee @@ -1205,15 +1205,20 @@ describe "Editor", -> expect(editor.renderedLines.find('.line:last').text()).toBe buffer.lineForRow(7) it "renders additional lines when the editor is resized", -> + editor.logRenderedLines() setEditorHeightInLines(editor, 10) + editor.logRenderedLines() $(window).trigger 'resize' expect(editor.renderedLines.find('.line').length).toBe 12 expect(editor.renderedLines.find('.line:first').text()).toBe buffer.lineForRow(0) expect(editor.renderedLines.find('.line:last').text()).toBe buffer.lineForRow(11) - it "renders correctly when scrolling after text is added to the buffer", -> + ffit "renders correctly when scrolling after text is added to the buffer", -> + editor.logRenderedLines() editor.insertText("1\n") + editor.logRenderedLines() + _.times 4, -> editor.moveCursorDown() expect(editor.renderedLines.find('.line:eq(2)').text()).toBe editor.lineForBufferRow(2) expect(editor.renderedLines.find('.line:eq(7)').text()).toBe editor.lineForBufferRow(7) diff --git a/src/app/editor.coffee b/src/app/editor.coffee index 71ad5498b..18e038e06 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -736,42 +736,84 @@ class Editor extends View renderLines: -> @clearRenderedLines() - @updateRenderedLines() + @updateRenderedLines(reset: true) clearRenderedLines: -> @lineCache = [] @renderedLines.find('.line').remove() - @firstRenderedScreenRow = -1 - @lastRenderedScreenRow = -1 + @firstRenderedScreenRow = null + @lastRenderedScreenRow = null - updateRenderedLines: -> + updateRenderedLines: (options={}) -> + {reset} = options firstVisibleScreenRow = @getFirstVisibleScreenRow() lastVisibleScreenRow = @getLastVisibleScreenRow() renderFrom = Math.max(0, firstVisibleScreenRow - @lineOverdraw) renderTo = Math.min(@getLastScreenRow(), lastVisibleScreenRow + @lineOverdraw) - if firstVisibleScreenRow < @firstRenderedScreenRow - @removeLineElements(Math.max(@firstRenderedScreenRow, renderTo + 1), @lastRenderedScreenRow) - @lastRenderedScreenRow = renderTo - newLines = @buildLineElements(renderFrom, Math.min(@firstRenderedScreenRow - 1, renderTo)) - @insertLineElements(renderFrom, newLines) - @firstRenderedScreenRow = renderFrom - renderedLines = true + intactRanges = + if @firstRenderedScreenRow? and @lastRenderedScreenRow? + [{from: @firstRenderedScreenRow, to: @lastRenderedScreenRow, domStart: 0}] + else + [] - if lastVisibleScreenRow > @lastRenderedScreenRow - if 0 <= @firstRenderedScreenRow < renderFrom - @removeLineElements(@firstRenderedScreenRow, Math.min(@lastRenderedScreenRow, renderFrom - 1)) - @firstRenderedScreenRow = renderFrom - startRowOfNewLines = Math.max(@lastRenderedScreenRow + 1, renderFrom) - newLines = @buildLineElements(startRowOfNewLines, renderTo) - @insertLineElements(startRowOfNewLines, newLines) - @lastRenderedScreenRow = renderTo - renderedLines = true + @truncateIntactRanges(intactRanges, renderFrom, renderTo) + @clearDirtyRanges(intactRanges) + @fillDirtyRanges(intactRanges, renderFrom, renderTo) + @firstRenderedScreenRow = renderFrom + @lastRenderedScreenRow = renderTo + @updatePaddingOfRenderedLines() - if renderedLines - @gutter.renderLineNumbers(renderFrom, renderTo) - @updatePaddingOfRenderedLines() + truncateIntactRanges: (intactRanges, renderFrom, renderTo) -> + i = 0 + while i < intactRanges.length + range = intactRanges[i] + if range.from < renderFrom + range.domStart += renderFrom - range.from + range.from = renderFrom + if range.to > renderTo + range.to = renderTo + if range.from >= range.to + intactRanges.splice(i--, 1) + i++ + intactRanges.sort (a, b) -> a.domStart - b.domStart + + clearDirtyRanges: (intactRanges) -> + renderedLines = @renderedLines[0] + killLine = (line) -> + next = line.nextSibling + renderedLines.removeChild(line) + next + + if intactRanges.length == 0 + @renderedLines.empty() + else + domPosition = 0 + currentLine = renderedLines.firstChild + for intactRange in intactRanges + while intactRange.domStart > domPosition + currentLine = killLine(currentLine) + domPosition++ + for i in [intactRange.from..intactRange.to] + currentLine = currentLine.nextSibling + domPosition++ + while currentLine + currentLine = killLine(currentLine) + + fillDirtyRanges: (intactRanges, renderFrom, renderTo) -> + renderedLines = @renderedLines[0] + nextIntact = intactRanges.shift() + currentLine = renderedLines.firstChild + screenRow = renderFrom + for row in [renderFrom..renderTo] + if row == nextIntact?.to + 1 + nextIntact = intactRanges.shift() + if !nextIntact or row < nextIntact.from + lineElement = @buildLineElementForScreenRow(row) + renderedLines.insertBefore(lineElement, currentLine) + else + currentLine = currentLine.nextSibling updatePaddingOfRenderedLines: -> paddingTop = @firstRenderedScreenRow * @lineHeight @@ -847,6 +889,11 @@ class Editor extends View @raw(buildLineHtml(line)) row++ + buildLineElementForScreenRow: (screenRow) -> + div = document.createElement('div') + div.innerHTML = @buildLineHtml(@activeEditSession.lineForScreenRow(screenRow)) + div.firstChild + buildLineHtml: (screenLine) -> scopeStack = [] line = [] diff --git a/src/app/line-map.coffee b/src/app/line-map.coffee index c897d65ec..eae630887 100644 --- a/src/app/line-map.coffee +++ b/src/app/line-map.coffee @@ -27,7 +27,7 @@ class LineMap @maxScreenLineLength = Math.max(@maxScreenLineLength, screenLine.text.length) lineForScreenRow: (row) -> - @linesForScreenRows(row, row)[0] + @screenLines[row] linesForScreenRows: (startRow, endRow) -> @screenLines[startRow..endRow]