diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 8dd34fde8..6f1cf3a70 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -486,6 +486,39 @@ describe "TextEditorPresenter", -> presenter = buildPresenter(scrollTop: 0, lineHeight: 10, explicitHeight: 500) expect(presenter.getState().verticalScrollbar.scrollHeight).toBe 500 + it "updates when new block decorations are measured, changed or destroyed", -> + presenter = buildPresenter(scrollTop: 0, lineHeight: 10) + expect(presenter.getState().verticalScrollbar.scrollHeight).toBe editor.getScreenLineCount() * 10 + + addBlockDecorationAtScreenRow = (screenRow) -> + editor.decorateMarker( + editor.markScreenPosition([screenRow, 0], invalidate: "never"), + type: "block", + item: document.createElement("div") + ) + + blockDecoration1 = addBlockDecorationAtScreenRow(0) + blockDecoration2 = addBlockDecorationAtScreenRow(3) + blockDecoration3 = addBlockDecorationAtScreenRow(7) + + presenter.setBlockDecorationSize(blockDecoration1, 0, 35.8) + presenter.setBlockDecorationSize(blockDecoration2, 0, 50.3) + presenter.setBlockDecorationSize(blockDecoration3, 0, 95.2) + + linesHeight = editor.getScreenLineCount() * 10 + blockDecorationsHeight = Math.round(35.8 + 50.3 + 95.2) + expect(presenter.getState().verticalScrollbar.scrollHeight).toBe(linesHeight + blockDecorationsHeight) + + presenter.setBlockDecorationSize(blockDecoration2, 0, 100.3) + + blockDecorationsHeight = Math.round(35.8 + 100.3 + 95.2) + expect(presenter.getState().verticalScrollbar.scrollHeight).toBe(linesHeight + blockDecorationsHeight) + + waitsForStateToUpdate presenter, -> blockDecoration3.destroy() + runs -> + blockDecorationsHeight = Math.round(35.8 + 100.3) + expect(presenter.getState().verticalScrollbar.scrollHeight).toBe(linesHeight + blockDecorationsHeight) + it "updates when the ::lineHeight changes", -> presenter = buildPresenter(scrollTop: 0, lineHeight: 10) expectStateUpdate presenter, -> presenter.setLineHeight(20) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 405e34548..6296e9331 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -28,6 +28,7 @@ class TextEditorPresenter @lineDecorationsByScreenRow = {} @lineNumberDecorationsByScreenRow = {} @customGutterDecorationsByGutterName = {} + @blockDecorationsDimensions = new Map @screenRowsToMeasure = [] @transferMeasurementsToModel() @transferMeasurementsFromModel() @@ -71,6 +72,7 @@ class TextEditorPresenter getPreMeasurementState: -> @updating = true + @updateBlockDecorations() if @shouldUpdateBlockDecorations @updateVerticalDimensions() @updateScrollbarDimensions() @@ -140,6 +142,7 @@ class TextEditorPresenter @shouldUpdateHiddenInputState = false @shouldUpdateContentState = false @shouldUpdateDecorations = false + @shouldUpdateBlockDecorations = false @shouldUpdateLinesState = false @shouldUpdateTilesState = false @shouldUpdateCursorsState = false @@ -158,6 +161,7 @@ class TextEditorPresenter @shouldUpdateHiddenInputState = true @shouldUpdateContentState = true @shouldUpdateDecorations = true + @shouldUpdateBlockDecorations = true @shouldUpdateLinesState = true @shouldUpdateTilesState = true @shouldUpdateCursorsState = true @@ -188,6 +192,8 @@ class TextEditorPresenter @shouldUpdateLineNumbersState = true @shouldUpdateDecorations = true @shouldUpdateOverlaysState = true + @shouldUpdateBlockDecorations = true + @shouldUpdateVerticalScrollState = true @shouldUpdateCustomGutterDecorationState = true @emitDidUpdateState() @@ -727,10 +733,19 @@ class TextEditorPresenter @scrollHeight = scrollHeight @updateScrollTop(@scrollTop) + getLinesHeight: -> + @lineHeight * @model.getScreenLineCount() + + getBlockDecorationsHeight: -> + sizes = Array.from(@blockDecorationsDimensions.values()) + sum = (a, b) -> a + b + height = sizes.map((size) -> size.height).reduce(sum, 0) + height + updateVerticalDimensions: -> if @lineHeight? oldContentHeight = @contentHeight - @contentHeight = @lineHeight * @model.getScreenLineCount() + @contentHeight = Math.round(@getLinesHeight() + @getBlockDecorationsHeight()) if @contentHeight isnt oldContentHeight @updateHeight() @@ -1364,6 +1379,24 @@ class TextEditorPresenter @emitDidUpdateState() + setBlockDecorationSize: (decoration, width, height) -> + @blockDecorationsDimensions.set(decoration.id, {width, height}) + + @shouldUpdateBlockDecorations = true + @shouldUpdateVerticalScrollState = true + @emitDidUpdateState() + + updateBlockDecorations: -> + blockDecorations = {} + for decoration in @model.getDecorations(type: "block") + blockDecorations[decoration.id] = decoration + + @blockDecorationsDimensions.forEach (value, key) => + unless blockDecorations.hasOwnProperty(key) + @blockDecorationsDimensions.delete(key) + + @shouldUpdateVerticalScrollState = true + observeCursor: (cursor) -> didChangePositionDisposable = cursor.onDidChangePosition => @shouldUpdateHiddenInputState = true if cursor.isLastCursor()