From 8338d37dde99c9952425207632525aeba791ab01 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Thu, 9 Feb 2012 17:45:18 -0700 Subject: [PATCH] WIP: LineWrapper change events cover all screen lines. Because the editor only repaints entire lines at a time, the loss of precision shouldn't matter. --- spec/atom/line-wrapper-spec.coffee | 43 +++++++++++++++++++++++++++++- src/atom/line-wrapper.coffee | 24 +++++++++++------ src/atom/range.coffee | 2 +- 3 files changed, 59 insertions(+), 10 deletions(-) diff --git a/spec/atom/line-wrapper-spec.coffee b/spec/atom/line-wrapper-spec.coffee index 3f797bc5c..6e4620207 100644 --- a/spec/atom/line-wrapper-spec.coffee +++ b/spec/atom/line-wrapper-spec.coffee @@ -39,6 +39,47 @@ describe "LineWrapper", -> changeHandler = jasmine.createSpy('changeHandler') wrapper.on 'change', changeHandler + fdescribe "when a single buffer line is updated", -> + describe "when the number of screen lines remains the same for the changed buffer line", -> + it "re-wraps the existing lines and emits a change event for all its screen lines", -> + buffer.insert([6, 28], '1234567') + expect(tokensText(wrapper.tokensForScreenRow(7))).toBe ' current < pivot ? left1234567.push(current) ' + expect(tokensText(wrapper.tokensForScreenRow(8))).toBe ': right.push(current);' + expect(tokensText(wrapper.tokensForScreenRow(9))).toBe ' }' + + expect(changeHandler).toHaveBeenCalled() + [event] = changeHandler.argsForCall[0] + expect(event.oldRange).toEqual([[7, 0], [8, 20]]) + expect(event.newRange).toEqual([[7, 0], [8, 22]]) + + describe "when the number of screen lines increases for the changed buffer line", -> + it "re-wraps and adds an additional screen line and emits a change event for all screen lines", -> + buffer.insert([6, 28], '1234567890') + expect(tokensText(wrapper.tokensForScreenRow(7))).toBe ' current < pivot ? ' + expect(tokensText(wrapper.tokensForScreenRow(8))).toBe 'left1234567890.push(current) : ' + expect(tokensText(wrapper.tokensForScreenRow(9))).toBe 'right.push(current);' + expect(tokensText(wrapper.tokensForScreenRow(10))).toBe ' }' + + expect(changeHandler).toHaveBeenCalled() + [event] = changeHandler.argsForCall[0] + expect(event.oldRange).toEqual([[7, 0], [8, 20]]) + expect(event.newRange).toEqual([[7, 0], [9, 20]]) + + describe "when the number of screen lines decreases for the changed buffer line", -> + it "re-wraps and removes a screen line and emits a change event for all screen lines", -> + buffer.change(new Range([6, 24], [6, 42]), '') + expect(tokensText(wrapper.tokensForScreenRow(7))).toBe ' current < pivot ? : right.push(current);' + expect(tokensText(wrapper.tokensForScreenRow(8))).toBe ' }' + + expect(changeHandler).toHaveBeenCalled() + [event] = changeHandler.argsForCall[0] + expect(event.oldRange).toEqual([[7, 0], [8, 20]]) + expect(event.newRange).toEqual([[7, 0], [7, 47]]) + + describe "when buffer lines are inserted", -> + + describe "when buffer lines are removed", -> + describe "when an unwrapped line is updated", -> describe "when the update does not cause the line to wrap", -> it "updates tokens for the corresponding screen line and emits a change event", -> @@ -88,7 +129,7 @@ describe "LineWrapper", -> describe "when a wrapped line is updated", -> describe "when the old text spans multiple screen lines", -> describe "when the new text spans fewer screen lines than the old text", -> - fit "updates tokens for the corresponding screen lines and emits a change event", -> + it "updates tokens for the corresponding screen lines and emits a change event", -> wrapper.setMaxLength(15) range = new Range([3, 8], [3, 47]) diff --git a/src/atom/line-wrapper.coffee b/src/atom/line-wrapper.coffee index 97ec33338..da9c397c5 100644 --- a/src/atom/line-wrapper.coffee +++ b/src/atom/line-wrapper.coffee @@ -9,19 +9,27 @@ class LineWrapper @buffer = @highlighter.buffer @buildWrappedLines() @highlighter.on 'change', (e) => - oldRange = @screenRangeFromBufferRange(e.oldRange) - oldCount = @wrappedLines[e.oldRange.start.row].screenLines.length + oldRange = new Range + + bufferRow = e.oldRange.start.row + oldRange.start.row = @firstScreenRowForBufferRow(bufferRow) + oldRange.end.row = @lastScreenRowForBufferRow(bufferRow) + oldRange.end.column = _.last(@wrappedLines[bufferRow].screenLines).textLength + @wrappedLines[e.oldRange.start.row] = @buildWrappedLineForBufferRow(e.newRange.start.row) - newCount = @wrappedLines[e.oldRange.start.row].screenLines.length - newRange = @screenRangeFromBufferRange(e.newRange) - - if newCount > oldCount - newRange.end.row = newRange.start.row + (newCount - 1) - newRange.end.column = @tokensForScreenRow(newRange.end.row).textLength + newRange = oldRange.copy() + newRange.end.row = @lastScreenRowForBufferRow(bufferRow) + newRange.end.column = _.last(@wrappedLines[bufferRow].screenLines).textLength @trigger 'change', { oldRange, newRange } + firstScreenRowForBufferRow: (bufferRow) -> + @screenPositionFromBufferPosition([bufferRow, 0]).row + + lastScreenRowForBufferRow: (bufferRow) -> + @screenPositionFromBufferPosition([bufferRow, @buffer.getLine(bufferRow).length]).row + setMaxLength: (@maxLength) -> @buildWrappedLines() diff --git a/src/atom/range.coffee b/src/atom/range.coffee index 3cf050910..5daab0192 100644 --- a/src/atom/range.coffee +++ b/src/atom/range.coffee @@ -3,7 +3,7 @@ _ = require 'underscore' module.exports = class Range - constructor: (pointA, pointB) -> + constructor: (pointA = new Point(0, 0), pointB = new Point(0, 0)) -> pointA = Point.fromObject(pointA) pointB = Point.fromObject(pointB)