mirror of
https://github.com/atom/atom.git
synced 2026-04-06 03:02:13 -04:00
Merge pull request #15486 from atom/as-highlights-outside-of-tiles
Move highlight decorations outside of tiles
This commit is contained in:
@@ -1508,7 +1508,7 @@ describe('TextEditorComponent', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('renders multi-line highlights that span across tiles', async () => {
|
||||
it('renders multi-line highlights', async () => {
|
||||
const {component, element, editor} = buildComponent({rowsPerTile: 3})
|
||||
const marker = editor.markScreenRange([[2, 4], [3, 4]])
|
||||
editor.decorateMarker(marker, {type: 'highlight', class: 'a'})
|
||||
@@ -1516,9 +1516,7 @@ describe('TextEditorComponent', () => {
|
||||
await component.getNextUpdatePromise()
|
||||
|
||||
{
|
||||
// We have 2 top-level highlight divs due to the regions being split
|
||||
// across 2 different tiles
|
||||
expect(element.querySelectorAll('.highlight.a').length).toBe(2)
|
||||
expect(element.querySelectorAll('.highlight.a').length).toBe(1)
|
||||
|
||||
const regions = element.querySelectorAll('.highlight.a .region.a')
|
||||
expect(regions.length).toBe(2)
|
||||
@@ -1539,11 +1537,10 @@ describe('TextEditorComponent', () => {
|
||||
await component.getNextUpdatePromise()
|
||||
|
||||
{
|
||||
// Still split across 2 tiles
|
||||
expect(element.querySelectorAll('.highlight.a').length).toBe(2)
|
||||
expect(element.querySelectorAll('.highlight.a').length).toBe(1)
|
||||
|
||||
const regions = element.querySelectorAll('.highlight.a .region.a')
|
||||
expect(regions.length).toBe(4) // Each tile renders its
|
||||
expect(regions.length).toBe(3)
|
||||
|
||||
const region0Rect = regions[0].getBoundingClientRect()
|
||||
expect(region0Rect.top).toBe(lineNodeForScreenRow(component, 2).getBoundingClientRect().top)
|
||||
@@ -1553,21 +1550,15 @@ describe('TextEditorComponent', () => {
|
||||
|
||||
const region1Rect = regions[1].getBoundingClientRect()
|
||||
expect(region1Rect.top).toBe(lineNodeForScreenRow(component, 3).getBoundingClientRect().top)
|
||||
expect(region1Rect.bottom).toBe(lineNodeForScreenRow(component, 4).getBoundingClientRect().top)
|
||||
expect(region1Rect.bottom).toBe(lineNodeForScreenRow(component, 5).getBoundingClientRect().top)
|
||||
expect(Math.round(region1Rect.left)).toBe(component.refs.content.getBoundingClientRect().left)
|
||||
expect(Math.round(region1Rect.right)).toBe(component.refs.content.getBoundingClientRect().right)
|
||||
|
||||
const region2Rect = regions[2].getBoundingClientRect()
|
||||
expect(region2Rect.top).toBe(lineNodeForScreenRow(component, 4).getBoundingClientRect().top)
|
||||
expect(region2Rect.bottom).toBe(lineNodeForScreenRow(component, 5).getBoundingClientRect().top)
|
||||
expect(region2Rect.top).toBe(lineNodeForScreenRow(component, 5).getBoundingClientRect().top)
|
||||
expect(region2Rect.bottom).toBe(lineNodeForScreenRow(component, 6).getBoundingClientRect().top)
|
||||
expect(Math.round(region2Rect.left)).toBe(component.refs.content.getBoundingClientRect().left)
|
||||
expect(Math.round(region2Rect.right)).toBe(component.refs.content.getBoundingClientRect().right)
|
||||
|
||||
const region3Rect = regions[3].getBoundingClientRect()
|
||||
expect(region3Rect.top).toBe(lineNodeForScreenRow(component, 5).getBoundingClientRect().top)
|
||||
expect(region3Rect.bottom).toBe(lineNodeForScreenRow(component, 5).getBoundingClientRect().bottom)
|
||||
expect(Math.round(region3Rect.left)).toBe(component.refs.content.getBoundingClientRect().left)
|
||||
expect(Math.round(region3Rect.right)).toBe(clientLeftForCharacter(component, 5, 4))
|
||||
expect(Math.round(region2Rect.right)).toBe(clientLeftForCharacter(component, 5, 4))
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1580,20 +1571,15 @@ describe('TextEditorComponent', () => {
|
||||
// Flash on initial appearence of highlight
|
||||
await component.getNextUpdatePromise()
|
||||
const highlights = element.querySelectorAll('.highlight.a')
|
||||
expect(highlights.length).toBe(2) // split across 2 tiles
|
||||
expect(highlights.length).toBe(1)
|
||||
|
||||
expect(highlights[0].classList.contains('b')).toBe(true)
|
||||
expect(highlights[1].classList.contains('b')).toBe(true)
|
||||
|
||||
await conditionPromise(() =>
|
||||
!highlights[0].classList.contains('b') &&
|
||||
!highlights[1].classList.contains('b')
|
||||
)
|
||||
await conditionPromise(() => !highlights[0].classList.contains('b'))
|
||||
|
||||
// Don't flash on next update if another flash wasn't requested
|
||||
await setScrollTop(component, 100)
|
||||
expect(highlights[0].classList.contains('b')).toBe(false)
|
||||
expect(highlights[1].classList.contains('b')).toBe(false)
|
||||
|
||||
// Flashing the same class again before the first flash completes
|
||||
// removes the flash class and adds it back on the next frame to ensure
|
||||
@@ -1601,22 +1587,13 @@ describe('TextEditorComponent', () => {
|
||||
decoration.flash('e', 100)
|
||||
await component.getNextUpdatePromise()
|
||||
expect(highlights[0].classList.contains('e')).toBe(true)
|
||||
expect(highlights[1].classList.contains('e')).toBe(true)
|
||||
|
||||
decoration.flash('e', 100)
|
||||
await component.getNextUpdatePromise()
|
||||
expect(highlights[0].classList.contains('e')).toBe(false)
|
||||
expect(highlights[1].classList.contains('e')).toBe(false)
|
||||
|
||||
await conditionPromise(() =>
|
||||
highlights[0].classList.contains('e') &&
|
||||
highlights[1].classList.contains('e')
|
||||
)
|
||||
|
||||
await conditionPromise(() =>
|
||||
!highlights[0].classList.contains('e') &&
|
||||
!highlights[1].classList.contains('e')
|
||||
)
|
||||
await conditionPromise(() => highlights[0].classList.contains('e'))
|
||||
await conditionPromise(() => !highlights[0].classList.contains('e'))
|
||||
})
|
||||
|
||||
it("flashing a highlight decoration doesn't unflash other highlight decorations", async () => {
|
||||
@@ -1628,16 +1605,14 @@ describe('TextEditorComponent', () => {
|
||||
decoration.flash('c', 1000)
|
||||
await component.getNextUpdatePromise()
|
||||
const highlights = element.querySelectorAll('.highlight.a')
|
||||
expect(highlights.length).toBe(1)
|
||||
expect(highlights[0].classList.contains('c')).toBe(true)
|
||||
expect(highlights[1].classList.contains('c')).toBe(true)
|
||||
|
||||
// Flash another class while the previously-flashed class is still highlighted
|
||||
decoration.flash('d', 100)
|
||||
await component.getNextUpdatePromise()
|
||||
expect(highlights[0].classList.contains('c')).toBe(true)
|
||||
expect(highlights[1].classList.contains('c')).toBe(true)
|
||||
expect(highlights[0].classList.contains('d')).toBe(true)
|
||||
expect(highlights[1].classList.contains('d')).toBe(true)
|
||||
})
|
||||
|
||||
it('supports layer decorations', async () => {
|
||||
@@ -2002,7 +1977,7 @@ describe('TextEditorComponent', () => {
|
||||
])
|
||||
assertLinesAreAlignedWithLineNumbers(component)
|
||||
expect(queryOnScreenLineElements(element).length).toBe(9)
|
||||
expect(item1.previousSibling.className).toBe('highlights')
|
||||
expect(item1.previousSibling).toBeNull()
|
||||
expect(item1.nextSibling).toBe(lineNodeForScreenRow(component, 0))
|
||||
expect(item2.previousSibling).toBe(lineNodeForScreenRow(component, 1))
|
||||
expect(item2.nextSibling).toBe(lineNodeForScreenRow(component, 2))
|
||||
@@ -2026,7 +2001,7 @@ describe('TextEditorComponent', () => {
|
||||
])
|
||||
assertLinesAreAlignedWithLineNumbers(component)
|
||||
expect(queryOnScreenLineElements(element).length).toBe(9)
|
||||
expect(item1.previousSibling.className).toBe('highlights')
|
||||
expect(item1.previousSibling).toBeNull()
|
||||
expect(item1.nextSibling).toBe(lineNodeForScreenRow(component, 0))
|
||||
expect(item2.previousSibling).toBe(lineNodeForScreenRow(component, 1))
|
||||
expect(item2.nextSibling).toBe(lineNodeForScreenRow(component, 2))
|
||||
@@ -2081,7 +2056,7 @@ describe('TextEditorComponent', () => {
|
||||
expect(element.contains(item1)).toBe(false)
|
||||
expect(item2.previousSibling).toBe(lineNodeForScreenRow(component, 0))
|
||||
expect(item2.nextSibling).toBe(lineNodeForScreenRow(component, 1))
|
||||
expect(item3.previousSibling.className).toBe('highlights')
|
||||
expect(item3.previousSibling).toBeNull()
|
||||
expect(item3.nextSibling).toBe(lineNodeForScreenRow(component, 0))
|
||||
expect(item4.nextSibling).toBe(lineNodeForScreenRow(component, 7))
|
||||
expect(item5.previousSibling).toBe(lineNodeForScreenRow(component, 7))
|
||||
@@ -2104,9 +2079,9 @@ describe('TextEditorComponent', () => {
|
||||
assertLinesAreAlignedWithLineNumbers(component)
|
||||
expect(queryOnScreenLineElements(element).length).toBe(9)
|
||||
expect(element.contains(item1)).toBe(false)
|
||||
expect(item2.previousSibling.className).toBe('highlights')
|
||||
expect(item2.previousSibling).toBeNull()
|
||||
expect(item2.nextSibling).toBe(lineNodeForScreenRow(component, 3))
|
||||
expect(item3.previousSibling.className).toBe('highlights')
|
||||
expect(item3.previousSibling).toBeNull()
|
||||
expect(item3.nextSibling).toBe(lineNodeForScreenRow(component, 0))
|
||||
expect(element.contains(item4)).toBe(false)
|
||||
expect(element.contains(item5)).toBe(false)
|
||||
@@ -2128,7 +2103,7 @@ describe('TextEditorComponent', () => {
|
||||
assertLinesAreAlignedWithLineNumbers(component)
|
||||
expect(queryOnScreenLineElements(element).length).toBe(9)
|
||||
expect(element.contains(item1)).toBe(false)
|
||||
expect(item2.previousSibling.className).toBe('highlights')
|
||||
expect(item2.previousSibling).toBeNull()
|
||||
expect(item2.nextSibling).toBe(lineNodeForScreenRow(component, 3))
|
||||
expect(element.contains(item3)).toBe(false)
|
||||
expect(item4.nextSibling).toBe(lineNodeForScreenRow(component, 9))
|
||||
@@ -2155,7 +2130,7 @@ describe('TextEditorComponent', () => {
|
||||
expect(element.contains(item1)).toBe(false)
|
||||
expect(item2.previousSibling).toBe(lineNodeForScreenRow(component, 0))
|
||||
expect(item2.nextSibling).toBe(lineNodeForScreenRow(component, 1))
|
||||
expect(item3.previousSibling.className).toBe('highlights')
|
||||
expect(item3.previousSibling).toBeNull()
|
||||
expect(item3.nextSibling).toBe(lineNodeForScreenRow(component, 0))
|
||||
expect(item4.nextSibling).toBe(lineNodeForScreenRow(component, 7))
|
||||
expect(item5.previousSibling).toBe(lineNodeForScreenRow(component, 7))
|
||||
@@ -2185,7 +2160,7 @@ describe('TextEditorComponent', () => {
|
||||
expect(element.contains(item1)).toBe(false)
|
||||
expect(item2.previousSibling).toBe(lineNodeForScreenRow(component, 0))
|
||||
expect(item2.nextSibling).toBe(lineNodeForScreenRow(component, 1))
|
||||
expect(item3.previousSibling.className).toBe('highlights')
|
||||
expect(item3.previousSibling).toBeNull()
|
||||
expect(item3.nextSibling).toBe(lineNodeForScreenRow(component, 0))
|
||||
expect(item4.nextSibling).toBe(lineNodeForScreenRow(component, 7))
|
||||
expect(item5.previousSibling).toBe(lineNodeForScreenRow(component, 7))
|
||||
@@ -2223,7 +2198,7 @@ describe('TextEditorComponent', () => {
|
||||
expect(element.contains(item1)).toBe(false)
|
||||
expect(item2.previousSibling).toBe(lineNodeForScreenRow(component, 0))
|
||||
expect(item2.nextSibling).toBe(lineNodeForScreenRow(component, 1))
|
||||
expect(item3.previousSibling.className).toBe('highlights')
|
||||
expect(item3.previousSibling).toBeNull()
|
||||
expect(item3.nextSibling).toBe(lineNodeForScreenRow(component, 0))
|
||||
expect(item3.nextSibling).toBe(lineNodeForScreenRow(component, 0))
|
||||
expect(item4.nextSibling).toBe(lineNodeForScreenRow(component, 7))
|
||||
@@ -2250,7 +2225,7 @@ describe('TextEditorComponent', () => {
|
||||
expect(element.contains(item1)).toBe(false)
|
||||
expect(item2.previousSibling).toBe(lineNodeForScreenRow(component, 0))
|
||||
expect(item2.nextSibling).toBe(lineNodeForScreenRow(component, 1))
|
||||
expect(item3.previousSibling.className).toBe('highlights')
|
||||
expect(item3.previousSibling).toBeNull()
|
||||
expect(item3.nextSibling).toBe(lineNodeForScreenRow(component, 0))
|
||||
expect(item4.previousSibling).toBe(lineNodeForScreenRow(component, 6))
|
||||
expect(item4.nextSibling).toBe(lineNodeForScreenRow(component, 7))
|
||||
|
||||
@@ -156,7 +156,7 @@ class TextEditorComponent {
|
||||
this.decorationsToRender = {
|
||||
lineNumbers: null,
|
||||
lines: null,
|
||||
highlights: new Map(),
|
||||
highlights: [],
|
||||
cursors: [],
|
||||
overlays: [],
|
||||
customGutter: new Map(),
|
||||
@@ -164,7 +164,7 @@ class TextEditorComponent {
|
||||
text: []
|
||||
}
|
||||
this.decorationsToMeasure = {
|
||||
highlights: new Map(),
|
||||
highlights: [],
|
||||
cursors: new Map()
|
||||
}
|
||||
this.textDecorationsByMarker = new Map()
|
||||
@@ -546,7 +546,6 @@ class TextEditorComponent {
|
||||
}
|
||||
|
||||
renderContent () {
|
||||
let children
|
||||
let style = {
|
||||
contain: 'strict',
|
||||
overflow: 'hidden',
|
||||
@@ -557,17 +556,6 @@ class TextEditorComponent {
|
||||
style.height = ceilToPhysicalPixelBoundary(this.getScrollHeight()) + 'px'
|
||||
style.willChange = 'transform'
|
||||
style.transform = `translate(${-roundToPhysicalPixelBoundary(this.getScrollLeft())}px, ${-roundToPhysicalPixelBoundary(this.getScrollTop())}px)`
|
||||
children = [
|
||||
this.renderLineTiles(),
|
||||
this.renderBlockDecorationMeasurementArea(),
|
||||
this.renderCharacterMeasurementLine()
|
||||
]
|
||||
} else {
|
||||
children = [
|
||||
this.renderLineTiles(),
|
||||
this.renderBlockDecorationMeasurementArea(),
|
||||
this.renderCharacterMeasurementLine()
|
||||
]
|
||||
}
|
||||
|
||||
return $.div(
|
||||
@@ -576,10 +564,23 @@ class TextEditorComponent {
|
||||
on: {mousedown: this.didMouseDownOnContent},
|
||||
style
|
||||
},
|
||||
children
|
||||
this.renderHighlightDecorations(),
|
||||
this.renderLineTiles(),
|
||||
this.renderBlockDecorationMeasurementArea(),
|
||||
this.renderCharacterMeasurementLine()
|
||||
)
|
||||
}
|
||||
|
||||
renderHighlightDecorations () {
|
||||
return $(HighlightsComponent, {
|
||||
hasInitialMeasurements: this.hasInitialMeasurements,
|
||||
highlightDecorations: this.decorationsToRender.highlights.slice(),
|
||||
width: this.getScrollWidth(),
|
||||
height: this.getScrollHeight(),
|
||||
lineHeight: this.getLineHeight()
|
||||
})
|
||||
}
|
||||
|
||||
renderLineTiles () {
|
||||
const children = []
|
||||
const style = {
|
||||
@@ -615,7 +616,6 @@ class TextEditorComponent {
|
||||
lineDecorations: this.decorationsToRender.lines.slice(tileStartRow - startRow, tileEndRow - startRow),
|
||||
textDecorations: this.decorationsToRender.text.slice(tileStartRow - startRow, tileEndRow - startRow),
|
||||
blockDecorations: this.decorationsToRender.blocks.get(tileStartRow),
|
||||
highlightDecorations: this.decorationsToRender.highlights.get(tileStartRow),
|
||||
displayLayer: this.props.model.displayLayer,
|
||||
nodePool: this.lineNodesPool,
|
||||
lineComponentsByScreenLineId
|
||||
@@ -963,7 +963,7 @@ class TextEditorComponent {
|
||||
this.decorationsToRender.customGutter.clear()
|
||||
this.decorationsToRender.blocks = new Map()
|
||||
this.decorationsToRender.text = []
|
||||
this.decorationsToMeasure.highlights.clear()
|
||||
this.decorationsToMeasure.highlights.length = 0
|
||||
this.decorationsToMeasure.cursors.clear()
|
||||
this.textDecorationsByMarker.clear()
|
||||
this.textDecorationBoundaries.length = 0
|
||||
@@ -1061,34 +1061,16 @@ class TextEditorComponent {
|
||||
|
||||
const {class: className, flashRequested, flashClass, flashDuration} = decoration
|
||||
decoration.flashRequested = false
|
||||
|
||||
let tileStartRow = this.tileStartRowForRow(screenRange.start.row)
|
||||
const rowsPerTile = this.getRowsPerTile()
|
||||
|
||||
while (tileStartRow <= screenRange.end.row) {
|
||||
const tileEndRow = tileStartRow + rowsPerTile
|
||||
const screenRangeInTile = constrainRangeToRows(screenRange, tileStartRow, tileEndRow)
|
||||
|
||||
let tileHighlights = this.decorationsToMeasure.highlights.get(tileStartRow)
|
||||
if (!tileHighlights) {
|
||||
tileHighlights = []
|
||||
this.decorationsToMeasure.highlights.set(tileStartRow, tileHighlights)
|
||||
}
|
||||
|
||||
tileHighlights.push({
|
||||
screenRange: screenRangeInTile,
|
||||
key,
|
||||
className,
|
||||
flashRequested,
|
||||
flashClass,
|
||||
flashDuration
|
||||
})
|
||||
|
||||
this.requestHorizontalMeasurement(screenRangeInTile.start.row, screenRangeInTile.start.column)
|
||||
this.requestHorizontalMeasurement(screenRangeInTile.end.row, screenRangeInTile.end.column)
|
||||
|
||||
tileStartRow = tileStartRow + rowsPerTile
|
||||
}
|
||||
this.decorationsToMeasure.highlights.push({
|
||||
screenRange,
|
||||
key,
|
||||
className,
|
||||
flashRequested,
|
||||
flashClass,
|
||||
flashDuration
|
||||
})
|
||||
this.requestHorizontalMeasurement(screenRange.start.row, screenRange.start.column)
|
||||
this.requestHorizontalMeasurement(screenRange.end.row, screenRange.end.column)
|
||||
}
|
||||
|
||||
addCursorDecorationToMeasure (decoration, marker, screenRange, reversed) {
|
||||
@@ -1309,18 +1291,16 @@ class TextEditorComponent {
|
||||
}
|
||||
|
||||
updateHighlightsToRender () {
|
||||
this.decorationsToRender.highlights.clear()
|
||||
this.decorationsToMeasure.highlights.forEach((highlights, tileRow) => {
|
||||
for (let i = 0, length = highlights.length; i < length; i++) {
|
||||
const highlight = highlights[i]
|
||||
const {start, end} = highlight.screenRange
|
||||
highlight.startPixelTop = this.pixelPositionAfterBlocksForRow(start.row)
|
||||
highlight.startPixelLeft = this.pixelLeftForRowAndColumn(start.row, start.column)
|
||||
highlight.endPixelTop = this.pixelPositionAfterBlocksForRow(end.row) + this.getLineHeight()
|
||||
highlight.endPixelLeft = this.pixelLeftForRowAndColumn(end.row, end.column)
|
||||
}
|
||||
this.decorationsToRender.highlights.set(tileRow, highlights)
|
||||
})
|
||||
this.decorationsToRender.highlights.length = 0
|
||||
for (let i = 0; i < this.decorationsToMeasure.highlights.length; i++) {
|
||||
const highlight = this.decorationsToMeasure.highlights[i]
|
||||
const {start, end} = highlight.screenRange
|
||||
highlight.startPixelTop = this.pixelPositionAfterBlocksForRow(start.row)
|
||||
highlight.startPixelLeft = this.pixelLeftForRowAndColumn(start.row, start.column)
|
||||
highlight.endPixelTop = this.pixelPositionAfterBlocksForRow(end.row) + this.getLineHeight()
|
||||
highlight.endPixelLeft = this.pixelLeftForRowAndColumn(end.row, end.column)
|
||||
this.decorationsToRender.highlights.push(highlight)
|
||||
}
|
||||
}
|
||||
|
||||
updateCursorsToRender () {
|
||||
@@ -3533,10 +3513,8 @@ class CursorsAndInputComponent {
|
||||
|
||||
class LinesTileComponent {
|
||||
constructor (props) {
|
||||
this.highlightComponentsByKey = new Map()
|
||||
this.props = props
|
||||
etch.initialize(this)
|
||||
this.updateHighlights()
|
||||
this.createLines()
|
||||
this.updateBlockDecorations({}, props)
|
||||
}
|
||||
@@ -3550,16 +3528,10 @@ class LinesTileComponent {
|
||||
this.updateLines(oldProps, newProps)
|
||||
this.updateBlockDecorations(oldProps, newProps)
|
||||
}
|
||||
this.updateHighlights()
|
||||
}
|
||||
}
|
||||
|
||||
destroy () {
|
||||
this.highlightComponentsByKey.forEach((highlightComponent) => {
|
||||
highlightComponent.destroy()
|
||||
})
|
||||
this.highlightComponentsByKey.clear()
|
||||
|
||||
for (let i = 0; i < this.lineComponents.length; i++) {
|
||||
this.lineComponents[i].destroy()
|
||||
}
|
||||
@@ -3580,12 +3552,7 @@ class LinesTileComponent {
|
||||
width: width + 'px',
|
||||
transform: `translateY(${top}px)`
|
||||
}
|
||||
},
|
||||
$.div({
|
||||
ref: 'highlights',
|
||||
className: 'highlights',
|
||||
style: {layout: 'contain'}
|
||||
})
|
||||
}
|
||||
// Lines and block decorations will be manually inserted here for efficiency
|
||||
)
|
||||
}
|
||||
@@ -3775,40 +3742,6 @@ class LinesTileComponent {
|
||||
}
|
||||
}
|
||||
|
||||
updateHighlights () {
|
||||
const {top, lineHeight, highlightDecorations} = this.props
|
||||
|
||||
const visibleHighlightDecorations = new Set()
|
||||
if (highlightDecorations) {
|
||||
for (let i = 0; i < highlightDecorations.length; i++) {
|
||||
const highlightDecoration = highlightDecorations[i]
|
||||
|
||||
const highlightProps = Object.assign(
|
||||
{parentTileTop: top, lineHeight},
|
||||
highlightDecorations[i]
|
||||
)
|
||||
let highlightComponent = this.highlightComponentsByKey.get(highlightDecoration.key)
|
||||
if (highlightComponent) {
|
||||
highlightComponent.update(highlightProps)
|
||||
} else {
|
||||
highlightComponent = new HighlightComponent(highlightProps)
|
||||
this.refs.highlights.appendChild(highlightComponent.element)
|
||||
this.highlightComponentsByKey.set(highlightDecoration.key, highlightComponent)
|
||||
}
|
||||
|
||||
highlightDecorations[i].flashRequested = false
|
||||
visibleHighlightDecorations.add(highlightDecoration.key)
|
||||
}
|
||||
}
|
||||
|
||||
this.highlightComponentsByKey.forEach((highlightComponent, key) => {
|
||||
if (!visibleHighlightDecorations.has(key)) {
|
||||
highlightComponent.destroy()
|
||||
this.highlightComponentsByKey.delete(key)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
shouldUpdate (newProps) {
|
||||
const oldProps = this.props
|
||||
if (oldProps.top !== newProps.top) return true
|
||||
@@ -3820,25 +3753,6 @@ class LinesTileComponent {
|
||||
if (!arraysEqual(oldProps.screenLines, newProps.screenLines)) return true
|
||||
if (!arraysEqual(oldProps.lineDecorations, newProps.lineDecorations)) return true
|
||||
|
||||
if (!oldProps.highlightDecorations && newProps.highlightDecorations) return true
|
||||
if (oldProps.highlightDecorations && !newProps.highlightDecorations) return true
|
||||
|
||||
if (oldProps.highlightDecorations && newProps.highlightDecorations) {
|
||||
if (oldProps.highlightDecorations.length !== newProps.highlightDecorations.length) return true
|
||||
|
||||
for (let i = 0, length = oldProps.highlightDecorations.length; i < length; i++) {
|
||||
const oldHighlight = oldProps.highlightDecorations[i]
|
||||
const newHighlight = newProps.highlightDecorations[i]
|
||||
if (oldHighlight.className !== newHighlight.className) return true
|
||||
if (newHighlight.flashRequested) return true
|
||||
if (oldHighlight.startPixelTop !== newHighlight.startPixelTop) return true
|
||||
if (oldHighlight.startPixelLeft !== newHighlight.startPixelLeft) return true
|
||||
if (oldHighlight.endPixelTop !== newHighlight.endPixelTop) return true
|
||||
if (oldHighlight.endPixelLeft !== newHighlight.endPixelLeft) return true
|
||||
if (!oldHighlight.screenRange.isEqual(newHighlight.screenRange)) return true
|
||||
}
|
||||
}
|
||||
|
||||
if (oldProps.blockDecorations && newProps.blockDecorations) {
|
||||
if (oldProps.blockDecorations.size !== newProps.blockDecorations.size) return true
|
||||
|
||||
@@ -4009,6 +3923,90 @@ class LineComponent {
|
||||
}
|
||||
}
|
||||
|
||||
class HighlightsComponent {
|
||||
constructor (props) {
|
||||
this.props = {}
|
||||
this.element = document.createElement('div')
|
||||
this.element.className = 'highlights'
|
||||
this.element.style.contain = 'strict'
|
||||
this.element.style.position = 'absolute'
|
||||
this.element.style.overflow = 'hidden'
|
||||
this.highlightComponentsByKey = new Map()
|
||||
this.update(props)
|
||||
}
|
||||
|
||||
destroy () {
|
||||
this.highlightComponentsByKey.forEach((highlightComponent) => {
|
||||
highlightComponent.destroy()
|
||||
})
|
||||
this.highlightComponentsByKey.clear()
|
||||
}
|
||||
|
||||
update (newProps) {
|
||||
if (this.shouldUpdate(newProps)) {
|
||||
this.props = newProps
|
||||
const {height, width, lineHeight, highlightDecorations} = this.props
|
||||
|
||||
this.element.style.height = height + 'px'
|
||||
this.element.style.width = width + 'px'
|
||||
|
||||
const visibleHighlightDecorations = new Set()
|
||||
if (highlightDecorations) {
|
||||
for (let i = 0; i < highlightDecorations.length; i++) {
|
||||
const highlightDecoration = highlightDecorations[i]
|
||||
const highlightProps = Object.assign({lineHeight}, highlightDecorations[i])
|
||||
|
||||
let highlightComponent = this.highlightComponentsByKey.get(highlightDecoration.key)
|
||||
if (highlightComponent) {
|
||||
highlightComponent.update(highlightProps)
|
||||
} else {
|
||||
highlightComponent = new HighlightComponent(highlightProps)
|
||||
this.element.appendChild(highlightComponent.element)
|
||||
this.highlightComponentsByKey.set(highlightDecoration.key, highlightComponent)
|
||||
}
|
||||
|
||||
highlightDecorations[i].flashRequested = false
|
||||
visibleHighlightDecorations.add(highlightDecoration.key)
|
||||
}
|
||||
}
|
||||
|
||||
this.highlightComponentsByKey.forEach((highlightComponent, key) => {
|
||||
if (!visibleHighlightDecorations.has(key)) {
|
||||
highlightComponent.destroy()
|
||||
this.highlightComponentsByKey.delete(key)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
shouldUpdate (newProps) {
|
||||
const oldProps = this.props
|
||||
|
||||
if (!newProps.hasInitialMeasurements) return false
|
||||
|
||||
if (oldProps.width !== newProps.width) return true
|
||||
if (oldProps.height !== newProps.height) return true
|
||||
if (oldProps.lineHeight !== newProps.lineHeight) return true
|
||||
if (!oldProps.highlightDecorations && newProps.highlightDecorations) return true
|
||||
if (oldProps.highlightDecorations && !newProps.highlightDecorations) return true
|
||||
if (oldProps.highlightDecorations && newProps.highlightDecorations) {
|
||||
if (oldProps.highlightDecorations.length !== newProps.highlightDecorations.length) return true
|
||||
|
||||
for (let i = 0, length = oldProps.highlightDecorations.length; i < length; i++) {
|
||||
const oldHighlight = oldProps.highlightDecorations[i]
|
||||
const newHighlight = newProps.highlightDecorations[i]
|
||||
if (oldHighlight.className !== newHighlight.className) return true
|
||||
if (newHighlight.flashRequested) return true
|
||||
if (oldHighlight.startPixelTop !== newHighlight.startPixelTop) return true
|
||||
if (oldHighlight.startPixelLeft !== newHighlight.startPixelLeft) return true
|
||||
if (oldHighlight.endPixelTop !== newHighlight.endPixelTop) return true
|
||||
if (oldHighlight.endPixelLeft !== newHighlight.endPixelLeft) return true
|
||||
if (!oldHighlight.screenRange.isEqual(newHighlight.screenRange)) return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class HighlightComponent {
|
||||
constructor (props) {
|
||||
this.props = props
|
||||
@@ -4054,15 +4052,12 @@ class HighlightComponent {
|
||||
}
|
||||
|
||||
render () {
|
||||
let {startPixelTop, endPixelTop} = this.props
|
||||
const {
|
||||
className, screenRange, parentTileTop, lineHeight,
|
||||
startPixelLeft, endPixelLeft
|
||||
className, screenRange, lineHeight,
|
||||
startPixelTop, startPixelLeft, endPixelTop, endPixelLeft
|
||||
} = this.props
|
||||
startPixelTop -= parentTileTop
|
||||
endPixelTop -= parentTileTop
|
||||
const regionClassName = 'region ' + className
|
||||
|
||||
let regionClassName = 'region ' + className
|
||||
let children
|
||||
if (screenRange.start.row === screenRange.end.row) {
|
||||
children = $.div({
|
||||
|
||||
@@ -70,10 +70,6 @@ atom-text-editor {
|
||||
}
|
||||
}
|
||||
|
||||
.lines {
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
background: none;
|
||||
padding: 0;
|
||||
|
||||
Reference in New Issue
Block a user