From 7beafa2da6a854cbf82c0d4fb7afb5286d0dda12 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 30 Jun 2016 12:42:15 +0200 Subject: [PATCH 1/9] Introduce TextEditor.prototype.update This allows TextEditor objects to be used within an etch component easily. --- spec/text-editor-spec.coffee | 17 +++++++++++ src/text-editor.coffee | 59 +++++++++++++++++++++++++++++++----- 2 files changed, 68 insertions(+), 8 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index c3de3dbc6..da9ad5431 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -94,6 +94,23 @@ describe "TextEditor", -> editor2.unfoldBufferRow(4) expect(editor2.isFoldedAtBufferRow(4)).not.toBe editor.isFoldedAtBufferRow(4) + describe ".update()", -> + it "updates the editor with the supplied config parameters", -> + atom.config.set('editor.showInvisibles', true) + editor.onDidChange(changeSpy = jasmine.createSpy('onDidChange')) + editor.update({ + tabLength: 6, softTabs: false, softWrapped: true, editorWidthInChars: 40, + ignoreInvisibles: true, mini: false, lineNumberGutterVisible: false + }) + expect(changeSpy.callCount).toBe(1) + expect(editor.getTabLength()).toBe(6) + expect(editor.getSoftTabs()).toBe(false) + expect(editor.isSoftWrapped()).toBe(true) + expect(editor.getEditorWidthInChars()).toBe(40) + expect(editor.getInvisibles()).toEqual({}) + expect(editor.isMini()).toBe(false) + expect(editor.isLineNumberGutterVisible()).toBe(false) + describe "config defaults", -> it "uses the `editor.tabLength`, `editor.softWrap`, and `editor.softTabs`, and `core.fileEncoding` config values", -> editor1 = null diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 1a3f83232..c7aa93606 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -187,6 +187,49 @@ class TextEditor extends Model if grammar? @setGrammar(grammar) + update: (params) -> + { + softTabs, tabLength, softWrapped, mini, placeholderText, lineNumberGutterVisible, + showInvisibles, ignoreInvisibles, editorWidthInChars + } = params + + resetDisplayLayer = false + + if softTabs? and softTabs isnt @softTabs + @setSoftTabs(softTabs) + + if tabLength? and tabLength isnt @tabLength + @setTabLength(tabLength, false) + resetDisplayLayer = true + + if softWrapped? and softWrapped isnt @softWrapped + @setSoftWrapped(softWrapped, false) + resetDisplayLayer = true + + if mini? and mini isnt @mini + @setMini(mini) + + if placeholderText? and placeholderText isnt @placeholderText + @setPlaceholderText(placeholderText) + + if lineNumberGutterVisible? and lineNumberGutterVisible isnt @lineNumberGutterVisible + @setLineNumberGutterVisible(lineNumberGutterVisible) + + if showInvisibles? and showInvisibles isnt @showInvisibles + @showInvisibles = showInvisibles + resetDisplayLayer = true + + if ignoreInvisibles? and ignoreInvisibles isnt @ignoreInvisibles + @setIgnoreInvisibles(ignoreInvisibles, false) + resetDisplayLayer = true + + if editorWidthInChars? and editorWidthInChars isnt @editorWidthInChars + @setEditorWidthInChars(editorWidthInChars, false) + resetDisplayLayer = true + + if resetDisplayLayer + @resetDisplayLayer() + serialize: -> tokenizedBufferState = @tokenizedBuffer.serialize() @@ -652,12 +695,12 @@ class TextEditor extends Model # # * `editorWidthInChars` A {Number} representing the width of the # {TextEditorElement} in characters. - setEditorWidthInChars: (editorWidthInChars) -> + setEditorWidthInChars: (editorWidthInChars, resetDisplayLayer=true) -> if editorWidthInChars > 0 previousWidthInChars = @editorWidthInChars @editorWidthInChars = editorWidthInChars if editorWidthInChars isnt previousWidthInChars and @isSoftWrapped() - @resetDisplayLayer() + @resetDisplayLayer() if resetDisplayLayer # Returns the editor width in characters. getEditorWidthInChars: -> @@ -2721,18 +2764,18 @@ class TextEditor extends Model # # * `tabLength` {Number} length of a single tab. Setting to `null` will # fallback to using the `editor.tabLength` config setting - setTabLength: (tabLength) -> + setTabLength: (tabLength, resetDisplayLayer=true) -> return if tabLength is @tabLength @tabLength = tabLength @tokenizedBuffer.setTabLength(@tabLength) - @resetDisplayLayer() + @resetDisplayLayer() if resetDisplayLayer - setIgnoreInvisibles: (ignoreInvisibles) -> + setIgnoreInvisibles: (ignoreInvisibles, resetDisplayLayer=true) -> return if ignoreInvisibles is @ignoreInvisibles @ignoreInvisibles = ignoreInvisibles - @resetDisplayLayer() + @resetDisplayLayer() if resetDisplayLayer getInvisibles: -> scopeDescriptor = @getRootScopeDescriptor() @@ -2805,10 +2848,10 @@ class TextEditor extends Model # * `softWrapped` A {Boolean} # # Returns a {Boolean}. - setSoftWrapped: (softWrapped) -> + setSoftWrapped: (softWrapped, resetDisplayLayer=true) -> if softWrapped isnt @softWrapped @softWrapped = softWrapped - @resetDisplayLayer() + @resetDisplayLayer() if resetDisplayLayer softWrapped = @isSoftWrapped() @emitter.emit 'did-change-soft-wrapped', softWrapped softWrapped From c769b169aacbdd8fecc9e4e999f6d1ec0ce20ad6 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 30 Jun 2016 15:05:21 +0200 Subject: [PATCH 2/9] Allow scrollPastEnd to be set from the editor --- spec/text-editor-presenter-spec.coffee | 11 --------- spec/text-editor-spec.coffee | 34 ++++++++++++++++++++++++++ src/text-editor-component.coffee | 3 +-- src/text-editor-element.coffee | 4 +-- src/text-editor-presenter.coffee | 15 ++++-------- src/text-editor.coffee | 22 ++++++++++++++--- 6 files changed, 60 insertions(+), 29 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index e658140a5..a4f9d5fa0 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -647,17 +647,6 @@ describe "TextEditorPresenter", -> expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) expect(getState(presenter).verticalScrollbar.scrollHeight).toBe presenter.contentHeight - it "doesn't add the computed clientHeight to the computed scrollHeight if editor.scrollPastEnd is true but the presenter is created with scrollPastEnd as false", -> - presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10, scrollPastEnd: false) - expectStateUpdate presenter, -> presenter.setScrollTop(300) - expect(getState(presenter).verticalScrollbar.scrollHeight).toBe presenter.contentHeight - - expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", true) - expect(getState(presenter).verticalScrollbar.scrollHeight).toBe presenter.contentHeight - - expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) - expect(getState(presenter).verticalScrollbar.scrollHeight).toBe presenter.contentHeight - describe ".scrollTop", -> it "tracks the value of ::scrollTop", -> presenter = buildPresenter(scrollTop: 10, explicitHeight: 20, horizontalScrollbarHeight: 10) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index da9ad5431..4e38b7e16 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -5689,6 +5689,40 @@ describe "TextEditor", -> editor.selectPageUp() expect(editor.getSelectedBufferRanges()).toEqual [[[0, 0], [12, 2]]] + describe "scroll past end", -> + it "returns the scrollPastEnd setting on the editor instance if set, or 'editor.scrollPastEnd' otherwise", -> + atom.config.set('editor.scrollPastEnd', true) + expect(editor.getScrollPastEnd()).toBe(true) + + atom.config.set('editor.scrollPastEnd', false) + expect(editor.getScrollPastEnd()).toBe(false) + + editor.setScrollPastEnd(true) + expect(editor.getScrollPastEnd()).toBe(true) + + atom.config.set('editor.scrollPastEnd', true) + atom.config.set('editor.scrollPastEnd', false) + expect(editor.getScrollPastEnd()).toBe(true) + + it "emits a onDidChangeScrollPastEnd event when it changes", -> + scrollPastEndSpy = jasmine.createSpy('onDidChangeScrollPastEnd') + editor.onDidChangeScrollPastEnd(scrollPastEndSpy) + + atom.config.set('editor.scrollPastEnd', true) + expect(scrollPastEndSpy).toHaveBeenCalled() + + scrollPastEndSpy.reset() + editor.setScrollPastEnd(false) + expect(scrollPastEndSpy).toHaveBeenCalled() + + scrollPastEndSpy.reset() + editor.setScrollPastEnd(false) + expect(scrollPastEndSpy).not.toHaveBeenCalled() + + atom.config.set('editor.scrollPastEnd', false) + atom.config.set('editor.scrollPastEnd', true) + expect(scrollPastEndSpy).not.toHaveBeenCalled() + describe "::setFirstVisibleScreenRow() and ::getFirstVisibleScreenRow()", -> beforeEach -> line = Array(9).join('0123456789') diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index e6fc0dc15..c9b9a67dd 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -43,7 +43,7 @@ class TextEditorComponent @assert domNode?, "TextEditorComponent::domNode was set to null." @domNodeValue = domNode - constructor: ({@editor, @hostElement, @rootElement, @stylesElement, @useShadowDOM, tileSize, @views, @themes, @config, @workspace, @assert, @grammars, scrollPastEnd}) -> + constructor: ({@editor, @hostElement, @rootElement, @stylesElement, @useShadowDOM, tileSize, @views, @themes, @config, @workspace, @assert, @grammars}) -> @tileSize = tileSize if tileSize? @disposables = new CompositeDisposable @@ -61,7 +61,6 @@ class TextEditorComponent stoppedScrollingDelay: 200 config: @config lineTopIndex: lineTopIndex - scrollPastEnd: scrollPastEnd @presenter.onDidUpdateState(@requestUpdate) diff --git a/src/text-editor-element.coffee b/src/text-editor-element.coffee index 0c9fa6123..204a8e845 100644 --- a/src/text-editor-element.coffee +++ b/src/text-editor-element.coffee @@ -17,7 +17,6 @@ class TextEditorElement extends HTMLElement focusOnAttach: false hasTiledRendering: true logicalDisplayBuffer: true - scrollPastEnd: true autoHeight: true createdCallback: -> @@ -91,7 +90,7 @@ class TextEditorElement extends HTMLElement @subscriptions.add @component.onDidChangeScrollLeft => @emitter.emit("did-change-scroll-left", arguments...) - initialize: (model, {@views, @config, @themes, @workspace, @assert, @styles, @grammars}, @autoHeight = true, @scrollPastEnd = true) -> + initialize: (model, {@views, @config, @themes, @workspace, @assert, @styles, @grammars}, @autoHeight = true) -> throw new Error("Must pass a views parameter when initializing TextEditorElements") unless @views? throw new Error("Must pass a config parameter when initializing TextEditorElements") unless @config? throw new Error("Must pass a themes parameter when initializing TextEditorElements") unless @themes? @@ -148,7 +147,6 @@ class TextEditorElement extends HTMLElement workspace: @workspace assert: @assert grammars: @grammars - scrollPastEnd: @scrollPastEnd ) @rootElement.appendChild(@component.getDomNode()) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 5ce25f81a..cbfc5feea 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -13,7 +13,7 @@ class TextEditorPresenter minimumReflowInterval: 200 constructor: (params) -> - {@model, @config, @lineTopIndex, scrollPastEnd} = params + {@model, @config, @lineTopIndex} = params {@cursorBlinkPeriod, @cursorBlinkResumeDelay, @stoppedScrollingDelay, @tileSize} = params {@contentFrameWidth} = params {@displayLayer} = @model @@ -44,8 +44,6 @@ class TextEditorPresenter @startReflowing() if @continuousReflow @updating = false - @scrollPastEndOverride = scrollPastEnd ? true - setLinesYardstick: (@linesYardstick) -> getLinesYardstick: -> @linesYardstick @@ -160,6 +158,9 @@ class TextEditorPresenter @disposables.add @model.onDidChangeMini => @shouldUpdateDecorations = true @emitDidUpdateState() + @disposables.add @model.onDidChangeScrollPastEnd => + @updateScrollHeight() + @emitDidUpdateState() @disposables.add @model.onDidChangeLineNumberGutterVisible(@emitDidUpdateState.bind(this)) @@ -173,7 +174,6 @@ class TextEditorPresenter observeConfig: -> configParams = {scope: @model.getRootScopeDescriptor()} - @scrollPastEnd = @config.get('editor.scrollPastEnd', configParams) @showLineNumbers = @config.get('editor.showLineNumbers', configParams) if @configDisposables? @@ -183,11 +183,6 @@ class TextEditorPresenter @configDisposables = new CompositeDisposable @disposables.add(@configDisposables) - @configDisposables.add @config.onDidChange 'editor.scrollPastEnd', configParams, ({newValue}) => - @scrollPastEnd = newValue - @updateScrollHeight() - - @emitDidUpdateState() @configDisposables.add @config.onDidChange 'editor.showLineNumbers', configParams, ({newValue}) => @showLineNumbers = newValue @emitDidUpdateState() @@ -651,7 +646,7 @@ class TextEditorPresenter return unless @contentHeight? and @clientHeight? contentHeight = @contentHeight - if @scrollPastEnd and @scrollPastEndOverride + if @model.getScrollPastEnd() extraScrollHeight = @clientHeight - (@lineHeight * 3) contentHeight += extraScrollHeight if extraScrollHeight > 0 scrollHeight = Math.max(contentHeight, @height) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index c7aa93606..d649bf136 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -142,7 +142,6 @@ class TextEditor extends Model @cursorsByMarkerId = new Map @selections = [] @autoHeight ?= true - @scrollPastEnd ?= true @hasTerminatedPendingState = false @showInvisibles ?= true @@ -283,6 +282,9 @@ class TextEditor extends Model subscriptions.add @config.onDidChange 'editor.softWrapHangingIndent', scope: scopeDescriptor, @resetDisplayLayer.bind(this) subscriptions.add @config.onDidChange 'editor.softWrapAtPreferredLineLength', scope: scopeDescriptor, @resetDisplayLayer.bind(this) subscriptions.add @config.onDidChange 'editor.preferredLineLength', scope: scopeDescriptor, @resetDisplayLayer.bind(this) + subscriptions.add @config.onDidChange 'editor.scrollPastEnd', scope: scopeDescriptor, => + unless @scrollPastEnd? + @emitter.emit('did-change-scroll-past-end') @resetDisplayLayer() @@ -3320,6 +3322,20 @@ class TextEditor extends Model scrollEvent = {screenRange, options} @emitter.emit "did-request-autoscroll", scrollEvent + getScrollPastEnd: -> + if @scrollPastEnd? + @scrollPastEnd + else + @config.get('editor.scrollPastEnd', scope: @getRootScopeDescriptor()) + + setScrollPastEnd: (scrollPastEnd) -> + if scrollPastEnd isnt @scrollPastEnd + @scrollPastEnd = scrollPastEnd + @emitter.emit('did-change-scroll-past-end') + + onDidChangeScrollPastEnd: (callback) -> + @emitter.on('did-change-scroll-past-end', callback) + getHorizontalScrollbarHeight: -> Grim.deprecate("This is now a view method. Call TextEditorElement::getHorizontalScrollbarHeight instead.") @@ -3376,7 +3392,7 @@ class TextEditor extends Model # Get the Element for the editor. getElement: -> - @editorElement ?= new TextEditorElement().initialize(this, atom, @autoHeight, @scrollPastEnd) + @editorElement ?= new TextEditorElement().initialize(this, atom, @autoHeight) # Essential: Retrieves the greyed out placeholder of a mini editor. # @@ -3470,7 +3486,7 @@ class TextEditor extends Model setFirstVisibleScreenRow: (screenRow, fromView) -> unless fromView maxScreenRow = @getScreenLineCount() - 1 - unless @config.get('editor.scrollPastEnd') and @scrollPastEnd + unless @getScrollPastEnd() if @height? and @lineHeightInPixels? maxScreenRow -= Math.floor(@height / @lineHeightInPixels) screenRow = Math.max(Math.min(screenRow, maxScreenRow), 0) From ccf73189eea81f3bcfb0ad9b9f61d5adcbc8bd35 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 30 Jun 2016 15:07:20 +0200 Subject: [PATCH 3/9] Allow scrollPastEnd to be updated in `TextEditor.prototype.update` --- spec/text-editor-spec.coffee | 3 ++- src/text-editor.coffee | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 4e38b7e16..a6363eab0 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -100,7 +100,7 @@ describe "TextEditor", -> editor.onDidChange(changeSpy = jasmine.createSpy('onDidChange')) editor.update({ tabLength: 6, softTabs: false, softWrapped: true, editorWidthInChars: 40, - ignoreInvisibles: true, mini: false, lineNumberGutterVisible: false + ignoreInvisibles: true, mini: false, lineNumberGutterVisible: false, scrollPastEnd: true }) expect(changeSpy.callCount).toBe(1) expect(editor.getTabLength()).toBe(6) @@ -110,6 +110,7 @@ describe "TextEditor", -> expect(editor.getInvisibles()).toEqual({}) expect(editor.isMini()).toBe(false) expect(editor.isLineNumberGutterVisible()).toBe(false) + expect(editor.getScrollPastEnd()).toBe(true) describe "config defaults", -> it "uses the `editor.tabLength`, `editor.softWrap`, and `editor.softTabs`, and `core.fileEncoding` config values", -> diff --git a/src/text-editor.coffee b/src/text-editor.coffee index d649bf136..05c938cd3 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -189,7 +189,7 @@ class TextEditor extends Model update: (params) -> { softTabs, tabLength, softWrapped, mini, placeholderText, lineNumberGutterVisible, - showInvisibles, ignoreInvisibles, editorWidthInChars + showInvisibles, ignoreInvisibles, editorWidthInChars, scrollPastEnd } = params resetDisplayLayer = false @@ -226,6 +226,9 @@ class TextEditor extends Model @setEditorWidthInChars(editorWidthInChars, false) resetDisplayLayer = true + if scrollPastEnd? and scrollPastEnd isnt @scrollPastEnd + @setScrollPastEnd(scrollPastEnd) + if resetDisplayLayer @resetDisplayLayer() From 7325381fd60458f3123c12f7363a9b839f13bfa3 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 30 Jun 2016 15:08:51 +0200 Subject: [PATCH 4/9] :art: --- spec/text-editor-spec.coffee | 68 ++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index a6363eab0..43f6f5157 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -5690,40 +5690,6 @@ describe "TextEditor", -> editor.selectPageUp() expect(editor.getSelectedBufferRanges()).toEqual [[[0, 0], [12, 2]]] - describe "scroll past end", -> - it "returns the scrollPastEnd setting on the editor instance if set, or 'editor.scrollPastEnd' otherwise", -> - atom.config.set('editor.scrollPastEnd', true) - expect(editor.getScrollPastEnd()).toBe(true) - - atom.config.set('editor.scrollPastEnd', false) - expect(editor.getScrollPastEnd()).toBe(false) - - editor.setScrollPastEnd(true) - expect(editor.getScrollPastEnd()).toBe(true) - - atom.config.set('editor.scrollPastEnd', true) - atom.config.set('editor.scrollPastEnd', false) - expect(editor.getScrollPastEnd()).toBe(true) - - it "emits a onDidChangeScrollPastEnd event when it changes", -> - scrollPastEndSpy = jasmine.createSpy('onDidChangeScrollPastEnd') - editor.onDidChangeScrollPastEnd(scrollPastEndSpy) - - atom.config.set('editor.scrollPastEnd', true) - expect(scrollPastEndSpy).toHaveBeenCalled() - - scrollPastEndSpy.reset() - editor.setScrollPastEnd(false) - expect(scrollPastEndSpy).toHaveBeenCalled() - - scrollPastEndSpy.reset() - editor.setScrollPastEnd(false) - expect(scrollPastEndSpy).not.toHaveBeenCalled() - - atom.config.set('editor.scrollPastEnd', false) - atom.config.set('editor.scrollPastEnd', true) - expect(scrollPastEndSpy).not.toHaveBeenCalled() - describe "::setFirstVisibleScreenRow() and ::getFirstVisibleScreenRow()", -> beforeEach -> line = Array(9).join('0123456789') @@ -5804,6 +5770,40 @@ describe "TextEditor", -> expect(scrollSpy).toHaveBeenCalledWith(screenRange: [[8, 20], [8, 20]], options: {center: true}) expect(scrollSpy).toHaveBeenCalledWith(screenRange: [[8, 20], [8, 20]], options: {center: false, reversed: true}) + describe "scroll past end", -> + it "returns the scrollPastEnd setting on the editor instance if set, or 'editor.scrollPastEnd' otherwise", -> + atom.config.set('editor.scrollPastEnd', true) + expect(editor.getScrollPastEnd()).toBe(true) + + atom.config.set('editor.scrollPastEnd', false) + expect(editor.getScrollPastEnd()).toBe(false) + + editor.setScrollPastEnd(true) + expect(editor.getScrollPastEnd()).toBe(true) + + atom.config.set('editor.scrollPastEnd', true) + atom.config.set('editor.scrollPastEnd', false) + expect(editor.getScrollPastEnd()).toBe(true) + + it "emits a onDidChangeScrollPastEnd event when it changes", -> + scrollPastEndSpy = jasmine.createSpy('onDidChangeScrollPastEnd') + editor.onDidChangeScrollPastEnd(scrollPastEndSpy) + + atom.config.set('editor.scrollPastEnd', true) + expect(scrollPastEndSpy).toHaveBeenCalled() + + scrollPastEndSpy.reset() + editor.setScrollPastEnd(false) + expect(scrollPastEndSpy).toHaveBeenCalled() + + scrollPastEndSpy.reset() + editor.setScrollPastEnd(false) + expect(scrollPastEndSpy).not.toHaveBeenCalled() + + atom.config.set('editor.scrollPastEnd', false) + atom.config.set('editor.scrollPastEnd', true) + expect(scrollPastEndSpy).not.toHaveBeenCalled() + describe '.get/setPlaceholderText()', -> it 'can be created with placeholderText', -> newEditor = atom.workspace.buildTextEditor( From 8cb0fbcc5cba08422a6522a964d038c95e25f870 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 30 Jun 2016 15:27:47 +0200 Subject: [PATCH 5/9] Allow autoHeight to be set from the editor --- spec/text-editor-spec.coffee | 25 +++++++++++++++++++++++++ src/text-editor-element.coffee | 11 +++++++---- src/text-editor.coffee | 14 ++++++++++++-- 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 43f6f5157..d504b1b2d 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -5804,6 +5804,31 @@ describe "TextEditor", -> atom.config.set('editor.scrollPastEnd', true) expect(scrollPastEndSpy).not.toHaveBeenCalled() + describe "auto height", -> + it "returns true by default but can be customized", -> + expect(editor.getAutoHeight()).toBe(true) + + editor.setAutoHeight(false) + expect(editor.getAutoHeight()).toBe(false) + + editor.setAutoHeight(true) + expect(editor.getAutoHeight()).toBe(true) + + it "emits a onDidChangeAutoHeight event when it changes", -> + autoHeightSpy = jasmine.createSpy('onDidChangeAutoHeight') + editor.onDidChangeAutoHeight(autoHeightSpy) + + editor.setAutoHeight(true) + expect(autoHeightSpy).toHaveBeenCalled() + + autoHeightSpy.reset() + editor.setAutoHeight(false) + expect(autoHeightSpy).toHaveBeenCalled() + + autoHeightSpy.reset() + editor.setAutoHeight(false) + expect(autoHeightSpy).not.toHaveBeenCalled() + describe '.get/setPlaceholderText()', -> it 'can be created with placeholderText', -> newEditor = atom.workspace.buildTextEditor( diff --git a/src/text-editor-element.coffee b/src/text-editor-element.coffee index 204a8e845..1de43c6bd 100644 --- a/src/text-editor-element.coffee +++ b/src/text-editor-element.coffee @@ -17,7 +17,6 @@ class TextEditorElement extends HTMLElement focusOnAttach: false hasTiledRendering: true logicalDisplayBuffer: true - autoHeight: true createdCallback: -> # Use globals when the following instance variables aren't set. @@ -39,8 +38,7 @@ class TextEditorElement extends HTMLElement @setAttribute('tabindex', -1) initializeContent: (attributes) -> - unless @autoHeight - @style.height = "100%" + @resetAutoHeight() if @config.get('editor.useShadowDOM') @useShadowDOM = true @@ -90,7 +88,7 @@ class TextEditorElement extends HTMLElement @subscriptions.add @component.onDidChangeScrollLeft => @emitter.emit("did-change-scroll-left", arguments...) - initialize: (model, {@views, @config, @themes, @workspace, @assert, @styles, @grammars}, @autoHeight = true) -> + initialize: (model, {@views, @config, @themes, @workspace, @assert, @styles, @grammars}) -> throw new Error("Must pass a views parameter when initializing TextEditorElements") unless @views? throw new Error("Must pass a config parameter when initializing TextEditorElements") unless @config? throw new Error("Must pass a themes parameter when initializing TextEditorElements") unless @themes? @@ -117,6 +115,7 @@ class TextEditorElement extends HTMLElement @model.onDidChangeEncoding => @addEncodingAttribute() @model.onDidDestroy => @unmountComponent() @model.onDidChangeMini (mini) => if mini then @addMiniAttribute() else @removeMiniAttribute() + @model.onDidChangeAutoHeight(@resetAutoHeight.bind(this)) @model getModel: -> @@ -193,6 +192,10 @@ class TextEditorElement extends HTMLElement removeMiniAttribute: -> @removeAttribute("mini") + resetAutoHeight: -> + unless @getModel().getAutoHeight() + @style.height = "100%" + addEncodingAttribute: -> @dataset.encoding = @model.getEncoding() diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 05c938cd3..9ff67ce92 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -141,7 +141,6 @@ class TextEditor extends Model @cursors = [] @cursorsByMarkerId = new Map @selections = [] - @autoHeight ?= true @hasTerminatedPendingState = false @showInvisibles ?= true @@ -3395,7 +3394,7 @@ class TextEditor extends Model # Get the Element for the editor. getElement: -> - @editorElement ?= new TextEditorElement().initialize(this, atom, @autoHeight) + @editorElement ?= new TextEditorElement().initialize(this, atom) # Essential: Retrieves the greyed out placeholder of a mini editor. # @@ -3470,6 +3469,17 @@ class TextEditor extends Model Grim.deprecate("This is now a view method. Call TextEditorElement::getHeight instead.") @height + getAutoHeight: -> + @autoHeight ? true + + setAutoHeight: (autoHeight) -> + if autoHeight isnt @autoHeight + @autoHeight = autoHeight + @emitter.emit('did-change-auto-height') + + onDidChangeAutoHeight: (callback) -> + @emitter.on('did-change-auto-height', callback) + setWidth: (width, reentrant=false) -> if reentrant oldWidth = @width From b46ae1e681f7f28e56a26104193d51c264dadf1c Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 30 Jun 2016 15:30:05 +0200 Subject: [PATCH 6/9] Allow autoHeight to be updated in `TextEditor.prototype.update` --- spec/text-editor-spec.coffee | 4 +++- src/text-editor.coffee | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index d504b1b2d..b892f59eb 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -100,7 +100,8 @@ describe "TextEditor", -> editor.onDidChange(changeSpy = jasmine.createSpy('onDidChange')) editor.update({ tabLength: 6, softTabs: false, softWrapped: true, editorWidthInChars: 40, - ignoreInvisibles: true, mini: false, lineNumberGutterVisible: false, scrollPastEnd: true + ignoreInvisibles: true, mini: false, lineNumberGutterVisible: false, scrollPastEnd: true, + autoHeight: false }) expect(changeSpy.callCount).toBe(1) expect(editor.getTabLength()).toBe(6) @@ -111,6 +112,7 @@ describe "TextEditor", -> expect(editor.isMini()).toBe(false) expect(editor.isLineNumberGutterVisible()).toBe(false) expect(editor.getScrollPastEnd()).toBe(true) + expect(editor.getAutoHeight()).toBe(false) describe "config defaults", -> it "uses the `editor.tabLength`, `editor.softWrap`, and `editor.softTabs`, and `core.fileEncoding` config values", -> diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 9ff67ce92..560d06768 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -188,7 +188,7 @@ class TextEditor extends Model update: (params) -> { softTabs, tabLength, softWrapped, mini, placeholderText, lineNumberGutterVisible, - showInvisibles, ignoreInvisibles, editorWidthInChars, scrollPastEnd + showInvisibles, ignoreInvisibles, editorWidthInChars, scrollPastEnd, autoHeight } = params resetDisplayLayer = false @@ -228,6 +228,9 @@ class TextEditor extends Model if scrollPastEnd? and scrollPastEnd isnt @scrollPastEnd @setScrollPastEnd(scrollPastEnd) + if autoHeight? and autoHeight isnt @autoHeight + @setAutoHeight(autoHeight) + if resetDisplayLayer @resetDisplayLayer() From 7efb407d8a40ed4b132143756d57ffd050b3d0af Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 30 Jun 2016 15:48:00 +0200 Subject: [PATCH 7/9] Write spec for TextEditorElement when autoHeight changes --- spec/text-editor-element-spec.coffee | 20 ++++++++++++++++++++ src/text-editor-element.coffee | 10 +++++++--- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/spec/text-editor-element-spec.coffee b/spec/text-editor-element-spec.coffee index c60a9762f..0677f0284 100644 --- a/spec/text-editor-element-spec.coffee +++ b/spec/text-editor-element-spec.coffee @@ -267,6 +267,26 @@ describe "TextEditorElement", -> element.getModel().setMini(false) expect(element.hasAttribute('mini')).toBe false + describe "on TextEditor::onDidChangeAutoHeight", -> + it "changes the element's height", -> + element = new TextEditorElement + jasmine.attachToDOM(element) + expect(element.style.height).toBe('') + element.getModel().setAutoHeight(false) + + waitsForPromise -> + atom.views.getNextUpdatePromise() + + runs -> + expect(element.style.height).toBe('100%') + element.getModel().setAutoHeight(true) + + waitsForPromise -> + atom.views.getNextUpdatePromise() + + runs -> + expect(element.style.height).toBe('') + describe "events", -> element = null diff --git a/src/text-editor-element.coffee b/src/text-editor-element.coffee index 1de43c6bd..4ab90a808 100644 --- a/src/text-editor-element.coffee +++ b/src/text-editor-element.coffee @@ -38,7 +38,8 @@ class TextEditorElement extends HTMLElement @setAttribute('tabindex', -1) initializeContent: (attributes) -> - @resetAutoHeight() + unless @getModel().getAutoHeight() + @style.height = "100%" if @config.get('editor.useShadowDOM') @useShadowDOM = true @@ -193,8 +194,11 @@ class TextEditorElement extends HTMLElement @removeAttribute("mini") resetAutoHeight: -> - unless @getModel().getAutoHeight() - @style.height = "100%" + @views.updateDocument => + if @getModel().getAutoHeight() + @style.height = "" + else + @style.height = "100%" addEncodingAttribute: -> @dataset.encoding = @model.getEncoding() From 811ab26f6196c14e133e3d9ce36f12ab659451dd Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 8 Jul 2016 09:42:08 +0200 Subject: [PATCH 8/9] Return an update promise in TextEditor.prototype.update() --- spec/text-editor-spec.coffee | 28 +++++++++++++++++----------- src/text-editor.coffee | 5 +++++ 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index b892f59eb..699492ecc 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -96,23 +96,29 @@ describe "TextEditor", -> describe ".update()", -> it "updates the editor with the supplied config parameters", -> + element = editor.element # force element initialization atom.config.set('editor.showInvisibles', true) editor.onDidChange(changeSpy = jasmine.createSpy('onDidChange')) - editor.update({ + updatePromise = editor.update({ tabLength: 6, softTabs: false, softWrapped: true, editorWidthInChars: 40, ignoreInvisibles: true, mini: false, lineNumberGutterVisible: false, scrollPastEnd: true, autoHeight: false }) - expect(changeSpy.callCount).toBe(1) - expect(editor.getTabLength()).toBe(6) - expect(editor.getSoftTabs()).toBe(false) - expect(editor.isSoftWrapped()).toBe(true) - expect(editor.getEditorWidthInChars()).toBe(40) - expect(editor.getInvisibles()).toEqual({}) - expect(editor.isMini()).toBe(false) - expect(editor.isLineNumberGutterVisible()).toBe(false) - expect(editor.getScrollPastEnd()).toBe(true) - expect(editor.getAutoHeight()).toBe(false) + + waitsForPromise -> + updatePromise + + runs -> + expect(changeSpy.callCount).toBe(1) + expect(editor.getTabLength()).toBe(6) + expect(editor.getSoftTabs()).toBe(false) + expect(editor.isSoftWrapped()).toBe(true) + expect(editor.getEditorWidthInChars()).toBe(40) + expect(editor.getInvisibles()).toEqual({}) + expect(editor.isMini()).toBe(false) + expect(editor.isLineNumberGutterVisible()).toBe(false) + expect(editor.getScrollPastEnd()).toBe(true) + expect(editor.getAutoHeight()).toBe(false) describe "config defaults", -> it "uses the `editor.tabLength`, `editor.softWrap`, and `editor.softTabs`, and `core.fileEncoding` config values", -> diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 560d06768..9fdc6bdd3 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -234,6 +234,11 @@ class TextEditor extends Model if resetDisplayLayer @resetDisplayLayer() + if @editorElement? + @editorElement.views.getNextUpdatePromise() + else + Promise.resolve() + serialize: -> tokenizedBufferState = @tokenizedBuffer.serialize() From de3b48b2d3d8a1e31f76fe748e52d396ce4949db Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 8 Jul 2016 10:07:37 +0200 Subject: [PATCH 9/9] Use editor.update in tests --- spec/text-editor-element-spec.coffee | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/spec/text-editor-element-spec.coffee b/spec/text-editor-element-spec.coffee index 0677f0284..a85070ef0 100644 --- a/spec/text-editor-element-spec.coffee +++ b/spec/text-editor-element-spec.coffee @@ -269,23 +269,21 @@ describe "TextEditorElement", -> describe "on TextEditor::onDidChangeAutoHeight", -> it "changes the element's height", -> - element = new TextEditorElement - jasmine.attachToDOM(element) - expect(element.style.height).toBe('') - element.getModel().setAutoHeight(false) + editor = atom.workspace.buildTextEditor() + jasmine.attachToDOM(editor.element) + expect(editor.element.style.height).toBe('') waitsForPromise -> - atom.views.getNextUpdatePromise() + editor.update({autoHeight: false}) runs -> - expect(element.style.height).toBe('100%') - element.getModel().setAutoHeight(true) + expect(editor.element.style.height).toBe('100%') waitsForPromise -> - atom.views.getNextUpdatePromise() + editor.update({autoHeight: true}) runs -> - expect(element.style.height).toBe('') + expect(editor.element.style.height).toBe('') describe "events", -> element = null