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)