diff --git a/src/vs/workbench/api/electron-browser/mainThreadSaveParticipant.ts b/src/vs/workbench/api/electron-browser/mainThreadSaveParticipant.ts index 41168607553769a9508a4883f41519a963f67347..db1d0da3b56defc3d2a9b741d0cb61e4531ef091 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadSaveParticipant.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadSaveParticipant.ts @@ -142,7 +142,7 @@ class FormatOnSaveParticipant implements INamedSaveParticpant { const model = editorModel.textEditorModel; if (env.reason === SaveReason.AUTO - || !this._configurationService.lookup('editor.formatOnSave', model.getLanguageIdentifier().language).value) { + || !this._configurationService.lookup('editor.formatOnSave', { overrideIdentifier: model.getLanguageIdentifier().language, resource: editorModel.getResource() }).value) { return undefined; } diff --git a/src/vs/workbench/browser/parts/editor/editorStatus.ts b/src/vs/workbench/browser/parts/editor/editorStatus.ts index 3fc06c6e87465a0b331bcc0d3252a1fd233ee18e..a631eb935947547560d26804eb8ffec5dfc79b15 100644 --- a/src/vs/workbench/browser/parts/editor/editorStatus.ts +++ b/src/vs/workbench/browser/parts/editor/editorStatus.ts @@ -33,7 +33,7 @@ import { IEditor as IBaseEditor, IEditorInput } from 'vs/platform/editor/common/ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IQuickOpenService, IPickOpenEntry, IFilePickOpenEntry } from 'vs/platform/quickOpen/common/quickOpen'; import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; -import { IFilesConfiguration, SUPPORTED_ENCODINGS, IFileService } from 'vs/platform/files/common/files'; +import { SUPPORTED_ENCODINGS, IFileService } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IModelService } from 'vs/editor/common/services/modelService'; @@ -1099,20 +1099,18 @@ export class ChangeEncodingAction extends Action { return undefined; } + const resource = toResource(activeEditor.input, { filter: 'file', supportSideBySide: true }); + if (!resource) { + return TPromise.as(null); + } + return TPromise.timeout(50 /* quick open is sensitive to being opened so soon after another */) .then(() => { - const resource = toResource(activeEditor.input, { filter: 'file', supportSideBySide: true }); - if (!resource) { - return TPromise.as(null); - } - return this.fileService.resolveContent(resource, { autoGuessEncoding: true, acceptTextOnly: true }).then(content => content.encoding, err => null); }) .then((guessedEncoding: string) => { - const configuration = this.configurationService.getConfiguration(); - const isReopenWithEncoding = (action === reopenWithEncodingPick); - const configuredEncoding = configuration && configuration.files && configuration.files.encoding; + const configuredEncoding = this.configurationService.lookup('files.encoding', { resource }).value; let directMatchIndex: number; let aliasMatchIndex: number; diff --git a/src/vs/workbench/parts/codeEditor/electron-browser/toggleWordWrap.ts b/src/vs/workbench/parts/codeEditor/electron-browser/toggleWordWrap.ts index e0bf3b526293579fa999190aedc1ac33d8a79f7e..4d4c999276f1c9bfc2e422b38f7720e10c3b3aaf 100644 --- a/src/vs/workbench/parts/codeEditor/electron-browser/toggleWordWrap.ts +++ b/src/vs/workbench/parts/codeEditor/electron-browser/toggleWordWrap.ts @@ -10,7 +10,6 @@ import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { ICommonCodeEditor, IEditorContribution, IModel } from 'vs/editor/common/editorCommon'; import { editorAction, ServicesAccessor, EditorAction, commonEditorContribution } from 'vs/editor/common/editorCommonExtensions'; import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { Disposable } from 'vs/base/common/lifecycle'; @@ -18,6 +17,7 @@ import { IMessageService } from 'vs/platform/message/common/message'; import Severity from 'vs/base/common/severity'; import URI from 'vs/base/common/uri'; import { InternalEditorOptions, EDITOR_DEFAULTS } from 'vs/editor/common/config/editorOptions'; +import { ITextResourceConfigurationService } from "vs/editor/common/services/resourceConfiguration"; const transientWordWrapState = 'transientWordWrapState'; const isWordWrapMinifiedKey = 'isWordWrapMinified'; @@ -52,8 +52,9 @@ function readTransientState(model: IModel, codeEditorService: ICodeEditorService return codeEditorService.getTransientModelProperty(model, transientWordWrapState); } -function readWordWrapState(model: IModel, configurationService: IConfigurationService, codeEditorService: ICodeEditorService): IWordWrapState { - let _configuredWordWrap = configurationService.lookup<'on' | 'off' | 'wordWrapColumn' | 'bounded'>('editor.wordWrap', model.getLanguageIdentifier().language).value; +function readWordWrapState(model: IModel, configurationService: ITextResourceConfigurationService, codeEditorService: ICodeEditorService): IWordWrapState { + const editorConfig = configurationService.getConfiguration(model.uri, 'editor') as { wordWrap: 'on' | 'off' | 'wordWrapColumn' | 'bounded'; wordWrapMinified: boolean }; + let _configuredWordWrap = editorConfig && typeof editorConfig.wordWrap === 'string' ? editorConfig.wordWrap : void 0; // Compatibility with old true or false values if (_configuredWordWrap === true) { @@ -62,11 +63,11 @@ function readWordWrapState(model: IModel, configurationService: IConfigurationSe _configuredWordWrap = 'off'; } - const _configuredWordWrapMinified = configurationService.lookup('editor.wordWrapMinified', model.getLanguageIdentifier().language); + const _configuredWordWrapMinified = editorConfig && typeof editorConfig.wordWrapMinified === 'boolean' ? editorConfig.wordWrapMinified : void 0; const _transientState = readTransientState(model, codeEditorService); return { configuredWordWrap: _configuredWordWrap, - configuredWordWrapMinified: (typeof _configuredWordWrapMinified.value === 'undefined' ? EDITOR_DEFAULTS.wordWrapMinified : _configuredWordWrapMinified.value), + configuredWordWrapMinified: (typeof _configuredWordWrapMinified === 'boolean' ? _configuredWordWrapMinified : EDITOR_DEFAULTS.wordWrapMinified), transientState: _transientState }; } @@ -154,7 +155,7 @@ class ToggleWordWrapAction extends EditorAction { return; } - const configurationService = accessor.get(IConfigurationService); + const textResourceConfigurationService = accessor.get(ITextResourceConfigurationService); const codeEditorService = accessor.get(ICodeEditorService); const model = editor.getModel(); @@ -163,7 +164,7 @@ class ToggleWordWrapAction extends EditorAction { } // Read the current state - const currentState = readWordWrapState(model, configurationService, codeEditorService); + const currentState = readWordWrapState(model, textResourceConfigurationService, codeEditorService); // Compute the new state const newState = toggleWordWrap(editor, currentState); // Write the new state @@ -181,7 +182,7 @@ class ToggleWordWrapController extends Disposable implements IEditorContribution constructor( private readonly editor: ICommonCodeEditor, @IContextKeyService readonly contextKeyService: IContextKeyService, - @IConfigurationService readonly configurationService: IConfigurationService, + @ITextResourceConfigurationService readonly configurationService: ITextResourceConfigurationService, @ICodeEditorService readonly codeEditorService: ICodeEditorService ) { super(); diff --git a/src/vs/workbench/parts/files/browser/files.contribution.ts b/src/vs/workbench/parts/files/browser/files.contribution.ts index 0ea5742f88b675265b071e54f7895ac89a3db3dc..74e2a22238ea2f785c9868af1477866a3dc41330 100644 --- a/src/vs/workbench/parts/files/browser/files.contribution.ts +++ b/src/vs/workbench/parts/files/browser/files.contribution.ts @@ -14,7 +14,7 @@ import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'v import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actionRegistry'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { IEditorRegistry, Extensions as EditorExtensions, IEditorInputFactory, EditorInput, IFileEditorInput } from 'vs/workbench/common/editor'; -import { AutoSaveConfiguration, HotExitConfiguration, SUPPORTED_ENCODINGS, IFilesConfiguration } from 'vs/platform/files/common/files'; +import { AutoSaveConfiguration, HotExitConfiguration, SUPPORTED_ENCODINGS } from 'vs/platform/files/common/files'; import { EditorDescriptor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { FILE_EDITOR_INPUT_ID, VIEWLET_ID } from 'vs/workbench/parts/files/common/files'; import { FileEditorTracker } from 'vs/workbench/parts/files/common/editors/fileEditorTracker'; @@ -111,22 +111,10 @@ interface ISerializedFileInput { // Register Editor Input Factory class FileEditorInputFactory implements IEditorInputFactory { - private configuredEncoding: string; constructor( @IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService ) { - this.onConfiguration(configurationService.getConfiguration()); - - this.registerListeners(); - } - - private registerListeners(): void { - this.configurationService.onDidUpdateConfiguration(e => this.onConfiguration(this.configurationService.getConfiguration())); - } - - private onConfiguration(config: IFilesConfiguration): void { - this.configuredEncoding = config.files && config.files.encoding; } public serialize(editorInput: EditorInput): string { @@ -138,7 +126,7 @@ class FileEditorInputFactory implements IEditorInputFactory { }; const encoding = fileEditorInput.getPreferredEncoding(); - if (encoding && encoding !== this.configuredEncoding) { + if (encoding && encoding !== this.configurationService.lookup('files.encoding', { resource }).value) { fileInput.encoding = encoding; } diff --git a/src/vs/workbench/services/backup/test/node/backupFileService.test.ts b/src/vs/workbench/services/backup/test/node/backupFileService.test.ts index 34006542bc8d0b0f88e62baecbb0e395c0f63f77..2abae9fa93745832899876d46be900f7f9cca3bd 100644 --- a/src/vs/workbench/services/backup/test/node/backupFileService.test.ts +++ b/src/vs/workbench/services/backup/test/node/backupFileService.test.ts @@ -21,6 +21,7 @@ import { parseArgs } from 'vs/platform/environment/node/argv'; import { RawTextSource } from 'vs/editor/common/model/textSource'; import { TestContextService } from 'vs/workbench/test/workbenchTestServices'; import { Workspace } from "vs/platform/workspace/common/workspace"; +import { TestConfigurationService } from "vs/platform/configuration/test/common/testConfigurationService"; class TestEnvironmentService extends EnvironmentService { @@ -49,7 +50,7 @@ const untitledBackupPath = path.join(workspaceBackupPath, 'untitled', crypto.cre class TestBackupFileService extends BackupFileService { constructor(workspace: Uri, backupHome: string, workspacesJsonPath: string) { - const fileService = new FileService(new TestContextService(new Workspace(workspace.fsPath, workspace.fsPath, [workspace])), { disableWatcher: true }); + const fileService = new FileService(new TestContextService(new Workspace(workspace.fsPath, workspace.fsPath, [workspace])), new TestConfigurationService(), { disableWatcher: true }); super(workspaceBackupPath, fileService); } diff --git a/src/vs/workbench/services/configuration/test/node/configurationEditingService.test.ts b/src/vs/workbench/services/configuration/test/node/configurationEditingService.test.ts index bbf2f240529c686ab2e1d4e8b31a351b0f329d07..d7db5a91f86b935ea06dcb2c3f5c019100cebec6 100644 --- a/src/vs/workbench/services/configuration/test/node/configurationEditingService.test.ts +++ b/src/vs/workbench/services/configuration/test/node/configurationEditingService.test.ts @@ -45,6 +45,7 @@ import { IModelService } from 'vs/editor/common/services/modelService'; import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; import { IChoiceService, IMessageService } from 'vs/platform/message/common/message'; import { IStorageService } from 'vs/platform/storage/common/storage'; +import { TestConfigurationService } from "vs/platform/configuration/test/common/testConfigurationService"; class SettingsTestEnvironmentService extends EnvironmentService { @@ -125,7 +126,7 @@ suite('ConfigurationEditingService', () => { instantiationService.stub(ITelemetryService, NullTelemetryService); instantiationService.stub(IModeService, ModeServiceImpl); instantiationService.stub(IModelService, instantiationService.createInstance(ModelServiceImpl)); - instantiationService.stub(IFileService, new FileService(workspaceService, { disableWatcher: true })); + instantiationService.stub(IFileService, new FileService(workspaceService, new TestConfigurationService(), { disableWatcher: true })); instantiationService.stub(IUntitledEditorService, instantiationService.createInstance(UntitledEditorService)); instantiationService.stub(IStorageService, new TestStorageService()); instantiationService.stub(IChoiceService, { diff --git a/src/vs/workbench/services/files/electron-browser/fileService.ts b/src/vs/workbench/services/files/electron-browser/fileService.ts index 73d0665dd7d35fdda2809a974e9749d1a509159b..a0a398e785512a69c63e6f8e7776cc56b3803c5e 100644 --- a/src/vs/workbench/services/files/electron-browser/fileService.ts +++ b/src/vs/workbench/services/files/electron-browser/fileService.ts @@ -73,8 +73,6 @@ export class FileService implements IFileService { // build config const fileServiceConfig: IFileServiceOptions = { errorLogger: (msg: string) => this.onFileServiceError(msg), - encoding: configuration.files && configuration.files.encoding, - autoGuessEncoding: configuration.files && configuration.files.autoGuessEncoding, encodingOverride: this.getEncodingOverrides(), watcherIgnoredPatterns, verboseLogging: environmentService.verbose, @@ -82,7 +80,7 @@ export class FileService implements IFileService { }; // create service - this.raw = new NodeFileService(contextService, fileServiceConfig); + this.raw = new NodeFileService(contextService, configurationService, fileServiceConfig); // Listeners this.registerListeners(); diff --git a/src/vs/workbench/services/files/node/fileService.ts b/src/vs/workbench/services/files/node/fileService.ts index 71a2402c6e3b888961819ecafeff7dab46cdc695..e3d19f65eca43ae0fe29be266a871e67a969b99a 100644 --- a/src/vs/workbench/services/files/node/fileService.ts +++ b/src/vs/workbench/services/files/node/fileService.ts @@ -11,7 +11,7 @@ import os = require('os'); import crypto = require('crypto'); import assert = require('assert'); -import { isParent, FileOperation, FileOperationEvent, IContent, IFileService, IResolveFileOptions, IResolveContentOptions, IFileStat, IStreamContent, IFileOperationResult, FileOperationResult, IUpdateContentOptions, FileChangeType, IImportResult, MAX_FILE_SIZE, FileChangesEvent } from 'vs/platform/files/common/files'; +import { isParent, FileOperation, FileOperationEvent, IContent, IFileService, IResolveFileOptions, IResolveContentOptions, IFileStat, IStreamContent, IFileOperationResult, FileOperationResult, IUpdateContentOptions, FileChangeType, IImportResult, MAX_FILE_SIZE, FileChangesEvent, IFilesConfiguration } from 'vs/platform/files/common/files'; import { isEqualOrParent } from 'vs/base/common/paths'; import { ResourceMap } from 'vs/base/common/map'; import arrays = require('vs/base/common/arrays'); @@ -36,6 +36,7 @@ import { FileWatcher as WindowsWatcherService } from 'vs/workbench/services/file import { toFileChangesEvent, normalize, IRawFileChange } from 'vs/workbench/services/files/node/watcher/common'; import Event, { Emitter } from 'vs/base/common/event'; import { FileWatcher as NsfwWatcherService } from 'vs/workbench/services/files/node/watcher/nsfw/watcherService'; +import { IConfigurationService } from "vs/platform/configuration/common/configuration"; export interface IEncodingOverride { resource: uri; @@ -45,9 +46,6 @@ export interface IEncodingOverride { export interface IFileServiceOptions { tmpDir?: string; errorLogger?: (msg: string) => void; - encoding?: string; - autoGuessEncoding?: boolean; - bom?: string; encodingOverride?: IEncodingOverride[]; watcherIgnoredPatterns?: string[]; disableWatcher?: boolean; @@ -93,6 +91,7 @@ export class FileService implements IFileService { constructor( private contextService: IWorkspaceContextService, + private configurationService: IConfigurationService, options: IFileServiceOptions, ) { this.toDispose = []; @@ -214,7 +213,7 @@ export class FileService implements IFileService { } // 2.) detect mimes - const autoGuessEncoding = (options && options.autoGuessEncoding) || (this.options && this.options.autoGuessEncoding); + const autoGuessEncoding = (options && options.autoGuessEncoding) || this.configuredAutoGuessEncoding(resource); return detectMimesFromFile(absolutePath, { autoGuessEncoding }).then((detected: IMimeAndEncoding) => { const isText = detected.mimes.indexOf(baseMime.MIME_BINARY) === -1; @@ -239,7 +238,7 @@ export class FileService implements IFileService { } else { preferredEncoding = detected.encoding; } - } else if (this.options.encoding === encoding.UTF8_with_bom) { + } else if (this.configuredEncoding(resource) === encoding.UTF8_with_bom) { preferredEncoding = encoding.UTF8; // if we did not detect UTF 8 BOM before, this can only be UTF 8 then } @@ -592,7 +591,7 @@ export class FileService implements IFileService { } else if (preferredEncoding) { fileEncoding = preferredEncoding; } else { - fileEncoding = this.options.encoding; + fileEncoding = this.configuredEncoding(resource); } if (!fileEncoding || !encoding.encodingExists(fileEncoding)) { @@ -602,6 +601,18 @@ export class FileService implements IFileService { return fileEncoding; } + private configuredAutoGuessEncoding(resource: uri): boolean { + const config = this.configurationService.getConfiguration(void 0, { resource }) as IFilesConfiguration; + + return config && config.files && config.files.autoGuessEncoding === true; + } + + private configuredEncoding(resource: uri): string { + const config = this.configurationService.getConfiguration(void 0, { resource }) as IFilesConfiguration; + + return config && config.files && config.files.encoding; + } + private getEncodingOverride(resource: uri): string { if (resource && this.options.encodingOverride && this.options.encodingOverride.length) { for (let i = 0; i < this.options.encodingOverride.length; i++) { diff --git a/src/vs/workbench/services/files/test/node/fileService.test.ts b/src/vs/workbench/services/files/test/node/fileService.test.ts index 95170fe1959527c65e75f9eddfce7ada6d1d0cce..aa98674ec561981a41c37d1b842a19786d48cfdc 100644 --- a/src/vs/workbench/services/files/test/node/fileService.test.ts +++ b/src/vs/workbench/services/files/test/node/fileService.test.ts @@ -21,6 +21,7 @@ import utils = require('vs/workbench/services/files/test/node/utils'); import { onError } from 'vs/base/test/common/utils'; import { TestContextService } from "vs/workbench/test/workbenchTestServices"; import { Workspace } from "vs/platform/workspace/common/workspace"; +import { TestConfigurationService } from "vs/platform/configuration/test/common/testConfigurationService"; suite('FileService', () => { let service: FileService; @@ -37,7 +38,7 @@ suite('FileService', () => { return onError(error, done); } - service = new FileService(new TestContextService(new Workspace(testDir, testDir, [uri.file(testDir)])), { disableWatcher: true }); + service = new FileService(new TestContextService(new Workspace(testDir, testDir, [uri.file(testDir)])), new TestConfigurationService(), { disableWatcher: true }); done(); }); }); @@ -753,8 +754,10 @@ suite('FileService', () => { encoding: 'utf16le' }); - let _service = new FileService(new TestContextService(new Workspace(_testDir, _testDir, [uri.file(_testDir)])), { - encoding: 'windows1252', + let configurationService = new TestConfigurationService(); + configurationService.setUserConfiguration('files', { encoding: 'windows1252' }); + + let _service = new FileService(new TestContextService(new Workspace(_testDir, _testDir, [uri.file(_testDir)])), configurationService, { encodingOverride, disableWatcher: true }); @@ -781,7 +784,7 @@ suite('FileService', () => { let _sourceDir = require.toUrl('./fixtures/service'); let resource = uri.file(path.join(testDir, 'index.html')); - let _service = new FileService(new TestContextService(new Workspace(_testDir, _testDir, [uri.file(_testDir)])), { + let _service = new FileService(new TestContextService(new Workspace(_testDir, _testDir, [uri.file(_testDir)])), new TestConfigurationService(), { disableWatcher: true }); diff --git a/src/vs/workbench/services/keybinding/test/node/keybindingEditing.test.ts b/src/vs/workbench/services/keybinding/test/node/keybindingEditing.test.ts index 5b822f91e8473b0f6ed5762e41d432236d93c2ff..4cd52b254320e0377fff41b27d7bbaff2309a8b5 100644 --- a/src/vs/workbench/services/keybinding/test/node/keybindingEditing.test.ts +++ b/src/vs/workbench/services/keybinding/test/node/keybindingEditing.test.ts @@ -44,6 +44,7 @@ import { IUserFriendlyKeybinding } from 'vs/platform/keybinding/common/keybindin import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; import { IChoiceService } from 'vs/platform/message/common/message'; import { IStorageService } from 'vs/platform/storage/common/storage'; +import { TestConfigurationService } from "vs/platform/configuration/test/common/testConfigurationService"; interface Modifiers { metaKey?: boolean; @@ -81,7 +82,7 @@ suite('Keybindings Editing', () => { instantiationService.stub(ITelemetryService, NullTelemetryService); instantiationService.stub(IModeService, ModeServiceImpl); instantiationService.stub(IModelService, instantiationService.createInstance(ModelServiceImpl)); - instantiationService.stub(IFileService, new FileService(new TestContextService(new Workspace(testDir, testDir, [uri.file(testDir)])), { disableWatcher: true })); + instantiationService.stub(IFileService, new FileService(new TestContextService(new Workspace(testDir, testDir, [uri.file(testDir)])), new TestConfigurationService(), { disableWatcher: true })); instantiationService.stub(IUntitledEditorService, instantiationService.createInstance(UntitledEditorService)); instantiationService.stub(ITextFileService, instantiationService.createInstance(TestTextFileService)); instantiationService.stub(ITextModelService, instantiationService.createInstance(TextModelResolverService));