From 82fb49fd1ed5bcc4e4c69df744c577e4854c5797 Mon Sep 17 00:00:00 2001 From: Corey Johnson & Nathan Sobo Date: Wed, 8 Feb 2012 13:15:27 -0700 Subject: [PATCH] :lipstick: Internal LineWrapper makeover Feeling good on the inside. --- spec/atom/line-wrapper-spec.coffee | 46 +++++++++---------- src/atom/line-wrapper.coffee | 71 ++++++++++++++---------------- 2 files changed, 57 insertions(+), 60 deletions(-) diff --git a/spec/atom/line-wrapper-spec.coffee b/spec/atom/line-wrapper-spec.coffee index 710409fc3..2c67079ae 100644 --- a/spec/atom/line-wrapper-spec.coffee +++ b/spec/atom/line-wrapper-spec.coffee @@ -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", -> diff --git a/src/atom/line-wrapper.coffee b/src/atom/line-wrapper.coffee index 5e8ffd90b..6d9328fbc 100644 --- a/src/atom/line-wrapper.coffee +++ b/src/atom/line-wrapper.coffee @@ -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++