Render multiple lines in a single fragment

This commit is contained in:
Nathan Sobo
2012-03-12 16:40:14 -06:00
parent 86cc45f4da
commit fa971d1e75
2 changed files with 40 additions and 74 deletions

View File

@@ -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) '

View File

@@ -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 "&hellip;"
else
appendNbsp = false
@span { class: token.type.replace('.', ' ') }, token.value
@raw '&nbsp;' 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 "&hellip;"
else
appendNbsp = false
@span { class: token.type.replace('.', ' ') }, token.value
@raw '&nbsp;' 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]