mirror of
https://github.com/atom/atom.git
synced 2026-02-19 02:44:29 -05:00
210 lines
6.8 KiB
JavaScript
210 lines
6.8 KiB
JavaScript
/** @babel */
|
|
|
|
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'],
|
|
['editor.showIndentGuide', 'setShowIndentGuide'],
|
|
['editor.softWrap', 'setSoftWrapped'],
|
|
['editor.softWrapHangingIndent', 'setSoftWrapIndentLength'],
|
|
['editor.softWrapAtPreferredLineLength', 'setSoftWrapAtPreferredLineLength'],
|
|
['editor.preferredLineLength', 'setPreferredLineLength'],
|
|
['editor.backUpBeforeSaving', 'setBackUpBeforeSaving'],
|
|
['editor.autoIndent', 'setAutoIndent'],
|
|
['editor.autoIndentOnPaste', 'setAutoIndentOnPaste'],
|
|
['editor.scrollPastEnd', 'setScrollPastEnd'],
|
|
['editor.undoGroupingInterval', 'setUndoGroupingInterval'],
|
|
['editor.nonWordCharacters', 'setNonWordCharacters'],
|
|
]
|
|
|
|
// Experimental: This global registry tracks registered `TextEditors`.
|
|
//
|
|
// If you want to add functionality to a wider set of text editors than just
|
|
// those appearing within workspace panes, use `atom.textEditors.observe` to
|
|
// invoke a callback for all current and future registered text editors.
|
|
//
|
|
// If you want packages to be able to add functionality to your non-pane text
|
|
// editors (such as a search field in a custom user interface element), register
|
|
// them for observation via `atom.textEditors.add`. **Important:** When you're
|
|
// done using your editor, be sure to call `dispose` on the returned disposable
|
|
// to avoid leaking editors.
|
|
export default class TextEditorRegistry {
|
|
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()
|
|
this.scopedSettingsDelegate = new ScopedSettingsDelegate(config)
|
|
}
|
|
|
|
destroy () {
|
|
this.subscriptions.dispose()
|
|
this.editorsWithMaintainedConfig = null
|
|
}
|
|
|
|
// Register a `TextEditor`.
|
|
//
|
|
// * `editor` The editor to register.
|
|
//
|
|
// Returns a {Disposable} on which `.dispose()` can be called to remove the
|
|
// added editor. To avoid any memory leaks this should be called when the
|
|
// editor is destroyed.
|
|
add (editor) {
|
|
this.editors.add(editor)
|
|
editor.registered = true
|
|
this.emitter.emit("did-add-editor", editor)
|
|
|
|
return new Disposable(() => this.remove(editor))
|
|
}
|
|
|
|
// Remove a `TextEditor`.
|
|
//
|
|
// * `editor` The editor to remove.
|
|
//
|
|
// Returns a {Boolean} indicating whether the editor was successfully removed.
|
|
remove (editor) {
|
|
var removed = this.editors.delete(editor)
|
|
editor.registered = false
|
|
return removed
|
|
}
|
|
|
|
// Invoke the given callback with all the current and future registered
|
|
// `TextEditors`.
|
|
//
|
|
// * `callback` {Function} to be called with current and future text editors.
|
|
//
|
|
// Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
|
|
observe (callback) {
|
|
this.editors.forEach(callback)
|
|
return this.emitter.on("did-add-editor", callback)
|
|
}
|
|
|
|
maintainGrammar (editor) {
|
|
|
|
}
|
|
|
|
maintainConfig (editor) {
|
|
this.editorsWithMaintainedConfig.add(editor)
|
|
this.subscribeToSettingsForEditorScope(editor)
|
|
editor.setScopedSettingsDelegate(this.scopedSettingsDelegate)
|
|
|
|
const configOptions = {scope: editor.getRootScopeDescriptor()}
|
|
for (const [settingKey, setterName] of EDITOR_SETTER_NAMES_BY_SETTING_KEY) {
|
|
editor[setterName](this.config.get(settingKey, configOptions))
|
|
}
|
|
|
|
const updateTabTypes = () => {
|
|
editor.setSoftTabs(shouldEditorUseSoftTabs(
|
|
editor,
|
|
this.config.get('editor.tabType', configOptions),
|
|
this.config.get('editor.softTabs', configOptions)
|
|
))
|
|
}
|
|
|
|
updateTabTypes()
|
|
this.subscriptions.add(editor.onDidTokenize(updateTabTypes))
|
|
}
|
|
|
|
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().isEqual(scopeDescriptor)) {
|
|
editor[setterName](newValue)
|
|
}
|
|
})
|
|
})
|
|
)
|
|
}
|
|
|
|
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().isEqual(scopeDescriptor)) {
|
|
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
|
|
}
|
|
}
|
|
}
|
|
|
|
class ScopedSettingsDelegate {
|
|
constructor (config) {
|
|
this.config = config
|
|
}
|
|
|
|
getNonWordCharacters(scope) {
|
|
return this.config.get('editor.nonWordCharacters', {scope: scope})
|
|
}
|
|
|
|
getIncreaseIndentPattern (scope) {
|
|
return this.config.get('editor.increaseIndentPattern', {scope: scope})
|
|
}
|
|
|
|
getDecreaseIndentPattern (scope) {
|
|
return this.config.get('editor.decreaseIndentPattern', {scope: scope})
|
|
}
|
|
|
|
getDecreaseNextIndentPattern (scope) {
|
|
return this.config.get('editor.decreaseNextIndentPattern', {scope: scope})
|
|
}
|
|
|
|
getFoldEndPattern (scope) {
|
|
return this.config.get('editor.foldEndPattern', {scope: scope})
|
|
}
|
|
|
|
getCommentStrings (scope) {
|
|
const commentStartEntries = this.config.getAll('editor.commentStart', {scope})
|
|
const commentEndEntries = this.config.getAll('editor.commentEnd', {scope})
|
|
const commentStartEntry = commentStartEntries[0]
|
|
const commentEndEntry = commentEndEntries.find(entry => {
|
|
return entry.scopeSelector === commentStartEntry.scopeSelector
|
|
})
|
|
return {
|
|
commentStartString: commentStartEntry && commentStartEntry.value,
|
|
commentEndString: commentEndEntry && commentEndEntry.value,
|
|
}
|
|
}
|
|
}
|