Preserve TextEditor settings when language mode changes

This change fixes #13829 which reports that the `softWrapped` setting of
an untitled TextEditor is lost when the buffer is saved to a file.  This
is caused by logic that updates TextEditor settings when the buffer's
language mode changes.

The fix is to preserve any TextEditor settings that would not change when
switching between the previous and current language mode of the buffer.
This commit is contained in:
David Wilson 2018-01-11 13:35:06 -08:00
parent 7f408e7791
commit dbd4a0a4c0
2 changed files with 76 additions and 9 deletions

View File

@ -154,6 +154,45 @@ describe('TextEditorRegistry', function () {
expect(editor.getEncoding()).toBe('utf8')
})
it('preserves editor settings that haven\'t changed between previous and current language modes', async function () {
await atom.packages.activatePackage('language-javascript')
registry.maintainConfig(editor)
await initialPackageActivation
expect(editor.getEncoding()).toBe('utf8')
editor.setEncoding('utf16le')
expect(editor.getEncoding()).toBe('utf16le')
expect(editor.isSoftWrapped()).toBe(false)
editor.setSoftWrapped(true)
expect(editor.isSoftWrapped()).toBe(true)
atom.grammars.assignLanguageMode(editor, 'source.js')
await initialPackageActivation
expect(editor.getEncoding()).toBe('utf16le')
expect(editor.isSoftWrapped()).toBe(true)
})
it('updates editor settings that have changed between previous and current language modes', async function () {
await atom.packages.activatePackage('language-javascript')
registry.maintainConfig(editor)
await initialPackageActivation
expect(editor.getEncoding()).toBe('utf8')
atom.config.set('core.fileEncoding', 'utf16be', {scopeSelector: '.text.plain.null-grammar'})
atom.config.set('core.fileEncoding', 'utf16le', {scopeSelector: '.source.js'})
expect(editor.getEncoding()).toBe('utf16be')
editor.setEncoding('utf8')
expect(editor.getEncoding()).toBe('utf8')
atom.grammars.assignLanguageMode(editor, 'source.js')
await initialPackageActivation
expect(editor.getEncoding()).toBe('utf16le')
})
it('returns a disposable that can be used to stop the registry from updating the editor\'s config', async function () {
await atom.packages.activatePackage('language-javascript')

View File

@ -1,3 +1,4 @@
const _ = require('underscore-plus')
const {Emitter, Disposable, CompositeDisposable} = require('event-kit')
const TextEditor = require('./text-editor')
const ScopeDescriptor = require('./scope-descriptor')
@ -147,11 +148,11 @@ class TextEditorRegistry {
}
this.editorsWithMaintainedConfig.add(editor)
this.subscribeToSettingsForEditorScope(editor)
const grammarChangeSubscription = editor.onDidChangeGrammar(() => {
this.subscribeToSettingsForEditorScope(editor)
this.updateAndMonitorEditorSettings(editor)
const languageChangeSubscription = editor.buffer.onDidChangeLanguageMode((newLanguageMode, oldLanguageMode) => {
this.updateAndMonitorEditorSettings(editor, oldLanguageMode)
})
this.subscriptions.add(grammarChangeSubscription)
this.subscriptions.add(languageChangeSubscription)
const updateTabTypes = () => {
const configOptions = {scope: editor.getRootScopeDescriptor()}
@ -169,8 +170,8 @@ class TextEditorRegistry {
return new Disposable(() => {
this.editorsWithMaintainedConfig.delete(editor)
tokenizeSubscription.dispose()
grammarChangeSubscription.dispose()
this.subscriptions.remove(grammarChangeSubscription)
languageChangeSubscription.dispose()
this.subscriptions.remove(languageChangeSubscription)
this.subscriptions.remove(tokenizeSubscription)
})
}
@ -214,14 +215,41 @@ class TextEditorRegistry {
atom.grammars.autoAssignLanguageMode(editor.getBuffer())
}
async subscribeToSettingsForEditorScope (editor) {
async updateAndMonitorEditorSettings (editor, oldLanguageMode) {
await this.initialPackageActivationPromise
this.updateEditorSettingsForLanguageMode(editor, oldLanguageMode)
await 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))
}
}
async subscribeToSettingsForEditorScope (editor) {
const scopeDescriptor = editor.getRootScopeDescriptor()
const scopeChain = scopeDescriptor.getScopeChain()
editor.update(this.textEditorParamsForScope(scopeDescriptor))
if (!this.scopesWithConfigSubscriptions.has(scopeChain)) {
this.scopesWithConfigSubscriptions.add(scopeChain)
const configOptions = {scope: scopeDescriptor}