mirror of
https://github.com/atom/atom.git
synced 2026-01-27 15:58:00 -05:00
Start moving config observation out of editor into editor registry
Signed-off-by: Nathan Sobo <nathan@github.com>
This commit is contained in:
committed by
Nathan Sobo
parent
e9650f611f
commit
eec1b70967
@@ -1,17 +1,31 @@
|
||||
/** @babel */
|
||||
|
||||
import {TextBuffer} from 'atom'
|
||||
import TextEditorRegistry from '../src/text-editor-registry'
|
||||
import TextEditor from '../src/text-editor'
|
||||
|
||||
describe('TextEditorRegistry', function () {
|
||||
let registry, editor
|
||||
|
||||
beforeEach(function () {
|
||||
registry = new TextEditorRegistry()
|
||||
registry = new TextEditorRegistry({
|
||||
config: atom.config
|
||||
})
|
||||
|
||||
editor = new TextEditor({
|
||||
buffer: new TextBuffer({filePath: 'test.js'}),
|
||||
config: atom.config,
|
||||
clipboard: atom.clipboard,
|
||||
grammarRegistry: atom.grammars
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
registry.destroy()
|
||||
})
|
||||
|
||||
describe('.add', function () {
|
||||
it('adds an editor to the list of registered editors', function () {
|
||||
editor = {}
|
||||
registry.add(editor)
|
||||
expect(editor.registered).toBe(true)
|
||||
expect(registry.editors.size).toBe(1)
|
||||
@@ -19,7 +33,6 @@ describe('TextEditorRegistry', function () {
|
||||
})
|
||||
|
||||
it('returns a Disposable that can unregister the editor', function () {
|
||||
editor = {}
|
||||
const disposable = registry.add(editor)
|
||||
expect(registry.editors.size).toBe(1)
|
||||
disposable.dispose()
|
||||
@@ -46,4 +59,92 @@ describe('TextEditorRegistry', function () {
|
||||
expect(spy.calls.length).toBe(2)
|
||||
})
|
||||
})
|
||||
|
||||
describe('.maintainGrammar', function () {
|
||||
it('assigns a grammar to the editor based on its path', async function () {
|
||||
await atom.packages.activatePackage('language-javascript')
|
||||
await atom.packages.activatePackage('language-c')
|
||||
|
||||
registry.maintainGrammar(editor)
|
||||
expect(editor.getGrammar().name).toBe('JavaScript')
|
||||
|
||||
editor.getBuffer().setPath('test.c')
|
||||
expect(editor.getGrammar().name).toBe('C')
|
||||
})
|
||||
|
||||
it('updates the editor\'s grammar when a more appropriate grammar is added for its path', async function () {
|
||||
expect(editor.getGrammar().name).toBe('Null Grammar')
|
||||
registry.maintainGrammar(editor)
|
||||
await atom.packages.activatePackage('language-javascript')
|
||||
expect(editor.getGrammar().name).toBe('JavaScript')
|
||||
});
|
||||
})
|
||||
|
||||
describe('.maintainConfig(editor)', function () {
|
||||
it('sets the encoding based on the config', function () {
|
||||
editor.setEncoding('utf8')
|
||||
expect(editor.getEncoding()).toBe('utf8')
|
||||
|
||||
atom.config.set('core.fileEncoding', 'utf16le')
|
||||
registry.maintainConfig(editor)
|
||||
expect(editor.getEncoding()).toBe('utf16le')
|
||||
|
||||
atom.config.set('core.fileEncoding', 'utf8')
|
||||
expect(editor.getEncoding()).toBe('utf8')
|
||||
});
|
||||
|
||||
it('sets the tab length based on the config', function () {
|
||||
editor.setTabLength(4)
|
||||
expect(editor.getTabLength()).toBe(4)
|
||||
|
||||
atom.config.set('editor.tabLength', 8)
|
||||
registry.maintainConfig(editor)
|
||||
expect(editor.getTabLength()).toBe(8)
|
||||
|
||||
atom.config.set('editor.tabLength', 4)
|
||||
expect(editor.getTabLength()).toBe(4)
|
||||
});
|
||||
|
||||
it('enables or disables atomic soft tabs based on the config', function () {
|
||||
editor.setAtomicSoftTabs(true)
|
||||
expect(editor.hasAtomicSoftTabs()).toBe(true)
|
||||
|
||||
atom.config.set('editor.atomicSoftTabs', false)
|
||||
registry.maintainConfig(editor)
|
||||
expect(editor.hasAtomicSoftTabs()).toBe(false)
|
||||
|
||||
atom.config.set('editor.atomicSoftTabs', true)
|
||||
expect(editor.hasAtomicSoftTabs()).toBe(true)
|
||||
});
|
||||
|
||||
it('enables or disables invisible based on the config', function () {
|
||||
editor.setShowInvisibles(true)
|
||||
expect(editor.doesShowInvisibles()).toBe(true)
|
||||
|
||||
atom.config.set('editor.showInvisibles', false)
|
||||
registry.maintainConfig(editor)
|
||||
expect(editor.doesShowInvisibles()).toBe(false)
|
||||
|
||||
atom.config.set('editor.showInvisibles', true)
|
||||
expect(editor.doesShowInvisibles()).toBe(true)
|
||||
});
|
||||
|
||||
it('sets the invisibles based on the config', function () {
|
||||
editor.setShowInvisibles(true)
|
||||
atom.config.set('editor.showInvisibles', true)
|
||||
|
||||
const invisibles1 = {'tab': 'a', 'cr': false, eol: false, space: false}
|
||||
const invisibles2 = {'tab': 'b', 'cr': false, eol: false, space: false}
|
||||
|
||||
editor.setInvisibles(invisibles1)
|
||||
expect(editor.getInvisibles()).toEqual(invisibles1)
|
||||
|
||||
atom.config.set('editor.invisibles', invisibles2)
|
||||
registry.maintainConfig(editor)
|
||||
expect(editor.getInvisibles()).toEqual(invisibles2)
|
||||
|
||||
atom.config.set('editor.invisibles', invisibles1)
|
||||
expect(editor.getInvisibles()).toEqual(invisibles1)
|
||||
});
|
||||
})
|
||||
})
|
||||
|
||||
@@ -195,7 +195,7 @@ class AtomEnvironment extends Model
|
||||
})
|
||||
@themes.workspace = @workspace
|
||||
|
||||
@textEditors = new TextEditorRegistry
|
||||
@textEditors = new TextEditorRegistry({@config})
|
||||
@autoUpdater = new AutoUpdateManager({@applicationDelegate})
|
||||
|
||||
@config.load()
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
/** @babel */
|
||||
|
||||
import {Emitter, Disposable} from "event-kit"
|
||||
import {Emitter, Disposable, CompositeDisposable} from "event-kit"
|
||||
|
||||
const EDITOR_SETTER_NAMES_BY_SETTING_KEY = [
|
||||
['core.fileEncoding', 'setEncoding'],
|
||||
['editor.atomicSoftTabs', 'setAtomicSoftTabs'],
|
||||
['editor.showInvisibles', 'setShowInvisibles'],
|
||||
['editor.tabLength', 'setTabLength'],
|
||||
['editor.invisibles', 'setInvisibles'],
|
||||
]
|
||||
|
||||
// Experimental: This global registry tracks registered `TextEditors`.
|
||||
//
|
||||
@@ -14,9 +22,18 @@ import {Emitter, Disposable} from "event-kit"
|
||||
// done using your editor, be sure to call `dispose` on the returned disposable
|
||||
// to avoid leaking editors.
|
||||
export default class TextEditorRegistry {
|
||||
constructor () {
|
||||
constructor ({config}) {
|
||||
this.config = config
|
||||
this.subscriptions = new CompositeDisposable()
|
||||
this.editors = new Set()
|
||||
this.emitter = new Emitter()
|
||||
this.scopesWithConfigSubscriptions = new Set()
|
||||
this.editorsWithMaintainedConfig = new Set()
|
||||
}
|
||||
|
||||
destroy () {
|
||||
this.subscriptions.dispose()
|
||||
this.editorsWithMaintainedConfig = null
|
||||
}
|
||||
|
||||
// Register a `TextEditor`.
|
||||
@@ -55,4 +72,40 @@ export default class TextEditorRegistry {
|
||||
this.editors.forEach(callback)
|
||||
return this.emitter.on("did-add-editor", callback)
|
||||
}
|
||||
|
||||
maintainGrammar (editor) {
|
||||
|
||||
}
|
||||
|
||||
maintainConfig (editor) {
|
||||
this.editorsWithMaintainedConfig.add(editor)
|
||||
this.subscribeToSettingsForEditorScope(editor)
|
||||
|
||||
const configOptions = {scope: editor.getRootScopeDescriptor()}
|
||||
for (const [settingKey, setterName] of EDITOR_SETTER_NAMES_BY_SETTING_KEY) {
|
||||
editor[setterName](atom.config.get(settingKey, configOptions))
|
||||
}
|
||||
}
|
||||
|
||||
subscribeToSettingsForEditorScope (editor) {
|
||||
const scopeDescriptor = editor.getRootScopeDescriptor()
|
||||
const scopeChain = scopeDescriptor.getScopeChain()
|
||||
|
||||
if (!this.scopesWithConfigSubscriptions.has(scopeChain)) {
|
||||
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}) => {
|
||||
this.editorsWithMaintainedConfig.forEach(editor => {
|
||||
if (editor.getRootScopeDescriptor().getScopeChain() === scopeChain) {
|
||||
editor[setterName](newValue)
|
||||
}
|
||||
})
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,6 +77,8 @@ class TextEditor extends Model
|
||||
height: null
|
||||
width: null
|
||||
registered: false
|
||||
atomicSoftTabs: true
|
||||
invisibles: null
|
||||
|
||||
Object.defineProperty @prototype, "element",
|
||||
get: -> @getElement()
|
||||
@@ -176,8 +178,6 @@ class TextEditor extends Model
|
||||
|
||||
@languageMode = new LanguageMode(this, @config)
|
||||
|
||||
@setEncoding(@config.get('core.fileEncoding', scope: @getRootScopeDescriptor()))
|
||||
|
||||
@gutterContainer = new GutterContainer(this)
|
||||
@lineNumberGutter = @gutterContainer.addGutter
|
||||
name: 'line-number'
|
||||
@@ -231,10 +231,7 @@ class TextEditor extends Model
|
||||
@scopedConfigSubscriptions = subscriptions = new CompositeDisposable
|
||||
|
||||
scopeDescriptor = @getRootScopeDescriptor()
|
||||
subscriptions.add @config.onDidChange 'editor.atomicSoftTabs', scope: scopeDescriptor, @resetDisplayLayer.bind(this)
|
||||
subscriptions.add @config.onDidChange 'editor.tabLength', scope: scopeDescriptor, @resetDisplayLayer.bind(this)
|
||||
subscriptions.add @config.onDidChange 'editor.invisibles', scope: scopeDescriptor, @resetDisplayLayer.bind(this)
|
||||
subscriptions.add @config.onDidChange 'editor.showInvisibles', scope: scopeDescriptor, @resetDisplayLayer.bind(this)
|
||||
subscriptions.add @config.onDidChange 'editor.showIndentGuide', scope: scopeDescriptor, @resetDisplayLayer.bind(this)
|
||||
subscriptions.add @config.onDidChange 'editor.softWrap', scope: scopeDescriptor, @resetDisplayLayer.bind(this)
|
||||
subscriptions.add @config.onDidChange 'editor.softWrapHangingIndent', scope: scopeDescriptor, @resetDisplayLayer.bind(this)
|
||||
@@ -2704,17 +2701,24 @@ class TextEditor extends Model
|
||||
# * `softTabs` A {Boolean}
|
||||
setSoftTabs: (@softTabs) -> @softTabs
|
||||
|
||||
# Returns a {Boolean} indicating whether atomic soft tabs are enabled for this editor.
|
||||
hasAtomicSoftTabs: -> @atomicSoftTabs
|
||||
|
||||
# Enable or disable atomic soft tabs for this editor.
|
||||
#
|
||||
# * `atomicSoftTabs` A {Boolean}
|
||||
setAtomicSoftTabs: (atomicSoftTabs) ->
|
||||
return if atomicSoftTabs is @atomicSoftTabs
|
||||
@atomicSoftTabs = atomicSoftTabs
|
||||
@resetDisplayLayer()
|
||||
|
||||
# Essential: Toggle soft tabs for this editor
|
||||
toggleSoftTabs: -> @setSoftTabs(not @getSoftTabs())
|
||||
|
||||
# Essential: Get the on-screen length of tab characters.
|
||||
#
|
||||
# Returns a {Number}.
|
||||
getTabLength: ->
|
||||
if @tabLength?
|
||||
@tabLength
|
||||
else
|
||||
@config.get('editor.tabLength', scope: @getRootScopeDescriptor())
|
||||
getTabLength: -> @tabLength
|
||||
|
||||
# Essential: Set the on-screen length of tab characters. Setting this to a
|
||||
# {Number} This will override the `editor.tabLength` setting.
|
||||
@@ -2728,19 +2732,35 @@ class TextEditor extends Model
|
||||
@tokenizedBuffer.setTabLength(@tabLength)
|
||||
@resetDisplayLayer()
|
||||
|
||||
setIgnoreInvisibles: (ignoreInvisibles) ->
|
||||
return if ignoreInvisibles is @ignoreInvisibles
|
||||
# Returns a {Boolean} indicating whether atomic soft tabs are enabled for this editor.
|
||||
doesShowInvisibles: -> @showInvisibles
|
||||
|
||||
@ignoreInvisibles = ignoreInvisibles
|
||||
# Enable or disable invisible character substitution for this editor.
|
||||
#
|
||||
# * `showInvisibles` A {Boolean}
|
||||
setShowInvisibles: (showInvisibles) ->
|
||||
return if showInvisibles is @showInvisibles
|
||||
@showInvisibles = showInvisibles
|
||||
@resetDisplayLayer()
|
||||
|
||||
# Returns an {Object} representing the current invisible character
|
||||
# substitutions for this editor. See {::setInvisibles}.
|
||||
getInvisibles: ->
|
||||
scopeDescriptor = @getRootScopeDescriptor()
|
||||
if @config.get('editor.showInvisibles', scope: scopeDescriptor) and not @ignoreInvisibles and @showInvisibles
|
||||
@config.get('editor.invisibles', scope: scopeDescriptor)
|
||||
if not @mini and @showInvisibles and @invisibles?
|
||||
@invisibles
|
||||
else
|
||||
{}
|
||||
|
||||
# Set the invisible character substitutions for this editor.
|
||||
#
|
||||
# * `invisibles` An {Object} whose keys are names of invisible characters
|
||||
# and whose values are 1-character {Strings}s to display in place of those
|
||||
# invisble characters
|
||||
setInvisibles: (invisibles) ->
|
||||
return if invisibles is @invisibles
|
||||
@invisibles = invisibles
|
||||
@resetDisplayLayer()
|
||||
|
||||
# Extended: Determine if the buffer uses hard or soft tabs.
|
||||
#
|
||||
# Returns `true` if the first non-comment line with leading whitespace starts
|
||||
|
||||
Reference in New Issue
Block a user