Start integrating tree-based LineTopIndex

This commit is contained in:
Antonio Scandurra
2015-12-18 10:41:21 +01:00
parent 3256c8b503
commit 6a403e441e
7 changed files with 18 additions and 122 deletions

View File

@@ -35,6 +35,7 @@
"jquery": "^2.1.1",
"key-path-helpers": "^0.4.0",
"less-cache": "0.22",
"line-top-index": "0.1.0",
"marked": "^0.3.4",
"normalize-package-data": "^2.0.0",
"nslog": "^3",

View File

@@ -1,5 +1,5 @@
LinesYardstick = require '../src/lines-yardstick'
LineTopIndex = require '../src/linear-line-top-index'
LineTopIndex = require 'line-top-index'
{toArray} = require 'underscore-plus'
describe "LinesYardstick", ->

View File

@@ -5,7 +5,7 @@ TextBuffer = require 'text-buffer'
TextEditor = require '../src/text-editor'
TextEditorPresenter = require '../src/text-editor-presenter'
FakeLinesYardstick = require './fake-lines-yardstick'
LineTopIndex = require '../src/linear-line-top-index'
LineTopIndex = require 'line-top-index'
describe "TextEditorPresenter", ->
# These `describe` and `it` blocks mirror the structure of the ::state object.

View File

