Fix rendering bug when folds hide the vertical scrollbar w/ soft wrap on

This commit is contained in:
Nathan Sobo
2017-10-03 10:32:29 -06:00
parent 3a3c58e04e
commit 293b52d797
2 changed files with 45 additions and 6 deletions

View File

@@ -286,6 +286,31 @@ describe('TextEditorComponent', () => {
expect(lineNumberNodeForScreenRow(component, 0).querySelector('.foldable')).toBeNull()
})
it('gracefully handles folds that change the soft-wrap boundary by causing the vertical scrollbar to disappear (regression)', async () => {
const text = ('x'.repeat(100) + '\n') + 'y\n'.repeat(28) + ' z\n'.repeat(50)
const {component, element, editor} = buildComponent({text, height: 1000, width: 500})
element.addEventListener('scroll', (event) => {
event.stopPropagation()
}, true)
editor.setSoftWrapped(true)
jasmine.attachToDOM(element)
await component.getNextUpdatePromise()
const firstScreenLineLengthWithVerticalScrollbar = element.querySelector('.line').textContent.length
setScrollTop(component, 620)
await component.getNextUpdatePromise()
editor.foldBufferRow(28)
await component.getNextUpdatePromise()
const firstLineElement = element.querySelector('.line')
expect(firstLineElement.dataset.screenRow).toBe('0')
expect(firstLineElement.textContent.length).toBeGreaterThan(firstScreenLineLengthWithVerticalScrollbar)
})
it('shows the foldable icon on the last screen row of a buffer row that can be folded', async () => {
const {component, element, editor} = buildComponent({text: 'abc\n de\nfghijklm\n no', softWrapped: true})
await setEditorWidthInCharacters(component, 5)

View File

@@ -362,7 +362,7 @@ class TextEditorComponent {
this.requestHorizontalMeasurement(screenRange.start.row, screenRange.start.column)
this.requestHorizontalMeasurement(screenRange.end.row, screenRange.end.column)
}
this.populateVisibleRowRange()
this.populateVisibleRowRange(this.getRenderedStartRow())
this.populateVisibleTiles()
this.queryScreenLinesToRender()
this.queryLongestLine()
@@ -2096,14 +2096,29 @@ class TextEditorComponent {
return marginInBaseCharacters * this.getBaseCharacterWidth()
}
// This method is called at the beginning of a frame render to relay any
// potential changes in the editor's width into the model before proceeding.
updateModelSoftWrapColumn () {
const {model} = this.props
const newEditorWidthInChars = this.getScrollContainerClientWidthInBaseCharacters()
if (newEditorWidthInChars !== model.getEditorWidthInChars()) {
this.suppressUpdates = true
const renderedStartRow = this.getRenderedStartRow()
this.props.model.setEditorWidthInChars(newEditorWidthInChars)
// Wrapping may cause a vertical scrollbar to appear, which will change the width again.
// Relaying a change in to the editor's client width may cause the
// vertical scrollbar to appear or disappear, which causes the editor's
// client width to change *again*. Make sure the display layer is fully
// populated for the visible area before recalculating the editor's
// width in characters. Then update the display layer *again* just in
// case a change in scrollbar visibility causes lines to wrap
// differently. We capture the renderedStartRow before resetting the
// display layer because once it has been reset, we can't compute the
// rendered start row accurately. 😥
this.populateVisibleRowRange(renderedStartRow)
this.props.model.setEditorWidthInChars(this.getScrollContainerClientWidthInBaseCharacters())
this.suppressUpdates = false
}
}
@@ -2867,12 +2882,11 @@ class TextEditorComponent {
}
}
// Ensure the spatial index is populated with rows that are currently
// visible so we *at least* get the longest row in the visible range.
populateVisibleRowRange () {
// Ensure the spatial index is populated with rows that are currently visible
populateVisibleRowRange (renderedStartRow) {
const editorHeightInTiles = this.getScrollContainerHeight() / this.getLineHeight()
const visibleTileCount = Math.ceil(editorHeightInTiles) + 1
const lastRenderedRow = this.getRenderedStartRow() + (visibleTileCount * this.getRowsPerTile())
const lastRenderedRow = renderedStartRow + (visibleTileCount * this.getRowsPerTile())
this.props.model.displayLayer.populateSpatialIndexIfNeeded(Infinity, lastRenderedRow)
}