diff --git a/spec/text-editor-component-spec.coffee b/spec/text-editor-component-spec.coffee index e81dbb498..38a0f8c27 100644 --- a/spec/text-editor-component-spec.coffee +++ b/spec/text-editor-component-spec.coffee @@ -552,14 +552,29 @@ describe "TextEditorComponent", -> nextAnimationFrame() expect(lineNumbersNode.style.backgroundColor).toBe 'rgb(255, 0, 0)' - describe "when the editor.showLineNumbers config is false", -> - it "doesn't render any line numbers", -> - expect(component.refs.gutter).toBeDefined() - atom.config.set("editor.showLineNumbers", false) - expect(component.refs.gutter).not.toBeDefined() - atom.config.set("editor.showLineNumbers", true) - expect(component.refs.gutter).toBeDefined() - expect(component.lineNumberNodeForScreenRow(3)).toBeDefined() + it "hides or shows the gutter based on the '::isGutterVisible' property on the model and the global 'editor.showLineNumbers' config setting", -> + expect(component.refs.gutter?).toBe true + + editor.setGutterVisible(false) + nextAnimationFrame() + + expect(component.refs.gutter?).toBe false + + atom.config.set("editor.showLineNumbers", false) + expect(nextAnimationFrame).toBe noAnimationFrame + + expect(component.refs.gutter?).toBe false + + editor.setGutterVisible(true) + expect(nextAnimationFrame).toBe noAnimationFrame + + expect(component.refs.gutter?).toBe false + + atom.config.set("editor.showLineNumbers", true) + nextAnimationFrame() + + expect(component.refs.gutter?).toBe true + expect(component.lineNumberNodeForScreenRow(3)?).toBe true describe "fold decorations", -> describe "rendering fold decorations", -> @@ -2502,7 +2517,8 @@ describe "TextEditorComponent", -> describe "when the 'mini' property is true", -> beforeEach -> - component.setProps(mini: true) + editor.setMini(true) + nextAnimationFrame() it "does not render the gutter", -> expect(componentNode.querySelector('.gutter')).toBeNull() diff --git a/spec/text-editor-element-spec.coffee b/spec/text-editor-element-spec.coffee index f29a8f91b..cbcc5fc16 100644 --- a/spec/text-editor-element-spec.coffee +++ b/spec/text-editor-element-spec.coffee @@ -10,16 +10,21 @@ describe "TextEditorElement", -> jasmineContent = document.body.querySelector('#jasmine-content') describe "instantiation", -> - it "honors the mini attribute", -> + it "honors the 'mini' attribute", -> jasmineContent.innerHTML = "" element = jasmineContent.firstChild expect(element.getModel().isMini()).toBe true - it "honors the placeholder-text attribute", -> + it "honors the 'placeholder-text' attribute", -> jasmineContent.innerHTML = "" element = jasmineContent.firstChild expect(element.getModel().getPlaceholderText()).toBe 'testing' + it "honors the 'gutter-hidden' attribute", -> + jasmineContent.innerHTML = "" + element = jasmineContent.firstChild + expect(element.getModel().isGutterVisible()).toBe false + it "honors the text content", -> jasmineContent.innerHTML = "testing" element = jasmineContent.firstChild diff --git a/src/lines-component.coffee b/src/lines-component.coffee index 272577097..ff8827a21 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -23,12 +23,12 @@ LinesComponent = React.createClass if performedInitialMeasurement {editor, overlayDecorations, highlightDecorations, scrollHeight, scrollWidth, placeholderText, backgroundColor} = @props {lineHeightInPixels, defaultCharWidth, scrollViewHeight, scopedCharacterWidthsChangeCount} = @props - {scrollTop, scrollLeft, cursorPixelRects, mini} = @props + {scrollTop, scrollLeft, cursorPixelRects} = @props style = height: Math.max(scrollHeight, scrollViewHeight) width: scrollWidth WebkitTransform: @getTransform() - backgroundColor: if mini then null else backgroundColor + backgroundColor: if editor.isMini() then null else backgroundColor div {className: 'lines', style}, div className: 'placeholder-text', placeholderText if placeholderText? @@ -162,7 +162,7 @@ LinesComponent = React.createClass @lineNodesByLineId.hasOwnProperty(lineId) buildLineHTML: (line, screenRow) -> - {mini, showIndentGuide, lineHeightInPixels, lineDecorations, lineWidth} = @props + {showIndentGuide, lineHeightInPixels, lineDecorations, lineWidth} = @props {tokens, text, lineEnding, fold, isSoftWrapped, indentLevel} = line classes = '' @@ -208,7 +208,7 @@ LinesComponent = React.createClass @buildEndOfLineHTML(line) or ' ' buildLineInnerHTML: (line) -> - {mini, showIndentGuide} = @props + {editor, showIndentGuide} = @props {tokens, text} = line innerHTML = "" @@ -217,7 +217,7 @@ LinesComponent = React.createClass lineIsWhitespaceOnly = firstTrailingWhitespacePosition is 0 for token in tokens 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 += @popScope(scopeStack) while scopeStack.length > 0 diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 1e8ea96d3..830bf8727 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -48,7 +48,7 @@ TextEditorComponent = React.createClass render: -> {focused, showIndentGuide, showLineNumbers, visible} = @state - {editor, mini, cursorBlinkPeriod, cursorBlinkResumeDelay, hostElement, useShadowDOM} = @props + {editor, cursorBlinkPeriod, cursorBlinkResumeDelay, hostElement, useShadowDOM} = @props maxLineNumberDigits = editor.getLineCount().toString().length hasSelection = editor.getLastSelection()? and !editor.getLastSelection().isEmpty() style = {} @@ -96,7 +96,7 @@ TextEditorComponent = React.createClass className += ' has-selection' if hasSelection div {className, style}, - if @shouldRenderGutter() + if @gutterVisible GutterComponent { ref: 'gutter', onMouseDown: @onGutterMouseDown, lineDecorations, defaultCharWidth, editor, renderedRowRange, maxLineNumberDigits, scrollViewHeight, @@ -118,7 +118,7 @@ TextEditorComponent = React.createClass @scrollingVertically, scrollHeight, scrollWidth, mouseWheelScreenRow, visible, scrollViewHeight, @scopedCharacterWidthsChangeCount, lineWidth, @useHardwareAcceleration, placeholderText, @performedInitialMeasurement, @backgroundColor, cursorPixelRects, - cursorBlinkPeriod, cursorBlinkResumeDelay, mini, useShadowDOM + cursorBlinkPeriod, cursorBlinkResumeDelay, useShadowDOM } ScrollbarComponent @@ -159,9 +159,6 @@ TextEditorComponent = React.createClass {editor} = @props Math.max(1, Math.ceil(editor.getHeight() / editor.getLineHeightInPixels())) - shouldRenderGutter: -> - not @props.mini and @state.showLineNumbers - getInitialState: -> {} getDefaultProps: -> @@ -190,7 +187,7 @@ TextEditorComponent = React.createClass @domPollingIntervalId = setInterval(@pollDOM, @domPollingInterval) @updateParentViewFocusedClassIfNeeded({}) - @updateParentViewMiniClassIfNeeded({}) + @updateParentViewMiniClass() @checkForVisibilityChange() componentWillUnmount: -> @@ -202,9 +199,6 @@ TextEditorComponent = React.createClass clearInterval(@domPollingIntervalId) @domPollingIntervalId = null - componentWillReceiveProps: (newProps) -> - @props.editor.setMini(newProps.mini) - componentDidUpdate: (prevProps, prevState) -> cursorMoved = @cursorMoved selectionChanged = @selectionChanged @@ -214,7 +208,7 @@ TextEditorComponent = React.createClass if @props.editor.isAlive() @updateParentViewFocusedClassIfNeeded(prevState) - @updateParentViewMiniClassIfNeeded(prevState) + @updateParentViewMiniClass() @props.hostElement.__spacePenView.trigger 'cursor:moved' if cursorMoved @props.hostElement.__spacePenView.trigger 'selection:changed' if selectionChanged @props.hostElement.__spacePenView.trigger 'editor:display-updated' @@ -308,8 +302,8 @@ TextEditorComponent = React.createClass cursorPixelRects getLineDecorations: (decorationsByMarkerId) -> - {editor, mini} = @props - return {} if mini + {editor} = @props + return {} if editor.isMini() decorationsByScreenRow = {} for markerId, decorations of decorationsByMarkerId @@ -377,6 +371,8 @@ TextEditorComponent = React.createClass observeEditor: -> {editor} = @props @subscribe editor.onDidChange(@onScreenLinesChanged) + @subscribe editor.onDidChangeGutterVisible(@updateGutterVisible) + @subscribe editor.onDidChangeMini(@setMini) @subscribe editor.observeGrammar(@onGrammarChanged) @subscribe editor.observeCursors(@onCursorAdded) @subscribe editor.observeSelections(@onSelectionAdded) @@ -463,7 +459,7 @@ TextEditorComponent = React.createClass scopeDescriptor = editor.getRootScopeDescriptor() subscriptions.add atom.config.observe 'editor.showIndentGuide', scope: scopeDescriptor, @setShowIndentGuide - subscriptions.add atom.config.observe 'editor.showLineNumbers', scope: scopeDescriptor, @setShowLineNumbers + subscriptions.add atom.config.observe 'editor.showLineNumbers', scope: scopeDescriptor, @updateGutterVisible subscriptions.add atom.config.observe 'editor.scrollSensitivity', scope: scopeDescriptor, @setScrollSensitivity focused: -> @@ -881,7 +877,7 @@ TextEditorComponent = React.createClass @backgroundColor = backgroundColor @requestUpdate() unless suppressUpdate - if @shouldRenderGutter() + if @refs.gutter? gutterBackgroundColor = getComputedStyle(@refs.gutter.getDOMNode()).backgroundColor if gutterBackgroundColor isnt @gutterBackgroundColor @gutterBackgroundColor = gutterBackgroundColor @@ -1001,6 +997,16 @@ TextEditorComponent = React.createClass setShowIndentGuide: (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 setInvisibles: (invisibles={}) -> grim.deprecate "Use config.set('editor.invisibles', invisibles) instead" @@ -1010,9 +1016,6 @@ TextEditorComponent = React.createClass setShowInvisibles: (showInvisibles) -> atom.config.set('editor.showInvisibles', showInvisibles) - setShowLineNumbers: (showLineNumbers) -> - @setState({showLineNumbers}) - setScrollSensitivity: (scrollSensitivity) -> if scrollSensitivity = parseInt(scrollSensitivity) @scrollSensitivity = Math.abs(scrollSensitivity) / 100 @@ -1047,10 +1050,9 @@ TextEditorComponent = React.createClass @props.hostElement.classList.toggle('is-focused', @state.focused) @props.rootElement.classList.toggle('is-focused', @state.focused) - updateParentViewMiniClassIfNeeded: (prevProps) -> - if prevProps.mini isnt @props.mini - @props.hostElement.classList.toggle('mini', @props.mini) - @props.rootElement.classList.toggle('mini', @props.mini) + updateParentViewMiniClass: -> + @props.hostElement.classList.toggle('mini', @props.editor.isMini()) + @props.rootElement.classList.toggle('mini', @props.editor.isMini()) runScrollBenchmark: -> unless process.env.NODE_ENV is 'production' diff --git a/src/text-editor-element.coffee b/src/text-editor-element.coffee index 3cc52642a..38b980b65 100644 --- a/src/text-editor-element.coffee +++ b/src/text-editor-element.coffee @@ -100,6 +100,7 @@ class TextEditorElement extends HTMLElement tabLength: 2 softTabs: true mini: @hasAttribute('mini') + gutterVisible: not @hasAttribute('gutter-hidden') placeholderText: @getAttribute('placeholder-text') )) @@ -109,7 +110,6 @@ class TextEditorElement extends HTMLElement rootElement: @rootElement stylesElement: @stylesElement editor: @model - mini: @model.mini lineOverdrawMargin: @lineOverdrawMargin useShadowDOM: @useShadowDOM ) diff --git a/src/text-editor-view.coffee b/src/text-editor-view.coffee index b5e60aa8e..bcd0dcfb1 100644 --- a/src/text-editor-view.coffee +++ b/src/text-editor-view.coffee @@ -127,7 +127,7 @@ class TextEditorView extends View Object.defineProperty @::, 'lastRenderedScreenRow', get: -> @component.getRenderedRowRange()[1] Object.defineProperty @::, 'active', get: -> @is(@getPaneView()?.activeView) Object.defineProperty @::, 'isFocused', get: -> document.activeElement is @element or document.activeElement is @element.component?.refs.input.getDOMNode() - Object.defineProperty @::, 'mini', get: -> @component?.props.mini + Object.defineProperty @::, 'mini', get: -> @model?.isMini() Object.defineProperty @::, 'component', get: -> @element?.component afterAttach: (onDom) -> diff --git a/src/text-editor.coffee b/src/text-editor.coffee index aeaeb49ea..826b4863a 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -77,7 +77,7 @@ class TextEditor extends Model '$verticalScrollbarWidth', '$horizontalScrollbarHeight', '$scrollTop', '$scrollLeft', 'manageScrollPosition', toProperty: 'displayBuffer' - constructor: ({@softTabs, initialLine, initialColumn, tabLength, softWrapped, @displayBuffer, buffer, registerEditor, suppressCursorCreation, @mini, @placeholderText}) -> + constructor: ({@softTabs, initialLine, initialColumn, tabLength, softWrapped, @displayBuffer, buffer, registerEditor, suppressCursorCreation, @mini, @placeholderText, @gutterVisible}) -> super @emitter = new Emitter @@ -533,9 +533,25 @@ class TextEditor extends Model if mini isnt @mini @mini = mini @updateInvisibles() + @emitter.emit 'did-change-mini', @mini + @mini isMini: -> @mini + onDidChangeMini: (callback) -> + @emitter.on 'did-change-mini', callback + + setGutterVisible: (gutterVisible) -> + unless gutterVisible is @gutterVisible + @gutterVisible = gutterVisible + @emitter.emit 'did-change-gutter-visible', @gutterVisible + @gutterVisible + + isGutterVisible: -> @gutterVisible ? true + + onDidChangeGutterVisible: (callback) -> + @emitter.on 'did-change-gutter-visible', callback + # Set the number of characters that can be displayed horizontally in the # editor. #