mirror of
https://github.com/atom/atom.git
synced 2026-04-06 03:02:13 -04:00
WIP: Handling display buffer changes. Cursor, selection specs failing
That's because the new CodeMirror-inspired line update code assumes that lines are the only thing in the rendered lines div.
This commit is contained in:
@@ -9,7 +9,7 @@ $ = require 'jquery'
|
||||
_ = require 'underscore'
|
||||
fs = require 'fs'
|
||||
|
||||
describe "Editor", ->
|
||||
fdescribe "Editor", ->
|
||||
[rootView, project, buffer, editor, cachedLineHeight] = []
|
||||
|
||||
getLineHeight = ->
|
||||
@@ -1205,20 +1205,15 @@ 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)
|
||||
|
||||
ffit "renders correctly when scrolling after text is added to the buffer", ->
|
||||
editor.logRenderedLines()
|
||||
it "renders correctly when scrolling after text is added to the buffer", ->
|
||||
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)
|
||||
@@ -1502,58 +1497,6 @@ describe "Editor", ->
|
||||
buffer.insert([0, 0], "–")
|
||||
expect(editor.find('.line:eq(0)').outerHeight()).toBe editor.find('.line:eq(1)').outerHeight()
|
||||
|
||||
describe ".spliceLineElements(startRow, rowCount, lineElements)", ->
|
||||
elements = null
|
||||
|
||||
beforeEach ->
|
||||
editor.attachToDom()
|
||||
elements = $$ ->
|
||||
@div "A", class: 'line'
|
||||
@div "B", class: 'line'
|
||||
|
||||
describe "when the start row is 0", ->
|
||||
describe "when the row count is 0", ->
|
||||
it "inserts the given elements before the first row", ->
|
||||
editor.spliceLineElements 0, 0, elements
|
||||
|
||||
expect(editor.renderedLines.find('.line:eq(0)').text()).toBe 'A'
|
||||
expect(editor.renderedLines.find('.line:eq(1)').text()).toBe 'B'
|
||||
expect(editor.renderedLines.find('.line:eq(2)').text()).toBe 'var quicksort = function () {'
|
||||
|
||||
describe "when the row count is > 0", ->
|
||||
it "replaces the initial rows with the given elements", ->
|
||||
editor.spliceLineElements 0, 2, elements
|
||||
|
||||
expect(editor.renderedLines.find('.line:eq(0)').text()).toBe 'A'
|
||||
expect(editor.renderedLines.find('.line:eq(1)').text()).toBe 'B'
|
||||
expect(editor.renderedLines.find('.line:eq(2)').text()).toBe ' if (items.length <= 1) return items;'
|
||||
|
||||
describe "when the start row is less than the last row", ->
|
||||
describe "when the row count is 0", ->
|
||||
it "inserts the elements at the specified location", ->
|
||||
editor.spliceLineElements 2, 0, elements
|
||||
|
||||
expect(editor.renderedLines.find('.line:eq(2)').text()).toBe 'A'
|
||||
expect(editor.renderedLines.find('.line:eq(3)').text()).toBe 'B'
|
||||
expect(editor.renderedLines.find('.line:eq(4)').text()).toBe ' if (items.length <= 1) return items;'
|
||||
|
||||
describe "when the row count is > 0", ->
|
||||
it "replaces the elements at the specified location", ->
|
||||
editor.spliceLineElements 2, 2, elements
|
||||
|
||||
expect(editor.renderedLines.find('.line:eq(2)').text()).toBe 'A'
|
||||
expect(editor.renderedLines.find('.line:eq(3)').text()).toBe 'B'
|
||||
expect(editor.renderedLines.find('.line:eq(4)').text()).toBe ' while(items.length > 0) {'
|
||||
|
||||
describe "when the start row is the last row", ->
|
||||
it "appends the elements to the end of the lines", ->
|
||||
editor.spliceLineElements 13, 0, elements
|
||||
|
||||
expect(editor.renderedLines.find('.line:eq(12)').text()).toBe '};'
|
||||
expect(editor.renderedLines.find('.line:eq(13)').text()).toBe 'A'
|
||||
expect(editor.renderedLines.find('.line:eq(14)').text()).toBe 'B'
|
||||
expect(editor.renderedLines.find('.line:eq(15)')).not.toExist()
|
||||
|
||||
describe "when editor.setShowInvisibles is called", ->
|
||||
it "displays spaces as •, tabs as ▸ and newlines as ¬ when true", ->
|
||||
editor.attachToDom()
|
||||
|
||||
@@ -42,6 +42,7 @@ class Editor extends View
|
||||
editSessions: null
|
||||
attached: false
|
||||
lineOverdraw: 100
|
||||
pendingChanges: null
|
||||
|
||||
@deserialize: (state, rootView) ->
|
||||
editSessions = state.editSessions.map (state) -> EditSession.deserialize(state, rootView.project)
|
||||
@@ -60,6 +61,7 @@ class Editor extends View
|
||||
@cursorViews = []
|
||||
@selectionViews = []
|
||||
@editSessions = []
|
||||
@pendingChanges = []
|
||||
|
||||
if editSession?
|
||||
@editSessions.push editSession
|
||||
@@ -745,16 +747,19 @@ class Editor extends View
|
||||
@firstRenderedScreenRow = null
|
||||
@lastRenderedScreenRow = null
|
||||
|
||||
updateRenderedLines: (options={}) ->
|
||||
{reset} = options
|
||||
updateRenderedLines: ->
|
||||
firstVisibleScreenRow = @getFirstVisibleScreenRow()
|
||||
lastVisibleScreenRow = @getLastVisibleScreenRow()
|
||||
|
||||
if @pendingChanges.length == 0 and @firstRenderedScreenRow <= firstVisibleScreenRow and lastVisibleScreenRow <= @lastRenderedScreenRow
|
||||
return
|
||||
|
||||
renderFrom = Math.max(0, firstVisibleScreenRow - @lineOverdraw)
|
||||
renderTo = Math.min(@getLastScreenRow(), lastVisibleScreenRow + @lineOverdraw)
|
||||
|
||||
intactRanges =
|
||||
if @firstRenderedScreenRow? and @lastRenderedScreenRow?
|
||||
[{from: @firstRenderedScreenRow, to: @lastRenderedScreenRow, domStart: 0}]
|
||||
@computeIntactRanges()
|
||||
else
|
||||
[]
|
||||
|
||||
@@ -764,6 +769,37 @@ class Editor extends View
|
||||
@firstRenderedScreenRow = renderFrom
|
||||
@lastRenderedScreenRow = renderTo
|
||||
@updatePaddingOfRenderedLines()
|
||||
@adjustMinWidthOfRenderedLines()
|
||||
# @handleScrollHeightChange()
|
||||
|
||||
computeIntactRanges: ->
|
||||
intactRanges = [{from: @firstRenderedScreenRow, to: @lastRenderedScreenRow, domStart: 0}]
|
||||
for change in @pendingChanges
|
||||
newIntactRanges = []
|
||||
delta = change.delta
|
||||
for range in intactRanges
|
||||
if change.to < range.from and change.delta != 0
|
||||
newIntactRanges.push(
|
||||
from: range.from + delta
|
||||
to: range.to + delta
|
||||
domStart: range.domStart
|
||||
)
|
||||
else if change.to < range.from or change.from > range.to
|
||||
newIntactRanges.push(range)
|
||||
else
|
||||
if change.from > range.from
|
||||
newIntactRanges.push(
|
||||
from: range.from
|
||||
to: change.from - 1
|
||||
domStart: range.domStart)
|
||||
if change.to < range.to
|
||||
newIntactRanges.push(
|
||||
from: change.to + delta + 1
|
||||
to: range.to + delta
|
||||
domStart: range.domStart + change.to + 1 - range.from
|
||||
)
|
||||
intactRanges = newIntactRanges
|
||||
intactRanges
|
||||
|
||||
truncateIntactRanges: (intactRanges, renderFrom, renderTo) ->
|
||||
i = 0
|
||||
@@ -831,63 +867,12 @@ class Editor extends View
|
||||
Math.ceil((@scrollTop() + @scrollView.height()) / @lineHeight) - 1
|
||||
|
||||
handleDisplayBufferChange: (e) ->
|
||||
oldScreenRange = e.oldRange
|
||||
newScreenRange = e.newRange
|
||||
|
||||
if @attached
|
||||
@handleScrollHeightChange() unless newScreenRange.coversSameRows(oldScreenRange)
|
||||
@adjustMinWidthOfRenderedLines()
|
||||
|
||||
return if oldScreenRange.start.row > @lastRenderedScreenRow
|
||||
|
||||
maxEndRow = Math.max(@getLastVisibleScreenRow() + @lineOverdraw, @lastRenderedScreenRow)
|
||||
@gutter.renderLineNumbers(@firstRenderedScreenRow, maxEndRow) if e.lineNumbersChanged
|
||||
|
||||
newScreenRange = newScreenRange.copy()
|
||||
oldScreenRange = oldScreenRange.copy()
|
||||
endOfShortestRange = Math.min(oldScreenRange.end.row, newScreenRange.end.row)
|
||||
|
||||
delta = @firstRenderedScreenRow - endOfShortestRange
|
||||
if delta > 0
|
||||
newScreenRange.start.row += delta
|
||||
newScreenRange.end.row += delta
|
||||
oldScreenRange.start.row += delta
|
||||
oldScreenRange.end.row += delta
|
||||
|
||||
oldScreenRange.start.row = Math.max(oldScreenRange.start.row, @firstRenderedScreenRow)
|
||||
oldScreenRange.end.row = Math.min(oldScreenRange.end.row, @lastRenderedScreenRow)
|
||||
newScreenRange.start.row = Math.max(newScreenRange.start.row, @firstRenderedScreenRow)
|
||||
newScreenRange.end.row = Math.min(newScreenRange.end.row, maxEndRow)
|
||||
|
||||
lineElements = @buildLineElements(newScreenRange.start.row, newScreenRange.end.row)
|
||||
@replaceLineElements(oldScreenRange.start.row, oldScreenRange.end.row, lineElements)
|
||||
|
||||
rowDelta = newScreenRange.end.row - oldScreenRange.end.row
|
||||
@lastRenderedScreenRow += rowDelta
|
||||
@updateRenderedLines() if rowDelta < 0
|
||||
|
||||
if @lastRenderedScreenRow > maxEndRow
|
||||
@removeLineElements(maxEndRow + 1, @lastRenderedScreenRow)
|
||||
@lastRenderedScreenRow = maxEndRow
|
||||
@updatePaddingOfRenderedLines()
|
||||
|
||||
@highlightCursorLine()
|
||||
|
||||
buildLineElements: (startRow, endRow) ->
|
||||
charWidth = @charWidth
|
||||
charHeight = @charHeight
|
||||
lines = @activeEditSession.linesForScreenRows(startRow, endRow)
|
||||
activeEditSession = @activeEditSession
|
||||
cursorScreenRow = @getCursorScreenPosition().row
|
||||
mini = @mini
|
||||
|
||||
buildLineHtml = (line) => @buildLineHtml(line)
|
||||
|
||||
$$ ->
|
||||
row = startRow
|
||||
for line in lines
|
||||
@raw(buildLineHtml(line))
|
||||
row++
|
||||
{ oldRange, newRange } = e
|
||||
from = oldRange.start.row
|
||||
to = oldRange.end.row
|
||||
delta = newRange.end.row - oldRange.end.row
|
||||
@pendingChanges.push({from, to, delta})
|
||||
@updateRenderedLines()
|
||||
|
||||
buildLineElementForScreenRow: (screenRow) ->
|
||||
div = document.createElement('div')
|
||||
@@ -955,41 +940,6 @@ class Editor extends View
|
||||
line.push('</pre>')
|
||||
line.join('')
|
||||
|
||||
insertLineElements: (row, lineElements) ->
|
||||
@spliceLineElements(row, 0, lineElements)
|
||||
|
||||
replaceLineElements: (startRow, endRow, lineElements) ->
|
||||
@spliceLineElements(startRow, endRow - startRow + 1, lineElements)
|
||||
|
||||
removeLineElements: (startRow, endRow) ->
|
||||
@spliceLineElements(startRow, endRow - startRow + 1)
|
||||
|
||||
spliceLineElements: (startScreenRow, rowCount, lineElements) ->
|
||||
throw new Error("Splicing at a negative start row: #{startScreenRow}") if startScreenRow < 0
|
||||
|
||||
if startScreenRow < @firstRenderedScreenRow
|
||||
startRow = 0
|
||||
else
|
||||
startRow = startScreenRow - @firstRenderedScreenRow
|
||||
|
||||
endRow = startRow + rowCount
|
||||
|
||||
elementToInsertBefore = @lineCache[startRow]
|
||||
elementsToReplace = @lineCache[startRow...endRow]
|
||||
@lineCache[startRow...endRow] = lineElements?.toArray() or []
|
||||
|
||||
lines = @renderedLines[0]
|
||||
if lineElements
|
||||
fragment = document.createDocumentFragment()
|
||||
lineElements.each -> fragment.appendChild(this)
|
||||
if elementToInsertBefore
|
||||
lines.insertBefore(fragment, elementToInsertBefore)
|
||||
else
|
||||
lines.appendChild(fragment)
|
||||
|
||||
elementsToReplace.forEach (element) =>
|
||||
lines.removeChild(element)
|
||||
|
||||
lineElementForScreenRow: (screenRow) ->
|
||||
element = @lineCache[screenRow - @firstRenderedScreenRow]
|
||||
$(element)
|
||||
|
||||
Reference in New Issue
Block a user