From 14e5d38354d1828eb5fc969fd47effe906430236 Mon Sep 17 00:00:00 2001 From: Jess Lin Date: Wed, 1 Apr 2015 15:31:50 -0700 Subject: [PATCH] [Gutter] TextEditorPresenter: Consolidate common gutter state under @state.gutters --- spec/text-editor-presenter-spec.coffee | 182 ++++++++++++------------ src/custom-gutter-component.coffee | 9 +- src/line-number-gutter-component.coffee | 3 +- src/text-editor-presenter.coffee | 25 ++-- 4 files changed, 111 insertions(+), 108 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index e091c937e..ed07c3d70 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -1767,97 +1767,6 @@ describe "TextEditorPresenter", -> } describe ".lineNumberGutter", -> - describe ".scrollHeight", -> - it "is initialized based on ::lineHeight, the number of lines, and ::explicitHeight", -> - presenter = buildPresenter() - expect(presenter.getState().lineNumberGutter.scrollHeight).toBe editor.getScreenLineCount() * 10 - - presenter = buildPresenter(explicitHeight: 500) - expect(presenter.getState().lineNumberGutter.scrollHeight).toBe 500 - - it "updates when the ::lineHeight changes", -> - presenter = buildPresenter() - expectStateUpdate presenter, -> presenter.setLineHeight(20) - expect(presenter.getState().lineNumberGutter.scrollHeight).toBe editor.getScreenLineCount() * 20 - - it "updates when the line count changes", -> - presenter = buildPresenter() - expectStateUpdate presenter, -> editor.getBuffer().append("\n\n\n") - expect(presenter.getState().lineNumberGutter.scrollHeight).toBe editor.getScreenLineCount() * 10 - - it "updates when ::explicitHeight changes", -> - presenter = buildPresenter() - expectStateUpdate presenter, -> presenter.setExplicitHeight(500) - expect(presenter.getState().lineNumberGutter.scrollHeight).toBe 500 - - it "adds the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true", -> - presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) - expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.getState().lineNumberGutter.scrollHeight).toBe presenter.contentHeight - - expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", true) - expect(presenter.getState().lineNumberGutter.scrollHeight).toBe presenter.contentHeight + presenter.clientHeight - (presenter.lineHeight * 3) - - expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) - expect(presenter.getState().lineNumberGutter.scrollHeight).toBe presenter.contentHeight - - describe ".scrollTop", -> - it "tracks the value of ::scrollTop", -> - presenter = buildPresenter(scrollTop: 10, explicitHeight: 20) - expect(presenter.getState().lineNumberGutter.scrollTop).toBe 10 - expectStateUpdate presenter, -> presenter.setScrollTop(50) - expect(presenter.getState().lineNumberGutter.scrollTop).toBe 50 - - it "never exceeds the computed scrollHeight minus the computed clientHeight", -> - presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) - expectStateUpdate presenter, -> presenter.setScrollTop(100) - expect(presenter.getState().lineNumberGutter.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight - - expectStateUpdate presenter, -> presenter.setExplicitHeight(60) - expect(presenter.getState().lineNumberGutter.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight - - expectStateUpdate presenter, -> presenter.setHorizontalScrollbarHeight(5) - expect(presenter.getState().lineNumberGutter.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight - - expectStateUpdate presenter, -> editor.getBuffer().delete([[8, 0], [12, 0]]) - expect(presenter.getState().lineNumberGutter.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight - - # Scroll top only gets smaller when needed as dimensions change, never bigger - scrollTopBefore = presenter.getState().verticalScrollbar.scrollTop - expectStateUpdate presenter, -> editor.getBuffer().insert([9, Infinity], '\n\n\n') - expect(presenter.getState().lineNumberGutter.scrollTop).toBe scrollTopBefore - - it "never goes negative", -> - presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) - expectStateUpdate presenter, -> presenter.setScrollTop(-100) - expect(presenter.getState().lineNumberGutter.scrollTop).toBe 0 - - it "adds the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true", -> - presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) - expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.getState().lineNumberGutter.scrollTop).toBe presenter.contentHeight - presenter.clientHeight - - atom.config.set("editor.scrollPastEnd", true) - expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(presenter.getState().lineNumberGutter.scrollTop).toBe presenter.contentHeight - (presenter.lineHeight * 3) - - expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) - expect(presenter.getState().lineNumberGutter.scrollTop).toBe presenter.contentHeight - presenter.clientHeight - - describe ".backgroundColor", -> - it "is assigned to ::gutterBackgroundColor if present, and to ::backgroundColor otherwise", -> - presenter = buildPresenter(backgroundColor: "rgba(255, 0, 0, 0)", gutterBackgroundColor: "rgba(0, 255, 0, 0)") - expect(presenter.getState().lineNumberGutter.backgroundColor).toBe "rgba(0, 255, 0, 0)" - - expectStateUpdate presenter, -> presenter.setGutterBackgroundColor("rgba(0, 0, 255, 0)") - expect(presenter.getState().lineNumberGutter.backgroundColor).toBe "rgba(0, 0, 255, 0)" - - expectStateUpdate presenter, -> presenter.setGutterBackgroundColor("rgba(0, 0, 0, 0)") - expect(presenter.getState().lineNumberGutter.backgroundColor).toBe "rgba(255, 0, 0, 0)" - - expectStateUpdate presenter, -> presenter.setBackgroundColor("rgba(0, 0, 255, 0)") - expect(presenter.getState().lineNumberGutter.backgroundColor).toBe "rgba(0, 0, 255, 0)" - describe ".maxLineNumberDigits", -> it "is set to the number of digits used by the greatest line number", -> presenter = buildPresenter() @@ -2191,6 +2100,97 @@ describe "TextEditorPresenter", -> expect(presenter.getState().focused).toBe false describe ".gutters", -> + describe ".scrollHeight", -> + it "is initialized based on ::lineHeight, the number of lines, and ::explicitHeight", -> + presenter = buildPresenter() + expect(presenter.getState().gutters.scrollHeight).toBe editor.getScreenLineCount() * 10 + + presenter = buildPresenter(explicitHeight: 500) + expect(presenter.getState().gutters.scrollHeight).toBe 500 + + it "updates when the ::lineHeight changes", -> + presenter = buildPresenter() + expectStateUpdate presenter, -> presenter.setLineHeight(20) + expect(presenter.getState().gutters.scrollHeight).toBe editor.getScreenLineCount() * 20 + + it "updates when the line count changes", -> + presenter = buildPresenter() + expectStateUpdate presenter, -> editor.getBuffer().append("\n\n\n") + expect(presenter.getState().gutters.scrollHeight).toBe editor.getScreenLineCount() * 10 + + it "updates when ::explicitHeight changes", -> + presenter = buildPresenter() + expectStateUpdate presenter, -> presenter.setExplicitHeight(500) + expect(presenter.getState().gutters.scrollHeight).toBe 500 + + it "adds the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true", -> + presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) + expectStateUpdate presenter, -> presenter.setScrollTop(300) + expect(presenter.getState().gutters.scrollHeight).toBe presenter.contentHeight + + expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", true) + expect(presenter.getState().gutters.scrollHeight).toBe presenter.contentHeight + presenter.clientHeight - (presenter.lineHeight * 3) + + expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) + expect(presenter.getState().gutters.scrollHeight).toBe presenter.contentHeight + + describe ".scrollTop", -> + it "tracks the value of ::scrollTop", -> + presenter = buildPresenter(scrollTop: 10, explicitHeight: 20) + expect(presenter.getState().gutters.scrollTop).toBe 10 + expectStateUpdate presenter, -> presenter.setScrollTop(50) + expect(presenter.getState().gutters.scrollTop).toBe 50 + + it "never exceeds the computed scrollHeight minus the computed clientHeight", -> + presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) + expectStateUpdate presenter, -> presenter.setScrollTop(100) + expect(presenter.getState().gutters.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + + expectStateUpdate presenter, -> presenter.setExplicitHeight(60) + expect(presenter.getState().gutters.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + + expectStateUpdate presenter, -> presenter.setHorizontalScrollbarHeight(5) + expect(presenter.getState().gutters.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + + expectStateUpdate presenter, -> editor.getBuffer().delete([[8, 0], [12, 0]]) + expect(presenter.getState().gutters.scrollTop).toBe presenter.scrollHeight - presenter.clientHeight + + # Scroll top only gets smaller when needed as dimensions change, never bigger + scrollTopBefore = presenter.getState().verticalScrollbar.scrollTop + expectStateUpdate presenter, -> editor.getBuffer().insert([9, Infinity], '\n\n\n') + expect(presenter.getState().gutters.scrollTop).toBe scrollTopBefore + + it "never goes negative", -> + presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) + expectStateUpdate presenter, -> presenter.setScrollTop(-100) + expect(presenter.getState().gutters.scrollTop).toBe 0 + + it "adds the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true", -> + presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10) + expectStateUpdate presenter, -> presenter.setScrollTop(300) + expect(presenter.getState().gutters.scrollTop).toBe presenter.contentHeight - presenter.clientHeight + + atom.config.set("editor.scrollPastEnd", true) + expectStateUpdate presenter, -> presenter.setScrollTop(300) + expect(presenter.getState().gutters.scrollTop).toBe presenter.contentHeight - (presenter.lineHeight * 3) + + expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) + expect(presenter.getState().gutters.scrollTop).toBe presenter.contentHeight - presenter.clientHeight + + describe ".backgroundColor", -> + it "is assigned to ::gutterBackgroundColor if present, and to ::backgroundColor otherwise", -> + presenter = buildPresenter(backgroundColor: "rgba(255, 0, 0, 0)", gutterBackgroundColor: "rgba(0, 255, 0, 0)") + expect(presenter.getState().gutters.backgroundColor).toBe "rgba(0, 255, 0, 0)" + + expectStateUpdate presenter, -> presenter.setGutterBackgroundColor("rgba(0, 0, 255, 0)") + expect(presenter.getState().gutters.backgroundColor).toBe "rgba(0, 0, 255, 0)" + + expectStateUpdate presenter, -> presenter.setGutterBackgroundColor("rgba(0, 0, 0, 0)") + expect(presenter.getState().gutters.backgroundColor).toBe "rgba(255, 0, 0, 0)" + + expectStateUpdate presenter, -> presenter.setBackgroundColor("rgba(0, 0, 255, 0)") + expect(presenter.getState().gutters.backgroundColor).toBe "rgba(0, 0, 255, 0)" + describe ".sortedDescriptions", -> gutterDescriptionWithName = (presenter, name) -> for gutterDesc in presenter.getState().gutters.sortedDescriptions diff --git a/src/custom-gutter-component.coffee b/src/custom-gutter-component.coffee index 4b374ba22..68f91f7ff 100644 --- a/src/custom-gutter-component.coffee +++ b/src/custom-gutter-component.coffee @@ -38,12 +38,11 @@ class CustomGutterComponent @visible = true updateSync: (state) -> - gutterProps = state.lineNumberGutter + @oldDimensionsAndBackgroundState ?= {} + newDimensionsAndBackgroundState = state.gutters + setDimensionsAndBackground(@oldDimensionsAndBackgroundState, newDimensionsAndBackgroundState, @decorationsNode) + decorationState = state.gutters.customDecorations[@getName()] - @oldState ?= {} - - setDimensionsAndBackground(@oldState, gutterProps, @decorationsNode) - return if !decorationState updatedDecorationIds = new Set diff --git a/src/line-number-gutter-component.coffee b/src/line-number-gutter-component.coffee index 56fc74edc..b79b08fdb 100644 --- a/src/line-number-gutter-component.coffee +++ b/src/line-number-gutter-component.coffee @@ -39,7 +39,8 @@ class LineNumberGutterComponent @appendDummyLineNumber() unless @dummyLineNumberNode? - setDimensionsAndBackground(@oldState, @newState, @lineNumbersNode) + newDimensionsAndBackgroundState = state.gutters + setDimensionsAndBackground(@oldState, newDimensionsAndBackgroundState, @lineNumbersNode) if @newState.maxLineNumberDigits isnt @oldState.maxLineNumberDigits @updateDummyLineNumber() diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 8b2cbf825..84400ee4f 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -121,10 +121,12 @@ class TextEditorPresenter @updateLinesState() @updateLineNumberGutterState() @updateLineNumbersState() + @updateCommonGutterState() @updateCustomGutterState() @updateCustomGutterDecorationState() @disposables.add @model.onDidChangeLineNumberGutterVisible => @updateLineNumberGutterState() + @updateCommonGutterState() @updateCustomGutterState() @disposables.add @model.onDidAddDecoration(@didAddDecoration.bind(this)) @disposables.add @model.onDidAddCursor(@didAddCursor.bind(this)) @@ -160,12 +162,14 @@ class TextEditorPresenter @configDisposables.add atom.config.onDidChange 'editor.showLineNumbers', configParams, ({newValue}) => @showLineNumbers = newValue @updateLineNumberGutterState() + @updateCommonGutterState() @updateCustomGutterState() didChangeGrammar: -> @observeConfig() @updateContentState() @updateLineNumberGutterState() + @updateCommonGutterState() @updateCustomGutterState() buildState: -> @@ -205,6 +209,7 @@ class TextEditorPresenter @updateOverlaysState() @updateLineNumberGutterState() @updateLineNumbersState() + @updateCommonGutterState() @updateCustomGutterState() @updateCustomGutterDecorationState() @@ -219,11 +224,11 @@ class TextEditorPresenter updateVerticalScrollState: -> @batch "shouldUpdateVerticalScrollState", -> @state.content.scrollHeight = @scrollHeight - @state.lineNumberGutter.scrollHeight = @scrollHeight + @state.gutters.scrollHeight = @scrollHeight @state.verticalScrollbar.scrollHeight = @scrollHeight @state.content.scrollTop = @scrollTop - @state.lineNumberGutter.scrollTop = @scrollTop + @state.gutters.scrollTop = @scrollTop @state.verticalScrollbar.scrollTop = @scrollTop updateHorizontalScrollState: -> @batch "shouldUpdateHorizontalScrollState", -> @@ -380,13 +385,12 @@ class TextEditorPresenter updateLineNumberGutterState: -> @batch "shouldUpdateLineNumberGutterState", -> @state.lineNumberGutter.maxLineNumberDigits = @model.getLineCount().toString().length - @state.lineNumberGutter.backgroundColor = @getGutterBackgroundColor() - getGutterBackgroundColor: -> - if @gutterBackgroundColor isnt "rgba(0, 0, 0, 0)" - @gutterBackgroundColor - else - @backgroundColor + updateCommonGutterState: -> + @state.gutters.backgroundColor = if @gutterBackgroundColor isnt "rgba(0, 0, 0, 0)" + @gutterBackgroundColor + else + @backgroundColor didAddGutter: (gutter) -> gutterDisposables = new CompositeDisposable @@ -403,9 +407,6 @@ class TextEditorPresenter updateCustomGutterState: -> @batch "shouldUpdateCustomGutterState", -> - # For now, just match the background color of the line-number gutter. - # TODO: Allow gutters to have different background colors. (?) - @state.gutters.backgroundColor = @getGutterBackgroundColor() @state.gutters.sortedDescriptions = [] if @model.isMini() return @@ -808,12 +809,14 @@ class TextEditorPresenter @backgroundColor = backgroundColor @updateContentState() @updateLineNumberGutterState() + @updateCommonGutterState() @updateCustomGutterState() setGutterBackgroundColor: (gutterBackgroundColor) -> unless @gutterBackgroundColor is gutterBackgroundColor @gutterBackgroundColor = gutterBackgroundColor @updateLineNumberGutterState() + @updateCommonGutterState() @updateCustomGutterState() setLineHeight: (lineHeight) ->