Skip to content

Commit

Permalink
Allow to configure files.encoding and files.autoGuessEncoding per lan…
Browse files Browse the repository at this point in the history
…guage

fixes #33903
fixes #19890
  • Loading branch information
bpasero committed Sep 11, 2017
1 parent 7770f2e commit 0008cde
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 77 deletions.
10 changes: 7 additions & 3 deletions src/vs/workbench/browser/parts/editor/editorStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 { SUPPORTED_ENCODINGS, IFileService } from 'vs/platform/files/common/files';
import { SUPPORTED_ENCODINGS, IFileService, IFilesConfiguration } 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';
Expand All @@ -46,6 +46,7 @@ import { ITextFileService } from 'vs/workbench/services/textfile/common/textfile
import { getCodeEditor as getEditorWidget } from 'vs/editor/common/services/codeEditorService';
import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions';
import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration';

// TODO@Sandeep layer breaker
// tslint:disable-next-line:import-patterns
Expand Down Expand Up @@ -1058,7 +1059,7 @@ export class ChangeEncodingAction extends Action {
actionLabel: string,
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
@IQuickOpenService private quickOpenService: IQuickOpenService,
@IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService,
@ITextResourceConfigurationService private textResourceConfigurationService: ITextResourceConfigurationService,
@IFileService private fileService: IFileService
) {
super(actionId, actionLabel);
Expand Down Expand Up @@ -1112,7 +1113,10 @@ export class ChangeEncodingAction extends Action {
})
.then((guessedEncoding: string) => {
const isReopenWithEncoding = (action === reopenWithEncodingPick);
const configuredEncoding = this.configurationService.lookup('files.encoding', { resource }).value;

const config = this.textResourceConfigurationService.getConfiguration(resource) as IFilesConfiguration;
const configuredEncoding = config && config.files && config.files.encoding;

let directMatchIndex: number;
let aliasMatchIndex: number;

Expand Down
58 changes: 33 additions & 25 deletions src/vs/workbench/common/editor/untitledEditorModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,28 @@
*--------------------------------------------------------------------------------------------*/
'use strict';

import { IDisposable } from 'vs/base/common/lifecycle';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { TPromise } from 'vs/base/common/winjs.base';
import { IEncodingSupport } from 'vs/workbench/common/editor';
import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel';
import URI from 'vs/base/common/uri';
import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry';
import { EndOfLinePreference } from 'vs/editor/common/editorCommon';
import { IFilesConfiguration, CONTENT_CHANGE_EVENT_BUFFER_DELAY } from 'vs/platform/files/common/files';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IModelService } from 'vs/editor/common/services/modelService';
import { IMode } from 'vs/editor/common/modes';
import Event, { Emitter } from 'vs/base/common/event';
import { RunOnceScheduler } from 'vs/base/common/async';
import { IBackupFileService, BACKUP_FILE_RESOLVE_OPTIONS } from 'vs/workbench/services/backup/common/backup';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration';

export class UntitledEditorModel extends BaseTextEditorModel implements IEncodingSupport {

public static DEFAULT_CONTENT_CHANGE_BUFFER_DELAY = CONTENT_CHANGE_EVENT_BUFFER_DELAY;

private textModelChangeListener: IDisposable;
private configurationChangeListener: IDisposable;
private toDispose: IDisposable[];

private dirty: boolean;
private _onDidChangeContent: Emitter<void>;
Expand All @@ -49,18 +48,25 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin
@IModelService modelService: IModelService,
@IBackupFileService private backupFileService: IBackupFileService,
@ITextFileService private textFileService: ITextFileService,
@IConfigurationService private configurationService: IConfigurationService
@ITextResourceConfigurationService private configurationService: ITextResourceConfigurationService
) {
super(modelService, modeService);

this.dirty = false;
this.versionId = 0;
this.toDispose = [];

this._onDidChangeContent = new Emitter<void>();
this.toDispose.push(this._onDidChangeContent);

this._onDidChangeDirty = new Emitter<void>();
this.toDispose.push(this._onDidChangeDirty);

this._onDidChangeEncoding = new Emitter<void>();
this.toDispose.push(this._onDidChangeEncoding);

this.contentChangeEventScheduler = new RunOnceScheduler(() => this._onDidChangeContent.fire(), UntitledEditorModel.DEFAULT_CONTENT_CHANGE_BUFFER_DELAY);
this.toDispose.push(this.contentChangeEventScheduler);

this.registerListeners();
}
Expand Down Expand Up @@ -88,11 +94,20 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin
private registerListeners(): void {

// Config Changes
this.configurationChangeListener = this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationChange(this.configurationService.getConfiguration<IFilesConfiguration>()));
this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfigurationChange()));
}

