From 0d093c3014a28cfad6f29b37aac731970d12865d Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 16 May 2012 17:28:07 -0600 Subject: [PATCH] --- spec/app/editor-spec.coffee | 65 ++++++++++++++++++++----------------- src/app/editor.coffee | 47 ++++++++++++++++++--------- 2 files changed, 68 insertions(+), 44 deletions(-) diff --git a/spec/app/editor-spec.coffee b/spec/app/editor-spec.coffee index c79ed713d..7d587d859 100644 --- a/spec/app/editor-spec.coffee +++ b/spec/app/editor-spec.coffee @@ -417,59 +417,67 @@ describe "Editor", -> describe "when the editor is attached and some lines at the end of the buffer are not visible on screen", -> beforeEach -> + editor.lineOverdraw = 2 editor.attachToDom(heightInLines: 5.5) - it "only renders the visible lines, setting the padding-bottom of the lines element to account for the missing lines", -> - expect(editor.visibleLines.find('.line').length).toBe 6 - expectedPaddingBottom = (buffer.numLines() - 6) * editor.lineHeight + fit "only renders the visible lines plus the overdrawn lines, setting the padding-bottom of the lines element to account for the missing lines", -> + expect(editor.visibleLines.find('.line').length).toBe 8 + expectedPaddingBottom = (buffer.numLines() - 8) * editor.lineHeight expect(editor.visibleLines.css('padding-bottom')).toBe "#{expectedPaddingBottom}px" + expect(editor.visibleLines.find('.line:first').text()).toBe buffer.lineForRow(0) + expect(editor.visibleLines.find('.line:last').text()).toBe buffer.lineForRow(7) describe "when scrolling vertically", -> describe "whes scrolling less than the editor's height", -> - it "removes lines that become invisible and builds lines that become visisble", -> - editor.scrollTop(editor.lineHeight * 2.5) - expect(editor.visibleLines.find('.line').length).toBe 6 - expect(editor.visibleLines.find('.line:first').text()).toBe buffer.lineForRow(2) + fit "draws new lines and removes old lines when the last visible line will exceed the last rendered line", -> + editor.scrollTop(editor.lineHeight * 1.5) + expect(editor.visibleLines.find('.line').length).toBe 8 + expect(editor.visibleLines.find('.line:first').text()).toBe buffer.lineForRow(0) expect(editor.visibleLines.find('.line:last').text()).toBe buffer.lineForRow(7) - editor.scrollTop(editor.lineHeight * 3.5) - expect(editor.visibleLines.find('.line').length).toBe 6 - expect(editor.visibleLines.find('.line:first').text()).toBe buffer.lineForRow(3) - expect(editor.visibleLines.find('.line:last').text()).toBe buffer.lineForRow(8) + editor.scrollTop(editor.lineHeight * 3.5) # first visible row will be 3, last will be 8 + expect(editor.visibleLines.find('.line').length).toBe 10 + expect(editor.visibleLines.find('.line:first').text()).toBe buffer.lineForRow(1) + expect(editor.visibleLines.find('.line:last').html()).toBe ' ' # line 10 is blank - editor.scrollTop(editor.lineHeight * 2.5) - expect(editor.visibleLines.find('.line').length).toBe 6 - expect(editor.visibleLines.find('.line:first').text()).toBe buffer.lineForRow(2) - expect(editor.visibleLines.find('.line:last').text()).toBe buffer.lineForRow(7) + editor.scrollTop(editor.lineHeight * 7.5) # first visible row is 7, last will be 12 + expect(editor.visibleLines.find('.line').length).toBe 8 + expect(editor.visibleLines.find('.line:first').text()).toBe buffer.lineForRow(5) + expect(editor.visibleLines.find('.line:last').text()).toBe buffer.lineForRow(12) + + editor.scrollTop(editor.lineHeight * 3.5) # first visible row will be 3, last will be 8 + expect(editor.visibleLines.find('.line').length).toBe 10 + expect(editor.visibleLines.find('.line:first').text()).toBe buffer.lineForRow(1) + expect(editor.visibleLines.find('.line:last').html()).toBe ' ' # line 10 is blank editor.scrollTop(0) - editor.verticalScrollbar.trigger 'scroll' - expect(editor.visibleLines.find('.line').length).toBe 6 + expect(editor.visibleLines.find('.line').length).toBe 8 expect(editor.visibleLines.find('.line:first').text()).toBe buffer.lineForRow(0) - expect(editor.visibleLines.find('.line:last').text()).toBe buffer.lineForRow(5) + expect(editor.visibleLines.find('.line:last').text()).toBe buffer.lineForRow(7) describe "when scrolling more than the editors height", -> - it "removes lines that become invisible and builds lines that become visible", -> + fit "removes lines that are offscreen and not in range of the overdraw and builds lines that become visible", -> editor.scrollTop(editor.scrollView.prop('scrollHeight') - editor.scrollView.height()) - expect(editor.visibleLines.find('.line').length).toBe 6 - expect(editor.visibleLines.find('.line:first').text()).toBe buffer.lineForRow(7) + expect(editor.visibleLines.find('.line').length).toBe 8 + expect(editor.visibleLines.find('.line:first').text()).toBe buffer.lineForRow(5) expect(editor.visibleLines.find('.line:last').text()).toBe buffer.lineForRow(12) editor.verticalScrollbar.scrollBottom(0) editor.verticalScrollbar.trigger 'scroll' - expect(editor.visibleLines.find('.line').length).toBe 6 + expect(editor.visibleLines.find('.line').length).toBe 8 expect(editor.visibleLines.find('.line:first').text()).toBe buffer.lineForRow(0) - expect(editor.visibleLines.find('.line:last').text()).toBe buffer.lineForRow(5) + expect(editor.visibleLines.find('.line:last').text()).toBe buffer.lineForRow(7) - it "adjusts the vertical padding of the lines element to account for non-rendered lines", -> + fit "adjusts the vertical padding of the lines element to account for non-rendered lines", -> editor.scrollTop(editor.lineHeight * 2.5) - expect(editor.visibleLines.css('padding-top')).toBe "#{2 * editor.lineHeight}px" + # first visible row is 2, first rendered is 0 + expect(editor.visibleLines.css('padding-top')).toBe "0px" expectedPaddingBottom = (buffer.numLines() - 8) * editor.lineHeight expect(editor.visibleLines.css('padding-bottom')).toBe "#{expectedPaddingBottom}px" - editor.verticalScrollbar.scrollBottom(editor.scrollView.prop('scrollHeight')) - editor.verticalScrollbar.trigger 'scroll' - expect(editor.visibleLines.css('padding-top')).toBe "#{7 * editor.lineHeight}px" + editor.scrollTop(editor.scrollView.prop('scrollHeight') - editor.scrollView.height()) + # scrolled to bottom, first visible row is 5 and first rendered row is 3 + expect(editor.visibleLines.css('padding-top')).toBe "#{3 * editor.lineHeight}px" expect(editor.visibleLines.css('padding-bottom')).toBe "0px" it "renders additional lines when the editor is resized", -> @@ -641,7 +649,6 @@ describe "Editor", -> editor.setFontSize(10) expect(editor.visibleLines.find(".line").length).toBeGreaterThan originalLineCount - describe "cursor movement", -> describe "when the arrow keys are pressed", -> it "moves the cursor by a single row/column", -> diff --git a/src/app/editor.coffee b/src/app/editor.coffee index 28e58e2bb..7bb27d8a3 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -47,6 +47,7 @@ class Editor extends View tabText: ' ' editSessions: null attached: false + lineOverdraw: 100 @deserialize: (viewState, rootView) -> viewState = _.clone(viewState) @@ -297,35 +298,50 @@ class Editor extends View @gutter.renderLineNumbers(firstVisibleScreenRow, lastVisibleScreenRow) - if firstVisibleScreenRow > @firstRenderedScreenRow - @removeLineElements(@firstRenderedScreenRow, firstVisibleScreenRow - 1) + renderFrom = Math.max(0, firstVisibleScreenRow - @lineOverdraw) + renderTo = Math.min(@getLastScreenRow(), lastVisibleScreenRow + @lineOverdraw) - if lastVisibleScreenRow < @lastRenderedScreenRow - @removeLineElements(lastVisibleScreenRow + 1, @lastRenderedScreenRow) if firstVisibleScreenRow < @firstRenderedScreenRow - newLinesStartRow = firstVisibleScreenRow newLinesEndRow = Math.min(@firstRenderedScreenRow - 1, lastVisibleScreenRow) - lineElements = @buildLineElements(newLinesStartRow, newLinesEndRow) - @insertLineElements(newLinesStartRow, lineElements) + lineElements = @buildLineElements(renderFrom, newLinesEndRow) + console.log "inserting", renderFrom, "to", newLinesEndRow + @insertLineElements(renderFrom, lineElements) + @firstRenderedScreenRow = renderFrom + adjustPaddingTop = true + + if renderTo < @lastRenderedScreenRow + console.log "removing", renderTo + 1, "to", @lastRenderedScreenRow + @removeLineElements(renderTo + 1, @lastRenderedScreenRow) + adjustPaddingBottom = true + + @lastRenderedScreenRow = renderTo if lastVisibleScreenRow > @lastRenderedScreenRow newLinesStartRow = Math.max(@lastRenderedScreenRow + 1, firstVisibleScreenRow) - newLinesEndRow = lastVisibleScreenRow - lineElements = @buildLineElements(newLinesStartRow, newLinesEndRow) + lineElements = @buildLineElements(newLinesStartRow, renderTo) + console.log "inserting", newLinesStartRow, "to", renderTo @insertLineElements(newLinesStartRow, lineElements) + @lastRenderedScreenRow = renderTo + adjustPaddingBottom = true - if firstVisibleScreenRow != @firstRenderedScreenRow - paddingTop = firstVisibleScreenRow * @lineHeight + if 0 <= @firstRenderedScreenRow < renderFrom + console.log "removing", @firstRenderedScreenRow, "to", renderFrom - 1 + @removeLineElements(@firstRenderedScreenRow, renderFrom - 1) + adjustPaddingTop = true + + @firstRenderedScreenRow = renderFrom + + if adjustPaddingTop + paddingTop = @firstRenderedScreenRow * @lineHeight @visibleLines.css('padding-top', paddingTop) @gutter.lineNumbers.css('padding-top', paddingTop) - @firstRenderedScreenRow = firstVisibleScreenRow + # @firstRenderedScreenRow = firstVisibleScreenRow - if lastVisibleScreenRow != @lastRenderedScreenRow - paddingBottom = (@getLastScreenRow() - lastVisibleScreenRow) * @lineHeight + if adjustPaddingBottom + paddingBottom = (@getLastScreenRow() - @lastRenderedScreenRow) * @lineHeight @visibleLines.css('padding-bottom', paddingBottom) @gutter.lineNumbers.css('padding-bottom', paddingBottom) - @lastRenderedScreenRow = lastVisibleScreenRow getFirstVisibleScreenRow: -> Math.floor(@scrollTop() / @lineHeight) @@ -464,6 +480,7 @@ class Editor extends View startRow = 0 else startRow = startScreenRow - @firstRenderedScreenRow + endRow = startRow + rowCount elementToInsertBefore = @lineCache[startRow]