@@ -29,10 +29,10 @@ class BlockDecorationsPresenter {
observeModel () {
this.disposables.add(this.model.onDidAddDecoration(this.didAddDecoration.bind(this)))
this.disposables.add(this.model.onDidChange((changeEvent) => {
let oldExtent = changeEvent.end - changeEvent.start
let newExtent = Math.max(0, changeEvent.end - changeEvent.start + changeEvent.screenDelta)
this.lineTopIndex.splice(changeEvent.start, oldExtent, newExtent)
this.disposables.add(this.model.buffer.onDidChange((changeEvent) => {
let oldExtent = changeEvent.oldRange.getExtent()
let newExtent = changeEvent.newRange.getExtent()
this.lineTopIndex.splice(changeEvent.oldRange.start, oldExtent, newExtent)
}))
for (let decoration of this.model.getDecorations({type: 'block'})) {
@@ -79,8 +79,7 @@ class BlockDecorationsPresenter {
this.didDestroyDecoration(decoration)
})
let screenRow = decoration.getMarker().getHeadScreenPosition().row
this.lineTopIndex.insertBlock(decoration.getId(), screenRow, 0)
this.lineTopIndex.insertBlock(decoration.getId(), decoration.getMarker().getHeadBufferPosition(), true, 0)
this.observedDecorations.add(decoration)
this.disposables.add(didMoveDisposable)
@@ -94,8 +93,7 @@ class BlockDecorationsPresenter {
return
}
let newScreenRow = decoration.getMarker().getHeadScreenPosition().row
this.lineTopIndex.moveBlock(decoration.getId(), newScreenRow)
this.lineTopIndex.moveBlock(decoration.getId(), decoration.getMarker().getHeadBufferPosition())
this.emitter.emit('did-update-state')
}

View File

@@ -1,107 +0,0 @@
"use babel"
export default class LineTopIndex {
constructor (params = {}) {
this.blocks = []
this.maxRow = params.maxRow || 0
this.setDefaultLineHeight(params.defaultLineHeight || 0)
}
setDefaultLineHeight (lineHeight) {
this.defaultLineHeight = lineHeight
}
getMaxRow () {
return this.maxRow
}
insertBlock (id, row, height) {
this.blocks.push({id, row, height})
this.blocks.sort((a, b) => a.row - b.row)
}
resizeBlock (id, height) {
let block = this.blocks.find((block) => block.id === id)
if (block) {
block.height = height
}
}
moveBlock (id, newRow) {
let block = this.blocks.find((block) => block.id === id)
if (block) {
block.row = newRow
this.blocks.sort((a, b) => a.row - b.row)
}
}
removeBlock (id) {
let index = this.blocks.findIndex((block) => block.id === id)
if (index !== -1) {
this.blocks.splice(index, 1)
}
}
allBlocks () {
return this.blocks
}
blocksHeightForRow (row) {
let blocksForRow = this.blocks.filter((block) => block.row === row)
return blocksForRow.reduce((a, b) => a + b.height, 0)
}
splice (startRow, oldExtent, newExtent) {
this.blocks.forEach(function (block) {
if (block.row >= startRow) {
if (block.row >= startRow + oldExtent) {
block.row += newExtent - oldExtent
} else {
block.row = startRow + newExtent
}
}
})
this.maxRow = this.maxRow + newExtent - oldExtent
}
pixelPositionForRow (row) {
row = Math.min(row, this.maxRow)
let linesHeight = row * this.defaultLineHeight
let blocksHeight = this.blocks.filter((block) => block.row <= row).reduce((a, b) => a + b.height, 0)
return linesHeight + blocksHeight
}
rowForPixelPosition (top, strategy) {
const roundingStrategy = strategy || 'floor'
let blocksHeight = 0
let lastRow = 0
let lastTop = 0
for (let block of this.blocks) {
let nextBlocksHeight = blocksHeight + block.height
let linesHeight = block.row * this.defaultLineHeight
if (nextBlocksHeight + linesHeight > top) {
while (lastRow < block.row && lastTop + this.defaultLineHeight <= top) {
lastTop += this.defaultLineHeight
lastRow++
}
return lastRow
} else {
blocksHeight = nextBlocksHeight
lastRow = block.row
lastTop = blocksHeight + linesHeight
}
}
let remainingHeight = Math.max(0, top - lastTop)
let remainingRows = Math.min(this.maxRow, lastRow + remainingHeight / this.defaultLineHeight)
switch (roundingStrategy) {
case 'floor':
return Math.floor(remainingRows)
case 'ceil':
return Math.ceil(remainingRows)
default:
throw new Error(`Cannot use '${roundingStrategy}' as a rounding strategy!`)
}
}
}

View File

@@ -14,7 +14,7 @@ OverlayManager = require './overlay-manager'
DOMElementPool = require './dom-element-pool'
LinesYardstick = require './lines-yardstick'
BlockDecorationsComponent = require './block-decorations-component'
LineTopIndex = require './linear-line-top-index'
LineTopIndex = require 'line-top-index'
module.exports =
class TextEditorComponent

View File

@@ -617,7 +617,8 @@ class TextEditorPresenter
line = @model.tokenizedLineForScreenRow(screenRow)
decorationClasses = @lineNumberDecorationClassesForRow(screenRow)
foldable = @model.isFoldableAtScreenRow(screenRow)
blockDecorationsHeight = @lineTopIndex.blocksHeightForRow(screenRow)
previousRowBottomPixelPosition = @lineTopIndex.pixelPositionForRow(screenRow - 1) + @lineHeight
blockDecorationsHeight = @lineTopIndex.pixelPositionForRow(screenRow) - previousRowBottomPixelPosition
tileState.lineNumbers[line.id] = {screenRow, bufferRow, softWrapped, decorationClasses, foldable, blockDecorationsHeight}
visibleLineNumberIds[line.id] = true
@@ -630,12 +631,15 @@ class TextEditorPresenter
updateStartRow: ->
return unless @scrollTop? and @lineHeight?
@startRow = Math.max(0, @lineTopIndex.rowForPixelPosition(@scrollTop, "floor"))
@startRow = Math.max(0, @lineTopIndex.rowForPixelPosition(@scrollTop))
updateEndRow: ->
return unless @scrollTop? and @lineHeight? and @height?
@endRow = @lineTopIndex.rowForPixelPosition(@scrollTop + @height + @lineHeight, 'ceil')
@endRow = Math.min(
@model.getScreenLineCount(),
@lineTopIndex.rowForPixelPosition(@scrollTop + @height + @lineHeight)
)
updateRowsPerPage: ->
rowsPerPage = Math.floor(@getClientHeight() / @lineHeight)
@@ -667,7 +671,7 @@ class TextEditorPresenter
updateVerticalDimensions: ->
if @lineHeight?
oldContentHeight = @contentHeight
@contentHeight = Math.round(@lineTopIndex.pixelPositionForRow(Infinity))
@contentHeight = Math.round(@lineTopIndex.pixelPositionForRow(@model.getScreenLineCount()))
if @contentHeight isnt oldContentHeight
@updateHeight()