From fa971d1e75374bea2d58e51ebdbed11a3b57d1bf Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 12 Mar 2012 16:40:14 -0600 Subject: [PATCH] Render multiple lines in a single fragment --- spec/atom/editor-spec.coffee | 1 - src/atom/editor.coffee | 113 +++++++++++++---------------------- 2 files changed, 40 insertions(+), 74 deletions(-) diff --git a/spec/atom/editor-spec.coffee b/spec/atom/editor-spec.coffee index a16e8a2e1..0eb44118c 100644 --- a/spec/atom/editor-spec.coffee +++ b/spec/atom/editor-spec.coffee @@ -82,7 +82,6 @@ describe "Editor", -> expect(region1.offset().top).toBe(editor.lines.find('.line:eq(7)').offset().top) expect(region2.offset().top).toBe(editor.lines.find('.line:eq(8)').offset().top) - # Many more tests for change events in the LineWrapper spec it "handles changes to wrapped lines correctly", -> buffer.insert([6, 28], '1234567') expect(editor.lines.find('.line:eq(7)').text()).toBe ' current < pivot ? left1234567.push(current) ' diff --git a/src/atom/editor.coffee b/src/atom/editor.coffee index 971a45308..2112f9c0b 100644 --- a/src/atom/editor.coffee +++ b/src/atom/editor.coffee @@ -134,29 +134,10 @@ class Editor extends View @on 'mousemove', moveHandler $(document).one 'mouseup', => @off 'mousemove', moveHandler - buildLineElement: (screenLine) -> - { tokens } = screenLine - charWidth = @charWidth - charHeight = @charHeight - $$ -> - @div class: 'line', => - appendNbsp = true - for token in tokens - if token.type is 'fold-placeholder' - @span ' ', class: 'fold-placeholder', style: "width: #{3 * charWidth}px; height: #{charHeight}px;", 'foldId': token.fold.id, => - @div class: "ellipsis", => @raw "…" - else - appendNbsp = false - @span { class: token.type.replace('.', ' ') }, token.value - @raw ' ' if appendNbsp - renderLines: -> @lineCache = [] @lines.find('.line').remove() - for screenLine in @getScreenLines() - line = @buildLineElement(screenLine) - @lineCache.push line - @lines.append line + @insertLineElements(0, @buildLineElements(0, @lastRow())) getScreenLines: -> @renderer.getLines() @@ -179,72 +160,58 @@ class Editor extends View @setCursorScreenPosition(row: 0, column: 0) - @buffer.on 'change', (e) => - @cursor.bufferChanged(e) + @buffer.on 'change', (e) => @cursor.bufferChanged(e) + @renderer.on 'change', (e) => @handleRendererChange(e) - @renderer.on 'change', (e) => - { oldRange, newRange } = e - unless newRange.isSingleLine() and newRange.coversSameRows(oldRange) - @gutter.renderLineNumbers(@getScreenLines()) + handleRendererChange: (e) -> + { oldRange, newRange } = e + unless newRange.isSingleLine() and newRange.coversSameRows(oldRange) + @gutter.renderLineNumbers(@getScreenLines()) - @cursor.refreshScreenPosition() unless e.bufferChanged - screenLines = @linesForRows(newRange.start.row, newRange.end.row) - if newRange.end.row > oldRange.end.row - # update, then insert elements - for row in [newRange.start.row..newRange.end.row] - if row <= oldRange.end.row - @updateLineElement(row, screenLines.shift()) - else - @insertLineElement(row, screenLines.shift()) - else - # traverse in reverse... remove, then update elements - screenLines.reverse() - for row in [oldRange.end.row..oldRange.start.row] - if row > newRange.end.row - @removeLineElement(row) - else - @updateLineElement(row, screenLines.shift()) + @cursor.refreshScreenPosition() unless e.bufferChanged + lineElements = @buildLineElements(newRange.start.row, newRange.end.row) + @replaceLineElements(oldRange.start.row, oldRange.end.row, lineElements) + + buildLineElements: (startRow, endRow) -> + charWidth = @charWidth + charHeight = @charHeight + lines = @renderer.linesForRows(startRow, endRow) + $$ -> + for line in lines + @div class: 'line', => + appendNbsp = true + for token in line.tokens + if token.type is 'fold-placeholder' + @span ' ', class: 'fold-placeholder', style: "width: #{3 * charWidth}px; height: #{charHeight}px;", 'foldId': token.fold.id, => + @div class: "ellipsis", => @raw "…" + else + appendNbsp = false + @span { class: token.type.replace('.', ' ') }, token.value + @raw ' ' if appendNbsp + + insertLineElements: (row, lineElements) -> + @spliceLineElements(row, 0, lineElements) + + replaceLineElements: (startRow, endRow, lineElements) -> + @spliceLineElements(startRow, endRow - startRow + 1, lineElements) spliceLineElements: (startRow, rowCount, lineElements) -> endRow = startRow + rowCount - insertBeforeElement = @lineCache[startRow] - removeElements = $(_.map @lineCache[startRow...endRow], (elt) -> elt[0]) - @lineCache[startRow...endRow] = lineElements or [] + elementToInsertBefore = @lineCache[startRow] + elementsToReplace = @lineCache[startRow...endRow] + @lineCache[startRow...endRow] = lineElements?.toArray() or [] if lineElements - if removeElements.length - removeElements.replaceWith(lineElements) - else if insertBeforeElement - insertBeforeElement.before(lineElements) + if elementsToReplace.length + $(elementsToReplace).replaceWith(lineElements) + else if elementToInsertBefore + $(elementToInsertBefore).before(lineElements) else @lines.append(lineElements) else removeElements.remove() - - updateLineElement: (row, screenLine) -> - if @lineCache.length == 0 - @insertLineElement(row, screenLine) - else - line = @buildLineElement(screenLine) - @lineCache[row].replaceWith(line) - @lineCache[row] = line - - insertLineElement: (row, screenLine) -> - newLineElement = @buildLineElement(screenLine) - insertBefore = @getLineElement(row) - if insertBefore - @lineCache.splice(row, 0, newLineElement) - insertBefore.before(newLineElement) - else - @lineCache.push newLineElement - @lines.append newLineElement - - removeLineElement: (row) -> - [lineElement] = @lineCache.splice(row, 1) - lineElement.remove() - getLineElement: (row) -> @lineCache[row]