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

Commit

Permalink
Merge pull request #213 from atom/ns-mb-fix-tabs-after-soft-wraps
Browse files Browse the repository at this point in the history
Re-expand tabs on wrapped lines after inserting soft-wraps
  • Loading branch information
Max Brunsfeld authored and Nathan Sobo committed Feb 17, 2017
1 parent fa44267 commit d554f8f
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 11 deletions.
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

0 comments on commit d554f8f

Please sign in to comment.