From 5acab853cd397ba647be769cc1375b511614fda8 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 11 Jul 2016 12:43:18 -0700 Subject: [PATCH] Remove all config observation from text editor --- spec/text-editor-registry-spec.js | 108 +++++++++++++++++++++++++++--- src/text-editor-registry.js | 49 ++++++++++++++ src/text-editor.coffee | 63 +++++++---------- 3 files changed, 172 insertions(+), 48 deletions(-) diff --git a/spec/text-editor-registry-spec.js b/spec/text-editor-registry-spec.js index a60773b42..94520d430 100644 --- a/spec/text-editor-registry-spec.js +++ b/spec/text-editor-registry-spec.js @@ -77,7 +77,7 @@ describe('TextEditorRegistry', function () { registry.maintainGrammar(editor) await atom.packages.activatePackage('language-javascript') expect(editor.getGrammar().name).toBe('JavaScript') - }); + }) }) describe('.maintainConfig(editor)', function () { @@ -91,7 +91,7 @@ describe('TextEditorRegistry', function () { atom.config.set('core.fileEncoding', 'utf8') expect(editor.getEncoding()).toBe('utf8') - }); + }) it('sets the tab length based on the config', function () { editor.setTabLength(4) @@ -103,7 +103,63 @@ describe('TextEditorRegistry', function () { atom.config.set('editor.tabLength', 4) expect(editor.getTabLength()).toBe(4) - }); + }) + + it('enables soft tabs when the tabType config setting is "soft"', function () { + atom.config.set('editor.tabType', 'soft') + registry.maintainConfig(editor) + expect(editor.getSoftTabs()).toBe(true) + }) + + it('disables soft tabs when the tabType config setting is "hard"', function () { + atom.config.set('editor.tabType', 'hard') + registry.maintainConfig(editor) + expect(editor.getSoftTabs()).toBe(false) + }) + + describe('when the "tabType" config setting is "auto"', function () { + it('enables or disables soft tabs based on the editor\'s content', function () { + registry.maintainConfig(editor) + atom.config.set('editor.tabType', 'auto') + + editor.setText('{\n hello;\n}') + expect(editor.getSoftTabs()).toBe(true) + + editor.setText('{\n\thello;\n}') + editor.tokenizedBuffer.retokenizeLines() + expect(editor.getSoftTabs()).toBe(false) + }) + }) + + describe('when the "tabType" config setting is "auto"', function () { + it('enables or disables soft tabs based on the "softTabs" config setting', function () { + registry.maintainConfig(editor) + + editor.setText('abc\ndef') + atom.config.set('editor.softTabs', true) + atom.config.set('editor.tabType', 'auto') + expect(editor.getSoftTabs()).toBe(true) + + atom.config.set('editor.softTabs', false) + expect(editor.getSoftTabs()).toBe(false) + }) + }) + + it('enables or disables soft tabs based on the config', function () { + editor.setSoftTabs(true) + expect(editor.getSoftTabs()).toBe(true) + + atom.config.set('editor.tabType', 'hard') + registry.maintainConfig(editor) + expect(editor.getSoftTabs()).toBe(false) + + atom.config.set('editor.tabType', 'soft') + expect(editor.getSoftTabs()).toBe(true) + + atom.config.set('editor.tabType', 'auto') + atom.config.set('editor.softTabs', true) + expect(editor.getSoftTabs()).toBe(true) + }) it('enables or disables atomic soft tabs based on the config', function () { editor.setAtomicSoftTabs(true) @@ -115,7 +171,7 @@ describe('TextEditorRegistry', function () { atom.config.set('editor.atomicSoftTabs', true) expect(editor.hasAtomicSoftTabs()).toBe(true) - }); + }) it('enables or disables invisible based on the config', function () { editor.setShowInvisibles(true) @@ -127,7 +183,7 @@ describe('TextEditorRegistry', function () { atom.config.set('editor.showInvisibles', true) expect(editor.doesShowInvisibles()).toBe(true) - }); + }) it('sets the invisibles based on the config', function () { editor.setShowInvisibles(true) @@ -145,7 +201,7 @@ describe('TextEditorRegistry', function () { atom.config.set('editor.invisibles', invisibles1) expect(editor.getInvisibles()).toEqual(invisibles1) - }); + }) it('enables or disables the indent guide based on the config', function () { editor.setShowIndentGuide(true) @@ -157,7 +213,7 @@ describe('TextEditorRegistry', function () { atom.config.set('editor.showIndentGuide', true) expect(editor.doesShowIndentGuide()).toBe(true) - }); + }) it('enables or disables soft wrap based on the config', function () { editor.setSoftWrapped(true) @@ -169,6 +225,42 @@ describe('TextEditorRegistry', function () { atom.config.set('editor.softWrap', true) expect(editor.isSoftWrapped()).toBe(true) - }); + }) + + it('sets the soft wrap indent length based on the config', function () { + editor.setSoftWrapIndentLength(4) + expect(editor.getSoftWrapIndentLength()).toBe(4) + + atom.config.set('editor.softWrapHangingIndent', 2) + registry.maintainConfig(editor) + expect(editor.getSoftWrapIndentLength()).toBe(2) + + atom.config.set('editor.softWrapHangingIndent', 4) + expect(editor.getSoftWrapIndentLength()).toBe(4) + }) + + it('enables or disables preferred line length-based soft wrap based on the config', function () { + editor.setSoftWrapAtPreferredLineLength(true) + expect(editor.doesSoftWrapAtPreferredLineLength()).toBe(true) + + atom.config.set('editor.softWrapAtPreferredLineLength', false) + registry.maintainConfig(editor) + expect(editor.doesSoftWrapAtPreferredLineLength()).toBe(false) + + atom.config.set('editor.softWrapAtPreferredLineLength', true) + expect(editor.doesSoftWrapAtPreferredLineLength()).toBe(true) + }) + + it('sets the preferred line length based on the config', function () { + editor.setPreferredLineLength(80) + expect(editor.getPreferredLineLength()).toBe(80) + + atom.config.set('editor.preferredLineLength', 110) + registry.maintainConfig(editor) + expect(editor.getPreferredLineLength()).toBe(110) + + atom.config.set('editor.preferredLineLength', 80) + expect(editor.getPreferredLineLength()).toBe(80) + }) }) }) diff --git a/src/text-editor-registry.js b/src/text-editor-registry.js index 0577291d0..da18881a6 100644 --- a/src/text-editor-registry.js +++ b/src/text-editor-registry.js @@ -10,6 +10,9 @@ const EDITOR_SETTER_NAMES_BY_SETTING_KEY = [ ['editor.invisibles', 'setInvisibles'], ['editor.showIndentGuide', 'setShowIndentGuide'], ['editor.softWrap', 'setSoftWrapped'], + ['editor.softWrapHangingIndent', 'setSoftWrapIndentLength'], + ['editor.softWrapAtPreferredLineLength', 'setSoftWrapAtPreferredLineLength'], + ['editor.preferredLineLength', 'setPreferredLineLength'], ] // Experimental: This global registry tracks registered `TextEditors`. @@ -87,6 +90,17 @@ export default class TextEditorRegistry { for (const [settingKey, setterName] of EDITOR_SETTER_NAMES_BY_SETTING_KEY) { editor[setterName](atom.config.get(settingKey, configOptions)) } + + const updateTabTypes = () => { + editor.setSoftTabs(shouldEditorUseSoftTabs( + editor, + atom.config.get('editor.tabType', configOptions), + atom.config.get('editor.softTabs', configOptions) + )) + } + + updateTabTypes() + this.subscriptions.add(editor.onDidTokenize(updateTabTypes)) } subscribeToSettingsForEditorScope (editor) { @@ -97,6 +111,7 @@ export default class TextEditorRegistry { this.scopesWithConfigSubscriptions.add(scopeChain) const configOptions = {scope: scopeDescriptor} + for (const [settingKey, setterName] of EDITOR_SETTER_NAMES_BY_SETTING_KEY) { this.subscriptions.add( this.config.onDidChange(settingKey, configOptions, ({newValue}) => { @@ -108,6 +123,40 @@ export default class TextEditorRegistry { }) ) } + + const updateTabTypes = () => { + const tabType = this.config.get('editor.tabType', configOptions) + const softTabs = this.config.get('editor.softTabs', configOptions) + + this.editorsWithMaintainedConfig.forEach(editor => { + if (editor.getRootScopeDescriptor().getScopeChain() === scopeChain) { + editor.setSoftTabs(shouldEditorUseSoftTabs(editor, tabType, softTabs)) + } + }) + } + + this.subscriptions.add( + this.config.onDidChange('editor.tabType', configOptions, updateTabTypes), + this.config.onDidChange('editor.softTabs', configOptions, updateTabTypes) + ) } } } + +function shouldEditorUseSoftTabs (editor, tabType, softTabs) { + switch (tabType) { + case 'hard': + return false + case 'soft': + return true + case 'auto': + switch (editor.usesSoftTabs()) { + case true: + return true + case false: + return false + default: + return softTabs + } + } +} diff --git a/src/text-editor.coffee b/src/text-editor.coffee index b15783a6f..361cd3eaf 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -162,12 +162,9 @@ class TextEditor extends Model @decorateMarkerLayer(@displayLayer.foldsMarkerLayer, {type: 'line-number', class: 'folded'}) - @disposables.add @tokenizedBuffer.observeGrammar @subscribeToScopedConfigSettings - for marker in @selectionsMarkerLayer.getMarkers() @addSelection(marker) - @subscribeToTabTypeConfig() @subscribeToBuffer() @subscribeToDisplayLayer() @@ -226,36 +223,19 @@ class TextEditor extends Model onDidTerminatePendingState: (callback) -> @emitter.on 'did-terminate-pending-state', callback - subscribeToScopedConfigSettings: => - @scopedConfigSubscriptions?.dispose() - @scopedConfigSubscriptions = subscriptions = new CompositeDisposable - - scopeDescriptor = @getRootScopeDescriptor() - 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) - - @resetDisplayLayer() - subscribeToDisplayLayer: -> @disposables.add @selectionsMarkerLayer.onDidCreateMarker @addSelection.bind(this) @disposables.add @tokenizedBuffer.onDidChangeGrammar @handleGrammarChange.bind(this) - @disposables.add @tokenizedBuffer.onDidTokenize @handleTokenization.bind(this) @disposables.add @displayLayer.onDidChangeSync (e) => @mergeIntersectingSelections() @emitter.emit 'did-change', e - subscribeToTabTypeConfig: -> - @tabTypeSubscription?.dispose() - @tabTypeSubscription = @config.observe 'editor.tabType', scope: @getRootScopeDescriptor(), => - @softTabs = @shouldUseSoftTabs(defaultValue: @softTabs) - resetDisplayLayer: -> @displayLayer.reset({ invisibles: @getInvisibles(), softWrapColumn: @getSoftWrapColumn(), - showIndentGuides: not @isMini() and @config.get('editor.showIndentGuide', scope: @getRootScopeDescriptor()), - atomicSoftTabs: @config.get('editor.atomicSoftTabs', scope: @getRootScopeDescriptor()), + showIndentGuides: not @isMini() and @doesShowIndentGuide(), + atomicSoftTabs: @hasAtomicSoftTabs(), tabLength: @getTabLength(), ratioForCharacter: @ratioForCharacter.bind(this), isWrapBoundary: isWrapBoundary, @@ -2765,6 +2745,13 @@ class TextEditor extends Model @showIndentGuide = showIndentGuide @resetDisplayLayer() + setSoftWrapIndentLength: (softWrapIndentLength) -> + return if softWrapIndentLength is @softWrapIndentLength + @softWrapIndentLength = softWrapIndentLength + @resetDisplayLayer() + + getSoftWrapIndentLength: -> @softWrapIndentLength + # Extended: Determine if the buffer uses hard or soft tabs. # # Returns `true` if the first non-comment line with leading whitespace starts @@ -2796,20 +2783,6 @@ class TextEditor extends Model return unless @getSoftTabs() @scanInBufferRange /\t/g, bufferRange, ({replace}) => replace(@getTabText()) - # Private: Computes whether or not this editor should use softTabs based on - # the `editor.tabType` setting. - # - # Returns a {Boolean} - shouldUseSoftTabs: ({defaultValue}) -> - tabType = @config.get('editor.tabType', scope: @getRootScopeDescriptor()) - switch tabType - when 'auto' - @usesSoftTabs() ? defaultValue ? @config.get('editor.softTabs') ? true - when 'hard' - false - when 'soft' - true - ### Section: Soft Wrap Behavior ### @@ -2838,6 +2811,20 @@ class TextEditor extends Model else @isSoftWrapped() + setSoftWrapAtPreferredLineLength: (softWrapAtPreferredLineLength) -> + return if softWrapAtPreferredLineLength is @softWrapAtPreferredLineLength + @softWrapAtPreferredLineLength = softWrapAtPreferredLineLength + @resetDisplayLayer() + + doesSoftWrapAtPreferredLineLength: -> @softWrapAtPreferredLineLength + + setPreferredLineLength: (preferredLineLength) -> + return if preferredLineLength is @preferredLineLength + @preferredLineLength = preferredLineLength + @resetDisplayLayer() + + getPreferredLineLength: -> @preferredLineLength + # Essential: Toggle soft wrapping for this editor # # Returns a {Boolean}. @@ -3342,12 +3329,8 @@ class TextEditor extends Model Section: Event Handlers ### - handleTokenization: -> - @softTabs = @shouldUseSoftTabs(defaultValue: @softTabs) - handleGrammarChange: -> @unfoldAll() - @subscribeToTabTypeConfig() @emitter.emit 'did-change-grammar', @getGrammar() ###