mirror of
https://github.com/atom/atom.git
synced 2026-01-25 06:48:28 -05:00
Integrate block decorations in the custom lines rendering routine
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
const {it, fit, ffit, fffit, beforeEach, afterEach, conditionPromise} = require('./async-spec-helpers')
|
||||
const {it, fit, ffit, fffit, beforeEach, afterEach, conditionPromise, timeoutPromise} = require('./async-spec-helpers')
|
||||
|
||||
const TextEditorComponent = require('../src/text-editor-component')
|
||||
const TextEditor = require('../src/text-editor')
|
||||
@@ -1268,7 +1268,7 @@ describe('TextEditorComponent', () => {
|
||||
|
||||
// move decoration2 and decoration3
|
||||
decoration2.getMarker().setHeadScreenPosition([1, 0])
|
||||
decoration3.getMarker().setHeadScreenPosition([3, 0])
|
||||
decoration3.getMarker().setHeadScreenPosition([0, 0])
|
||||
await component.getNextUpdatePromise()
|
||||
expect(component.getRenderedStartRow()).toBe(0)
|
||||
expect(component.getRenderedEndRow()).toBe(6)
|
||||
@@ -1278,24 +1278,23 @@ describe('TextEditorComponent', () => {
|
||||
getElementHeight(item4) + getElementHeight(item5) + getElementHeight(item6)
|
||||
)
|
||||
expect(tileNodeForScreenRow(component, 0).offsetHeight).toBe(
|
||||
3 * component.getLineHeight() + getElementHeight(item2)
|
||||
3 * component.getLineHeight() + getElementHeight(item2) + getElementHeight(item3)
|
||||
)
|
||||
expect(tileNodeForScreenRow(component, 3).offsetHeight).toBe(
|
||||
3 * component.getLineHeight() + getElementHeight(item3)
|
||||
3 * component.getLineHeight()
|
||||
)
|
||||
expect(element.querySelectorAll('.line').length).toBe(6)
|
||||
expect(element.contains(item1)).toBe(false)
|
||||
expect(item2.previousSibling).toBe(lineNodeForScreenRow(component, 0))
|
||||
expect(item2.nextSibling).toBe(lineNodeForScreenRow(component, 1))
|
||||
expect(item3.previousSibling).toBeNull()
|
||||
expect(item3.nextSibling).toBe(lineNodeForScreenRow(component, 3))
|
||||
expect(item3.nextSibling).toBe(lineNodeForScreenRow(component, 0))
|
||||
expect(element.contains(item4)).toBe(false)
|
||||
expect(element.contains(item5)).toBe(false)
|
||||
expect(element.contains(item6)).toBe(false)
|
||||
|
||||
// change the text
|
||||
editor.setCursorScreenPosition([0, 5])
|
||||
editor.insertNewline()
|
||||
editor.getBuffer().setTextInRange([[0, 5], [0, 5]], '\n\n')
|
||||
await component.getNextUpdatePromise()
|
||||
expect(component.getRenderedStartRow()).toBe(0)
|
||||
expect(component.getRenderedEndRow()).toBe(6)
|
||||
@@ -1305,17 +1304,17 @@ describe('TextEditorComponent', () => {
|
||||
getElementHeight(item4) + getElementHeight(item5) + getElementHeight(item6)
|
||||
)
|
||||
expect(tileNodeForScreenRow(component, 0).offsetHeight).toBe(
|
||||
3 * component.getLineHeight() + getElementHeight(item2)
|
||||
3 * component.getLineHeight() + getElementHeight(item3)
|
||||
)
|
||||
expect(tileNodeForScreenRow(component, 3).offsetHeight).toBe(
|
||||
3 * component.getLineHeight() + getElementHeight(item3)
|
||||
3 * component.getLineHeight() + getElementHeight(item2)
|
||||
)
|
||||
expect(element.querySelectorAll('.line').length).toBe(6)
|
||||
expect(element.contains(item1)).toBe(false)
|
||||
expect(item2.previousSibling).toBe(lineNodeForScreenRow(component, 1))
|
||||
expect(item2.nextSibling).toBe(lineNodeForScreenRow(component, 2))
|
||||
expect(item3.previousSibling).toBe(lineNodeForScreenRow(component, 3))
|
||||
expect(item3.nextSibling).toBe(lineNodeForScreenRow(component, 4))
|
||||
expect(item2.previousSibling).toBeNull()
|
||||
expect(item2.nextSibling).toBe(lineNodeForScreenRow(component, 3))
|
||||
expect(item3.previousSibling).toBeNull()
|
||||
expect(item3.nextSibling).toBe(lineNodeForScreenRow(component, 0))
|
||||
expect(element.contains(item4)).toBe(false)
|
||||
expect(element.contains(item5)).toBe(false)
|
||||
expect(element.contains(item6)).toBe(false)
|
||||
@@ -1331,17 +1330,17 @@ describe('TextEditorComponent', () => {
|
||||
getElementHeight(item4) + getElementHeight(item5) + getElementHeight(item6)
|
||||
)
|
||||
expect(tileNodeForScreenRow(component, 0).offsetHeight).toBe(
|
||||
3 * component.getLineHeight() + getElementHeight(item2)
|
||||
3 * component.getLineHeight() + getElementHeight(item2) + getElementHeight(item3)
|
||||
)
|
||||
expect(tileNodeForScreenRow(component, 3).offsetHeight).toBe(
|
||||
3 * component.getLineHeight() + getElementHeight(item3)
|
||||
3 * component.getLineHeight()
|
||||
)
|
||||
expect(element.querySelectorAll('.line').length).toBe(6)
|
||||
expect(element.contains(item1)).toBe(false)
|
||||
expect(item2.previousSibling).toBe(lineNodeForScreenRow(component, 0))
|
||||
expect(item2.nextSibling).toBe(lineNodeForScreenRow(component, 1))
|
||||
expect(item3.previousSibling).toBeNull()
|
||||
expect(item3.nextSibling).toBe(lineNodeForScreenRow(component, 3))
|
||||
expect(item3.nextSibling).toBe(lineNodeForScreenRow(component, 0))
|
||||
expect(element.contains(item4)).toBe(false)
|
||||
expect(element.contains(item5)).toBe(false)
|
||||
expect(element.contains(item6)).toBe(false)
|
||||
|
||||
@@ -480,8 +480,6 @@ class TextEditorComponent {
|
||||
const tileHeight = this.pixelPositionBeforeBlocksForRow(tileEndRow) - this.pixelPositionBeforeBlocksForRow(tileStartRow)
|
||||
const tileIndex = this.tileIndexForTileStartRow(tileStartRow)
|
||||
|
||||
const highlightDecorations = this.decorationsToRender.highlights.get(tileStartRow)
|
||||
|
||||
tileNodes[tileIndex] = $(LinesTileComponent, {
|
||||
key: tileIndex,
|
||||
measuredContent: this.measuredContent,
|
||||
@@ -493,8 +491,8 @@ class TextEditorComponent {
|
||||
tileStartRow, tileEndRow,
|
||||
screenLines: this.renderedScreenLines,
|
||||
lineDecorations: this.decorationsToRender.lines,
|
||||
blockDecorations: this.decorationsToRender.blocks,
|
||||
highlightDecorations,
|
||||
blockDecorations: this.decorationsToRender.blocks.get(tileStartRow),
|
||||
highlightDecorations: this.decorationsToRender.highlights.get(tileStartRow),
|
||||
displayLayer,
|
||||
lineNodesByScreenLineId,
|
||||
textNodesByScreenLineId
|
||||
@@ -946,12 +944,21 @@ class TextEditorComponent {
|
||||
|
||||
addBlockDecorationToRender (decoration, screenRange, reversed) {
|
||||
const screenPosition = reversed ? screenRange.start : screenRange.end
|
||||
let rowDecorations = this.decorationsToRender.blocks.get(screenPosition.row)
|
||||
if (rowDecorations == null) {
|
||||
rowDecorations = []
|
||||
this.decorationsToRender.blocks.set(screenPosition.row, rowDecorations)
|
||||
const tileStartRow = this.tileStartRowForRow(screenPosition.row)
|
||||
const screenLine = this.renderedScreenLines[screenPosition.row - this.getRenderedStartRow()]
|
||||
|
||||
let decorationsByScreenLine = this.decorationsToRender.blocks.get(tileStartRow)
|
||||
if (!decorationsByScreenLine) {
|
||||
decorationsByScreenLine = new Map()
|
||||
this.decorationsToRender.blocks.set(tileStartRow, decorationsByScreenLine)
|
||||
}
|
||||
rowDecorations.push(decoration)
|
||||
|
||||
let decorations = decorationsByScreenLine.get(screenLine.id)
|
||||
if (!decorations) {
|
||||
decorations = []
|
||||
decorationsByScreenLine.set(screenLine.id, decorations)
|
||||
}
|
||||
decorations.push(decoration)
|
||||
}
|
||||
|
||||
updateAbsolutePositionedDecorations () {
|
||||
@@ -2590,25 +2597,31 @@ class LinesTileComponent {
|
||||
}
|
||||
}
|
||||
|
||||
if (oldProps.blockDecorations.size !== newProps.blockDecorations.size) return true
|
||||
if (oldProps.blockDecorations && newProps.blockDecorations) {
|
||||
if (oldProps.blockDecorations.size !== newProps.blockDecorations.size) return true
|
||||
|
||||
let blockDecorationsChanged = false
|
||||
let blockDecorationsChanged = false
|
||||
|
||||
oldProps.blockDecorations.forEach((oldDecorations, row) => {
|
||||
if (!blockDecorationsChanged) {
|
||||
const newDecorations = newProps.blockDecorations.get(row)
|
||||
blockDecorationsChanged = (newDecorations == null || !arraysEqual(oldDecorations, newDecorations))
|
||||
}
|
||||
})
|
||||
if (blockDecorationsChanged) return true
|
||||
oldProps.blockDecorations.forEach((oldDecorations, screenLineId) => {
|
||||
if (!blockDecorationsChanged) {
|
||||
const newDecorations = newProps.blockDecorations.get(screenLineId)
|
||||
blockDecorationsChanged = (newDecorations == null || !arraysEqual(oldDecorations, newDecorations))
|
||||
}
|
||||
})
|
||||
if (blockDecorationsChanged) return true
|
||||
|
||||
newProps.blockDecorations.forEach((newDecorations, row) => {
|
||||
if (!blockDecorationsChanged) {
|
||||
const oldDecorations = oldProps.blockDecorations.get(row)
|
||||
blockDecorationsChanged = (oldDecorations == null)
|
||||
}
|
||||
})
|
||||
if (blockDecorationsChanged) return true
|
||||
newProps.blockDecorations.forEach((newDecorations, screenLineId) => {
|
||||
if (!blockDecorationsChanged) {
|
||||
const oldDecorations = oldProps.blockDecorations.get(screenLineId)
|
||||
blockDecorationsChanged = (oldDecorations == null)
|
||||
}
|
||||
})
|
||||
if (blockDecorationsChanged) return true
|
||||
} else if (oldProps.blockDecorations) {
|
||||
return true
|
||||
} else if (newProps.blockDecorations) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
@@ -2616,11 +2629,12 @@ class LinesTileComponent {
|
||||
|
||||
class LinesComponent {
|
||||
constructor (props) {
|
||||
this.props = {}
|
||||
const {
|
||||
width, height, tileStartRow, tileEndRow, renderedStartRow,
|
||||
screenLines, lineDecorations,
|
||||
displayLayer, lineNodesByScreenLineId, textNodesByScreenLineId
|
||||
} = this.props = props
|
||||
} = props
|
||||
|
||||
this.element = document.createElement('div')
|
||||
this.element.style.position = 'absolute'
|
||||
@@ -2644,6 +2658,8 @@ class LinesComponent {
|
||||
this.element.appendChild(component.element)
|
||||
this.lineComponents.push(component)
|
||||
}
|
||||
this.updateBlockDecorations(props)
|
||||
this.props = props
|
||||
}
|
||||
|
||||
destroy () {
|
||||
@@ -2653,11 +2669,7 @@ class LinesComponent {
|
||||
}
|
||||
|
||||
update (props) {
|
||||
var {
|
||||
width, height, tileStartRow, tileEndRow, renderedStartRow,
|
||||
screenLines, lineDecorations,
|
||||
displayLayer, lineNodesByScreenLineId, textNodesByScreenLineId
|
||||
} = props
|
||||
var {width, height} = props
|
||||
|
||||
if (this.props.width !== width) {
|
||||
this.element.style.width = width + 'px'
|
||||
@@ -2667,6 +2679,19 @@ class LinesComponent {
|
||||
this.element.style.height = height + 'px'
|
||||
}
|
||||
|
||||
this.updateLines(props)
|
||||
this.updateBlockDecorations(props)
|
||||
|
||||
this.props = props
|
||||
}
|
||||
|
||||
updateLines (props) {
|
||||
var {
|
||||
tileStartRow, tileEndRow, renderedStartRow,
|
||||
screenLines, lineDecorations,
|
||||
displayLayer, lineNodesByScreenLineId, textNodesByScreenLineId
|
||||
} = props
|
||||
|
||||
var oldScreenLines = this.props.screenLines
|
||||
var newScreenLines = screenLines
|
||||
var oldScreenLinesEndIndex = this.props.tileEndRow - this.props.renderedStartRow
|
||||
@@ -2718,7 +2743,7 @@ class LinesComponent {
|
||||
lineNodesByScreenLineId,
|
||||
textNodesByScreenLineId
|
||||
})
|
||||
this.element.insertBefore(newScreenLineComponent.element, oldScreenLineComponent.element)
|
||||
this.element.insertBefore(newScreenLineComponent.element, this.getFirstElementForScreenLine(oldScreenLine))
|
||||
newScreenLineComponents.push(newScreenLineComponent)
|
||||
|
||||
newScreenLineIndex++
|
||||
@@ -2752,8 +2777,67 @@ class LinesComponent {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.props = props
|
||||
getFirstElementForScreenLine (screenLine) {
|
||||
var blockDecorations = this.props.blockDecorations ? this.props.blockDecorations.get(screenLine.id) : null
|
||||
if (blockDecorations) {
|
||||
var blockDecorationElementsBeforeOldScreenLine = []
|
||||
for (var i = 0; i < blockDecorations.length; i++) {
|
||||
var decoration = blockDecorations[i]
|
||||
if (decoration.position !== 'after') {
|
||||
blockDecorationElementsBeforeOldScreenLine.push(
|
||||
TextEditor.viewForItem(decoration.item)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < blockDecorationElementsBeforeOldScreenLine.length; i++) {
|
||||
var blockDecorationElement = blockDecorationElementsBeforeOldScreenLine[i]
|
||||
if (!blockDecorationElementsBeforeOldScreenLine.includes(blockDecorationElement.previousSibling)) {
|
||||
return blockDecorationElement
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.props.lineNodesByScreenLineId.get(screenLine.id)
|
||||
}
|
||||
|
||||
updateBlockDecorations (props) {
|
||||
var {blockDecorations, lineNodesByScreenLineId} = props
|
||||
|
||||
if (this.props.blockDecorations) {
|
||||
this.props.blockDecorations.forEach((oldDecorations, screenLineId) => {
|
||||
var newDecorations = props.blockDecorations ? props.blockDecorations.get(screenLineId) : null
|
||||
for (var i = 0; i < oldDecorations.length; i++) {
|
||||
var oldDecoration = oldDecorations[i]
|
||||
if (newDecorations && newDecorations.includes(oldDecoration)) continue
|
||||
|
||||
var element = TextEditor.viewForItem(oldDecoration.item)
|
||||
if (element.parentElement !== this.element) continue
|
||||
|
||||
element.remove()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (props.blockDecorations) {
|
||||
props.blockDecorations.forEach((newDecorations, screenLineId) => {
|
||||
var oldDecorations = this.props.blockDecorations ? this.props.blockDecorations.get(screenLineId) : null
|
||||
for (var i = 0; i < newDecorations.length; i++) {
|
||||
var newDecoration = newDecorations[i]
|
||||
if (oldDecorations && oldDecorations.includes(newDecoration)) continue
|
||||
|
||||
var element = TextEditor.viewForItem(newDecoration.item)
|
||||
var lineNode = lineNodesByScreenLineId.get(screenLineId)
|
||||
if (newDecoration.position === 'after') {
|
||||
this.element.insertBefore(element, lineNode.nextSibling)
|
||||
} else {
|
||||
this.element.insertBefore(element, lineNode)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user