private onConfigurationChange(configuration: IFilesConfiguration): void {
this.configuredEncoding = configuration && configuration.files && configuration.files.encoding;
private onConfigurationChange(): void {
const configuration = this.configurationService.getConfiguration<IFilesConfiguration>(this.resource);
const configuredEncoding = configuration && configuration.files && configuration.files.encoding;

if (this.configuredEncoding !== configuredEncoding) {
this.configuredEncoding = configuredEncoding;

if (!this.preferredEncoding) {
this._onDidChangeEncoding.fire(); // do not fire event if we have a preferred encoding set
}
}
}

public getVersionId(): number {
Expand Down Expand Up @@ -170,13 +185,16 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin
this.setDirty(this.hasAssociatedFilePath || !!backupContent);

return this.doLoad(backupContent || this.initialValue || '').then(model => {
const configuration = this.configurationService.getConfiguration<IFilesConfiguration>();
const configuration = this.configurationService.getConfiguration<IFilesConfiguration>(this.resource);

// Encoding
this.configuredEncoding = configuration && configuration.files && configuration.files.encoding;

// Listen to content changes
this.textModelChangeListener = this.textEditorModel.onDidChangeContent(() => this.onModelContentChanged());
this.toDispose.push(this.textEditorModel.onDidChangeContent(() => this.onModelContentChanged()));

// Listen to mode changes
this.toDispose.push(this.textEditorModel.onDidChangeLanguage(() => this.onModelModeChanged()));

return model;
});
Expand Down Expand Up @@ -216,23 +234,13 @@ export class UntitledEditorModel extends BaseTextEditorModel implements IEncodin
this.contentChangeEventScheduler.schedule();
}

private onModelModeChanged(): void {
this.onConfigurationChange(); // mode change can have impact on config
}

public dispose(): void {
super.dispose();

if (this.textModelChangeListener) {
this.textModelChangeListener.dispose();
this.textModelChangeListener = null;
}

if (this.configurationChangeListener) {
this.configurationChangeListener.dispose();
this.configurationChangeListener = null;
}

this.contentChangeEventScheduler.dispose();

this._onDidChangeContent.dispose();
this._onDidChangeDirty.dispose();
this._onDidChangeEncoding.dispose();
this.toDispose = dispose(this.toDispose);
}
}
6 changes: 4 additions & 2 deletions src/vs/workbench/parts/files/browser/files.contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,16 +201,18 @@ configurationRegistry.registerConfiguration({
},
'files.encoding': {
'type': 'string',
'overridable': true,
'enum': Object.keys(SUPPORTED_ENCODINGS),
'default': 'utf8',
'description': nls.localize('encoding', "The default character set encoding to use when reading and writing files."),
'description': nls.localize('encoding', "The default character set encoding to use when reading and writing files. This setting can be configured per language too."),
'scope': ConfigurationScope.RESOURCE,
'enumDescriptions': Object.keys(SUPPORTED_ENCODINGS).map(key => SUPPORTED_ENCODINGS[key].labelLong)
},
'files.autoGuessEncoding': {
'type': 'boolean',
'overridable': true,
'default': false,
'description': nls.localize('autoGuessEncoding', "When enabled, will attempt to guess the character set encoding when opening files"),
'description': nls.localize('autoGuessEncoding', "When enabled, will attempt to guess the character set encoding when opening files. This setting can be configured per language too."),
'scope': ConfigurationScope.RESOURCE
},
'files.eol': {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { FileService } from 'vs/workbench/services/files/node/fileService';
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
import { parseArgs } from 'vs/platform/environment/node/argv';
import { RawTextSource } from 'vs/editor/common/model/textSource';
import { TestContextService } from 'vs/workbench/test/workbenchTestServices';
import { TestContextService, TestTextResourceConfigurationService } from 'vs/workbench/test/workbenchTestServices';
import { Workspace } from 'vs/platform/workspace/common/workspace';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';

Expand Down Expand Up @@ -49,7 +49,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])), new TestConfigurationService(), { disableWatcher: true });
const fileService = new FileService(new TestContextService(new Workspace(workspace.fsPath, workspace.fsPath, [workspace])), new TestTextResourceConfigurationService(), new TestConfigurationService(), { disableWatcher: true });

