mirror of
https://github.com/atom/atom.git
synced 2026-01-24 06:18:03 -05:00
💄 Internal LineWrapper makeover
Feeling good on the inside.
This commit is contained in:
@@ -10,48 +10,48 @@ fdescribe "LineWrapper", ->
|
||||
buffer = new Buffer(require.resolve('fixtures/sample.js'))
|
||||
wrapper = new LineWrapper(50, new Highlighter(buffer))
|
||||
|
||||
describe ".segmentsForRow(row)", ->
|
||||
describe "line wrapping", ->
|
||||
describe "when the line does not need to wrap", ->
|
||||
it "returns tokens for a single segment", ->
|
||||
line = buffer.getLine(0)
|
||||
expect(line.length).toBeLessThan(50)
|
||||
segments = wrapper.segmentsForRow(0)
|
||||
expect(segments.length).toBe 1
|
||||
expect(segments[0].endColumn).toBe line.length
|
||||
screenLines = wrapper.wrappedLines[0].screenLines
|
||||
expect(screenLines.length).toBe 1
|
||||
expect(screenLines[0].endColumn).toBe line.length
|
||||
|
||||
describe "when the line needs to wrap once", ->
|
||||
it "breaks the line into 2 segments at the beginning of the first word that exceeds the max length", ->
|
||||
it "breaks the line into 2 screenLines at the beginning of the first word that exceeds the max length", ->
|
||||
line = buffer.getLine(6)
|
||||
expect(line.length).toBeGreaterThan 50
|
||||
segments = wrapper.segmentsForRow(6)
|
||||
expect(segments.length).toBe 2
|
||||
expect(segments[0].endColumn).toBe 45
|
||||
expect(segments[0].map((t) -> t.value).join('')).toBe ' current < pivot ? left.push(current) : '
|
||||
screenLines = wrapper.wrappedLines[6].screenLines
|
||||
expect(screenLines.length).toBe 2
|
||||
expect(screenLines[0].endColumn).toBe 45
|
||||
expect(screenLines[0].map((t) -> t.value).join('')).toBe ' current < pivot ? left.push(current) : '
|
||||
|
||||
expect(segments[1].endColumn).toBe 65
|
||||
expect(segments[1].map((t) -> t.value).join('')).toBe 'right.push(current);'
|
||||
expect(screenLines[1].endColumn).toBe 65
|
||||
expect(screenLines[1].map((t) -> t.value).join('')).toBe 'right.push(current);'
|
||||
|
||||
describe "when the line needs to wrap more than once", ->
|
||||
it "breaks the line into multiple segments", ->
|
||||
it "breaks the line into multiple screenLines", ->
|
||||
wrapper.setMaxLength(30)
|
||||
segments = wrapper.segmentsForRow(6)
|
||||
screenLines = wrapper.wrappedLines[6].screenLines
|
||||
|
||||
expect(segments.length).toBe 3
|
||||
expect(screenLines.length).toBe 3
|
||||
|
||||
expect(segments[0].endColumn).toBe 24
|
||||
expect(_.pluck(segments[0], 'value').join('')).toBe ' current < pivot ? '
|
||||
expect(screenLines[0].endColumn).toBe 24
|
||||
expect(_.pluck(screenLines[0], 'value').join('')).toBe ' current < pivot ? '
|
||||
|
||||
expect(segments[1].endColumn).toBe 45
|
||||
expect(_.pluck(segments[1], 'value').join('')).toBe 'left.push(current) : '
|
||||
expect(screenLines[1].endColumn).toBe 45
|
||||
expect(_.pluck(screenLines[1], 'value').join('')).toBe 'left.push(current) : '
|
||||
|
||||
expect(segments[2].endColumn).toBe 65
|
||||
expect(_.pluck(segments[2], 'value').join('')).toBe 'right.push(current);'
|
||||
expect(screenLines[2].endColumn).toBe 65
|
||||
expect(_.pluck(screenLines[2], 'value').join('')).toBe 'right.push(current);'
|
||||
|
||||
describe ".tokensForScreenRow(row)", ->
|
||||
it "returns tokens for the line fragment corresponding to the given screen row", ->
|
||||
expect(wrapper.tokensForScreenRow(3)).toEqual(wrapper.segmentsForRow(3)[0])
|
||||
expect(wrapper.tokensForScreenRow(4)).toEqual(wrapper.segmentsForRow(3)[1])
|
||||
expect(wrapper.tokensForScreenRow(5)).toEqual(wrapper.segmentsForRow(4)[0])
|
||||
expect(wrapper.tokensForScreenRow(3)).toEqual(wrapper.wrappedLines[3].screenLines[0])
|
||||
expect(wrapper.tokensForScreenRow(4)).toEqual(wrapper.wrappedLines[3].screenLines[1])
|
||||
expect(wrapper.tokensForScreenRow(5)).toEqual(wrapper.wrappedLines[4].screenLines[0])
|
||||
|
||||
describe ".screenPositionFromBufferPosition(point)", ->
|
||||
it "translates the given buffer position to a screen position, accounting for wrapped lines", ->
|
||||
|
||||
@@ -5,24 +5,21 @@ module.exports =
|
||||
class LineWrapper
|
||||
constructor: (@maxLength, @highlighter) ->
|
||||
@buffer = @highlighter.buffer
|
||||
@segmentBuffer()
|
||||
@buildWrappedLines()
|
||||
|
||||
setMaxLength: (@maxLength) ->
|
||||
@segmentBuffer()
|
||||
@buildWrappedLines()
|
||||
|
||||
segmentBuffer: ->
|
||||
@lines = @segmentRows(0, @buffer.lastRow())
|
||||
buildWrappedLines: ->
|
||||
@wrappedLines = @buildWrappedLinesForBufferRows(0, @buffer.lastRow())
|
||||
|
||||
segmentsForRow: (row) ->
|
||||
@lines[row]
|
||||
|
||||
segmentRows: (start, end) ->
|
||||
buildWrappedLinesForBufferRows: (start, end) ->
|
||||
for row in [start..end]
|
||||
@segmentRow(row)
|
||||
@buildWrappedLineForBufferRow(row)
|
||||
|
||||
segmentRow: (row) ->
|
||||
buildWrappedLineForBufferRow: (bufferRow) ->
|
||||
wordRegex = getWordRegex()
|
||||
line = @buffer.getLine(row)
|
||||
line = @buffer.getLine(bufferRow)
|
||||
|
||||
breakIndices = []
|
||||
lastBreakIndex = 0
|
||||
@@ -34,37 +31,37 @@ class LineWrapper
|
||||
breakIndices.push(startIndex)
|
||||
lastBreakIndex = startIndex
|
||||
|
||||
currentSegment = []
|
||||
currentSegment.startColumn = 0
|
||||
currentSegment.endColumn = 0
|
||||
currentSegment.textLength = 0
|
||||
segments = [currentSegment]
|
||||
currentScreenLine = []
|
||||
currentScreenLine.startColumn = 0
|
||||
currentScreenLine.endColumn = 0
|
||||
currentScreenLine.textLength = 0
|
||||
screenLines = [currentScreenLine]
|
||||
nextBreak = breakIndices.shift()
|
||||
for token in @highlighter.tokensForRow(row)
|
||||
if currentSegment.endColumn >= nextBreak
|
||||
for token in @highlighter.tokensForRow(bufferRow)
|
||||
if currentScreenLine.endColumn >= nextBreak
|
||||
nextBreak = breakIndices.shift()
|
||||
newSegment = []
|
||||
newSegment.startColumn = currentSegment.endColumn
|
||||
newSegment.endColumn = currentSegment.endColumn
|
||||
newSegment.textLength = 0
|
||||
segments.push(newSegment)
|
||||
currentSegment = newSegment
|
||||
currentSegment.push token
|
||||
currentSegment.endColumn += token.value.length
|
||||
currentSegment.textLength += token.value.length
|
||||
newScreenLine = []
|
||||
newScreenLine.startColumn = currentScreenLine.endColumn
|
||||
newScreenLine.endColumn = currentScreenLine.endColumn
|
||||
newScreenLine.textLength = 0
|
||||
screenLines.push(newScreenLine)
|
||||
currentScreenLine = newScreenLine
|
||||
currentScreenLine.push token
|
||||
currentScreenLine.endColumn += token.value.length
|
||||
currentScreenLine.textLength += token.value.length
|
||||
|
||||
segments
|
||||
{ screenLines }
|
||||
|
||||
screenPositionFromBufferPosition: (bufferPosition) ->
|
||||
bufferPosition = Point.fromObject(bufferPosition)
|
||||
row = 0
|
||||
for segments in @lines[0...bufferPosition.row]
|
||||
row += segments.length
|
||||
for wrappedLine in @wrappedLines[0...bufferPosition.row]
|
||||
row += wrappedLine.screenLines.length
|
||||
|
||||
column = bufferPosition.column
|
||||
for segment in @lines[bufferPosition.row]
|
||||
break if segment.endColumn > bufferPosition.column
|
||||
column -= segment.textLength
|
||||
for screenLine in @wrappedLines[bufferPosition.row].screenLines
|
||||
break if screenLine.endColumn > bufferPosition.column
|
||||
column -= screenLine.textLength
|
||||
row++
|
||||
|
||||
new Point(row, column)
|
||||
@@ -73,8 +70,8 @@ class LineWrapper
|
||||
screenPosition = Point.fromObject(screenPosition)
|
||||
bufferRow = 0
|
||||
currentScreenRow = 0
|
||||
for screenLines in @lines
|
||||
for screenLine in screenLines
|
||||
for wrappedLine in @wrappedLines
|
||||
for screenLine in wrappedLine.screenLines
|
||||
if currentScreenRow == screenPosition.row
|
||||
return new Point(bufferRow, screenLine.startColumn + screenPosition.column)
|
||||
currentScreenRow++
|
||||
@@ -82,7 +79,7 @@ class LineWrapper
|
||||
|
||||
tokensForScreenRow: (screenRow) ->
|
||||
currentScreenRow = 0
|
||||
for screenLines in @lines
|
||||
for screenLine in screenLines
|
||||
for wrappedLine in @wrappedLines
|
||||
for screenLine in wrappedLine.screenLines
|
||||
return screenLine if currentScreenRow == screenRow
|
||||
currentScreenRow++
|
||||
|
||||
Reference in New Issue
Block a user