diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 87c32475d..1d1b214ec 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -1313,7 +1313,7 @@ describe "TextEditorPresenter", -> expect(lineStateForScreenRow(presenter, 6).blockDecorations).toEqual([]) expect(lineStateForScreenRow(presenter, 7).blockDecorations).toEqual([]) expect(lineStateForScreenRow(presenter, 8).blockDecorations).toEqual([]) - expect(lineStateForScreenRow(presenter, 9).blockDecorations).toEqual([blockDecoration3, blockDecoration2]) + expect(lineStateForScreenRow(presenter, 9).blockDecorations).toEqual([blockDecoration2, blockDecoration3]) expect(lineStateForScreenRow(presenter, 10).blockDecorations).toEqual([]) expect(lineStateForScreenRow(presenter, 11).blockDecorations).toEqual([]) expect(lineStateForScreenRow(presenter, 12).blockDecorations).toEqual([]) @@ -2166,12 +2166,12 @@ describe "TextEditorPresenter", -> expectValues stateForBlockDecoration(presenter, blockDecoration2), { decoration: blockDecoration2 screenRow: 4 - isVisible: true + isVisible: false } expectValues stateForBlockDecoration(presenter, blockDecoration3), { decoration: blockDecoration3 screenRow: 4 - isVisible: true + isVisible: false } expectValues stateForBlockDecoration(presenter, blockDecoration4), { decoration: blockDecoration4 @@ -2212,16 +2212,23 @@ describe "TextEditorPresenter", -> screenRow: 4 isVisible: false } - expectValues stateForBlockDecoration(presenter, blockDecoration4), { - decoration: blockDecoration4 - screenRow: 10 - isVisible: true - } + expect(stateForBlockDecoration(presenter, blockDecoration4)).toBeUndefined() presenter.invalidateBlockDecorationDimensions(blockDecoration1) presenter.setBlockDecorationDimensions(blockDecoration2, 0, 10) presenter.setBlockDecorationDimensions(blockDecoration3, 0, 10) + expectValues stateForBlockDecoration(presenter, blockDecoration1), { + decoration: blockDecoration1 + screenRow: 0 + isVisible: false + } + expect(stateForBlockDecoration(presenter, blockDecoration2)).toBeUndefined() + expect(stateForBlockDecoration(presenter, blockDecoration3)).toBeUndefined() + expect(stateForBlockDecoration(presenter, blockDecoration4)).toBeUndefined() + + presenter.setScrollTop(140) + expectValues stateForBlockDecoration(presenter, blockDecoration1), { decoration: blockDecoration1 screenRow: 0 @@ -2235,6 +2242,7 @@ describe "TextEditorPresenter", -> isVisible: true } + describe ".overlays", -> [item] = [] stateForOverlay = (presenter, decoration) -> diff --git a/src/block-decorations-presenter.js b/src/block-decorations-presenter.js index 7f7258226..076cfea12 100644 --- a/src/block-decorations-presenter.js +++ b/src/block-decorations-presenter.js @@ -8,10 +8,7 @@ class BlockDecorationsPresenter { this.model = model this.disposables = new EventKit.CompositeDisposable() this.emitter = new EventKit.Emitter() - this.firstUpdate = true this.lineTopIndex = lineTopIndex - this.blocksByDecoration = new Map() - this.decorationsByBlock = new Map() this.observedDecorations = new Set() this.measuredDecorations = new Set() @@ -31,30 +28,24 @@ class BlockDecorationsPresenter { } observeModel () { - this.disposables.add(this.model.onDidAddDecoration(this.observeDecoration.bind(this))) + this.disposables.add(this.model.onDidAddDecoration(this.didAddDecoration.bind(this))) this.disposables.add(this.model.onDidChange((changeEvent) => { let oldExtent = changeEvent.end - changeEvent.start let newExtent = Math.max(0, changeEvent.end - changeEvent.start + changeEvent.screenDelta) this.lineTopIndex.splice(changeEvent.start, oldExtent, newExtent) })) - } - update () { - if (this.firstUpdate) { - for (let decoration of this.model.getDecorations({type: 'block'})) { - this.observeDecoration(decoration) - } - this.firstUpdate = false + for (let decoration of this.model.getDecorations({type: 'block'})) { + this.didAddDecoration(decoration) } } setDimensionsForDecoration (decoration, width, height) { - let block = this.blocksByDecoration.get(decoration) - if (block) { - this.lineTopIndex.resizeBlock(decoration.getMarker().id, height) + if (this.observedDecorations.has(decoration)) { + this.lineTopIndex.resizeBlock(decoration.getId(), height) } else { - this.observeDecoration(decoration) - this.lineTopIndex.resizeBlock(decoration.getMarker().id, height) + this.didAddDecoration(decoration) + this.lineTopIndex.resizeBlock(decoration.getId(), height) } this.measuredDecorations.add(decoration) @@ -71,30 +62,7 @@ class BlockDecorationsPresenter { 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) - } - - decorationsForScreenRowRange (startRow, endRow, mouseWheelScreenRow) { - let blocks = this.lineTopIndex.allBlocks() - let decorationsByScreenRow = new Map() - for (let block of blocks) { - let decoration = this.decorationsByBlock.get(block.id) - let hasntMeasuredDecoration = !this.measuredDecorations.has(decoration) - let isWithinVisibleRange = startRow <= block.row && block.row < endRow - let isVisible = isWithinVisibleRange || block.row === mouseWheelScreenRow - if (decoration && (isVisible || hasntMeasuredDecoration)) { - let decorations = decorationsByScreenRow.get(block.row) || [] - decorations.push({decoration, isVisible}) - decorationsByScreenRow.set(block.row, decorations) - } - } - - return decorationsByScreenRow - } - - observeDecoration (decoration) { + didAddDecoration (decoration) { if (!decoration.isType('block') || this.observedDecorations.has(decoration)) { return } @@ -108,21 +76,15 @@ class BlockDecorationsPresenter { this.disposables.remove(didDestroyDisposable) didMoveDisposable.dispose() didDestroyDisposable.dispose() - this.observedDecorations.delete(decoration) this.didDestroyDecoration(decoration) }) + let screenRow = decoration.getMarker().getHeadScreenPosition().row + this.lineTopIndex.insertBlock(decoration.getId(), screenRow, 0) + + this.observedDecorations.add(decoration) this.disposables.add(didMoveDisposable) this.disposables.add(didDestroyDisposable) - this.didAddDecoration(decoration) - this.observedDecorations.add(decoration) - } - - didAddDecoration (decoration) { - let screenRow = decoration.getMarker().getHeadScreenPosition().row - this.lineTopIndex.insertBlock(decoration.getMarker().id, screenRow, 0) - this.decorationsByBlock.set(decoration.getMarker().id, decoration) - this.blocksByDecoration.set(decoration, decoration.getMarker().id) this.emitter.emit('did-update-state') } @@ -133,17 +95,15 @@ class BlockDecorationsPresenter { } let newScreenRow = decoration.getMarker().getHeadScreenPosition().row - this.lineTopIndex.moveBlock(decoration.getMarker().id, newScreenRow) + this.lineTopIndex.moveBlock(decoration.getId(), newScreenRow) this.emitter.emit('did-update-state') } didDestroyDecoration (decoration) { - let block = this.blocksByDecoration.get(decoration) - if (block) { - this.lineTopIndex.removeBlock(decoration.getMarker().id) - this.blocksByDecoration.delete(decoration) - this.decorationsByBlock.delete(block) + if (this.observedDecorations.has(decoration)) { + this.lineTopIndex.removeBlock(decoration.getId()) + this.observedDecorations.delete(decoration) + this.emitter.emit('did-update-state') } - this.emitter.emit('did-update-state') } } diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index ca05ea36a..5a0630296 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -74,8 +74,6 @@ class TextEditorPresenter getPreMeasurementState: -> @updating = true - @blockDecorationsPresenter.update() - @updateVerticalDimensions() @updateScrollbarDimensions() @@ -87,11 +85,10 @@ class TextEditorPresenter @updateCommonGutterState() @updateReflowState() - @updateBlockDecorationsState() - if @shouldUpdateDecorations @fetchDecorations() @updateLineDecorations() + @updateBlockDecorations() if @shouldUpdateLinesState or @shouldUpdateLineNumbersState @updateTilesState() @@ -489,7 +486,7 @@ class TextEditorPresenter throw new Error("No line exists for row #{screenRow}. Last screen row: #{@model.getLastScreenRow()}") visibleLineIds[line.id] = true - blockDecorations = this.blockDecorationsPresenter.decorationsForScreenRow(screenRow) + blockDecorations = @blockDecorationsByScreenRow[screenRow] ? [] if tileState.lines.hasOwnProperty(line.id) lineState = tileState.lines[line.id] lineState.screenRow = screenRow @@ -943,6 +940,7 @@ class TextEditorPresenter @shouldUpdateLinesState = true @shouldUpdateLineNumbersState = true @shouldUpdateCustomGutterDecorationState = true + @shouldUpdateDecorations = true @emitDidUpdateState() @@ -1208,15 +1206,21 @@ class TextEditorPresenter return unless 0 <= @startRow <= @endRow <= Infinity @decorations = @model.decorationsStateForScreenRowRange(@startRow, @endRow - 1) - updateBlockDecorationsState: -> + updateBlockDecorations: -> @state.content.blockDecorations = {} + @blockDecorationsByScreenRow = {} - startRow = @getStartTileRow() - endRow = @getEndTileRow() + @tileSize - decorations = @blockDecorationsPresenter.decorationsForScreenRowRange(startRow, endRow, @mouseWheelScreenRow) - decorations.forEach (decorations, screenRow) => - for {decoration, isVisible} in decorations - @state.content.blockDecorations[decoration.id] = {decoration, screenRow, isVisible} + for decoration in @model.getDecorations({type: "block"}) + screenRow = decoration.getMarker().getHeadScreenPosition().row + @updateBlockDecorationState(decoration, screenRow) + @blockDecorationsByScreenRow[screenRow] ?= [] + @blockDecorationsByScreenRow[screenRow].push(decoration) + + updateBlockDecorationState: (decoration, screenRow) -> + hasntMeasuredDecoration = !@blockDecorationsPresenter.measuredDecorations.has(decoration) + isVisible = @startRow <= screenRow < @endRow || screenRow is @mouseWheelScreenRow + if isVisible or hasntMeasuredDecoration + @state.content.blockDecorations[decoration.id] = {decoration, screenRow, isVisible} updateLineDecorations: -> @lineDecorationsByScreenRow = {}