🐎 Cache gutterVisible state in React component

This avoids a config read on every render.
This commit is contained in:
Nathan Sobo 2015-01-12 11:13:51 -07:00
parent f00b0b7f7a
commit 002918049d
5 changed files with 38 additions and 29 deletions

View File

@ -561,12 +561,12 @@ describe "TextEditorComponent", ->
expect(component.refs.gutter?).toBe false expect(component.refs.gutter?).toBe false
atom.config.set("editor.showLineNumbers", false) atom.config.set("editor.showLineNumbers", false)
nextAnimationFrame() expect(nextAnimationFrame).toBe noAnimationFrame
expect(component.refs.gutter?).toBe false expect(component.refs.gutter?).toBe false
editor.setGutterVisible(true) editor.setGutterVisible(true)
nextAnimationFrame() expect(nextAnimationFrame).toBe noAnimationFrame
expect(component.refs.gutter?).toBe false expect(component.refs.gutter?).toBe false
@ -2517,7 +2517,8 @@ describe "TextEditorComponent", ->
describe "when the 'mini' property is true", -> describe "when the 'mini' property is true", ->
beforeEach -> beforeEach ->
component.setProps(mini: true) editor.setMini(true)
nextAnimationFrame()
it "does not render the gutter", -> it "does not render the gutter", ->
expect(componentNode.querySelector('.gutter')).toBeNull() expect(componentNode.querySelector('.gutter')).toBeNull()

View File

@ -23,12 +23,12 @@ LinesComponent = React.createClass
if performedInitialMeasurement if performedInitialMeasurement
{editor, overlayDecorations, highlightDecorations, scrollHeight, scrollWidth, placeholderText, backgroundColor} = @props {editor, overlayDecorations, highlightDecorations, scrollHeight, scrollWidth, placeholderText, backgroundColor} = @props
{lineHeightInPixels, defaultCharWidth, scrollViewHeight, scopedCharacterWidthsChangeCount} = @props {lineHeightInPixels, defaultCharWidth, scrollViewHeight, scopedCharacterWidthsChangeCount} = @props
{scrollTop, scrollLeft, cursorPixelRects, mini} = @props {scrollTop, scrollLeft, cursorPixelRects} = @props
style = style =
height: Math.max(scrollHeight, scrollViewHeight) height: Math.max(scrollHeight, scrollViewHeight)
width: scrollWidth width: scrollWidth
WebkitTransform: @getTransform() WebkitTransform: @getTransform()
backgroundColor: if mini then null else backgroundColor backgroundColor: if editor.isMini() then null else backgroundColor
div {className: 'lines', style}, div {className: 'lines', style},
div className: 'placeholder-text', placeholderText if placeholderText? div className: 'placeholder-text', placeholderText if placeholderText?
@ -162,7 +162,7 @@ LinesComponent = React.createClass
@lineNodesByLineId.hasOwnProperty(lineId) @lineNodesByLineId.hasOwnProperty(lineId)
buildLineHTML: (line, screenRow) -> buildLineHTML: (line, screenRow) ->
{mini, showIndentGuide, lineHeightInPixels, lineDecorations, lineWidth} = @props {showIndentGuide, lineHeightInPixels, lineDecorations, lineWidth} = @props
{tokens, text, lineEnding, fold, isSoftWrapped, indentLevel} = line {tokens, text, lineEnding, fold, isSoftWrapped, indentLevel} = line
classes = '' classes = ''
@ -208,7 +208,7 @@ LinesComponent = React.createClass
@buildEndOfLineHTML(line) or ' ' @buildEndOfLineHTML(line) or ' '
buildLineInnerHTML: (line) -> buildLineInnerHTML: (line) ->
{mini, showIndentGuide} = @props {editor, showIndentGuide} = @props
{tokens, text} = line {tokens, text} = line
innerHTML = "" innerHTML = ""
@ -217,7 +217,7 @@ LinesComponent = React.createClass
lineIsWhitespaceOnly = firstTrailingWhitespacePosition is 0 lineIsWhitespaceOnly = firstTrailingWhitespacePosition is 0
for token in tokens for token in tokens
innerHTML += @updateScopeStack(scopeStack, token.scopes) innerHTML += @updateScopeStack(scopeStack, token.scopes)
hasIndentGuide = not mini and showIndentGuide and (token.hasLeadingWhitespace() or (token.hasTrailingWhitespace() and lineIsWhitespaceOnly)) hasIndentGuide = not editor.isMini() and showIndentGuide and (token.hasLeadingWhitespace() or (token.hasTrailingWhitespace() and lineIsWhitespaceOnly))
innerHTML += token.getValueAsHtml({hasIndentGuide}) innerHTML += token.getValueAsHtml({hasIndentGuide})
innerHTML += @popScope(scopeStack) while scopeStack.length > 0 innerHTML += @popScope(scopeStack) while scopeStack.length > 0

