From 9b83ce6545bb04d8028e2a3fe76167052d765820 Mon Sep 17 00:00:00 2001 From: Corey Johnson & Nathan Sobo Date: Thu, 24 May 2012 11:17:37 -0700 Subject: [PATCH] renderer tells editor when the gutter needs to be updated --- benchmark/benchmark-suite.coffee | 2 +- spec/app/editor-spec.coffee | 10 +++++++++- spec/app/renderer-spec.coffee | 27 +++++++++++++++++++++++++++ src/app/editor.coffee | 4 ++-- src/app/renderer.coffee | 18 +++++++++++------- 5 files changed, 50 insertions(+), 11 deletions(-) diff --git a/benchmark/benchmark-suite.coffee b/benchmark/benchmark-suite.coffee index 276c330ac..9c1fc04ba 100644 --- a/benchmark/benchmark-suite.coffee +++ b/benchmark/benchmark-suite.coffee @@ -27,7 +27,7 @@ describe "editor.", -> editor.setBuffer new Buffer(require.resolve('fixtures/medium.coffee')) describe "at-begining.", -> - benchmark "insert-delete", -> + fbenchmark "insert-delete", -> editor.insertText('x') editor.backspace() diff --git a/spec/app/editor-spec.coffee b/spec/app/editor-spec.coffee index 01b7885d6..49ea60881 100644 --- a/spec/app/editor-spec.coffee +++ b/spec/app/editor-spec.coffee @@ -583,11 +583,19 @@ describe "Editor", -> expect(editor.gutter.find('.line-number:eq(5)').text()).toBe '5' describe "when there are folds", -> - it "skips line numbers", -> + it "skips line numbers covered by the fold and updates them when the fold changes", -> editor.createFold(3, 5) expect(editor.gutter.find('.line-number:eq(3)').text()).toBe '4' expect(editor.gutter.find('.line-number:eq(4)').text()).toBe '7' + buffer.insert([4,0], "\n\n") + expect(editor.gutter.find('.line-number:eq(3)').text()).toBe '4' + expect(editor.gutter.find('.line-number:eq(4)').text()).toBe '9' + + buffer.delete([[3,0], [6,0]]) + expect(editor.gutter.find('.line-number:eq(3)').text()).toBe '4' + expect(editor.gutter.find('.line-number:eq(4)').text()).toBe '6' + describe "when the scrollView is scrolled to the right", -> it "adds a drop shadow to the gutter", -> editor.attachToDom() diff --git a/spec/app/renderer-spec.coffee b/spec/app/renderer-spec.coffee index da184e3c2..5f292e75f 100644 --- a/spec/app/renderer-spec.coffee +++ b/spec/app/renderer-spec.coffee @@ -10,6 +10,13 @@ describe "Renderer", -> changeHandler = jasmine.createSpy 'changeHandler' renderer.on 'change', changeHandler + describe "when the buffer changes", -> + it "renders line numbers correctly", -> + originalLineCount = renderer.lineCount() + oneHundredLines = [0..100].join("\n") + buffer.insert([0,0], oneHundredLines) + expect(renderer.lineCount()).toBe 100 + originalLineCount + describe "soft wrapping", -> beforeEach -> renderer.setMaxLineLength(50) @@ -55,6 +62,7 @@ describe "Renderer", -> [[event]]= changeHandler.argsForCall expect(event.oldRange).toEqual([[7, 0], [8, 20]]) expect(event.newRange).toEqual([[7, 0], [7, 47]]) + expect(event.lineNumbersChanged).toBeTruthy() describe "when the update causes a line to softwrap an additional time", -> it "rewraps the line and emits a change event", -> @@ -68,6 +76,7 @@ describe "Renderer", -> [[event]] = changeHandler.argsForCall expect(event.oldRange).toEqual([[7, 0], [8, 20]]) expect(event.newRange).toEqual([[7, 0], [9, 20]]) + expect(event.lineNumbersChanged).toBeTruthy() describe "when buffer lines are inserted", -> it "inserts / updates wrapped lines and emits a change event", -> @@ -81,6 +90,7 @@ describe "Renderer", -> [event] = changeHandler.argsForCall[0] expect(event.oldRange).toEqual([[7, 0], [8, 20]]) expect(event.newRange).toEqual([[7, 0], [10, 20]]) + expect(event.lineNumbersChanged).toBeTruthy() describe "when buffer lines are removed", -> it "removes lines and emits a change event", -> @@ -94,6 +104,7 @@ describe "Renderer", -> [event] = changeHandler.argsForCall[0] expect(event.oldRange).toEqual([[3, 0], [11, 45]]) expect(event.newRange).toEqual([[3, 0], [5, 45]]) + expect(event.lineNumbersChanged).toBeTruthy() describe "position translation", -> it "translates positions accounting for wrapped lines", -> @@ -128,6 +139,7 @@ describe "Renderer", -> [event] = changeHandler.argsForCall[0] expect(event.oldRange).toEqual([[0, 0], [15, 2]]) expect(event.newRange).toEqual([[0, 0], [18, 2]]) + expect(event.lineNumbersChanged).toBeTruthy() describe "folding", -> beforeEach -> @@ -151,6 +163,7 @@ describe "Renderer", -> [event] = changeHandler.argsForCall[0] expect(event.oldRange).toEqual [[4, 0], [7, 1]] expect(event.newRange).toEqual [[4, 0], [4, 101]] + expect(event.lineNumbersChanged).toBeTruthy() changeHandler.reset() fold.destroy() @@ -165,6 +178,7 @@ describe "Renderer", -> [[event]] = changeHandler.argsForCall expect(event.oldRange).toEqual [[4, 0], [4, 101]] expect(event.newRange).toEqual [[4, 0], [7, 1]] + expect(event.lineNumbersChanged).toBeTruthy() describe "when a fold spans a single line", -> it "renders a fold placeholder for the folded line but does not skip any lines", -> @@ -181,6 +195,10 @@ describe "Renderer", -> [[event]] = changeHandler.argsForCall expect(event.oldRange).toEqual [[4, 0], [4, 101]] expect(event.newRange).toEqual [[4, 0], [4, 101]] + + # Line numbers don't actually change, but it's not worth the complexity to have this + # be false for single line folds since they are so rare + expect(event.lineNumbersChanged).toBeTruthy() changeHandler.reset() fold.destroy() @@ -196,6 +214,7 @@ describe "Renderer", -> [[event]] = changeHandler.argsForCall expect(event.oldRange).toEqual [[4, 0], [4, 101]] expect(event.newRange).toEqual [[4, 0], [4, 101]] + expect(event.lineNumbersChanged).toBeTruthy() changeHandler.reset() describe "when a fold is nested within another fold", -> @@ -255,6 +274,7 @@ describe "Renderer", -> [[event]] = changeHandler.argsForCall expect(event.oldRange).toEqual [[1, 0], [3, 1]] expect(event.newRange).toEqual [[1, 0], [1, 6]] + expect(event.lineNumbersChanged).toBeTruthy() describe "when the old range surrounds two nested folds", -> it "removes both folds and replaces the selection with the new text", -> @@ -271,6 +291,7 @@ describe "Renderer", -> [[event]] = changeHandler.argsForCall expect(event.oldRange).toEqual [[1, 0], [3, 2]] expect(event.newRange).toEqual [[1, 0], [1, 9]] + expect(event.lineNumbersChanged).toBeTruthy() describe "when the old range precedes lines with a fold", -> it "updates the buffer and re-positions subsequent folds", -> @@ -286,6 +307,7 @@ describe "Renderer", -> [[event]] = changeHandler.argsForCall expect(event.oldRange).toEqual [[0, 0], [1, 1]] expect(event.newRange).toEqual [[0, 0], [0, 3]] + expect(event.lineNumbersChanged).toBeTruthy() changeHandler.reset() fold1.destroy() @@ -300,6 +322,7 @@ describe "Renderer", -> [[event]] = changeHandler.argsForCall expect(event.oldRange).toEqual [[1, 0], [1, 1]] expect(event.newRange).toEqual [[1, 0], [3, 101]] + expect(event.lineNumbersChanged).toBeTruthy() describe "when the old range straddles the beginning of a fold", -> it "replaces lines in the portion of the range that precedes the fold and adjusts the end of the fold to encompass additional lines", -> @@ -326,6 +349,7 @@ describe "Renderer", -> [[event]] = changeHandler.argsForCall expect(event.oldRange).toEqual [[6, 0], [7, 2]] # Expands ranges to encompes entire line expect(event.newRange).toEqual [[6, 0], [6, 5]] + expect(event.lineNumbersChanged).toBeTruthy() describe "when the old range is inside a fold", -> describe "when the end of the new range precedes the end of the fold", -> @@ -346,6 +370,7 @@ describe "Renderer", -> [[event]] = changeHandler.argsForCall expect(event.oldRange).toEqual [[2, 0], [2, 1]] expect(event.newRange).toEqual [[2, 0], [2, 1]] + expect(event.lineNumbersChanged).toBeTruthy() describe "when the end of the new range exceeds the end of the fold", -> it "expands the fold to contain all the inserted lines", -> @@ -365,6 +390,7 @@ describe "Renderer", -> [[event]] = changeHandler.argsForCall expect(event.oldRange).toEqual [[2, 0], [2, 1]] expect(event.newRange).toEqual [[2, 0], [2, 1]] + expect(event.lineNumbersChanged).toBeTruthy() describe "when the old range straddles the end of the fold", -> describe "when the end of the new range precedes the end of the fold", -> @@ -390,6 +416,7 @@ describe "Renderer", -> [[event]] = changeHandler.argsForCall expect(event.oldRange).toEqual [[3, 0], [3, 1]] expect(event.newRange).toEqual [[3, 0], [4, 1]] + expect(event.lineNumbersChanged).toBeTruthy() describe "position translation", -> it "translates positions to account for folded lines and characters and the placeholder", -> diff --git a/src/app/editor.coffee b/src/app/editor.coffee index 8031abdc2..ca4f59db0 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -424,7 +424,7 @@ class Editor extends View @compositeCursor.updateBufferPosition() unless e.bufferChanged if @attached - unless newScreenRange.isSingleLine() and newScreenRange.coversSameRows(oldScreenRange) + if e.lineNumbersChanged @gutter.renderLineNumbers(@getFirstVisibleScreenRow(), @getLastVisibleScreenRow()) @verticalScrollbarContent.height(@lineHeight * @screenLineCount()) @@ -454,7 +454,7 @@ class Editor extends View if rowDelta > 0 @removeLineElements(@lastRenderedScreenRow + 1, @lastRenderedScreenRow + rowDelta) - else + else if rowDelta < 0 @lastRenderedScreenRow += rowDelta @updateVisibleLines() diff --git a/src/app/renderer.coffee b/src/app/renderer.coffee index d4861ee0e..633d5c255 100644 --- a/src/app/renderer.coffee +++ b/src/app/renderer.coffee @@ -37,7 +37,7 @@ class Renderer oldRange = @rangeForAllLines() @buildLineMap() newRange = @rangeForAllLines() - @trigger 'change', { oldRange, newRange } + @trigger 'change', { oldRange, newRange, lineNumbersChanged: true } lineForRow: (row) -> @lineMap.lineForScreenRow(row) @@ -62,7 +62,7 @@ class Renderer @lineMap.replaceScreenRows(oldScreenRange.start.row, oldScreenRange.end.row, lines) newScreenRange = @screenLineRangeForBufferRange(bufferRange) - @trigger 'change', oldRange: oldScreenRange, newRange: newScreenRange + @trigger 'change', oldRange: oldScreenRange, newRange: newScreenRange, lineNumbersChanged: true @trigger 'fold', bufferRange fold @@ -76,7 +76,7 @@ class Renderer @lineMap.replaceScreenRows(oldScreenRange.start.row, oldScreenRange.end.row, lines) newScreenRange = @screenLineRangeForBufferRange(bufferRange) - @trigger 'change', oldRange: oldScreenRange, newRange: newScreenRange + @trigger 'change', oldRange: oldScreenRange, newRange: newScreenRange, lineNumbersChanged: true @trigger 'unfold', bufferRange screenRowForBufferRow: (bufferRow) -> @@ -111,16 +111,20 @@ class Renderer @handleHighlighterChange(@lastHighlighterChangeEvent) handleHighlighterChange: (e) -> - oldRange = @bufferRangeForScreenRange(@screenRangeForBufferRange(e.oldRange.copy())) - newRange = @bufferRangeForScreenRange(@screenRangeForBufferRange(e.newRange.copy())) + newRange = e.newRange.copy() + newRange.start.row = @bufferRowForScreenRow(@screenRowForBufferRow(newRange.start.row)) - oldScreenRange = @screenLineRangeForBufferRange(oldRange) + oldScreenRange = @screenLineRangeForBufferRange(e.oldRange) newScreenLines = @buildLinesForBufferRows(newRange.start.row, newRange.end.row) @lineMap.replaceScreenRows oldScreenRange.start.row, oldScreenRange.end.row, newScreenLines newScreenRange = @screenLineRangeForBufferRange(newRange) - @trigger 'change', { oldRange: oldScreenRange, newRange: newScreenRange, bufferChanged: true } + @trigger 'change', + oldRange: oldScreenRange + newRange: newScreenRange + bufferChanged: true + lineNumbersChanged: !e.oldRange.coversSameRows(newRange) or !oldScreenRange.coversSameRows(newScreenRange) buildLineForBufferRow: (bufferRow) -> @buildLinesForBufferRows(bufferRow, bufferRow)