/
githubmirror
/
atom
Обзор
Документация
Войти
/
githubmirror
/
atom
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/text-editor-registry.js
348 строк
11 KB
Amin Yahyaabadi
Convert var to const/let in src files
30 мар 2021, 18:12
30 мар 2021, 18:12
6473f52
Код
Авторство
О чём код?
const _ = require('underscore-plus'); const { Emitter, Disposable, CompositeDisposable } = require('event-kit'); const TextEditor = require('./text-editor'); const ScopeDescriptor = require('./scope-descriptor'); const EDITOR_PARAMS_BY_SETTING_KEY = [ ['core.fileEncoding', 'encoding'], ['editor.atomicSoftTabs', 'atomicSoftTabs'], ['editor.showInvisibles', 'showInvisibles'], ['editor.tabLength', 'tabLength'], ['editor.invisibles', 'invisibles'], ['editor.showCursorOnSelection', 'showCursorOnSelection'], ['editor.showIndentGuide', 'showIndentGuide'], ['editor.showLineNumbers', 'showLineNumbers'], ['editor.softWrap', 'softWrapped'], ['editor.softWrapHangingIndent', 'softWrapHangingIndentLength'], ['editor.softWrapAtPreferredLineLength', 'softWrapAtPreferredLineLength'], ['editor.preferredLineLength', 'preferredLineLength'], ['editor.maxScreenLineLength', 'maxScreenLineLength'], ['editor.autoIndent', 'autoIndent'], ['editor.autoIndentOnPaste', 'autoIndentOnPaste'], ['editor.scrollPastEnd', 'scrollPastEnd'], ['editor.undoGroupingInterval', 'undoGroupingInterval'], ['editor.scrollSensitivity', 'scrollSensitivity'] ]; // 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. module.exports = class TextEditorRegistry { constructor({ config, assert, packageManager }) { this.config = config; this.assert = assert; this.packageManager = packageManager; this.clear(); } deserialize(state) { this.editorGrammarOverrides = state.editorGrammarOverrides; } serialize() { return { editorGrammarOverrides: Object.assign({}, this.editorGrammarOverrides) }; } clear() { if (this.subscriptions) { this.subscriptions.dispose(); } this.subscriptions = new CompositeDisposable(); this.editors = new Set(); this.emitter = new Emitter(); this.scopesWithConfigSubscriptions = new Set(); this.editorsWithMaintainedConfig = new Set(); this.editorsWithMaintainedGrammar = new Set(); this.editorGrammarOverrides = {}; this.editorGrammarScores = new WeakMap(); } 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)); } build(params) { params = Object.assign({ assert: this.assert }, params); let scope = null; if (params.buffer) { const { grammar } = params.buffer.getLanguageMode(); if (grammar) { scope = new ScopeDescriptor({ scopes: [grammar.scopeName] }); } } Object.assign(params, this.textEditorParamsForScope(scope)); return new TextEditor(params); } // Remove a `TextEditor`. // // * `editor` The editor to remove. // // Returns a {Boolean} indicating whether the editor was successfully removed. remove(editor) { const removed = this.editors.delete(editor); editor.registered = false; return removed; } // Gets the currently active text editor. // // Returns the currently active text editor, or `null` if there is none. getActiveTextEditor() { for (let ed of this.editors) { // fast path, works as long as there's a shadow DOM inside the text editor if (ed.getElement() === document.activeElement) { return ed; } else { let editorElement = ed.getElement(); let current = document.activeElement; while (current) { if (current === editorElement) { return ed; } current = current.parentNode; } } } return null; } // 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); } // Keep a {TextEditor}'s configuration in sync with Atom's settings. // // * `editor` The editor whose configuration will be maintained. // // Returns a {Disposable} that can be used to stop updating the editor's // configuration. maintainConfig(editor) { if (this.editorsWithMaintainedConfig.has(editor)) { return new Disposable(noop); } this.editorsWithMaintainedConfig.add(editor); this.updateAndMonitorEditorSettings(editor); const languageChangeSubscription = editor.buffer.onDidChangeLanguageMode( (newLanguageMode, oldLanguageMode) => { this.updateAndMonitorEditorSettings(editor, oldLanguageMode); } ); this.subscriptions.add(languageChangeSubscription); const updateTabTypes = () => { const configOptions = { scope: editor.getRootScopeDescriptor() }; editor.setSoftTabs( shouldEditorUseSoftTabs( editor, this.config.get('editor.tabType', configOptions), this.config.get('editor.softTabs', configOptions) ) ); }; updateTabTypes(); const tokenizeSubscription = editor.onDidTokenize(updateTabTypes); this.subscriptions.add(tokenizeSubscription); return new Disposable(() => { this.editorsWithMaintainedConfig.delete(editor); tokenizeSubscription.dispose(); languageChangeSubscription.dispose(); this.subscriptions.remove(languageChangeSubscription); this.subscriptions.remove(tokenizeSubscription); }); } // Deprecated: set a {TextEditor}'s grammar based on its path and content, // and continue to update its grammar as grammars are added or updated, or // the editor's file path changes. // // * `editor` The editor whose grammar will be maintained. // // Returns a {Disposable} that can be used to stop updating the editor's // grammar. maintainGrammar(editor) { atom.grammars.maintainLanguageMode(editor.getBuffer()); } // Deprecated: Force a {TextEditor} to use a different grammar than the // one that would otherwise be selected for it. // // * `editor` The editor whose gramamr will be set. // * `languageId` The {String} language ID for the desired {Grammar}. setGrammarOverride(editor, languageId) { atom.grammars.assignLanguageMode(editor.getBuffer(), languageId); } // Deprecated: Retrieve the grammar scope name that has been set as a // grammar override for the given {TextEditor}. // // * `editor` The editor. // // Returns a {String} scope name, or `null` if no override has been set // for the given editor. getGrammarOverride(editor) { return atom.grammars.getAssignedLanguageId(editor.getBuffer()); } // Deprecated: Remove any grammar override that has been set for the given {TextEditor}. // // * `editor` The editor. clearGrammarOverride(editor) { atom.grammars.autoAssignLanguageMode(editor.getBuffer()); } async updateAndMonitorEditorSettings(editor, oldLanguageMode) { await this.packageManager.getActivatePromise(); this.updateEditorSettingsForLanguageMode(editor, oldLanguageMode); this.subscribeToSettingsForEditorScope(editor); } updateEditorSettingsForLanguageMode(editor, oldLanguageMode) { const newLanguageMode = editor.buffer.getLanguageMode(); if (oldLanguageMode) { const newSettings = this.textEditorParamsForScope( newLanguageMode.rootScopeDescriptor ); const oldSettings = this.textEditorParamsForScope( oldLanguageMode.rootScopeDescriptor ); const updatedSettings = {}; for (const [, paramName] of EDITOR_PARAMS_BY_SETTING_KEY) { // Update the setting only if it has changed between the two language // modes. This prevents user-modified settings in an editor (like // 'softWrapped') from being reset when the language mode changes. if (!_.isEqual(newSettings[paramName], oldSettings[paramName])) { updatedSettings[paramName] = newSettings[paramName]; } } if (_.size(updatedSettings) > 0) { editor.update(updatedSettings); } } else { editor.update( this.textEditorParamsForScope(newLanguageMode.rootScopeDescriptor) ); } } subscribeToSettingsForEditorScope(editor) { if (!this.editorsWithMaintainedConfig) return; const scopeDescriptor = editor.getRootScopeDescriptor(); const scopeChain = scopeDescriptor.getScopeChain(); if (!this.scopesWithConfigSubscriptions.has(scopeChain)) { this.scopesWithConfigSubscriptions.add(scopeChain); const configOptions = { scope: scopeDescriptor }; for (const [settingKey, paramName] of EDITOR_PARAMS_BY_SETTING_KEY) { this.subscriptions.add( this.config.onDidChange(settingKey, configOptions, ({ newValue }) => { this.editorsWithMaintainedConfig.forEach(editor => { if (editor.getRootScopeDescriptor().isEqual(scopeDescriptor)) { editor.update({ [paramName]: 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 ) ); } } textEditorParamsForScope(scopeDescriptor) { const result = {}; const configOptions = { scope: scopeDescriptor }; for (const [settingKey, paramName] of EDITOR_PARAMS_BY_SETTING_KEY) { result[paramName] = this.config.get(settingKey, configOptions); } return result; } }; 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; } } } function noop() {}