From 44dabf1e2fb6f058d7d2e024063f036bf75bc73b Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 25 Feb 2016 10:22:10 -0500 Subject: [PATCH 01/22] Added .getElement to TextEditor. --- src/text-editor.coffee | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index c0a6f2057..d1c092598 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -11,6 +11,7 @@ Selection = require './selection' TextMateScopeSelector = require('first-mate').ScopeSelector {Directory} = require "pathwatcher" GutterContainer = require './gutter-container' +TextEditorElement = require './text-editor-element' # Essential: This class represents all essential editing state for a single # {TextBuffer}, including cursor and selection positions, folds, and soft wraps. @@ -61,6 +62,10 @@ class TextEditor extends Model suppressSelectionMerging: false selectionFlashDuration: 500 gutterContainer: null + editorElement: null + + Object.defineProperty @prototype, "element", + get: -> @getElement() @deserialize: (state, atomEnvironment) -> try @@ -3142,6 +3147,10 @@ class TextEditor extends Model Section: TextEditor Rendering ### + # Get the Element for the editor. + getElement: -> + @editorElement ?= new TextEditorElement().initialize(this, atom) + # Essential: Retrieves the greyed out placeholder of a mini editor. # # Returns a {String}. From 10f0064a63c93b36511ce265453e6394f4e594e4 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 25 Feb 2016 10:24:31 -0500 Subject: [PATCH 02/22] Call .getElement if the model has it. --- src/view-registry.coffee | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/view-registry.coffee b/src/view-registry.coffee index ef7151353..5fbfba729 100644 --- a/src/view-registry.coffee +++ b/src/view-registry.coffee @@ -171,6 +171,11 @@ class ViewRegistry if object instanceof HTMLElement return object + if typeof object?.getElement is 'function' + element = object.getElement() + if element instanceof HTMLElement + return element + if object?.element instanceof HTMLElement return object.element From 02c7bb3ddd8ef2980e5c7be69c2dfb0e78967370 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 25 Feb 2016 10:24:38 -0500 Subject: [PATCH 03/22] Don't need this view provider anymore. --- src/atom-environment.coffee | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/atom-environment.coffee b/src/atom-environment.coffee index c42bf05aa..dc1bef7d4 100644 --- a/src/atom-environment.coffee +++ b/src/atom-environment.coffee @@ -254,8 +254,6 @@ class AtomEnvironment extends Model new PaneAxisElement().initialize(model, env) @views.addViewProvider Pane, (model, env) -> new PaneElement().initialize(model, env) - @views.addViewProvider TextEditor, (model, env) -> - new TextEditorElement().initialize(model, env) @views.addViewProvider(Gutter, createGutterView) registerDefaultOpeners: -> From dfb1d1d62d091bfc6e87fb3e56bd2c9b81d36d89 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 25 Feb 2016 10:24:51 -0500 Subject: [PATCH 04/22] Expose a bound buildTextEditor. --- src/workspace.coffee | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/workspace.coffee b/src/workspace.coffee index 0bfff7e0f..e0a913f94 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -43,6 +43,12 @@ class Workspace extends Model @defaultDirectorySearcher = new DefaultDirectorySearcher() @consumeServices(@packageManager) + # One cannot simply .bind here since it could be used as a component with + # Etch, which means it'd be `new`d in which case `this` would the new + # object. + realThis = this + @buildTextEditor = (params) -> realThis.buildTextEditor_(params) + @panelContainers = top: new PanelContainer({location: 'top'}) left: new PanelContainer({location: 'left'}) @@ -550,7 +556,7 @@ class Workspace extends Model # Extended: Create a new text editor. # # Returns a {TextEditor}. - buildTextEditor: (params) -> + buildTextEditor_: (params) -> params = _.extend({ @config, @notificationManager, @packageManager, @clipboard, @viewRegistry, @grammarRegistry, @project, @assert, @applicationDelegate From 768f5ee5ca1c9eb2a896e668661c54e6dbc1541f Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 25 Feb 2016 14:00:49 -0500 Subject: [PATCH 05/22] Maybe a better comment? --- src/workspace.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/workspace.coffee b/src/workspace.coffee index e0a913f94..15ffc6e6a 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -44,8 +44,8 @@ class Workspace extends Model @consumeServices(@packageManager) # One cannot simply .bind here since it could be used as a component with - # Etch, which means it'd be `new`d in which case `this` would the new - # object. + # Etch, in which case it'd be `new`d. And when it's `new`d, `this` is always + # the newly created object. realThis = this @buildTextEditor = (params) -> realThis.buildTextEditor_(params) From 55e1496b96b93d9cec2a48dd261081165b09632e Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 25 Feb 2016 14:49:07 -0500 Subject: [PATCH 06/22] Call the prototype method directly. h/t @maxbrunsfeld --- src/workspace.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/workspace.coffee b/src/workspace.coffee index 15ffc6e6a..31c381428 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -47,7 +47,7 @@ class Workspace extends Model # Etch, in which case it'd be `new`d. And when it's `new`d, `this` is always # the newly created object. realThis = this - @buildTextEditor = (params) -> realThis.buildTextEditor_(params) + @buildTextEditor = -> Workspace.prototype.buildTextEditor.apply(realThis, arguments) @panelContainers = top: new PanelContainer({location: 'top'}) @@ -556,7 +556,7 @@ class Workspace extends Model # Extended: Create a new text editor. # # Returns a {TextEditor}. - buildTextEditor_: (params) -> + buildTextEditor: (params) -> params = _.extend({ @config, @notificationManager, @packageManager, @clipboard, @viewRegistry, @grammarRegistry, @project, @assert, @applicationDelegate From f3ce468a7068a09c26e2f76078ad5a820253cf9b Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 25 Feb 2016 15:01:40 -0500 Subject: [PATCH 07/22] Support specifying whether to ignore invisibles and the grammar. --- src/text-editor.coffee | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index d1c092598..e1706d5f1 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -97,7 +97,7 @@ class TextEditor extends Model softWrapped, @displayBuffer, @selectionsMarkerLayer, buffer, suppressCursorCreation, @mini, @placeholderText, lineNumberGutterVisible, largeFileMode, @config, @notificationManager, @packageManager, @clipboard, @viewRegistry, @grammarRegistry, - @project, @assert, @applicationDelegate, @pending + @project, @assert, @applicationDelegate, @pending, grammarName, ignoreInvisibles } = params throw new Error("Must pass a config parameter when constructing TextEditors") unless @config? @@ -119,7 +119,7 @@ class TextEditor extends Model buffer ?= new TextBuffer @displayBuffer ?= new DisplayBuffer({ - buffer, tabLength, softWrapped, ignoreInvisibles: @mini, largeFileMode, + buffer, tabLength, softWrapped, ignoreInvisibles: @mini || ignoreInvisibles, largeFileMode, @config, @assert, @grammarRegistry, @packageManager }) @buffer = @displayBuffer.buffer @@ -148,6 +148,9 @@ class TextEditor extends Model priority: 0 visible: lineNumberGutterVisible + if grammarName? + @setGrammar(@grammarRegistry.grammarForScopeName(grammarName)) + serialize: -> deserializer: 'TextEditor' id: @id From 822cd780555278b615e0da32020115b0d5fe7295 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 25 Feb 2016 15:18:29 -0500 Subject: [PATCH 08/22] Use the computed style to find the height --- src/text-editor-component.coffee | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index bdd0befcd..d5103c1fb 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -731,8 +731,7 @@ class TextEditorComponent measureDimensions: -> return unless @mounted - {position} = getComputedStyle(@hostElement) - {height} = @hostElement.style + {position, height} = getComputedStyle(@hostElement) if position is 'absolute' or height @presenter.setAutoHeight(false) From 2af53231f16c602423f223fe99fb834a730d5f9f Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 25 Feb 2016 15:21:56 -0500 Subject: [PATCH 09/22] Less lint. --- src/text-editor.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index e1706d5f1..19b7e8c86 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -119,7 +119,7 @@ class TextEditor extends Model buffer ?= new TextBuffer @displayBuffer ?= new DisplayBuffer({ - buffer, tabLength, softWrapped, ignoreInvisibles: @mini || ignoreInvisibles, largeFileMode, + buffer, tabLength, softWrapped, ignoreInvisibles: @mini or ignoreInvisibles, largeFileMode, @config, @assert, @grammarRegistry, @packageManager }) @buffer = @displayBuffer.buffer From dd780a7c5a415f513acae6d501df1f4f23c1cf93 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 25 Feb 2016 15:41:55 -0500 Subject: [PATCH 10/22] Revert "Use the computed style to find the height" This reverts commit 822cd780555278b615e0da32020115b0d5fe7295. --- src/text-editor-component.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index d5103c1fb..bdd0befcd 100644 --- a/src/text-editor-component.coffee +++ b/src/text-editor-component.coffee @@ -731,7 +731,8 @@ class TextEditorComponent measureDimensions: -> return unless @mounted - {position, height} = getComputedStyle(@hostElement) + {position} = getComputedStyle(@hostElement) + {height} = @hostElement.style if position is 'absolute' or height @presenter.setAutoHeight(false) From dd83619c45a8fc0e4decf0127bfa38d0f46a128d Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 25 Feb 2016 16:05:57 -0500 Subject: [PATCH 11/22] Add autoHeight setting. --- src/text-editor-element.coffee | 4 ++++ src/text-editor.coffee | 9 +++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/text-editor-element.coffee b/src/text-editor-element.coffee index 380417163..554f73cef 100644 --- a/src/text-editor-element.coffee +++ b/src/text-editor-element.coffee @@ -344,6 +344,10 @@ class TextEditorElement extends HTMLElement @style.height = height + "px" @component.measureDimensions() + disableAutoHeight: -> + @style.height = "100%" + @component.measureDimensions() + getHeight: -> @offsetHeight diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 19b7e8c86..06e58aa1e 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -97,7 +97,7 @@ class TextEditor extends Model softWrapped, @displayBuffer, @selectionsMarkerLayer, buffer, suppressCursorCreation, @mini, @placeholderText, lineNumberGutterVisible, largeFileMode, @config, @notificationManager, @packageManager, @clipboard, @viewRegistry, @grammarRegistry, - @project, @assert, @applicationDelegate, @pending, grammarName, ignoreInvisibles + @project, @assert, @applicationDelegate, @pending, grammarName, ignoreInvisibles, @autoHeight } = params throw new Error("Must pass a config parameter when constructing TextEditors") unless @config? @@ -116,6 +116,7 @@ class TextEditor extends Model @cursors = [] @cursorsByMarkerId = new Map @selections = [] + @autoHeight ?= true buffer ?= new TextBuffer @displayBuffer ?= new DisplayBuffer({ @@ -3152,7 +3153,11 @@ class TextEditor extends Model # Get the Element for the editor. getElement: -> - @editorElement ?= new TextEditorElement().initialize(this, atom) + if not @editorElement? + @editorElement = new TextEditorElement().initialize(this, atom) + if not @autoHeight + @editorElement.disableAutoHeight() + @editorElement # Essential: Retrieves the greyed out placeholder of a mini editor. # From ff0b9e30a9bea281bfad8ab55e57bce4daf5e386 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 25 Feb 2016 16:59:58 -0500 Subject: [PATCH 12/22] Add ignoreScrollPastEnd --- src/text-editor-component.coffee | 3 ++- src/text-editor-element.coffee | 4 +++- src/text-editor-presenter.coffee | 4 ++-- src/text-editor.coffee | 11 ++++++----- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index bdd0befcd..5a4097fc5 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}) -> + constructor: ({@editor, @hostElement, @rootElement, @stylesElement, @useShadowDOM, tileSize, @views, @themes, @config, @workspace, @assert, @grammars, ignoreScrollPastEnd}) -> @tileSize = tileSize if tileSize? @disposables = new CompositeDisposable @@ -61,6 +61,7 @@ class TextEditorComponent stoppedScrollingDelay: 200 config: @config lineTopIndex: lineTopIndex + ignoreScrollPastEnd: ignoreScrollPastEnd @presenter.onDidUpdateState(@requestUpdate) diff --git a/src/text-editor-element.coffee b/src/text-editor-element.coffee index 554f73cef..6fad33dc3 100644 --- a/src/text-editor-element.coffee +++ b/src/text-editor-element.coffee @@ -17,6 +17,7 @@ class TextEditorElement extends HTMLElement focusOnAttach: false hasTiledRendering: true logicalDisplayBuffer: true + ignoreScrollPastEnd: false createdCallback: -> # Use globals when the following instance variables aren't set. @@ -86,7 +87,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}) -> + initialize: (model, {@views, @config, @themes, @workspace, @assert, @styles, @grammars}, @ignoreScrollPastEnd = false) -> throw new Error("Must pass a config 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? @@ -143,6 +144,7 @@ class TextEditorElement extends HTMLElement workspace: @workspace assert: @assert grammars: @grammars + ignoreScrollPastEnd: @ignoreScrollPastEnd ) @rootElement.appendChild(@component.getDomNode()) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index a3504caa8..0db175c2b 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} = params + {@model, @config, @lineTopIndex, @ignoreScrollPastEnd} = params {@cursorBlinkPeriod, @cursorBlinkResumeDelay, @stoppedScrollingDelay, @tileSize} = params {@contentFrameWidth} = params @@ -661,7 +661,7 @@ class TextEditorPresenter return unless @contentHeight? and @clientHeight? contentHeight = @contentHeight - if @scrollPastEnd + if @scrollPastEnd and not @ignoreScrollPastEnd 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 c1a4150e9..c22a1a73f 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -97,7 +97,7 @@ class TextEditor extends Model softWrapped, @displayBuffer, @selectionsMarkerLayer, buffer, suppressCursorCreation, @mini, @placeholderText, lineNumberGutterVisible, largeFileMode, @config, @notificationManager, @packageManager, @clipboard, @viewRegistry, @grammarRegistry, - @project, @assert, @applicationDelegate, @pending, grammarName, ignoreInvisibles, @autoHeight + @project, @assert, @applicationDelegate, @pending, grammarName, ignoreInvisibles, @autoHeight, @ignoreScrollPastEnd } = params throw new Error("Must pass a config parameter when constructing TextEditors") unless @config? @@ -117,6 +117,7 @@ class TextEditor extends Model @cursorsByMarkerId = new Map @selections = [] @autoHeight ?= true + @ignoreScrollPastEnd ?= false buffer ?= new TextBuffer @displayBuffer ?= new DisplayBuffer({ @@ -3153,9 +3154,9 @@ class TextEditor extends Model # Get the Element for the editor. getElement: -> - if not @editorElement? - @editorElement = new TextEditorElement().initialize(this, atom) - if not @autoHeight + unless @editorElement? + @editorElement = new TextEditorElement().initialize(this, atom, @ignoreScrollPastEnd) + unless @autoHeight @editorElement.disableAutoHeight() @editorElement @@ -3233,7 +3234,7 @@ class TextEditor extends Model setFirstVisibleScreenRow: (screenRow, fromView) -> unless fromView maxScreenRow = @getScreenLineCount() - 1 - unless @config.get('editor.scrollPastEnd') + unless @config.get('editor.scrollPastEnd') and not @ignoreScrollPastEnd height = @displayBuffer.getHeight() lineHeightInPixels = @displayBuffer.getLineHeightInPixels() if height? and lineHeightInPixels? From dfd3e1b94840de8eecd89aa9793bc32f4260037c Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 25 Feb 2016 17:11:04 -0500 Subject: [PATCH 13/22] Take autoHeight as an argument. --- src/text-editor-element.coffee | 9 ++++----- src/text-editor.coffee | 6 +----- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/text-editor-element.coffee b/src/text-editor-element.coffee index 6fad33dc3..02f688e2c 100644 --- a/src/text-editor-element.coffee +++ b/src/text-editor-element.coffee @@ -39,6 +39,9 @@ class TextEditorElement extends HTMLElement @setAttribute('tabindex', -1) initializeContent: (attributes) -> + unless @autoHeight + @style.height = "100%" + if @config.get('editor.useShadowDOM') @useShadowDOM = true @@ -87,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}, @ignoreScrollPastEnd = false) -> + initialize: (model, {@views, @config, @themes, @workspace, @assert, @styles, @grammars}, @autoHeight = true, @ignoreScrollPastEnd = false) -> throw new Error("Must pass a config 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? @@ -346,10 +349,6 @@ class TextEditorElement extends HTMLElement @style.height = height + "px" @component.measureDimensions() - disableAutoHeight: -> - @style.height = "100%" - @component.measureDimensions() - getHeight: -> @offsetHeight diff --git a/src/text-editor.coffee b/src/text-editor.coffee index c22a1a73f..2823b993e 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -3154,11 +3154,7 @@ class TextEditor extends Model # Get the Element for the editor. getElement: -> - unless @editorElement? - @editorElement = new TextEditorElement().initialize(this, atom, @ignoreScrollPastEnd) - unless @autoHeight - @editorElement.disableAutoHeight() - @editorElement + @editorElement ?= new TextEditorElement().initialize(this, atom, @autoHeight, @ignoreScrollPastEnd) # Essential: Retrieves the greyed out placeholder of a mini editor. # From 4cd7cbda021b8673a6a93eb31e9e8c5e1106b74d Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 1 Mar 2016 10:53:31 -0500 Subject: [PATCH 14/22] Test ignoreScrollPastEnd. --- spec/text-editor-presenter-spec.coffee | 28 ++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 05ac87c0c..62d1e4747 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -635,16 +635,28 @@ describe "TextEditorPresenter", -> expectStateUpdate presenter, -> presenter.setExplicitHeight(500) expect(getState(presenter).verticalScrollbar.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(getState(presenter).verticalScrollbar.scrollHeight).toBe presenter.contentHeight + describe "scrollPastEnd", -> + 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(getState(presenter).verticalScrollbar.scrollHeight).toBe presenter.contentHeight - expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", true) - expect(getState(presenter).verticalScrollbar.scrollHeight).toBe presenter.contentHeight + presenter.clientHeight - (presenter.lineHeight * 3) + expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", true) + expect(getState(presenter).verticalScrollbar.scrollHeight).toBe presenter.contentHeight + presenter.clientHeight - (presenter.lineHeight * 3) - expectStateUpdate presenter, -> atom.config.set("editor.scrollPastEnd", false) - expect(getState(presenter).verticalScrollbar.scrollHeight).toBe presenter.contentHeight + 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 ignoreScrollPastEnd is true", -> + presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10, ignoreScrollPastEnd: true) + 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", -> From d929543aa2c9d8a0d2e8a771247059ebd90b5326 Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 1 Mar 2016 10:56:03 -0500 Subject: [PATCH 15/22] Test for getElement. --- spec/view-registry-spec.coffee | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/spec/view-registry-spec.coffee b/spec/view-registry-spec.coffee index 16672b25d..68a482b48 100644 --- a/spec/view-registry-spec.coffee +++ b/spec/view-registry-spec.coffee @@ -23,6 +23,15 @@ describe "ViewRegistry", -> component = new TestComponent expect(registry.getView(component)).toBe component.element + describe "when passed an object with a getElement function", -> + it "returns the return value of getElement if it's an instance of HTMLElement", -> + class TestComponent + getElement: -> + @myElement ?= document.createElement('div') + + component = new TestComponent + expect(registry.getView(component)).toBe component.myElement + describe "when passed a model object", -> describe "when a view provider is registered matching the object's constructor", -> it "constructs a view element and assigns the model on it", -> From e0d44aad5df4abd92082e3f99dc1ae66001a7a00 Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 1 Mar 2016 11:07:55 -0500 Subject: [PATCH 16/22] Test getElement. --- spec/text-editor-spec.coffee | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 1c0d3ad02..ae8ec54a9 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -5828,3 +5828,7 @@ describe "TextEditor", -> screenRange: marker1.getRange(), rangeIsReversed: false } + + describe "::getElement", -> + it "returns an element", -> + expect(editor.getElement() instanceof HTMLElement).toBe(true) From e1c5aad0a6972ce9950363770db6af30d56677c9 Mon Sep 17 00:00:00 2001 From: joshaber Date: Tue, 1 Mar 2016 11:43:38 -0500 Subject: [PATCH 17/22] Test ignoreInvisibles and grammarName. --- spec/text-editor-spec.coffee | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index ae8ec54a9..c75084fd5 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -5829,6 +5829,29 @@ describe "TextEditor", -> rangeIsReversed: false } + describe "when the editor is constructed with the ignoreInvisibles option set to true", -> + beforeEach -> + atom.workspace.destroyActivePane() + waitsForPromise -> + atom.workspace.open('sample.js', ignoreInvisibles: true).then (o) -> editor = o + + it "ignores invisibles even if editor.showInvisibles is true", -> + atom.config.set('editor.showInvisibles', true) + invisibles = editor.tokenizedLineForScreenRow(0).invisibles + expect(invisibles).toBe(null) + + describe "when the editor is constructed with the grammarName option set", -> + beforeEach -> + atom.workspace.destroyActivePane() + waitsForPromise -> + atom.packages.activatePackage('language-coffee-script') + + waitsForPromise -> + atom.workspace.open('sample.js', grammarName: 'source.coffee').then (o) -> editor = o + + it "sets the grammar", -> + expect(editor.getGrammar().name).toBe 'CoffeeScript' + describe "::getElement", -> it "returns an element", -> expect(editor.getElement() instanceof HTMLElement).toBe(true) From db20cecfc08b262aad2ca01e98d7e5943007d2ec Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 3 Mar 2016 09:59:45 -0500 Subject: [PATCH 18/22] s/ignoreInvisibles/showInvisibles --- spec/text-editor-spec.coffee | 4 ++-- src/text-editor.coffee | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index c75084fd5..637244964 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -5829,11 +5829,11 @@ describe "TextEditor", -> rangeIsReversed: false } - describe "when the editor is constructed with the ignoreInvisibles option set to true", -> + describe "when the editor is constructed with the showInvisibles option set to false", -> beforeEach -> atom.workspace.destroyActivePane() waitsForPromise -> - atom.workspace.open('sample.js', ignoreInvisibles: true).then (o) -> editor = o + atom.workspace.open('sample.js', showInvisibles: false).then (o) -> editor = o it "ignores invisibles even if editor.showInvisibles is true", -> atom.config.set('editor.showInvisibles', true) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 6ce96088b..6eeb2cff5 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -100,7 +100,7 @@ class TextEditor extends Model softWrapped, @displayBuffer, @selectionsMarkerLayer, buffer, suppressCursorCreation, @mini, @placeholderText, lineNumberGutterVisible, largeFileMode, @config, @notificationManager, @packageManager, @clipboard, @viewRegistry, @grammarRegistry, - @project, @assert, @applicationDelegate, grammarName, ignoreInvisibles, @autoHeight, @ignoreScrollPastEnd + @project, @assert, @applicationDelegate, grammarName, showInvisibles, @autoHeight, @ignoreScrollPastEnd } = params throw new Error("Must pass a config parameter when constructing TextEditors") unless @config? @@ -123,9 +123,11 @@ class TextEditor extends Model @ignoreScrollPastEnd ?= false @hasTerminatedPendingState = false + showInvisibles ?= true + buffer ?= new TextBuffer @displayBuffer ?= new DisplayBuffer({ - buffer, tabLength, softWrapped, ignoreInvisibles: @mini or ignoreInvisibles, largeFileMode, + buffer, tabLength, softWrapped, ignoreInvisibles: @mini or !showInvisibles, largeFileMode, @config, @assert, @grammarRegistry, @packageManager }) @buffer = @displayBuffer.buffer From 98c8a08ac3837dc59c00e77a913af5f1358f6a14 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 3 Mar 2016 10:06:15 -0500 Subject: [PATCH 19/22] s/ignoreScrollPastEnd/scrollPastEnd --- spec/text-editor-presenter-spec.coffee | 4 ++-- src/text-editor-component.coffee | 4 ++-- src/text-editor-element.coffee | 6 +++--- src/text-editor-presenter.coffee | 6 ++++-- src/text-editor.coffee | 8 ++++---- 5 files changed, 15 insertions(+), 13 deletions(-) diff --git a/spec/text-editor-presenter-spec.coffee b/spec/text-editor-presenter-spec.coffee index 62d1e4747..f8117af09 100644 --- a/spec/text-editor-presenter-spec.coffee +++ b/spec/text-editor-presenter-spec.coffee @@ -647,8 +647,8 @@ 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 ignoreScrollPastEnd is true", -> - presenter = buildPresenter(scrollTop: 10, explicitHeight: 50, horizontalScrollbarHeight: 10, ignoreScrollPastEnd: true) + 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 diff --git a/src/text-editor-component.coffee b/src/text-editor-component.coffee index 5a4097fc5..9b091100d 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, ignoreScrollPastEnd}) -> + constructor: ({@editor, @hostElement, @rootElement, @stylesElement, @useShadowDOM, tileSize, @views, @themes, @config, @workspace, @assert, @grammars, scrollPastEnd}) -> @tileSize = tileSize if tileSize? @disposables = new CompositeDisposable @@ -61,7 +61,7 @@ class TextEditorComponent stoppedScrollingDelay: 200 config: @config lineTopIndex: lineTopIndex - ignoreScrollPastEnd: ignoreScrollPastEnd + scrollPastEnd: scrollPastEnd @presenter.onDidUpdateState(@requestUpdate) diff --git a/src/text-editor-element.coffee b/src/text-editor-element.coffee index 02f688e2c..df13f2a15 100644 --- a/src/text-editor-element.coffee +++ b/src/text-editor-element.coffee @@ -17,7 +17,7 @@ class TextEditorElement extends HTMLElement focusOnAttach: false hasTiledRendering: true logicalDisplayBuffer: true - ignoreScrollPastEnd: false + scrollPastEnd: true createdCallback: -> # Use globals when the following instance variables aren't set. @@ -90,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, @ignoreScrollPastEnd = false) -> + initialize: (model, {@views, @config, @themes, @workspace, @assert, @styles, @grammars}, @autoHeight = true, @scrollPastEnd = true) -> throw new Error("Must pass a config 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? @@ -147,7 +147,7 @@ class TextEditorElement extends HTMLElement workspace: @workspace assert: @assert grammars: @grammars - ignoreScrollPastEnd: @ignoreScrollPastEnd + scrollPastEnd: @scrollPastEnd ) @rootElement.appendChild(@component.getDomNode()) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 0db175c2b..1fa662c59 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, @ignoreScrollPastEnd} = params + {@model, @config, @lineTopIndex, scrollPastEnd} = params {@cursorBlinkPeriod, @cursorBlinkResumeDelay, @stoppedScrollingDelay, @tileSize} = params {@contentFrameWidth} = params @@ -42,6 +42,8 @@ class TextEditorPresenter @startReflowing() if @continuousReflow @updating = false + @scrollPastEndOverride = scrollPastEnd || true + setLinesYardstick: (@linesYardstick) -> getLinesYardstick: -> @linesYardstick @@ -661,7 +663,7 @@ class TextEditorPresenter return unless @contentHeight? and @clientHeight? contentHeight = @contentHeight - if @scrollPastEnd and not @ignoreScrollPastEnd + if @scrollPastEnd and @scrollPastEndOverride 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 6eeb2cff5..54ea283e9 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -100,7 +100,7 @@ class TextEditor extends Model softWrapped, @displayBuffer, @selectionsMarkerLayer, buffer, suppressCursorCreation, @mini, @placeholderText, lineNumberGutterVisible, largeFileMode, @config, @notificationManager, @packageManager, @clipboard, @viewRegistry, @grammarRegistry, - @project, @assert, @applicationDelegate, grammarName, showInvisibles, @autoHeight, @ignoreScrollPastEnd + @project, @assert, @applicationDelegate, grammarName, showInvisibles, @autoHeight, @scrollPastEnd } = params throw new Error("Must pass a config parameter when constructing TextEditors") unless @config? @@ -120,7 +120,7 @@ class TextEditor extends Model @cursorsByMarkerId = new Map @selections = [] @autoHeight ?= true - @ignoreScrollPastEnd ?= false + @scrollPastEnd ?= true @hasTerminatedPendingState = false showInvisibles ?= true @@ -3156,7 +3156,7 @@ class TextEditor extends Model # Get the Element for the editor. getElement: -> - @editorElement ?= new TextEditorElement().initialize(this, atom, @autoHeight, @ignoreScrollPastEnd) + @editorElement ?= new TextEditorElement().initialize(this, atom, @autoHeight, @scrollPastEnd) # Essential: Retrieves the greyed out placeholder of a mini editor. # @@ -3232,7 +3232,7 @@ class TextEditor extends Model setFirstVisibleScreenRow: (screenRow, fromView) -> unless fromView maxScreenRow = @getScreenLineCount() - 1 - unless @config.get('editor.scrollPastEnd') and not @ignoreScrollPastEnd + unless @config.get('editor.scrollPastEnd') and @scrollPastEnd height = @displayBuffer.getHeight() lineHeightInPixels = @displayBuffer.getLineHeightInPixels() if height? and lineHeightInPixels? From 928205a44ae7b18d7257a6853e34e33d5ed562c9 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 3 Mar 2016 10:09:18 -0500 Subject: [PATCH 20/22] s/grammarName/grammar --- spec/text-editor-spec.coffee | 4 ++-- src/text-editor.coffee | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 637244964..9d2a2a58c 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -5840,14 +5840,14 @@ describe "TextEditor", -> invisibles = editor.tokenizedLineForScreenRow(0).invisibles expect(invisibles).toBe(null) - describe "when the editor is constructed with the grammarName option set", -> + describe "when the editor is constructed with the grammar option set", -> beforeEach -> atom.workspace.destroyActivePane() waitsForPromise -> atom.packages.activatePackage('language-coffee-script') waitsForPromise -> - atom.workspace.open('sample.js', grammarName: 'source.coffee').then (o) -> editor = o + atom.workspace.open('sample.js', grammar: atom.grammars.grammarForScopeName('source.coffee')).then (o) -> editor = o it "sets the grammar", -> expect(editor.getGrammar().name).toBe 'CoffeeScript' diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 54ea283e9..b981dcbb2 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -100,7 +100,7 @@ class TextEditor extends Model softWrapped, @displayBuffer, @selectionsMarkerLayer, buffer, suppressCursorCreation, @mini, @placeholderText, lineNumberGutterVisible, largeFileMode, @config, @notificationManager, @packageManager, @clipboard, @viewRegistry, @grammarRegistry, - @project, @assert, @applicationDelegate, grammarName, showInvisibles, @autoHeight, @scrollPastEnd + @project, @assert, @applicationDelegate, grammar, showInvisibles, @autoHeight, @scrollPastEnd } = params throw new Error("Must pass a config parameter when constructing TextEditors") unless @config? @@ -156,8 +156,8 @@ class TextEditor extends Model priority: 0 visible: lineNumberGutterVisible - if grammarName? - @setGrammar(@grammarRegistry.grammarForScopeName(grammarName)) + if grammar? + @setGrammar(grammar) serialize: -> deserializer: 'TextEditor' From 10acfd057fbf994fe2ddd5dd12d66b7dba5cee94 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 3 Mar 2016 10:13:26 -0500 Subject: [PATCH 21/22] Err, yeah, we care about undefined, not false. --- src/text-editor-presenter.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/text-editor-presenter.coffee b/src/text-editor-presenter.coffee index 1fa662c59..ef1b403c3 100644 --- a/src/text-editor-presenter.coffee +++ b/src/text-editor-presenter.coffee @@ -42,7 +42,7 @@ class TextEditorPresenter @startReflowing() if @continuousReflow @updating = false - @scrollPastEndOverride = scrollPastEnd || true + @scrollPastEndOverride = scrollPastEnd ? true setLinesYardstick: (@linesYardstick) -> From dba1fbd40845304960b447bf0fc3c15a3ad2ef71 Mon Sep 17 00:00:00 2001 From: joshaber Date: Thu, 3 Mar 2016 10:15:13 -0500 Subject: [PATCH 22/22] De-lint. --- src/text-editor.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index b981dcbb2..d5937d307 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -127,7 +127,7 @@ class TextEditor extends Model buffer ?= new TextBuffer @displayBuffer ?= new DisplayBuffer({ - buffer, tabLength, softWrapped, ignoreInvisibles: @mini or !showInvisibles, largeFileMode, + buffer, tabLength, softWrapped, ignoreInvisibles: @mini or not showInvisibles, largeFileMode, @config, @assert, @grammarRegistry, @packageManager }) @buffer = @displayBuffer.buffer