diff --git a/spec/app/editor-spec.coffee b/spec/app/editor-spec.coffee index f291c727b..686a6b1d8 100644 --- a/spec/app/editor-spec.coffee +++ b/spec/app/editor-spec.coffee @@ -392,7 +392,7 @@ describe "Editor", -> otherEditor.simulateDomAttachment() expect(otherEditor.setMaxLineLength).toHaveBeenCalled() - describe "when some lines at the end of the buffer are not visible on screen", -> + describe "when some lines at the end of the buffer are not visible on screen when the editor is attached", -> beforeEach -> editor.attachToDom(heightInLines: 5.5) @@ -401,21 +401,37 @@ describe "Editor", -> expectedMarginBottom = (buffer.numLines() - 6) * editor.lineHeight expect(editor.lines.find('.line:last').css('margin-bottom')).toBe "#{expectedMarginBottom}px" - it "renders additional lines when the editor is scrolled down, adjusting margins appropriately", -> + fit "when the lines are scrolled down, removes lines that become invisible and build lines that are become visisble", -> editor.scroller.scrollTop(editor.lineHeight * 2.5) editor.scroller.trigger 'scroll' - expect(editor.lines.find('.line').length).toBe 8 - expect(editor.lines.find('.line:first').text()).toBe buffer.lineForRow(0) + expect(editor.lines.find('.line').length).toBe 6 + expect(editor.lines.find('.line:first').text()).toBe buffer.lineForRow(2) expect(editor.lines.find('.line:last').text()).toBe buffer.lineForRow(7) + editor.scroller.scrollTop(editor.lineHeight * 3.5) + editor.scroller.trigger 'scroll' + + expect(editor.lines.find('.line').length).toBe 6 + expect(editor.lines.find('.line:first').text()).toBe buffer.lineForRow(3) + expect(editor.lines.find('.line:last').text()).toBe buffer.lineForRow(8) + + it "adjusts margins to account for non-rendered lines", -> + editor.scroller.scrollTop(editor.lineHeight * 2.5) + editor.scroller.trigger 'scroll' + for line, index in editor.lines.find('.line') + marginTop = $(line).css('margin-top') marginBottom = $(line).css('margin-bottom') - if index == 7 - expectedMarginBottom = (buffer.numLines() - 8) * editor.lineHeight + if index == 0 + expectedMarginTop = editor.lineHeight * 2 + expect(marginTop).toBe "#{expectedMarginTop}px" + else if index == 5 + expectedMarginBottom = (editor.getLastScreenRow() - 7) * editor.lineHeight expect(marginBottom).toBe "#{expectedMarginBottom}px" else expect(marginBottom).toBe '0px' + expect(marginTop).toBe '0px' it "renders additional lines when the editor is resized", -> setEditorHeightInLines(editor, 10) @@ -425,6 +441,16 @@ describe "Editor", -> expect(editor.lines.find('.line:first').text()).toBe buffer.lineForRow(0) expect(editor.lines.find('.line:last').text()).toBe buffer.lineForRow(9) + # describe "when lines at the beginning of the buffer are not visible on screen when the editor is attached", -> + # beforeEach -> + # editor.attachToDom(heightInLines: 5.5) + + # it "only renders the visible lines, giving the first line a margin-top to account for the missing lines", -> + # expect(editor.lines.find('.line').length).toBe 6 + # expectedMarginBottom = (buffer.numLines() - 6) * editor.lineHeight + # expect(editor.lines.find('.line:last').css('margin-bottom')).toBe "#{expectedMarginBottom}px" + + describe "gutter rendering", -> it "creates a line number element for each line in the buffer", -> expect(editor.gutter.find('.line-number').length).toEqual(buffer.numLines()) diff --git a/src/app/editor.coffee b/src/app/editor.coffee index aa1fda214..f90d2dfdf 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -240,21 +240,30 @@ class Editor extends View @lineCache = [] @lines.find('.line').remove() - lastVisibleScreenRow = @getLastVisibleScreenRow() + @firstRenderedScreenRow = 0 + @lastRenderedScreenRow = @getLastVisibleScreenRow() - lineElements = @buildLineElements(0, lastVisibleScreenRow) - lineElements.last().css('margin-bottom', (@getLastScreenRow() - lastVisibleScreenRow) * @lineHeight) + lineElements = @buildLineElements(@firstRenderedScreenRow, @lastRenderedScreenRow) + lineElements.last().css('margin-bottom', (@getLastScreenRow() - @lastRenderedScreenRow) * @lineHeight) @insertLineElements(0, lineElements) updateLines: -> + firstVisibleScreenRow = @getFirstVisibleScreenRow() lastVisibleScreenRow = @getLastVisibleScreenRow() - highestRenderedScreenRow = @lines.find('.line').length - 1 - if lastVisibleScreenRow > highestRenderedScreenRow + if firstVisibleScreenRow > @firstRenderedScreenRow + @lines.find('.line:first').css('margin-top', 'inherit') + @removeLineElements(@firstRenderedScreenRow, firstVisibleScreenRow - 1) + @lines.find('.line:first').css('margin-top', firstVisibleScreenRow * @lineHeight) + + if lastVisibleScreenRow > @lastRenderedScreenRow @lines.find('.line:last').css('margin-bottom', 'inherit') - lineElements = @buildLineElements(highestRenderedScreenRow + 1, lastVisibleScreenRow) + lineElements = @buildLineElements(@lastRenderedScreenRow + 1, lastVisibleScreenRow) lineElements.last().css('margin-bottom', (@getLastScreenRow() - lastVisibleScreenRow) * @lineHeight) - @insertLineElements(highestRenderedScreenRow + 1, lineElements) + @insertLineElements(@lastRenderedScreenRow + 1, lineElements) + @lastRenderedScreenRow = lastVisibleScreenRow + + @firstRenderedScreenRow = firstVisibleScreenRow getFirstVisibleScreenRow: -> Math.floor(@scroller.scrollTop() / @lineHeight) @@ -369,7 +378,11 @@ class Editor extends View replaceLineElements: (startRow, endRow, lineElements) -> @spliceLineElements(startRow, endRow - startRow + 1, lineElements) - spliceLineElements: (startRow, rowCount, lineElements) -> + removeLineElements: (startRow, endRow) -> + @spliceLineElements(startRow, endRow - startRow + 1) + + spliceLineElements: (startScreenRow, rowCount, lineElements) -> + startRow = startScreenRow - @firstRenderedScreenRow endRow = startRow + rowCount elementToInsertBefore = @lineCache[startRow] elementsToReplace = @lineCache[startRow...endRow]