Skip to content
This repository has been archived by the owner on Dec 15, 2022. It is now read-only.

Re-expand tabs on wrapped lines after inserting soft-wraps #213

Merged
merged 2 commits into from Feb 17, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 15 additions & 0 deletions spec/display-layer-spec.js
Expand Up @@ -846,6 +846,21 @@ describe('DisplayLayer', () => {
expect(JSON.stringify(displayLayer.getText())).toBe(JSON.stringify('abc \ndef '))
})

it('re-expands tabs on soft-wrapped lines', () => {
const buffer = new TextBuffer({
text: 'fah\t\t\tcodexelectric valence\t ble'
})

const displayLayer = buffer.addDisplayLayer({
tabLength: 4,
softWrapColumn: 12
})

displayLayer.getText()
expect(displayLayer.indexedBufferRowCount).toBe(buffer.getLineCount())
verifyLineLengths(displayLayer)
})

it('correctly soft wraps lines when hard tabs are wider than the softWrapColumn', () => {
const buffer = new TextBuffer({
text: '\they'
Expand Down
41 changes: 30 additions & 11 deletions src/display-layer.js
Expand Up @@ -779,6 +779,7 @@ class DisplayLayer {

const insertedScreenLineLengths = []
const insertedTabCounts = []
const currentScreenLineTabColumns = []
let rightmostInsertedScreenPosition = Point(0, -1)
let bufferRow = startBufferRow
let screenRow = startScreenRow
Expand All @@ -793,11 +794,10 @@ class DisplayLayer {
let bufferLine = this.buffer.lineForRow(bufferRow)
if (bufferLine == null) break
let bufferLineLength = bufferLine.length
let tabCount = 0
currentScreenLineTabColumns.length = 0
let screenLineWidth = 0
let lastWrapBoundaryUnexpandedScreenColumn = 0
let lastWrapBoundaryExpandedScreenColumn = 0
let lastWrapBoundaryTabCount = -1
let lastWrapBoundaryScreenLineWidth = 0
let firstNonWhitespaceScreenColumn = -1

Expand All @@ -819,7 +819,6 @@ class DisplayLayer {
this.isWrapBoundary(previousCharacter, character)) {
lastWrapBoundaryUnexpandedScreenColumn = unexpandedScreenColumn
lastWrapBoundaryExpandedScreenColumn = expandedScreenColumn
lastWrapBoundaryTabCount = tabCount
lastWrapBoundaryScreenLineWidth = screenLineWidth
}
}
Expand Down Expand Up @@ -852,26 +851,46 @@ class DisplayLayer {
const unexpandedWrapColumn = lastWrapBoundaryUnexpandedScreenColumn || unexpandedScreenColumn
const expandedWrapColumn = lastWrapBoundaryExpandedScreenColumn || expandedScreenColumn
const wrapWidth = lastWrapBoundaryScreenLineWidth || screenLineWidth
const wrapTabCount = lastWrapBoundaryTabCount >= 0 ? lastWrapBoundaryTabCount : tabCount
this.spatialIndex.splice(
Point(screenRow, unexpandedWrapColumn),
Point.ZERO,
Point(1, indentLength)
)
insertedTabCounts.push(wrapTabCount)
tabCount -= wrapTabCount

insertedScreenLineLengths.push(expandedWrapColumn)
if (expandedWrapColumn > rightmostInsertedScreenPosition.column) {
rightmostInsertedScreenPosition.row = screenRow
rightmostInsertedScreenPosition.column = expandedWrapColumn
}
screenRow++
unexpandedScreenColumn = indentLength + (unexpandedScreenColumn - unexpandedWrapColumn)
expandedScreenColumn = indentLength + (expandedScreenColumn - expandedWrapColumn)

// To determine the expanded screen column following the wrap, we need
// to re-expand each tab following the wrap boundary, because tabs may
// take on different lengths due to starting at different screen columns.
let unexpandedScreenColumnAfterLastTab = indentLength
let expandedScreenColumnAfterLastTab = indentLength
let tabCountPrecedingWrap = 0
for (let i = 0; i < currentScreenLineTabColumns.length; i++) {
const tabColumn = currentScreenLineTabColumns[i]
if (tabColumn < unexpandedWrapColumn) {
tabCountPrecedingWrap++
} else {
const tabColumnAfterWrap = indentLength + tabColumn - unexpandedWrapColumn
expandedScreenColumnAfterLastTab += (tabColumnAfterWrap - unexpandedScreenColumnAfterLastTab)
expandedScreenColumnAfterLastTab += this.tabLength - (expandedScreenColumnAfterLastTab % this.tabLength)
unexpandedScreenColumnAfterLastTab = tabColumnAfterWrap + 1
currentScreenLineTabColumns[i - tabCountPrecedingWrap] = tabColumnAfterWrap
}
}
insertedTabCounts.push(tabCountPrecedingWrap)
currentScreenLineTabColumns.length -= tabCountPrecedingWrap

unexpandedScreenColumn = unexpandedScreenColumn - unexpandedWrapColumn + indentLength
expandedScreenColumn = expandedScreenColumnAfterLastTab + unexpandedScreenColumn - unexpandedScreenColumnAfterLastTab
screenLineWidth = (indentLength * this.ratioForCharacter(' ')) + (screenLineWidth - wrapWidth)

lastWrapBoundaryUnexpandedScreenColumn = 0
lastWrapBoundaryExpandedScreenColumn = 0
lastWrapBoundaryTabCount = -1
lastWrapBoundaryScreenLineWidth = 0
}

Expand All @@ -894,7 +913,7 @@ class DisplayLayer {
// If there is no fold at this position, check if we need to handle
// a hard tab at this position and advance by a single buffer column.
if (character === '\t') {
tabCount++
currentScreenLineTabColumns.push(unexpandedScreenColumn)
const distanceToNextTabStop = this.tabLength - (expandedScreenColumn % this.tabLength)
expandedScreenColumn += distanceToNextTabStop
screenLineWidth += distanceToNextTabStop * this.ratioForCharacter(' ')
Expand All @@ -909,7 +928,7 @@ class DisplayLayer {

expandedScreenColumn--
insertedScreenLineLengths.push(expandedScreenColumn)
insertedTabCounts.push(tabCount)
insertedTabCounts.push(currentScreenLineTabColumns.length)
if (expandedScreenColumn > rightmostInsertedScreenPosition.column) {
rightmostInsertedScreenPosition.row = screenRow
rightmostInsertedScreenPosition.column = expandedScreenColumn
Expand Down