super(workspaceBackupPath, fileService);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { parseArgs } from 'vs/platform/environment/node/argv';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
import extfs = require('vs/base/node/extfs');
import { TestTextFileService, TestEditorGroupService, TestLifecycleService, TestBackupFileService } from 'vs/workbench/test/workbenchTestServices';
import { TestTextFileService, TestEditorGroupService, TestLifecycleService, TestBackupFileService, TestTextResourceConfigurationService } from 'vs/workbench/test/workbenchTestServices';
import uuid = require('vs/base/common/uuid');
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
import { WorkspaceService, EmptyWorkspaceServiceImpl, WorkspaceServiceImpl } from 'vs/workbench/services/configuration/node/configuration';
Expand Down Expand Up @@ -125,7 +125,7 @@ suite('ConfigurationEditingService', () => {
instantiationService.stub(ITelemetryService, NullTelemetryService);
instantiationService.stub(IModeService, ModeServiceImpl);
instantiationService.stub(IModelService, instantiationService.createInstance(ModelServiceImpl));
instantiationService.stub(IFileService, new FileService(workspaceService, new TestConfigurationService(), { disableWatcher: true }));
instantiationService.stub(IFileService, new FileService(workspaceService, new TestTextResourceConfigurationService(), new TestConfigurationService(), { disableWatcher: true }));
instantiationService.stub(IUntitledEditorService, instantiationService.createInstance(UntitledEditorService));
instantiationService.stub(ITextFileService, instantiationService.createInstance(TestTextFileService));
instantiationService.stub(ITextModelService, <ITextModelService>instantiationService.createInstance(TextModelResolverService));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag
import Event, { Emitter } from 'vs/base/common/event';

import { shell } from 'electron';
import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration';

export class FileService implements IFileService {

Expand All @@ -52,7 +53,8 @@ export class FileService implements IFileService {
@IEditorGroupService private editorGroupService: IEditorGroupService,
@ILifecycleService private lifecycleService: ILifecycleService,
@IMessageService private messageService: IMessageService,
@IStorageService private storageService: IStorageService
@IStorageService private storageService: IStorageService,
@ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService
) {
this.toUnbind = [];
this.activeOutOfWorkspaceWatchers = new ResourceMap<uri>();
Expand Down Expand Up @@ -80,7 +82,7 @@ export class FileService implements IFileService {
};

// create service
this.raw = new NodeFileService(contextService, configurationService, fileServiceConfig);
this.raw = new NodeFileService(contextService, textResourceConfigurationService, configurationService, fileServiceConfig);

// Listeners
this.registerListeners();
Expand Down
8 changes: 5 additions & 3 deletions src/vs/workbench/services/files/node/fileService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';

export interface IEncodingOverride {
Expand Down Expand Up @@ -93,8 +94,9 @@ export class FileService implements IFileService {

constructor(
private contextService: IWorkspaceContextService,
private textResourceConfigurationService: ITextResourceConfigurationService,
private configurationService: IConfigurationService,
options: IFileServiceOptions,
options: IFileServiceOptions
) {
this.toDispose = [];
this.options = options || Object.create(null);
Expand Down Expand Up @@ -638,13 +640,13 @@ export class FileService implements IFileService {
}

private configuredAutoGuessEncoding(resource: uri): boolean {
const config = this.configurationService.getConfiguration(void 0, { resource }) as IFilesConfiguration;
const config = this.textResourceConfigurationService.getConfiguration(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;
const config = this.textResourceConfigurationService.getConfiguration(resource) as IFilesConfiguration;

return config && config.files && config.files.encoding;
}
Expand Down
Loading

0 comments on commit 0008cde

Please sign in to comment.