diff --git a/src/vs/editor/common/services/modelService.ts b/src/vs/editor/common/services/modelService.ts index e96abb9939810fd029607efd7643d3fce87f606d..357f5878f50c0e311ec00f34b86bc9d3ca919ca3 100644 --- a/src/vs/editor/common/services/modelService.ts +++ b/src/vs/editor/common/services/modelService.ts @@ -27,7 +27,7 @@ export interface IModelService { getModels(): IModel[]; - getCreationOptions(language: string): ITextModelCreationOptions; + getCreationOptions(language: string, resource: URI): ITextModelCreationOptions; getModel(resource: URI): IModel; diff --git a/src/vs/editor/common/services/modelServiceImpl.ts b/src/vs/editor/common/services/modelServiceImpl.ts index d09a2f657cd82adba34f8c576f28da539ed19f60..0afd6ef04a787ef2ce18c9e087456ade6d1ea743 100644 --- a/src/vs/editor/common/services/modelServiceImpl.ts +++ b/src/vs/editor/common/services/modelServiceImpl.ts @@ -194,8 +194,8 @@ export class ModelServiceImpl implements IModelService { private _onModelRemoved: Emitter; private _onModelModeChanged: Emitter<{ model: editorCommon.IModel; oldModeId: string; }>; - private _modelCreationOptionsByLanguage: { - [language: string]: editorCommon.ITextModelCreationOptions; + private _modelCreationOptionsByLanguageAndResource: { + [languageAndResource: string]: editorCommon.ITextModelCreationOptions; }; /** @@ -210,7 +210,7 @@ export class ModelServiceImpl implements IModelService { this._markerService = markerService; this._configurationService = configurationService; this._models = {}; - this._modelCreationOptionsByLanguage = Object.create(null); + this._modelCreationOptionsByLanguageAndResource = Object.create(null); this._onModelAdded = new Emitter(); this._onModelRemoved = new Emitter(); this._onModelModeChanged = new Emitter<{ model: editorCommon.IModel; oldModeId: string; }>(); @@ -238,7 +238,7 @@ export class ModelServiceImpl implements IModelService { } let newDefaultEOL = DEFAULT_EOL; - const eol = config.files && config.files.eol; // TODO@Sandeep (https://github.com/Microsoft/vscode/issues/29119) + const eol = config.files && config.files.eol; if (eol === '\r\n') { newDefaultEOL = editorCommon.DefaultEndOfLine.CRLF; } else if (eol === '\n') { @@ -264,18 +264,18 @@ export class ModelServiceImpl implements IModelService { }; } - public getCreationOptions(language: string): editorCommon.ITextModelCreationOptions { - let creationOptions = this._modelCreationOptionsByLanguage[language]; + public getCreationOptions(language: string, resource: URI): editorCommon.ITextModelCreationOptions { + let creationOptions = this._modelCreationOptionsByLanguageAndResource[language + resource]; if (!creationOptions) { - creationOptions = ModelServiceImpl._readModelOptions(this._configurationService.getConfiguration(null, { overrideIdentifier: language })); - this._modelCreationOptionsByLanguage[language] = creationOptions; + creationOptions = ModelServiceImpl._readModelOptions(this._configurationService.getConfiguration(null, { overrideIdentifier: language, resource })); + this._modelCreationOptionsByLanguageAndResource[language + resource] = creationOptions; } return creationOptions; } private _updateModelOptions(): void { - let oldOptionsByLanguage = this._modelCreationOptionsByLanguage; - this._modelCreationOptionsByLanguage = Object.create(null); + let oldOptionsByLanguageAndResource = this._modelCreationOptionsByLanguageAndResource; + this._modelCreationOptionsByLanguageAndResource = Object.create(null); // Update options on all models let keys = Object.keys(this._models); @@ -283,8 +283,9 @@ export class ModelServiceImpl implements IModelService { let modelId = keys[i]; let modelData = this._models[modelId]; const language = modelData.model.getLanguageIdentifier().language; - const oldOptions = oldOptionsByLanguage[language]; - const newOptions = this.getCreationOptions(language); + const uri = modelData.model.uri; + const oldOptions = oldOptionsByLanguageAndResource[language + uri]; + const newOptions = this.getCreationOptions(language, uri); ModelServiceImpl._setModelOptionsForModel(modelData.model, newOptions, oldOptions); } } @@ -341,13 +342,16 @@ export class ModelServiceImpl implements IModelService { this._markerService.read({ resource: model.uri }).map(marker => marker.owner).forEach(owner => this._markerService.remove(owner, [model.uri])); } } + + // clean up cache + delete this._modelCreationOptionsByLanguageAndResource[model.getLanguageIdentifier().language + model.uri]; } // --- begin IModelService private _createModelData(value: string | IRawTextSource, languageIdentifier: LanguageIdentifier, resource: URI): ModelData { // create & save the model - const options = this.getCreationOptions(languageIdentifier.language); + const options = this.getCreationOptions(languageIdentifier.language, resource); const rawTextSource = (typeof value === 'string' ? RawTextSource.fromString(value) : value); let model: Model = new Model(rawTextSource, options, languageIdentifier, resource); let modelId = MODEL_ID(model.uri); @@ -364,7 +368,7 @@ export class ModelServiceImpl implements IModelService { } public updateModel(model: editorCommon.IModel, value: string | IRawTextSource): void { - let options = this.getCreationOptions(model.getLanguageIdentifier().language); + let options = this.getCreationOptions(model.getLanguageIdentifier().language, model.uri); const textSource = TextSource.create(value, options.defaultEOL); // Return early if the text is already set in that form @@ -485,8 +489,8 @@ export class ModelServiceImpl implements IModelService { const model = modelData.model; const oldModeId = (e.data).oldLanguage; const newModeId = model.getLanguageIdentifier().language; - const oldOptions = this.getCreationOptions(oldModeId); - const newOptions = this.getCreationOptions(newModeId); + const oldOptions = this.getCreationOptions(oldModeId, model.uri); + const newOptions = this.getCreationOptions(newModeId, model.uri); ModelServiceImpl._setModelOptionsForModel(model, newOptions, oldOptions); this._onModelModeChanged.fire({ model, oldModeId }); } diff --git a/src/vs/editor/contrib/indentation/common/indentation.ts b/src/vs/editor/contrib/indentation/common/indentation.ts index 47322484a43d902b1d3b028c1a7e1dfdc911e104..bda4cbaf38f8e7add39a91b2790f37f8bfb4fe9f 100644 --- a/src/vs/editor/contrib/indentation/common/indentation.ts +++ b/src/vs/editor/contrib/indentation/common/indentation.ts @@ -224,7 +224,7 @@ export class ChangeIndentationSizeAction extends EditorAction { return undefined; } - let creationOpts = modelService.getCreationOptions(model.getLanguageIdentifier().language); + let creationOpts = modelService.getCreationOptions(model.getLanguageIdentifier().language, model.uri); const picks = [1, 2, 3, 4, 5, 6, 7, 8].map(n => ({ id: n.toString(), label: n.toString(), @@ -300,7 +300,7 @@ export class DetectIndentation extends EditorAction { return; } - let creationOpts = modelService.getCreationOptions(model.getLanguageIdentifier().language); + let creationOpts = modelService.getCreationOptions(model.getLanguageIdentifier().language, model.uri); model.detectIndentation(creationOpts.insertSpaces, creationOpts.tabSize); } } diff --git a/src/vs/editor/test/common/services/modelService.test.ts b/src/vs/editor/test/common/services/modelService.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..0309a2c7068d907c3c6d6cd23c393ead01c53254 --- /dev/null +++ b/src/vs/editor/test/common/services/modelService.test.ts @@ -0,0 +1,38 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import * as assert from 'assert'; +import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; +import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; +import URI from 'vs/base/common/uri'; +import * as platform from 'vs/base/common/platform'; +import { DefaultEndOfLine } from "vs/editor/common/editorCommon"; + +suite('ModelService', () => { + let modelService: ModelServiceImpl; + + setup(() => { + const configService = new TestConfigurationService(); + configService.setUserConfiguration('files', { 'eol': '\n' }); + configService.setUserConfiguration('files', { 'eol': '\r\n' }, URI.file(platform.isWindows ? 'c:\\myroot' : '/myroot')); + + modelService = new ModelServiceImpl(null, configService); + }); + + teardown(() => { + modelService.dispose(); + }); + + test('EOL setting respected depending on root', () => { + const model1 = modelService.createModel('farboo', null, null); + const model2 = modelService.createModel('farboo', null, URI.file(platform.isWindows ? 'c:\\myroot\\myfile.txt' : '/myroot/myfile.txt')); + const model3 = modelService.createModel('farboo', null, URI.file(platform.isWindows ? 'c:\\other\\myfile.txt' : '/other/myfile.txt')); + + assert.equal(model1.getOptions().defaultEOL, DefaultEndOfLine.LF); + assert.equal(model2.getOptions().defaultEOL, DefaultEndOfLine.CRLF); + assert.equal(model3.getOptions().defaultEOL, DefaultEndOfLine.LF); + }); +}); \ No newline at end of file diff --git a/src/vs/workbench/api/electron-browser/mainThreadEditor.ts b/src/vs/workbench/api/electron-browser/mainThreadEditor.ts index a875e16c35ef2d8dcddfd649d571d2aeac0a5747..6b8fde31d351225f781306bd21e1554dd78a7c3a 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadEditor.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadEditor.ts @@ -179,7 +179,7 @@ export class MainThreadTextEditor { if (newConfiguration.tabSize === 'auto' || newConfiguration.insertSpaces === 'auto') { // one of the options was set to 'auto' => detect indentation - let creationOpts = this._modelService.getCreationOptions(this._model.getLanguageIdentifier().language); + let creationOpts = this._modelService.getCreationOptions(this._model.getLanguageIdentifier().language, this._model.uri); let insertSpaces = creationOpts.insertSpaces; let tabSize = creationOpts.tabSize; diff --git a/src/vs/workbench/parts/files/browser/files.contribution.ts b/src/vs/workbench/parts/files/browser/files.contribution.ts index ac7b2f472ad83773c12c726c2c821f74a7d0e501..d595510708a5c330b741cddca4665851bf673574 100644 --- a/src/vs/workbench/parts/files/browser/files.contribution.ts +++ b/src/vs/workbench/parts/files/browser/files.contribution.ts @@ -220,6 +220,7 @@ configurationRegistry.registerConfiguration({ ], 'default': (platform.isLinux || platform.isMacintosh) ? '\n' : '\r\n', 'description': nls.localize('eol', "The default end of line character. Use \\n for LF and \\r\\n for CRLF."), + 'scope': ConfigurationScope.RESOURCE }, 'files.trimTrailingWhitespace': { 'type': 'boolean',