View File

@ -48,7 +48,7 @@ TextEditorComponent = React.createClass
render: -> render: ->
{focused, showIndentGuide, showLineNumbers, visible} = @state {focused, showIndentGuide, showLineNumbers, visible} = @state
{editor, mini, cursorBlinkPeriod, cursorBlinkResumeDelay, hostElement, useShadowDOM} = @props {editor, cursorBlinkPeriod, cursorBlinkResumeDelay, hostElement, useShadowDOM} = @props
maxLineNumberDigits = editor.getLineCount().toString().length maxLineNumberDigits = editor.getLineCount().toString().length
hasSelection = editor.getLastSelection()? and !editor.getLastSelection().isEmpty() hasSelection = editor.getLastSelection()? and !editor.getLastSelection().isEmpty()
style = {} style = {}
@ -96,7 +96,7 @@ TextEditorComponent = React.createClass
className += ' has-selection' if hasSelection className += ' has-selection' if hasSelection
div {className, style}, div {className, style},
if @shouldRenderGutter() if @gutterVisible
GutterComponent { GutterComponent {
ref: 'gutter', onMouseDown: @onGutterMouseDown, lineDecorations, ref: 'gutter', onMouseDown: @onGutterMouseDown, lineDecorations,
defaultCharWidth, editor, renderedRowRange, maxLineNumberDigits, scrollViewHeight, defaultCharWidth, editor, renderedRowRange, maxLineNumberDigits, scrollViewHeight,
@ -118,7 +118,7 @@ TextEditorComponent = React.createClass
@scrollingVertically, scrollHeight, scrollWidth, mouseWheelScreenRow, @scrollingVertically, scrollHeight, scrollWidth, mouseWheelScreenRow,
visible, scrollViewHeight, @scopedCharacterWidthsChangeCount, lineWidth, @useHardwareAcceleration, visible, scrollViewHeight, @scopedCharacterWidthsChangeCount, lineWidth, @useHardwareAcceleration,
placeholderText, @performedInitialMeasurement, @backgroundColor, cursorPixelRects, placeholderText, @performedInitialMeasurement, @backgroundColor, cursorPixelRects,
cursorBlinkPeriod, cursorBlinkResumeDelay, mini, useShadowDOM cursorBlinkPeriod, cursorBlinkResumeDelay, useShadowDOM
} }
ScrollbarComponent ScrollbarComponent
@ -159,9 +159,6 @@ TextEditorComponent = React.createClass
{editor} = @props {editor} = @props
Math.max(1, Math.ceil(editor.getHeight() / editor.getLineHeightInPixels())) Math.max(1, Math.ceil(editor.getHeight() / editor.getLineHeightInPixels()))
shouldRenderGutter: ->
not @props.mini and @props.editor.isGutterVisible() and atom.config.get('editor.showLineNumbers')
getInitialState: -> {} getInitialState: -> {}
getDefaultProps: -> getDefaultProps: ->
@ -190,7 +187,7 @@ TextEditorComponent = React.createClass
@domPollingIntervalId = setInterval(@pollDOM, @domPollingInterval) @domPollingIntervalId = setInterval(@pollDOM, @domPollingInterval)
@updateParentViewFocusedClassIfNeeded({}) @updateParentViewFocusedClassIfNeeded({})
@updateParentViewMiniClassIfNeeded({}) @updateParentViewMiniClass()
@checkForVisibilityChange() @checkForVisibilityChange()
componentWillUnmount: -> componentWillUnmount: ->
@ -202,9 +199,6 @@ TextEditorComponent = React.createClass
clearInterval(@domPollingIntervalId) clearInterval(@domPollingIntervalId)
@domPollingIntervalId = null @domPollingIntervalId = null
componentWillReceiveProps: (newProps) ->
@props.editor.setMini(newProps.mini)
componentDidUpdate: (prevProps, prevState) -> componentDidUpdate: (prevProps, prevState) ->
cursorMoved = @cursorMoved cursorMoved = @cursorMoved
selectionChanged = @selectionChanged selectionChanged = @selectionChanged
@ -214,7 +208,7 @@ TextEditorComponent = React.createClass
if @props.editor.isAlive() if @props.editor.isAlive()
@updateParentViewFocusedClassIfNeeded(prevState) @updateParentViewFocusedClassIfNeeded(prevState)
@updateParentViewMiniClassIfNeeded(prevState) @updateParentViewMiniClass()
@props.hostElement.__spacePenView.trigger 'cursor:moved' if cursorMoved @props.hostElement.__spacePenView.trigger 'cursor:moved' if cursorMoved
@props.hostElement.__spacePenView.trigger 'selection:changed' if selectionChanged @props.hostElement.__spacePenView.trigger 'selection:changed' if selectionChanged
@props.hostElement.__spacePenView.trigger 'editor:display-updated' @props.hostElement.__spacePenView.trigger 'editor:display-updated'
@ -308,8 +302,8 @@ TextEditorComponent = React.createClass
cursorPixelRects cursorPixelRects
getLineDecorations: (decorationsByMarkerId) -> getLineDecorations: (decorationsByMarkerId) ->
{editor, mini} = @props {editor} = @props
return {} if mini return {} if editor.isMini()
decorationsByScreenRow = {} decorationsByScreenRow = {}
for markerId, decorations of decorationsByMarkerId for markerId, decorations of decorationsByMarkerId
@ -377,6 +371,8 @@ TextEditorComponent = React.createClass
observeEditor: -> observeEditor: ->
{editor} = @props {editor} = @props
@subscribe editor.onDidChange(@onScreenLinesChanged) @subscribe editor.onDidChange(@onScreenLinesChanged)
@subscribe editor.onDidChangeGutterVisible(@updateGutterVisible)
@subscribe editor.onDidChangeMini(@setMini)
@subscribe editor.observeGrammar(@onGrammarChanged) @subscribe editor.observeGrammar(@onGrammarChanged)
@subscribe editor.observeCursors(@onCursorAdded) @subscribe editor.observeCursors(@onCursorAdded)
@subscribe editor.observeSelections(@onSelectionAdded) @subscribe editor.observeSelections(@onSelectionAdded)
@ -463,8 +459,7 @@ TextEditorComponent = React.createClass
scopeDescriptor = editor.getRootScopeDescriptor() scopeDescriptor = editor.getRootScopeDescriptor()
subscriptions.add atom.config.observe 'editor.showIndentGuide', scope: scopeDescriptor, @setShowIndentGuide subscriptions.add atom.config.observe 'editor.showIndentGuide', scope: scopeDescriptor, @setShowIndentGuide
subscriptions.add atom.config.onDidChange 'editor.showLineNumbers', scope: scopeDescriptor, @requestUpdate subscriptions.add atom.config.observe 'editor.showLineNumbers', scope: scopeDescriptor, @updateGutterVisible
subscriptions.add editor.onDidChangeGutterVisible @requestUpdate
subscriptions.add atom.config.observe 'editor.scrollSensitivity', scope: scopeDescriptor, @setScrollSensitivity subscriptions.add atom.config.observe 'editor.scrollSensitivity', scope: scopeDescriptor, @setScrollSensitivity
focused: -> focused: ->
@ -882,7 +877,7 @@ TextEditorComponent = React.createClass
@backgroundColor = backgroundColor @backgroundColor = backgroundColor
@requestUpdate() unless suppressUpdate @requestUpdate() unless suppressUpdate
if @shouldRenderGutter() if @refs.gutter?
gutterBackgroundColor = getComputedStyle(@refs.gutter.getDOMNode()).backgroundColor gutterBackgroundColor = getComputedStyle(@refs.gutter.getDOMNode()).backgroundColor
if gutterBackgroundColor isnt @gutterBackgroundColor if gutterBackgroundColor isnt @gutterBackgroundColor
@gutterBackgroundColor = gutterBackgroundColor @gutterBackgroundColor = gutterBackgroundColor
@ -1002,6 +997,16 @@ TextEditorComponent = React.createClass
setShowIndentGuide: (showIndentGuide) -> setShowIndentGuide: (showIndentGuide) ->
@setState({showIndentGuide}) @setState({showIndentGuide})
setMini: ->
@updateGutterVisible()
@requestUpdate()
updateGutterVisible: ->
gutterVisible = not @props.editor.isMini() and @props.editor.isGutterVisible() and atom.config.get('editor.showLineNumbers')
if gutterVisible isnt @gutterVisible
@gutterVisible = gutterVisible
@requestUpdate()
# Deprecated # Deprecated
setInvisibles: (invisibles={}) -> setInvisibles: (invisibles={}) ->
grim.deprecate "Use config.set('editor.invisibles', invisibles) instead" grim.deprecate "Use config.set('editor.invisibles', invisibles) instead"
@ -1045,10 +1050,9 @@ TextEditorComponent = React.createClass
@props.hostElement.classList.toggle('is-focused', @state.focused) @props.hostElement.classList.toggle('is-focused', @state.focused)
@props.rootElement.classList.toggle('is-focused', @state.focused) @props.rootElement.classList.toggle('is-focused', @state.focused)
updateParentViewMiniClassIfNeeded: (prevProps) -> updateParentViewMiniClass: ->
if prevProps.mini isnt @props.mini @props.hostElement.classList.toggle('mini', @props.editor.isMini())
@props.hostElement.classList.toggle('mini', @props.mini) @props.rootElement.classList.toggle('mini', @props.editor.isMini())
@props.rootElement.classList.toggle('mini', @props.mini)
runScrollBenchmark: -> runScrollBenchmark: ->
unless process.env.NODE_ENV is 'production' unless process.env.NODE_ENV is 'production'

View File

@ -109,7 +109,6 @@ class TextEditorElement extends HTMLElement
rootElement: @rootElement rootElement: @rootElement
stylesElement: @stylesElement stylesElement: @stylesElement
editor: @model editor: @model
mini: @model.mini
lineOverdrawMargin: @lineOverdrawMargin lineOverdrawMargin: @lineOverdrawMargin
useShadowDOM: @useShadowDOM useShadowDOM: @useShadowDOM
) )

View File

@ -533,9 +533,14 @@ class TextEditor extends Model
if mini isnt @mini if mini isnt @mini
@mini = mini @mini = mini
@updateInvisibles() @updateInvisibles()
@emitter.emit 'did-change-mini', @mini
@mini
isMini: -> @mini isMini: -> @mini
onDidChangeMini: (callback) ->
@emitter.on 'did-change-mini', callback
setGutterVisible: (gutterVisible) -> setGutterVisible: (gutterVisible) ->
unless gutterVisible is @gutterVisible unless gutterVisible is @gutterVisible
@gutterVisible = gutterVisible @gutterVisible = gutterVisible