From 9eed6c7834ec7de2774dee1b1e0d32a04600937f Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 7 Sep 2015 13:25:13 +0200 Subject: [PATCH] Add "Continuous Reflow" mode --- spec/text-editor-component-spec.coffee | 50 +++++++++++++++++++++++++ src/config-schema.coffee | 4 ++ src/line-number-gutter-component.coffee | 3 ++ src/lines-component.coffee | 2 +- src/text-editor-presenter.coffee | 25 +++++++++++++ 5 files changed, 83 insertions(+), 1 deletion(-) diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index 2e914048e..77503cd00 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -450,6 +450,31 @@ describe "TextEditorComponent", -> nextAnimationFrame() expect(component.lineNodeForScreenRow(10).innerHTML).toBe 'CE' + it "keeps rebuilding lines when continuous reflow is on", -> + atom.config.set("editor.continuousReflow", true) + nextAnimationFrame() + + oldLineNodes = componentNode.querySelectorAll(".line") + + advanceClock(10) + expect(nextAnimationFrame).toBe(noAnimationFrame) + + advanceClock(component.presenter.minimumReflowInterval - 10) + nextAnimationFrame() + + newLineNodes = componentNode.querySelectorAll(".line") + expect(oldLineNodes).not.toEqual(newLineNodes) + oldLineNodes = newLineNodes + + atom.config.set("editor.continuousReflow", false) + nextAnimationFrame() + + newLineNodes = componentNode.querySelectorAll(".line") + expect(oldLineNodes).toEqual(newLineNodes) + + advanceClock(component.presenter.minimumReflowInterval) + expect(nextAnimationFrame).toBe(noAnimationFrame) + describe "when soft wrapping is enabled", -> beforeEach -> editor.setText "a line that wraps \n" @@ -827,6 +852,31 @@ describe "TextEditorComponent", -> expect(componentNode.querySelector('.gutter').style.display).toBe '' expect(component.lineNumberNodeForScreenRow(3)?).toBe true + it "keeps rebuilding line numbers when continuous reflow is on", -> + atom.config.set("editor.continuousReflow", true) + nextAnimationFrame() + + oldLineNodes = componentNode.querySelectorAll(".line-number") + + advanceClock(10) + expect(nextAnimationFrame).toBe(noAnimationFrame) + + advanceClock(component.presenter.minimumReflowInterval - 10) + nextAnimationFrame() + + newLineNodes = componentNode.querySelectorAll(".line-number") + expect(oldLineNodes).not.toEqual(newLineNodes) + oldLineNodes = newLineNodes + + atom.config.set("editor.continuousReflow", false) + nextAnimationFrame() + + newLineNodes = componentNode.querySelectorAll(".line-number") + expect(oldLineNodes).toEqual(newLineNodes) + + advanceClock(component.presenter.minimumReflowInterval) + expect(nextAnimationFrame).toBe(noAnimationFrame) + describe "fold decorations", -> describe "rendering fold decorations", -> it "adds the foldable class to line numbers when the line is foldable", -> diff --git a/src/config-schema.coffee b/src/config-schema.coffee index d8eeb6fe3..7f70a0c98 100644 --- a/src/config-schema.coffee +++ b/src/config-schema.coffee @@ -217,6 +217,10 @@ module.exports = type: 'boolean' default: process.platform isnt 'darwin' description: 'Increase/decrease the editor font size when pressing the Ctrl key and scrolling the mouse up/down.' + continuousReflow: + type: 'boolean' + default: false + description: 'Track down expensive layouts or style recalculations by continously reflowing the editor. (Has performance overhead)' if process.platform in ['win32', 'linux'] module.exports.core.properties.autoHideMenuBar = diff --git a/src/line-number-gutter-component.coffee b/src/line-number-gutter-component.coffee index 8eef6bd27..c86c36951 100644 --- a/src/line-number-gutter-component.coffee +++ b/src/line-number-gutter-component.coffee @@ -62,6 +62,9 @@ class LineNumberGutterComponent extends TiledComponent buildComponentForTile: (id) -> new LineNumbersTileComponent({id}) + shouldRecreateAllTilesOnUpdate: -> + @newState.continuousReflow + ### Section: Private Methods ### diff --git a/src/lines-component.coffee b/src/lines-component.coffee index 2b80235dc..40c4daa8a 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -32,7 +32,7 @@ class LinesComponent extends TiledComponent @domNode shouldRecreateAllTilesOnUpdate: -> - @oldState.indentGuidesVisible isnt @newState.indentGuidesVisible + @oldState.indentGuidesVisible isnt @newState.indentGuidesVisible or @newState.continuousReflow beforeUpdateSync: (state) -> if @newState.maxHeight isnt @oldState.maxHeight diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 2c0900092..7bacfb466 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -11,6 +11,7 @@ class TextEditorPresenter mouseWheelScreenRow: null scopedCharacterWidthsChangeCount: 0 overlayDimensions: {} + minimumReflowInterval: 200 constructor: (params) -> {@model, @autoHeight, @explicitHeight, @contentFrameWidth, @scrollTop, @scrollLeft, @boundingClientRect, @windowWidth, @windowHeight, @gutterWidth} = params @@ -35,6 +36,7 @@ class TextEditorPresenter @observeConfig() @buildState() @startBlinkingCursors() if @focused + @startReflowing() if @continuousReflow @updating = false destroy: -> @@ -72,6 +74,7 @@ class TextEditorPresenter @updateStartRow() @updateEndRow() @updateCommonGutterState() + @updateReflowState() @updateFocusedState() if @shouldUpdateFocusedState @updateHeightState() if @shouldUpdateHeightState @@ -169,6 +172,7 @@ class TextEditorPresenter observeConfig: -> configParams = {scope: @model.getRootScopeDescriptor()} + @continuousReflow = atom.config.get('editor.continuousReflow', configParams) @scrollPastEnd = atom.config.get('editor.scrollPastEnd', configParams) @showLineNumbers = atom.config.get('editor.showLineNumbers', configParams) @showIndentGuide = atom.config.get('editor.showIndentGuide', configParams) @@ -199,6 +203,16 @@ class TextEditorPresenter @emitDidUpdateState() + @configDisposables.add atom.config.onDidChange 'editor.continuousReflow', configParams, ({newValue}) => + @continuousReflow = newValue + + if @continuousReflow + @startReflowing() + else + @stopReflowing() + + @emitDidUpdateState() + didChangeGrammar: -> @observeConfig() @shouldUpdateContentState = true @@ -254,6 +268,17 @@ class TextEditorPresenter @resetTrackedUpdates() + updateReflowState: -> + @state.content.continuousReflow = @continuousReflow + @lineNumberGutter.continuousReflow = @continuousReflow + + startReflowing: -> + @reflowingInterval = setInterval(@emitDidUpdateState.bind(this), @minimumReflowInterval) + + stopReflowing: -> + clearInterval(@reflowingInterval) + @reflowingInterval = null + updateFocusedState: -> @state.focused = @focused