diff --git a/spec/lines-yardstick-spec.coffee b/spec/lines-yardstick-spec.coffee index ae85a0e9d..fbf5c53bf 100644 --- a/spec/lines-yardstick-spec.coffee +++ b/spec/lines-yardstick-spec.coffee @@ -1,4 +1,5 @@ -LinesYardstick = require "../src/lines-yardstick" +LinesYardstick = require '../src/lines-yardstick' +LineTopIndex = require '../src/linear-line-top-index' {toArray} = require 'underscore-plus' describe "LinesYardstick", -> @@ -56,7 +57,7 @@ describe "LinesYardstick", -> textNodes editor.setLineHeightInPixels(14) - linesYardstick = new LinesYardstick(editor, mockPresenter, mockLineNodesProvider, atom.grammars) + linesYardstick = new LinesYardstick(editor, mockPresenter, mockLineNodesProvider, new LineTopIndex(), atom.grammars) afterEach -> lineNode.remove() for lineNode in createdLineNodes diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js index f4afad9ca..d214201fa 100644 --- a/spec/text-editor-component-spec.js +++ b/spec/text-editor-component-spec.js @@ -1663,7 +1663,7 @@ describe('TextEditorComponent', function () { atom.themes.removeStylesheet('test') }) - it("renders all the editor's block decorations, inserting them in the appropriate spots between lines", async function () { + it("renders visible and yet-to-be-measured block decorations, inserting them in the appropriate spots between lines and refreshing them when needed", async function () { wrapperNode.style.height = 9 * lineHeightInPixels + 'px' component.measureDimensions() await nextViewUpdatePromise() @@ -1680,7 +1680,7 @@ describe('TextEditorComponent', function () { atom-text-editor .decoration-4 { width: 30px; height: 120px; } ` - await nextViewUpdatePromise() + await nextAnimationFramePromise() expect(component.getDomNode().querySelectorAll(".line").length).toBe(7) @@ -1694,19 +1694,17 @@ describe('TextEditorComponent', function () { expect(component.getTopmostDOMNode().querySelector(".decoration-1")).toBe(item1) expect(component.getTopmostDOMNode().querySelector(".decoration-2")).toBe(item2) expect(component.getTopmostDOMNode().querySelector(".decoration-3")).toBe(item3) - expect(component.getTopmostDOMNode().querySelector(".decoration-4")).toBe(item4) + expect(component.getTopmostDOMNode().querySelector(".decoration-4")).toBeNull() expect(item1.getBoundingClientRect().top).toBe(editor.getLineHeightInPixels() * 0) expect(item2.getBoundingClientRect().top).toBe(editor.getLineHeightInPixels() * 2 + 80) expect(item3.getBoundingClientRect().top).toBe(editor.getLineHeightInPixels() * 4 + 80 + 40) - expect(item4.getBoundingClientRect().top).toBe(0) // hidden - expect(item4.getBoundingClientRect().height).toBe(120) editor.setCursorScreenPosition([0, 0]) editor.insertNewline() blockDecoration1.destroy() - await nextViewUpdatePromise() + await nextAnimationFramePromise() expect(component.getDomNode().querySelectorAll(".line").length).toBe(7) @@ -1720,21 +1718,19 @@ describe('TextEditorComponent', function () { expect(component.getTopmostDOMNode().querySelector(".decoration-1")).toBeNull() expect(component.getTopmostDOMNode().querySelector(".decoration-2")).toBe(item2) expect(component.getTopmostDOMNode().querySelector(".decoration-3")).toBe(item3) - expect(component.getTopmostDOMNode().querySelector(".decoration-4")).toBe(item4) + expect(component.getTopmostDOMNode().querySelector(".decoration-4")).toBeNull() - expect(item1.getBoundingClientRect().height).toBe(0) // deleted expect(item2.getBoundingClientRect().top).toBe(editor.getLineHeightInPixels() * 3) expect(item3.getBoundingClientRect().top).toBe(editor.getLineHeightInPixels() * 5 + 40) - expect(item4.getBoundingClientRect().top).toBe(0) // hidden - expect(item4.getBoundingClientRect().height).toBe(120) - await nextViewUpdatePromise() + await nextAnimationFramePromise() atom.styles.addStyleSheet ` atom-text-editor .decoration-2 { height: 60px !important; } ` - await nextViewUpdatePromise() + await nextAnimationFramePromise() // causes the DOM to update and to retrieve new styles + await nextAnimationFramePromise() // applies the changes expect(component.getDomNode().querySelectorAll(".line").length).toBe(7) @@ -1748,13 +1744,10 @@ describe('TextEditorComponent', function () { expect(component.getTopmostDOMNode().querySelector(".decoration-1")).toBeNull() expect(component.getTopmostDOMNode().querySelector(".decoration-2")).toBe(item2) expect(component.getTopmostDOMNode().querySelector(".decoration-3")).toBe(item3) - expect(component.getTopmostDOMNode().querySelector(".decoration-4")).toBe(item4) + expect(component.getTopmostDOMNode().querySelector(".decoration-4")).toBeNull() - expect(item1.getBoundingClientRect().height).toBe(0) // deleted expect(item2.getBoundingClientRect().top).toBe(editor.getLineHeightInPixels() * 3) expect(item3.getBoundingClientRect().top).toBe(editor.getLineHeightInPixels() * 5 + 60) - expect(item4.getBoundingClientRect().top).toBe(0) // hidden - expect(item4.getBoundingClientRect().height).toBe(120) // hidden }) }) diff --git a/src/block-decorations-presenter.js b/src/block-decorations-presenter.js index 51944e584..bfe08dd63 100644 --- a/src/block-decorations-presenter.js +++ b/src/block-decorations-presenter.js @@ -70,6 +70,11 @@ class BlockDecorationsPresenter { this.emitter.emit('did-update-state') } + measurementsChanged () { + this.measuredDecorations.clear() + this.emitter.emit('did-update-state') + } + decorationsForScreenRow (screenRow) { let blocks = this.lineTopIndex.allBlocks().filter((block) => block.row === screenRow) return blocks.map((block) => this.decorationsByBlock.get(block.id)).filter((decoration) => decoration) diff --git a/src/lines-tile-component.coffee b/src/lines-tile-component.coffee index 6c676dfc2..73e88aa32 100644 --- a/src/lines-tile-component.coffee +++ b/src/lines-tile-component.coffee @@ -144,7 +144,7 @@ class LinesTileComponent return unless insertionPoint? if newLineState.screenRow isnt oldLineState.screenRow - insertionPoint.dataset.screenRow = screenRow + insertionPoint.dataset.screenRow = newLineState.screenRow blockDecorationsSelector = newLineState.blockDecorations.map((d) -> "#atom--block-decoration-#{d.id}").join(',') if blockDecorationsSelector isnt oldLineState.blockDecorationsSelector diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index afe46c705..c35139d7c 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -283,13 +283,13 @@ class TextEditorComponent observeConfig: -> @disposables.add @config.onDidChange 'editor.fontSize', => @sampleFontStyling() - @invalidateCharacterWidths() + @invalidateMeasurements() @disposables.add @config.onDidChange 'editor.fontFamily', => @sampleFontStyling() - @invalidateCharacterWidths() + @invalidateMeasurements() @disposables.add @config.onDidChange 'editor.lineHeight', => @sampleFontStyling() - @invalidateCharacterWidths() + @invalidateMeasurements() onGrammarChanged: => if @scopedConfigDisposables? @@ -576,7 +576,7 @@ class TextEditorComponent handleStylingChange: => @sampleFontStyling() @sampleBackgroundColors() - @invalidateCharacterWidths() + @invalidateMeasurements() handleDragUntilMouseUp: (dragHandler) -> dragging = false @@ -730,7 +730,7 @@ class TextEditorComponent if @fontSize isnt oldFontSize or @fontFamily isnt oldFontFamily or @lineHeight isnt oldLineHeight @clearPoolAfterUpdate = true @measureLineHeightAndDefaultCharWidth() - @invalidateCharacterWidths() + @invalidateMeasurements() sampleBackgroundColors: (suppressUpdate) -> {backgroundColor} = getComputedStyle(@hostElement) @@ -840,7 +840,7 @@ class TextEditorComponent setFontSize: (fontSize) -> @getTopmostDOMNode().style.fontSize = fontSize + 'px' @sampleFontStyling() - @invalidateCharacterWidths() + @invalidateMeasurements() getFontFamily: -> getComputedStyle(@getTopmostDOMNode()).fontFamily @@ -848,16 +848,16 @@ class TextEditorComponent setFontFamily: (fontFamily) -> @getTopmostDOMNode().style.fontFamily = fontFamily @sampleFontStyling() - @invalidateCharacterWidths() + @invalidateMeasurements() setLineHeight: (lineHeight) -> @getTopmostDOMNode().style.lineHeight = lineHeight @sampleFontStyling() - @invalidateCharacterWidths() + @invalidateMeasurements() - invalidateCharacterWidths: -> + invalidateMeasurements: -> @linesYardstick.invalidateCache() - @presenter.characterWidthsChanged() + @presenter.measurementsChanged() setShowIndentGuide: (showIndentGuide) -> @config.set("editor.showIndentGuide", showIndentGuide) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 78bc67a08..5b1f01b35 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -1152,9 +1152,12 @@ class TextEditorPresenter @koreanCharWidth = koreanCharWidth @model.setDefaultCharWidth(baseCharacterWidth, doubleWidthCharWidth, halfWidthCharWidth, koreanCharWidth) @restoreScrollLeftIfNeeded() - @characterWidthsChanged() + @measurementsChanged() - characterWidthsChanged: -> + measurementsChanged: -> + @blockDecorationsPresenter.measurementsChanged() + + @shouldUpdateHeightState = true @shouldUpdateHorizontalScrollState = true @shouldUpdateVerticalScrollState = true @shouldUpdateScrollbarsState = true @@ -1162,8 +1165,10 @@ class TextEditorPresenter @shouldUpdateContentState = true @shouldUpdateDecorations = true @shouldUpdateLinesState = true + @shouldUpdateLineNumbersState = true @shouldUpdateCursorsState = true @shouldUpdateOverlaysState = true + @shouldUpdateCustomGutterDecorationState = true @emitDidUpdateState()