提交 31ce12f0 编写于 作者: B Benjamin Pasero

Investigate to make IConfigurationService sync if already blocking startup (fixes #4264)

上级 5ce53709
......@@ -508,12 +508,11 @@ export class MainThreadModeServiceImpl extends ModeServiceImpl {
public onReady(): TPromise<boolean> {
if (!this._onReadyPromise) {
this._onReadyPromise = this._configurationService.loadConfiguration().then((configuration: IFilesConfiguration) => {
return this._extensionService.onReady().then(() => {
this.onConfigurationChange(configuration);
const configuration = this._configurationService.getConfiguration<IFilesConfiguration>();
this._onReadyPromise = this._extensionService.onReady().then(() => {
this.onConfigurationChange(configuration);
return true;
});
return true;
});
}
......
......@@ -277,9 +277,7 @@ export class ModelServiceImpl implements IModelService {
this._configurationServiceSubscription = this._configurationService.addListener2(ConfigurationServiceEventTypes.UPDATED, (e: IConfigurationServiceEvent) => {
readConfig(e.config);
});
this._configurationService.loadConfiguration().then((config) => {
readConfig(config);
});
readConfig(this._configurationService.getConfiguration());
this._models = {};
......
......@@ -6,7 +6,6 @@
import {createDecorator, ServiceIdentifier} from 'vs/platform/instantiation/common/instantiation';
import {IEventEmitter} from 'vs/base/common/eventEmitter';
import Event from 'vs/base/common/event';
import winjs = require('vs/base/common/winjs.base');
export const IConfigurationService = createDecorator<IConfigurationService>('configurationService');
......@@ -17,7 +16,7 @@ export interface IConfigurationService extends IEventEmitter {
* Fetches the appropriate section of the configuration JSON file.
* This will be an object keyed off the section name.
*/
loadConfiguration(section?: string): winjs.TPromise<any>;
getConfiguration<T>(section?: string): T;
/**
* Returns iff the workspace has configuration or not.
......
......@@ -5,19 +5,19 @@
'use strict';
import paths = require('vs/base/common/paths');
import winjs = require('vs/base/common/winjs.base');
import eventEmitter = require('vs/base/common/eventEmitter');
import {TPromise} from 'vs/base/common/winjs.base';
import {EventEmitter} from 'vs/base/common/eventEmitter';
import objects = require('vs/base/common/objects');
import errors = require('vs/base/common/errors');
import uri from 'vs/base/common/uri';
import model = require('./model');
import {RunOnceScheduler} from 'vs/base/common/async';
import lifecycle = require('vs/base/common/lifecycle');
import {IDisposable, cAll} from 'vs/base/common/lifecycle';
import collections = require('vs/base/common/collections');
import {IConfigurationService, ConfigurationServiceEventTypes} from './configuration';
import {IEventService} from 'vs/platform/event/common/event';
import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace';
import Files = require('vs/platform/files/common/files');
import {EventType, FileChangeType, FileChangesEvent} from 'vs/platform/files/common/files';
import {IConfigurationRegistry, Extensions} from './configurationRegistry';
import {Registry} from 'vs/platform/platform';
import Event, {fromEventEmitter} from 'vs/base/common/event';
......@@ -42,7 +42,7 @@ interface ILoadConfigResult {
globals: { contents: any; parseErrors: string[]; };
}
export abstract class ConfigurationService extends eventEmitter.EventEmitter implements IConfigurationService, lifecycle.IDisposable {
export abstract class ConfigurationService extends EventEmitter implements IConfigurationService, IDisposable {
public serviceId = IConfigurationService;
......@@ -54,9 +54,10 @@ export abstract class ConfigurationService extends eventEmitter.EventEmitter imp
protected eventService: IEventService;
protected workspaceSettingsRootFolder: string;
private loadConfigurationPromise: winjs.TPromise<any>;
private bulkFetchFromWorkspacePromise: winjs.TPromise<any>;
private workspaceFilePathToConfiguration: { [relativeWorkspacePath: string]: winjs.TPromise<model.IConfigFile> };
private cachedConfig: ILoadConfigResult;
private bulkFetchFromWorkspacePromise: TPromise<any>;
private workspaceFilePathToConfiguration: { [relativeWorkspacePath: string]: TPromise<model.IConfigFile> };
private callOnDispose: Function;
private reloadConfigurationScheduler: RunOnceScheduler;
......@@ -68,102 +69,106 @@ export abstract class ConfigurationService extends eventEmitter.EventEmitter imp
this.workspaceSettingsRootFolder = workspaceSettingsRootFolder;
this.workspaceFilePathToConfiguration = Object.create(null);
this.cachedConfig = {
merged: {},
consolidated: { contents: {}, parseErrors: [] },
globals: { contents: {}, parseErrors: [] }
};
let unbind = this.eventService.addListener(Files.EventType.FILE_CHANGES, (events) => this.handleFileEvents(events));
let subscription = (<IConfigurationRegistry>Registry.as(Extensions.Configuration)).onDidRegisterConfiguration(() => this.reloadConfiguration());
this.onDidUpdateConfiguration = fromEventEmitter(this, ConfigurationServiceEventTypes.UPDATED);
this.registerListeners();
}
protected registerListeners(): void {
let unbind = this.eventService.addListener(EventType.FILE_CHANGES, (events) => this.handleFileEvents(events));
let subscription = Registry.as<IConfigurationRegistry>(Extensions.Configuration).onDidRegisterConfiguration(() => this.handleConfigurationChange());
this.callOnDispose = () => {
unbind();
subscription.dispose();
};
this.onDidUpdateConfiguration = fromEventEmitter(this, ConfigurationServiceEventTypes.UPDATED);
}
protected abstract resolveContents(resource: uri[]): winjs.TPromise<IContent[]>;
protected abstract resolveContent(resource: uri): winjs.TPromise<IContent>;
public initialize(): TPromise<void> {
return this.loadConfiguration().then(() => null);
}
protected abstract resolveStat(resource: uri): winjs.TPromise<IStat>;
protected abstract resolveContents(resource: uri[]): TPromise<IContent[]>;
public dispose(): void {
if (this.reloadConfigurationScheduler) {
this.reloadConfigurationScheduler.dispose();
}
protected abstract resolveContent(resource: uri): TPromise<IContent>;
this.callOnDispose = lifecycle.cAll(this.callOnDispose);
protected abstract resolveStat(resource: uri): TPromise<IStat>;
super.dispose();
}
public getConfiguration<T>(section?: string): T {
let result = section ? this.cachedConfig.merged[section] : this.cachedConfig.merged;
public loadConfiguration(section?: string): winjs.TPromise<any> {
if (!this.loadConfigurationPromise) {
this.loadConfigurationPromise = this.doLoadConfiguration();
let parseErrors = this.cachedConfig.consolidated.parseErrors;
if (this.cachedConfig.globals.parseErrors) {
parseErrors.push.apply(parseErrors, this.cachedConfig.globals.parseErrors);
}
return this.loadConfigurationPromise.then((res: ILoadConfigResult) => {
let result = section ? res.merged[section] : res.merged;
let parseErrors = res.consolidated.parseErrors;
if (res.globals.parseErrors) {
parseErrors.push.apply(parseErrors, res.globals.parseErrors);
if (parseErrors.length > 0) {
if (!result) {
result = {};
}
result.$parseErrors = parseErrors;
}
if (parseErrors.length > 0) {
if (!result) {
result = {};
}
result.$parseErrors = parseErrors;
}
return result;
}
return result;
private loadConfiguration(section?: string): TPromise<any> {
return this.doLoadConfiguration().then((res: ILoadConfigResult) => {
this.cachedConfig = res;
return this.getConfiguration(section);
});
}
private doLoadConfiguration(): winjs.TPromise<ILoadConfigResult> {
private doLoadConfiguration(): TPromise<ILoadConfigResult> {
// Load globals
return this.loadGlobalConfiguration().then((globals) => {
// Load workspace locals
return this.loadWorkspaceConfiguration().then((values) => {
// Consolidate
let consolidated = model.consolidate(values);
// Override with workspace locals
let merged = objects.mixin(
objects.clone(globals.contents), // target: global/default values (but dont modify!)
consolidated.contents, // source: workspace configured values
true // overwrite
);
return {
merged: merged,
consolidated: consolidated,
globals: globals
};
});
const globals = this.loadGlobalConfiguration();
// Load workspace locals
return this.loadWorkspaceConfiguration().then((values) => {
// Consolidate
let consolidated = model.consolidate(values);
// Override with workspace locals
let merged = objects.mixin(
objects.clone(globals.contents), // target: global/default values (but dont modify!)
consolidated.contents, // source: workspace configured values
true // overwrite
);
return {
merged: merged,
consolidated: consolidated,
globals: globals
};
});
}
protected loadGlobalConfiguration(): winjs.TPromise<{ contents: any; parseErrors: string[]; }> {
return winjs.TPromise.as({
protected loadGlobalConfiguration(): { contents: any; parseErrors?: string[]; } {
return {
contents: model.getDefaultValues()
});
};
}
public hasWorkspaceConfiguration(): boolean {
return !!this.workspaceFilePathToConfiguration['.vscode/' + model.CONFIG_DEFAULT_NAME + '.json'];
}
protected loadWorkspaceConfiguration(section?: string): winjs.TPromise<{ [relativeWorkspacePath: string]: model.IConfigFile }> {
protected loadWorkspaceConfiguration(section?: string): TPromise<{ [relativeWorkspacePath: string]: model.IConfigFile }> {
// once: when invoked for the first time we fetch *all* json
// files using the bulk stats and content routes
if (!this.bulkFetchFromWorkspacePromise) {
this.bulkFetchFromWorkspacePromise = this.resolveStat(this.contextService.toResource(this.workspaceSettingsRootFolder)).then((stat) => {
if (!stat.isDirectory) {
return winjs.TPromise.as([]);
return TPromise.as([]);
}
return this.resolveContents(stat.children.filter((stat) => paths.extname(stat.resource.fsPath) === '.json').map(stat => stat.resource));
......@@ -172,7 +177,7 @@ export abstract class ConfigurationService extends eventEmitter.EventEmitter imp
return []; // never fail this call
}
}).then((contents: IContent[]) => {
contents.forEach(content => this.workspaceFilePathToConfiguration[this.contextService.toWorkspaceRelativePath(content.resource)] = winjs.TPromise.as(model.newConfigFile(content.value)));
contents.forEach(content => this.workspaceFilePathToConfiguration[this.contextService.toWorkspaceRelativePath(content.resource)] = TPromise.as(model.newConfigFile(content.value)));
}, errors.onUnexpectedError);
}
......@@ -180,14 +185,14 @@ export abstract class ConfigurationService extends eventEmitter.EventEmitter imp
// we can merge them into a single configuration object. this
// happens whenever a config file changes, is deleted, or added
return this.bulkFetchFromWorkspacePromise.then(() => {
return winjs.TPromise.join(this.workspaceFilePathToConfiguration);
return TPromise.join(this.workspaceFilePathToConfiguration);
});
}
protected reloadConfiguration(): void {
protected handleConfigurationChange(): void {
if (!this.reloadConfigurationScheduler) {
this.reloadConfigurationScheduler = new RunOnceScheduler(() => {
this.doReloadConfiguration().then((config) => this.emit(ConfigurationServiceEventTypes.UPDATED, { config: config })).done(null, errors.onUnexpectedError);
this.loadConfiguration().then((config) => this.emit(ConfigurationServiceEventTypes.UPDATED, { config: config })).done(null, errors.onUnexpectedError);
}, ConfigurationService.RELOAD_CONFIGURATION_DELAY);
}
......@@ -196,13 +201,7 @@ export abstract class ConfigurationService extends eventEmitter.EventEmitter imp
}
}
private doReloadConfiguration(section?: string): winjs.TPromise<any> {
this.loadConfigurationPromise = null;
return this.loadConfiguration(section);
}
private handleFileEvents(event: Files.FileChangesEvent): void {
private handleFileEvents(event: FileChangesEvent): void {
let events = event.changes;
let affectedByChanges = false;
for (let i = 0, len = events.length; i < len; i++) {
......@@ -212,7 +211,7 @@ export abstract class ConfigurationService extends eventEmitter.EventEmitter imp
}
// Handle case where ".vscode" got deleted
if (workspacePath === this.workspaceSettingsRootFolder && events[i].type === Files.FileChangeType.DELETED) {
if (workspacePath === this.workspaceSettingsRootFolder && events[i].type === FileChangeType.DELETED) {
this.workspaceFilePathToConfiguration = Object.create(null);
affectedByChanges = true;
}
......@@ -225,18 +224,28 @@ export abstract class ConfigurationService extends eventEmitter.EventEmitter imp
// insert 'fetch-promises' for add and update events and
// remove promises for delete events
switch (events[i].type) {
case Files.FileChangeType.DELETED:
case FileChangeType.DELETED:
affectedByChanges = collections.remove(this.workspaceFilePathToConfiguration, workspacePath);
break;
case Files.FileChangeType.UPDATED:
case Files.FileChangeType.ADDED:
case FileChangeType.UPDATED:
case FileChangeType.ADDED:
this.workspaceFilePathToConfiguration[workspacePath] = this.resolveContent(events[i].resource).then(content => model.newConfigFile(content.value), errors.onUnexpectedError);
affectedByChanges = true;
}
}
if (affectedByChanges) {
this.reloadConfiguration();
this.handleConfigurationChange();
}
}
public dispose(): void {
if (this.reloadConfigurationScheduler) {
this.reloadConfigurationScheduler.dispose();
}
this.callOnDispose = cAll(this.callOnDispose);
super.dispose();
}
}
......@@ -61,7 +61,7 @@ export class ConfigurationContext {
constructor(configurationService: IConfigurationService) {
this._subscription = configurationService.onDidUpdateConfiguration(e => this._updateConfigurationContext(e.config));
configurationService.loadConfiguration().then(config => this._updateConfigurationContext(config));
this._updateConfigurationContext(configurationService.getConfiguration());
}
public dispose() {
......
......@@ -77,12 +77,11 @@ export class ElectronTelemetryService extends MainTelemetryService implements IT
}
private loadOptinSettings(): void {
this.configurationService.loadConfiguration(TELEMETRY_SECTION_ID).done(config => {
this.config.userOptIn = config ? config.enableTelemetry : this.config.userOptIn;
this._optInStatusLoaded = true;
this.publicLog('optInStatus', {optIn: this.config.userOptIn});
this.flushBuffer();
});
const config = this.configurationService.getConfiguration<any>(TELEMETRY_SECTION_ID);
this.config.userOptIn = config ? config.enableTelemetry : this.config.userOptIn;
this._optInStatusLoaded = true;
this.publicLog('optInStatus', {optIn: this.config.userOptIn});
this.flushBuffer();
this.toUnbind.push(this.configurationService.addListener(ConfigurationServiceEventTypes.UPDATED, (e: IConfigurationServiceEvent) => {
this.config.userOptIn = e.config && e.config[TELEMETRY_SECTION_ID] ? e.config[TELEMETRY_SECTION_ID].enableTelemetry : this.config.userOptIn;
......
......@@ -88,9 +88,7 @@ export class MainThreadConfiguration {
this._toDispose.push(this._configurationService.addListener2(ConfigurationServiceEventTypes.UPDATED, (e:IConfigurationServiceEvent) => {
this._proxy._acceptConfigurationChanged(e.config);
}));
this._configurationService.loadConfiguration().then((config) => {
this._proxy._acceptConfigurationChanged(config);
});
this._proxy._acceptConfigurationChanged(this._configurationService.getConfiguration());
}
public dispose(): void {
......
......@@ -102,7 +102,7 @@ class StateChange {
this.tabFocusMode = false;
}
public combine(other:StateChange) {
public combine(other: StateChange) {
this.indentation = this.indentation || other.indentation;
this.selectionStatus = this.selectionStatus || other.selectionStatus;
this.mode = this.mode || other.mode;
......@@ -321,7 +321,7 @@ export class EditorStatus implements IStatusbarItem {
}
}
private _renderNow(changed:StateChange): void {
private _renderNow(changed: StateChange): void {
if (changed.tabFocusMode) {
if (this.state.tabFocusMode && this.state.tabFocusMode === true) {
show(this.tabFocusModeElement);
......@@ -488,7 +488,7 @@ export class EditorStatus implements IStatusbarItem {
update.indentation = (
modelOpts.insertSpaces
? nls.localize('spacesSize', "Spaces: {0}", modelOpts.tabSize)
: nls.localize({ key: 'tabSize', comment: ['Tab corresponds to the tab key']}, "Tab Size: {0}", modelOpts.tabSize)
: nls.localize({ key: 'tabSize', comment: ['Tab corresponds to the tab key'] }, "Tab Size: {0}", modelOpts.tabSize)
);
}
}
......@@ -868,49 +868,48 @@ export class ChangeEncodingAction extends Action {
}
return TPromise.timeout(50 /* quick open is sensitive to being opened so soon after another */).then(() => {
const configuration = this.configurationService.getConfiguration<IFilesConfiguration>();
let isReopenWithEncoding = (action === reopenWithEncodingPick);
let configuredEncoding = configuration && configuration.files && configuration.files.encoding;
let directMatchIndex: number;
let aliasMatchIndex: number;
// All encodings are valid picks
let picks: IPickOpenEntry[] = Object.keys(SUPPORTED_ENCODINGS)
.sort((k1, k2) => {
if (k1 === configuredEncoding) {
return -1;
} else if (k2 === configuredEncoding) {
return 1;
}
return this.configurationService.loadConfiguration().then((configuration: IFilesConfiguration) => {
let configuredEncoding = configuration && configuration.files && configuration.files.encoding;
let directMatchIndex: number;
let aliasMatchIndex: number;
// All encodings are valid picks
let picks: IPickOpenEntry[] = Object.keys(SUPPORTED_ENCODINGS)
.sort((k1, k2) => {
if (k1 === configuredEncoding) {
return -1;
} else if (k2 === configuredEncoding) {
return 1;
}
return SUPPORTED_ENCODINGS[k1].order - SUPPORTED_ENCODINGS[k2].order;
})
.filter(k => {
return !isReopenWithEncoding || !SUPPORTED_ENCODINGS[k].encodeOnly; // hide those that can only be used for encoding if we are about to decode
})
.map((key, index) => {
if (key === encodingSupport.getEncoding()) {
directMatchIndex = index;
} else if (SUPPORTED_ENCODINGS[key].alias === encodingSupport.getEncoding()) {
aliasMatchIndex = index;
}
return { id: key, label: SUPPORTED_ENCODINGS[key].labelLong };
});
return this.quickOpenService.pick(picks, {
placeHolder: isReopenWithEncoding ? nls.localize('pickEncodingForReopen', "Select File Encoding to Reopen File") : nls.localize('pickEncodingForSave', "Select File Encoding to Save with"),
autoFocus: { autoFocusIndex: typeof directMatchIndex === 'number' ? directMatchIndex : typeof aliasMatchIndex === 'number' ? aliasMatchIndex : void 0 }
}).then((encoding) => {
if (encoding) {
activeEditor = this.editorService.getActiveEditor();
encodingSupport = <any>asFileOrUntitledEditorInput(activeEditor.input);
if (encodingSupport && types.areFunctions(encodingSupport.setEncoding, encodingSupport.getEncoding) && encodingSupport.getEncoding() !== encoding.id) {
encodingSupport.setEncoding(encoding.id, isReopenWithEncoding ? EncodingMode.Decode : EncodingMode.Encode); // Set new encoding
}
return SUPPORTED_ENCODINGS[k1].order - SUPPORTED_ENCODINGS[k2].order;
})
.filter(k => {
return !isReopenWithEncoding || !SUPPORTED_ENCODINGS[k].encodeOnly; // hide those that can only be used for encoding if we are about to decode
})
.map((key, index) => {
if (key === encodingSupport.getEncoding()) {
directMatchIndex = index;
} else if (SUPPORTED_ENCODINGS[key].alias === encodingSupport.getEncoding()) {
aliasMatchIndex = index;
}
return { id: key, label: SUPPORTED_ENCODINGS[key].labelLong };
});
return this.quickOpenService.pick(picks, {
placeHolder: isReopenWithEncoding ? nls.localize('pickEncodingForReopen', "Select File Encoding to Reopen File") : nls.localize('pickEncodingForSave', "Select File Encoding to Save with"),
autoFocus: { autoFocusIndex: typeof directMatchIndex === 'number' ? directMatchIndex : typeof aliasMatchIndex === 'number' ? aliasMatchIndex : void 0 }
}).then((encoding) => {
if (encoding) {
activeEditor = this.editorService.getActiveEditor();
encodingSupport = <any>asFileOrUntitledEditorInput(activeEditor.input);
if (encodingSupport && types.areFunctions(encodingSupport.setEncoding, encodingSupport.getEncoding) && encodingSupport.getEncoding() !== encoding.id) {
encodingSupport.setEncoding(encoding.id, isReopenWithEncoding ? EncodingMode.Decode : EncodingMode.Encode); // Set new encoding
}
}
});
});
});
......
......@@ -9,7 +9,6 @@ import 'vs/css!./media/texteditor';
import {TPromise} from 'vs/base/common/winjs.base';
import {Dimension, Builder} from 'vs/base/browser/builder';
import objects = require('vs/base/common/objects');
import errors = require('vs/base/common/errors');
import {CodeEditorWidget} from 'vs/editor/browser/widget/codeEditorWidget';
import {Preferences} from 'vs/workbench/common/constants';
import {IEditorViewState} from 'vs/editor/common/editorCommon';
......@@ -164,9 +163,7 @@ export abstract class BaseTextEditor extends BaseEditor {
}));
// Configuration
this.configurationService.loadConfiguration().then((config) => {
this.applyConfiguration(config);
}, errors.onUnexpectedError);
this.applyConfiguration(this.configurationService.getConfiguration<IFilesConfiguration>());
}
/**
......
......@@ -87,23 +87,22 @@ export class UntitledEditorModel extends StringEditorModel implements IEncodingS
public load(): TPromise<EditorModel> {
return super.load().then((model) => {
return this.configurationService.loadConfiguration().then((configuration: IFilesConfiguration) => {
const configuration = this.configurationService.getConfiguration<IFilesConfiguration>();
// Encoding
this.configuredEncoding = configuration && configuration.files && configuration.files.encoding;
// Encoding
this.configuredEncoding = configuration && configuration.files && configuration.files.encoding;
// Listen to content changes
this.textModelChangeListener = this.textEditorModel.addListener(EventType.ModelContentChanged, (e: IModelContentChangedEvent) => this.onModelContentChanged(e));
// Listen to content changes
this.textModelChangeListener = this.textEditorModel.addListener(EventType.ModelContentChanged, (e: IModelContentChangedEvent) => this.onModelContentChanged(e));
// Emit initial dirty event if we are
if (this.dirty) {
setTimeout(() => {
this.eventService.emit(WorkbenchEventType.UNTITLED_FILE_DIRTY, new UntitledEditorEvent(this.resource));
}, 0 /* prevent race condition between creating model and emitting dirty event */);
}
// Emit initial dirty event if we are
if (this.dirty) {
setTimeout(() => {
this.eventService.emit(WorkbenchEventType.UNTITLED_FILE_DIRTY, new UntitledEditorEvent(this.resource));
}, 0 /* prevent race condition between creating model and emitting dirty event */);
}
return model;
});
return model;
});
}
......
......@@ -186,14 +186,13 @@ export abstract class BaseZoomAction extends Action {
return TPromise.as(false); // Subclass to implement
}
protected loadConfiguredZoomLevel(): TPromise<number> {
return this.configurationService.loadConfiguration().then((windowConfig: IWindowConfiguration) => {
if (windowConfig.window && typeof windowConfig.window.zoomLevel === 'number') {
return windowConfig.window.zoomLevel;
}
protected getConfiguredZoomLevel(): number {
const windowConfig = this.configurationService.getConfiguration<IWindowConfiguration>();
if (windowConfig.window && typeof windowConfig.window.zoomLevel === 'number') {
return windowConfig.window.zoomLevel;
}
return 0; // default
});
return 0; // default
}
}
......@@ -211,16 +210,16 @@ export class ZoomOutAction extends BaseZoomAction {
}
public run(): TPromise<boolean> {
return this.loadConfiguredZoomLevel().then(level => {
let newZoomLevelCandiate = webFrame.getZoomLevel() - 1;
if (newZoomLevelCandiate < 0 && newZoomLevelCandiate < level) {
newZoomLevelCandiate = Math.min(level, 0); // do not zoom below configured level or below 0
}
const level = this.getConfiguredZoomLevel();
webFrame.setZoomLevel(newZoomLevelCandiate);
let newZoomLevelCandiate = webFrame.getZoomLevel() - 1;
if (newZoomLevelCandiate < 0 && newZoomLevelCandiate < level) {
newZoomLevelCandiate = Math.min(level, 0); // do not zoom below configured level or below 0
}
return true;
});
webFrame.setZoomLevel(newZoomLevelCandiate);
return TPromise.as(true);
}
}
......@@ -238,11 +237,10 @@ export class ZoomResetAction extends BaseZoomAction {
}
public run(): TPromise<boolean> {
return this.loadConfiguredZoomLevel().then(level => {
webFrame.setZoomLevel(level);
const level = this.getConfiguredZoomLevel();
webFrame.setZoomLevel(level);
return true;
});
return TPromise.as(true);
}
}
......
......@@ -53,12 +53,10 @@ export class CrashReporter {
public start(rawConfiguration:Electron.CrashReporterStartOptions): void {
if (!this.isStarted) {
if (!this.config) {
this.configurationService.loadConfiguration(TELEMETRY_SECTION_ID).done((c) => {
this.config = c;
if (this.config && this.config.enableCrashReporter) {
this.doStart(rawConfiguration);
}
});
this.config = this.configurationService.getConfiguration(TELEMETRY_SECTION_ID);
if (this.config && this.config.enableCrashReporter) {
this.doStart(rawConfiguration);
}
} else {
if (this.config.enableCrashReporter) {
this.doStart(rawConfiguration);
......
......@@ -17,7 +17,10 @@ import uri from 'vs/base/common/uri';
import strings = require('vs/base/common/strings');
import {IResourceInput} from 'vs/platform/editor/common/editor';
import {IEnv} from 'vs/base/node/env';
import {EventService} from 'vs/platform/event/common/eventService';
import {WorkspaceContextService} from 'vs/workbench/services/workspace/common/contextService';
import {IWorkspace, IConfiguration, IEnvironment} from 'vs/platform/workspace/common/workspace';
import {ConfigurationService} from 'vs/workbench/services/configuration/node/configurationService';
import path = require('path');
import fs = require('fs');
......@@ -25,6 +28,9 @@ import fs = require('fs');
import gracefulFs = require('graceful-fs');
gracefulFs.gracefulify(fs);
const timers = (<any>window).MonacoEnvironment.timers;
const domContentLoaded: Function = (<any>winjs).Utilities.ready;
export interface IPath {
filePath: string;
lineNumber?: number;
......@@ -50,7 +56,6 @@ export function startup(environment: IMainEnvironment, globalSettings: IGlobalSe
env: environment
};
// Shell Options
let filesToOpen = environment.filesToOpen && environment.filesToOpen.length ? toInputs(environment.filesToOpen) : null;
let filesToCreate = environment.filesToCreate && environment.filesToCreate.length ? toInputs(environment.filesToCreate) : null;
......@@ -121,27 +126,39 @@ function getWorkspace(environment: IMainEnvironment): IWorkspace {
}
function openWorkbench(workspace: IWorkspace, configuration: IConfiguration, options: IOptions): winjs.TPromise<void> {
(<any>window).MonacoEnvironment.timers.beforeReady = new Date();
return (<any>winjs).Utilities.ready(() => {
(<any>window).MonacoEnvironment.timers.afterReady = new Date();
// Monaco Workbench Shell
let beforeOpen = new Date();
let shell = new WorkbenchShell(document.body, workspace, configuration, options);
shell.open();
shell.joinCreation().then(() => {
timer.start(timer.Topic.STARTUP, 'Open Shell, Viewlet & Editor', beforeOpen, 'Workbench has opened after this event with viewlet and editor restored').stop();
});
// Inform user about loading issues from the loader
(<any>self).require.config({
onError: (err: any) => {
if (err.errorCode === 'load') {
shell.onUnexpectedError(errors.loaderError(err));
let eventService = new EventService();
let contextService = new WorkspaceContextService(eventService, workspace, configuration, options);
let configurationService = new ConfigurationService(contextService, eventService);
// Since the configuration service is one of the core services that is used in so many places, we initialize it
// right before startup of the workbench shell to have its data ready for consumers
return configurationService.initialize().then(() => {
timers.beforeReady = new Date();
return domContentLoaded(() => {
timers.afterReady = new Date();
// Open Shell
let beforeOpen = new Date();
let shell = new WorkbenchShell(document.body, workspace, {
configurationService,
eventService,
contextService
}, configuration, options);
shell.open();
shell.joinCreation().then(() => {
timer.start(timer.Topic.STARTUP, 'Open Shell, Viewlet & Editor', beforeOpen, 'Workbench has opened after this event with viewlet and editor restored').stop();
});
// Inform user about loading issues from the loader
(<any>self).require.config({
onError: (err: any) => {
if (err.errorCode === 'load') {
shell.onUnexpectedError(errors.loaderError(err));
}
}
}
});
}, true);
});
}, true);
});
}
\ No newline at end of file
......@@ -14,7 +14,6 @@ import 'vs/css!vs/workbench/browser/media/hc-black-theme';
import * as nls from 'vs/nls';
import {TPromise} from 'vs/base/common/winjs.base';
import {Dimension, Builder, $} from 'vs/base/browser/builder';
import objects = require('vs/base/common/objects');
import dom = require('vs/base/browser/dom');
import aria = require('vs/base/browser/ui/aria/aria');
import {dispose, IDisposable} from 'vs/base/common/lifecycle';
......@@ -34,7 +33,6 @@ import {IWindowService, WindowService} from 'vs/workbench/services/window/electr
import {MessageService} from 'vs/workbench/services/message/electron-browser/messageService';
import {RequestService} from 'vs/workbench/services/request/node/requestService';
import {IConfigurationService} from 'vs/platform/configuration/common/configuration';
import {ConfigurationService} from 'vs/workbench/services/configuration/node/configurationService';
import {FileService} from 'vs/workbench/services/files/electron-browser/fileService';
import {SearchService} from 'vs/workbench/services/search/node/searchService';
import {LifecycleService} from 'vs/workbench/services/lifecycle/electron-browser/lifecycleService';
......@@ -69,9 +67,7 @@ import {MainThreadEditors} from 'vs/workbench/api/node/extHostEditors';
import {MainThreadWorkspace} from 'vs/workbench/api/node/extHostWorkspace';
import {MainThreadConfiguration} from 'vs/workbench/api/node/extHostConfiguration';
import {MainThreadLanguageFeatures} from 'vs/workbench/api/node/extHostLanguageFeatures';
import {EventService} from 'vs/platform/event/common/eventService';
import {IOptions} from 'vs/workbench/common/options';
import {WorkspaceContextService} from 'vs/workbench/services/workspace/common/contextService';
import {IStorageService, StorageScope, StorageEvent, StorageEventType} from 'vs/platform/storage/common/storage';
import {MainThreadStorage} from 'vs/platform/storage/common/remotable.storage';
import {IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
......@@ -100,6 +96,15 @@ import {IExtensionsService} from 'vs/workbench/parts/extensions/common/extension
import {ExtensionsService} from 'vs/workbench/parts/extensions/node/extensionsService';
import {ReloadWindowAction} from 'vs/workbench/electron-browser/actions';
/**
* Services that we require for the Shell
*/
export interface ICoreServices {
contextService: IWorkspaceContextService;
eventService: IEventService;
configurationService: IConfigurationService;
}
/**
* The Monaco Workbench Shell contains the Monaco workbench with a rich header containing navigation and the activity bar.
* With the Shell being the top level element in the page, it is also responsible for driving the layouting.
......@@ -107,11 +112,13 @@ import {ReloadWindowAction} from 'vs/workbench/electron-browser/actions';
export class WorkbenchShell {
private storageService: IStorageService;
private messageService: IMessageService;
private eventService: IEventService;
private contextViewService: ContextViewService;
private windowService: IWindowService;
private threadService: MainThreadService;
private configurationService: IConfigurationService;
private themeService: IThemeService;
private contextService: WorkspaceContextService;
private contextService: IWorkspaceContextService;
private telemetryService: ElectronTelemetryService;
private keybindingService: WorkbenchKeybindingService;
......@@ -128,12 +135,16 @@ export class WorkbenchShell {
private options: IOptions;
private workbench: Workbench;
constructor(container: HTMLElement, workspace: IWorkspace, configuration: IConfiguration, options: IOptions) {
constructor(container: HTMLElement, workspace: IWorkspace, services: ICoreServices, configuration: IConfiguration, options: IOptions) {
this.container = container;
this.workspace = workspace;
this.configuration = configuration;
this.options = objects.mixin({}, options);
this.options = options;
this.contextService = services.contextService;
this.eventService = services.eventService;
this.configurationService = services.configurationService;
this.toUnbind = [];
this.previousErrorTime = 0;
......@@ -221,32 +232,23 @@ export class WorkbenchShell {
}
private initInstantiationService(): IInstantiationService {
let eventService = new EventService();
this.contextService = new WorkspaceContextService(eventService, this.workspace, this.configuration, this.options);
this.windowService = new WindowService();
let disableWorkspaceStorage = this.configuration.env.extensionTestsPath || (!this.workspace && !this.configuration.env.extensionDevelopmentPath); // without workspace or in any extension test, we use inMemory storage unless we develop an extension where we want to preserve state
this.storageService = new Storage(this.contextService, window.localStorage, disableWorkspaceStorage ? inMemoryLocalStorageInstance : window.localStorage);
let configService = new ConfigurationService(
this.contextService,
eventService
);
// no telemetry in a window for extension development!
let enableTelemetry = this.configuration.env.isBuilt && !this.configuration.env.extensionDevelopmentPath ? !!this.configuration.env.enableTelemetry : false;
this.telemetryService = new ElectronTelemetryService(configService, this.storageService, { enableTelemetry: enableTelemetry, version: this.configuration.env.version, commitHash: this.configuration.env.commitHash });
this.telemetryService = new ElectronTelemetryService(this.configurationService, this.storageService, { enableTelemetry: enableTelemetry, version: this.configuration.env.version, commitHash: this.configuration.env.commitHash });
this.keybindingService = new WorkbenchKeybindingService(configService, this.contextService, eventService, this.telemetryService, <any>window);
this.keybindingService = new WorkbenchKeybindingService(this.configurationService, this.contextService, this.configurationService, this.telemetryService, <any>window);
this.messageService = new MessageService(this.contextService, this.windowService, this.telemetryService, this.keybindingService);
this.keybindingService.setMessageService(this.messageService);
let fileService = new FileService(
configService,
eventService,
this.configurationService,
this.eventService,
this.contextService
);
......@@ -259,7 +261,7 @@ export class WorkbenchShell {
let requestService = new RequestService(
this.contextService,
configService,
this.configurationService,
this.telemetryService
);
lifecycleService.onShutdown(() => requestService.dispose());
......@@ -269,8 +271,8 @@ export class WorkbenchShell {
let extensionService = new MainProcessExtensionService(this.contextService, this.threadService, this.messageService, this.telemetryService);
this.keybindingService.setExtensionService(extensionService);
let modeService = new MainThreadModeServiceImpl(this.threadService, extensionService, configService);
let modelService = new ModelServiceImpl(this.threadService, markerService, modeService, configService, this.messageService);
let modeService = new MainThreadModeServiceImpl(this.threadService, extensionService, this.configurationService);
let modelService = new ModelServiceImpl(this.threadService, markerService, modeService, this.configurationService, this.messageService);
let editorWorkerService = new EditorWorkerServiceImpl(modelService);
let untitledEditorService = new UntitledEditorService();
......@@ -278,7 +280,7 @@ export class WorkbenchShell {
let result = createInstantiationService();
result.addSingleton(ITelemetryService, this.telemetryService);
result.addSingleton(IEventService, eventService);
result.addSingleton(IEventService, this.eventService);
result.addSingleton(IRequestService, requestService);
result.addSingleton(IWorkspaceContextService, this.contextService);
result.addSingleton(IContextViewService, this.contextViewService);
......@@ -291,9 +293,9 @@ export class WorkbenchShell {
result.addSingleton(IModeService, modeService);
result.addSingleton(IFileService, fileService);
result.addSingleton(IUntitledEditorService, untitledEditorService);
result.addSingleton(ISearchService, new SearchService(modelService, untitledEditorService, this.contextService, configService));
result.addSingleton(ISearchService, new SearchService(modelService, untitledEditorService, this.contextService, this.configurationService));
result.addSingleton(IWindowService, this.windowService);
result.addSingleton(IConfigurationService, configService);
result.addSingleton(IConfigurationService, this.configurationService);
result.addSingleton(IKeybindingService, this.keybindingService);
result.addSingleton(IMarkerService, markerService);
result.addSingleton(IModelService, modelService);
......
......@@ -337,6 +337,6 @@ export class ConfigurationManager {
}
public loadLaunchConfig(): TPromise<debug.IGlobalConfig> {
return this.configurationService.loadConfiguration('launch');
return TPromise.as(this.configurationService.getConfiguration<debug.IGlobalConfig>('launch'));
}
}
......@@ -53,7 +53,12 @@ export abstract class TextFileService implements ITextFileService {
protected init(): void {
this.registerListeners();
this.loadConfiguration();
const configuration = this.configurationService.getConfiguration<IFilesConfiguration>();
this.onConfigurationChange(configuration);
// we want to find out about this setting from telemetry
this.telemetryService.publicLog('autoSave', this.getAutoSaveConfiguration());
}
public get onAutoSaveConfigurationChange(): Event<IAutoSaveConfiguration> {
......@@ -88,15 +93,6 @@ export abstract class TextFileService implements ITextFileService {
}
}
private loadConfiguration(): void {
this.configurationService.loadConfiguration().done((configuration: IFilesConfiguration) => {
this.onConfigurationChange(configuration);
// we want to find out about this setting from telemetry
this.telemetryService.publicLog('autoSave', this.getAutoSaveConfiguration());
}, errors.onUnexpectedError);
}
private onConfigurationChange(configuration: IFilesConfiguration): void {
const wasAutoSaveEnabled = (this.getAutoSaveMode() !== AutoSaveMode.OFF);
......@@ -254,7 +250,7 @@ export abstract class TextFileService implements ITextFileService {
}
if (this.configuredAutoSaveDelay && this.configuredAutoSaveDelay > 0) {
return this.configuredAutoSaveDelay <= 1000 ? AutoSaveMode.AFTER_SHORT_DELAY : AutoSaveMode.AFTER_LONG_DELAY;
return this.configuredAutoSaveDelay <= 1000 ? AutoSaveMode.AFTER_SHORT_DELAY : AutoSaveMode.AFTER_LONG_DELAY;
}
return AutoSaveMode.OFF;
......
......@@ -130,21 +130,18 @@ export class ExplorerView extends CollapsibleViewletView {
public create(): TPromise<void> {
// Load Config
return this.configurationService.loadConfiguration().then((configuration: IFilesConfiguration) => {
// Update configuration
const configuration = this.configurationService.getConfiguration<IFilesConfiguration>();
this.onConfigurationUpdated(configuration);
// Update configuration
this.onConfigurationUpdated(configuration);
// Load and Fill Viewer
return this.refresh(false, false).then(() => {
// Load and Fill Viewer
return this.refresh(false, false).then(() => {
// When the explorer viewer is loaded, listen to changes to the editor input
this.toDispose.push(this.eventService.addListener2(WorkbenchEventType.EDITOR_INPUT_CHANGING, (e: EditorEvent) => this.onEditorInputChanging(e)));
// When the explorer viewer is loaded, listen to changes to the editor input
this.toDispose.push(this.eventService.addListener2(WorkbenchEventType.EDITOR_INPUT_CHANGING, (e: EditorEvent) => this.onEditorInputChanging(e)));
// Also handle configuration updates
this.toDispose.push(this.configurationService.addListener2(ConfigurationServiceEventTypes.UPDATED, (e: IConfigurationServiceEvent) => this.onConfigurationUpdated(e.config, true)));
});
// Also handle configuration updates
this.toDispose.push(this.configurationService.addListener2(ConfigurationServiceEventTypes.UPDATED, (e: IConfigurationServiceEvent) => this.onConfigurationUpdated(e.config, true)));
});
}
......@@ -316,9 +313,9 @@ export class ExplorerView extends CollapsibleViewletView {
dnd: dnd,
accessibilityProvider: accessibility
}, {
autoExpandSingleChildren: true,
ariaLabel: nls.localize('treeAriaLabel', "Files Explorer")
});
autoExpandSingleChildren: true,
ariaLabel: nls.localize('treeAriaLabel', "Files Explorer")
});
this.toDispose.push(lifecycle.toDisposable(() => renderer.dispose()));
......
......@@ -90,19 +90,16 @@ export class WorkingFilesView extends AdaptiveCollapsibleViewletView {
public create(): TPromise<void> {
// Load Config
return this.configurationService.loadConfiguration().then((configuration) => {
const configuration = this.configurationService.getConfiguration<IFilesConfiguration>();
this.onConfigurationUpdated(configuration);
// Update configuration
this.onConfigurationUpdated(configuration);
// listeners
this.registerListeners();
// listeners
this.registerListeners();
// highlight active input
this.highlightInput(this.editorService.getActiveEditorInput());
// highlight active input
this.highlightInput(this.editorService.getActiveEditorInput());
return super.create();
});
return super.create();
}
private onConfigurationUpdated(configuration: IFilesConfiguration): void {
......@@ -296,10 +293,10 @@ export class WorkingFilesView extends AdaptiveCollapsibleViewletView {
dnd: dnd,
accessibilityProvider: accessibility
}, {
indentPixels: 0,
twistiePixels: 8,
ariaLabel: nls.localize('treeAriaLabel', "Working Files")
});
indentPixels: 0,
twistiePixels: 8,
ariaLabel: nls.localize('treeAriaLabel', "Working Files")
});
this.tree.setInput(this.model);
......
......@@ -2,12 +2,11 @@
* 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 {IWorkbenchContribution} from 'vs/workbench/common/contributions';
import {ICodeEditorService} from 'vs/editor/common/services/codeEditorService';
import errors = require('vs/base/common/errors');
import {TextFileChangeEvent, EventType} from 'vs/workbench/parts/files/common/files';
import {IFilesConfiguration} from 'vs/platform/files/common/files';
import {IPosition, IEditorSelection, IModel} from 'vs/editor/common/editorCommon';
......@@ -30,7 +29,7 @@ export class SaveParticipant implements IWorkbenchContribution {
this.trimTrailingWhitespace = false;
this.registerListeners();
this.loadConfiguration();
this.onConfigurationChange(this.configurationService.getConfiguration<IFilesConfiguration>());
}
private registerListeners(): void {
......@@ -38,12 +37,6 @@ export class SaveParticipant implements IWorkbenchContribution {
this.toUnbind.push(this.configurationService.addListener(ConfigurationServiceEventTypes.UPDATED, (e: IConfigurationServiceEvent) => this.onConfigurationChange(e.config)));
}
private loadConfiguration(): void {
this.configurationService.loadConfiguration().done((configuration: IFilesConfiguration) => {
this.onConfigurationChange(configuration);
}, errors.onUnexpectedError);
}
private onConfigurationChange(configuration: IFilesConfiguration): void {
this.trimTrailingWhitespace = configuration && configuration.files && configuration.files.trimTrailingWhitespace;
}
......
......@@ -275,7 +275,7 @@ export class AutoFetcher implements git.IAutoFetcher, lifecycle.IDisposable
this.toDispose = [];
this.toDispose.push(this.configurationService.addListener2(ConfigurationServiceEventTypes.UPDATED, e => this.onConfiguration(e.config.git)));
configurationService.loadConfiguration('git').done(c => this.onConfiguration(c));
this.onConfiguration(configurationService.getConfiguration<git.IGitConfiguration>('git'));
}
public get state(): git.AutoFetcherState {
......
......@@ -144,7 +144,7 @@ function createNativeRawGitService(workspaceRoot: string, path: string, defaultE
class ElectronRawGitService extends DelayedRawGitService {
constructor(workspaceRoot: string, @IConfigurationService configurationService: IConfigurationService) {
super(configurationService.loadConfiguration().then(conf => {
super(TPromise.as(configurationService.getConfiguration<any>()).then(conf => {
var enabled = conf.git ? conf.git.enabled : true;
if (!enabled) {
......
......@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import errors = require('vs/base/common/errors');
import types = require('vs/base/common/types');
import URI from 'vs/base/common/uri';
import {EventType} from 'vs/base/common/events';
......@@ -72,9 +71,7 @@ export class MarkdownFileTracker implements IWorkbenchContribution {
this.editorInputChangeListener = this.eventService.addListener(WorkbenchEventType.EDITOR_INPUT_CHANGED, (e: EditorEvent) => this.onEditorInputChanged(e));
// initially read the config for CSS styles in preview
this.configurationService.loadConfiguration().done((config) => {
this.readMarkdownConfiguration(config);
}, errors.onUnexpectedError);
this.readMarkdownConfiguration(this.configurationService.getConfiguration<ILanguageConfiguration>());
// listen to theme changes
this.themeChangeListener = this.storageService.addListener(StorageEventType.STORAGE, (e: StorageEvent) => {
......
......@@ -122,7 +122,7 @@ export class OpenFileHandler extends QuickOpenHandler {
filePattern: searchValue
};
return this.queryBuilder.file(query).then((query) => this.searchService.search(query)).then((complete) => {
return this.searchService.search(this.queryBuilder.file(query)).then((complete) => {
let results: QuickOpenEntry[] = [];
for (let i = 0; i < complete.results.length; i++) {
let fileMatch = complete.results[i];
......
......@@ -909,9 +909,7 @@ export class SearchViewlet extends Viewlet {
this.toggleFileTypes(true, true, true);
}
this.configurationService.loadConfiguration().then((configuration) => {
this.updateGlobalPatternExclusions(configuration);
}).done(null, errors.onUnexpectedError);
this.updateGlobalPatternExclusions(this.configurationService.getConfiguration<ISearchConfiguration>());
return TPromise.as(null);
}
......@@ -1148,8 +1146,7 @@ export class SearchViewlet extends Viewlet {
maxResults: SearchViewlet.MAX_TEXT_RESULTS,
};
this.queryBuilder.text(content, options)
.then(query => this.onQueryTriggered(query, patternExcludes, patternIncludes), errors.onUnexpectedError);
this.onQueryTriggered(this.queryBuilder.text(content, options), patternExcludes, patternIncludes);
if (!preserveFocus) {
this.findInput.focus(); // focus back to input field
......
......@@ -6,7 +6,6 @@
import glob = require('vs/base/common/glob');
import objects = require('vs/base/common/objects');
import {TPromise} from 'vs/base/common/winjs.base';
import search = require('vs/platform/search/common/search');
import {IConfigurationService} from 'vs/platform/configuration/common/configuration';
......@@ -34,34 +33,34 @@ export class QueryBuilder {
constructor( @IConfigurationService private configurationService: IConfigurationService) {
}
public text(contentPattern: search.IPatternInfo, options?: search.IQueryOptions): TPromise<search.ISearchQuery> {
public text(contentPattern: search.IPatternInfo, options?: search.IQueryOptions): search.ISearchQuery {
return this.query(search.QueryType.Text, contentPattern, options);
}
public file(options?: search.IQueryOptions): TPromise<search.ISearchQuery> {
public file(options?: search.IQueryOptions): search.ISearchQuery {
return this.query(search.QueryType.File, null, options);
}
private query(type: search.QueryType, contentPattern: search.IPatternInfo, options: search.IQueryOptions = {}): TPromise<search.ISearchQuery> {
return this.configurationService.loadConfiguration().then((configuration: search.ISearchConfiguration) => {
let excludePattern = getExcludes(configuration);
if (!options.excludePattern) {
options.excludePattern = excludePattern;
} else {
objects.mixin(options.excludePattern, excludePattern, false /* no overwrite */);
}
private query(type: search.QueryType, contentPattern: search.IPatternInfo, options: search.IQueryOptions = {}): search.ISearchQuery {
const configuration = this.configurationService.getConfiguration<search.ISearchConfiguration>();
return {
type: type,
folderResources: options.folderResources,
extraFileResources: options.extraFileResources,
filePattern: options.filePattern,
excludePattern: options.excludePattern,
includePattern: options.includePattern,
maxResults: options.maxResults,
fileEncoding: options.fileEncoding,
contentPattern: contentPattern
};
});
let excludePattern = getExcludes(configuration);
if (!options.excludePattern) {
options.excludePattern = excludePattern;
} else {
objects.mixin(options.excludePattern, excludePattern, false /* no overwrite */);
}
return {
type: type,
folderResources: options.folderResources,
extraFileResources: options.extraFileResources,
filePattern: options.filePattern,
excludePattern: options.excludePattern,
includePattern: options.includePattern,
maxResults: options.maxResults,
fileEncoding: options.fileEncoding,
contentPattern: contentPattern
};
}
}
\ No newline at end of file
......@@ -533,7 +533,7 @@ class TaskService extends EventEmitter implements ITaskService {
if (!this._taskSystemPromise) {
let variables = new SystemVariables(this.editorService, this.contextService);
let clearOutput = true;
this._taskSystemPromise = this.configurationService.loadConfiguration('tasks').then((config: TaskConfiguration) => {
this._taskSystemPromise = TPromise.as(this.configurationService.getConfiguration<TaskConfiguration>('tasks')).then((config: TaskConfiguration) => {
let parseErrors: string[] = config ? (<any>config).$parseErrors : null;
if (parseErrors) {
let isAffected = false;
......
......@@ -24,14 +24,28 @@ import fs = require('fs');
export class ConfigurationService extends CommonConfigurationService {
public serviceId = IConfigurationService;
protected contextService: IWorkspaceContextService;
private toDispose: Function;
constructor(contextService: IWorkspaceContextService, eventService: IEventService) {
super(contextService, eventService);
this.registerListeners();
}
protected registerListeners(): void {
super.registerListeners();
this.toDispose = this.eventService.addListener(EventType.WORKBENCH_OPTIONS_CHANGED, (e) => this.onOptionsChanged(e));
}
private onOptionsChanged(e: OptionsChangeEvent): void {
if (e.key === 'globalSettings') {
this.handleConfigurationChange();
}
}
protected resolveContents(resources: uri[]): TPromise<IContent[]> {
let contents: IContent[] = [];
......@@ -88,16 +102,6 @@ export class ConfigurationService extends CommonConfigurationService {
});
}
private registerListeners(): void {
this.toDispose = this.eventService.addListener(EventType.WORKBENCH_OPTIONS_CHANGED, (e) => this.onOptionsChanged(e));
}
private onOptionsChanged(e: OptionsChangeEvent): void {
if (e.key === 'globalSettings') {
this.reloadConfiguration();
}
}
protected loadWorkspaceConfiguration(section?: string): TPromise<{ [relativeWorkspacePath: string]: IConfigFile }> {
// Return early if we don't have a workspace
......@@ -105,25 +109,26 @@ export class ConfigurationService extends CommonConfigurationService {
return TPromise.as({});
}
// Migrate as needed (.settings => .vscode)
return super.loadWorkspaceConfiguration(section);
}
protected loadGlobalConfiguration(): TPromise<{ contents: any; parseErrors?: string[]; }> {
return super.loadGlobalConfiguration().then((defaults) => {
let globalSettings = this.contextService.getOptions().globalSettings;
return {
contents: objects.mixin(
objects.clone(defaults.contents), // target: default values (but don't modify!)
globalSettings.settings, // source: global configured values
true // overwrite
),
parseErrors: globalSettings.settingsParseErrors
};
});
protected loadGlobalConfiguration(): { contents: any; parseErrors?: string[]; } {
const defaults = super.loadGlobalConfiguration();
const globalSettings = this.contextService.getOptions().globalSettings;
return {
contents: objects.mixin(
objects.clone(defaults.contents), // target: default values (but don't modify!)
globalSettings.settings, // source: global configured values
true // overwrite
),
parseErrors: globalSettings.settingsParseErrors
};
}
public dispose(): void {
super.dispose();
this.toDispose();
}
}
\ No newline at end of file
......@@ -12,7 +12,7 @@ import errors = require('vs/base/common/errors');
import strings = require('vs/base/common/strings');
import uri from 'vs/base/common/uri';
import timer = require('vs/base/common/timer');
import files = require('vs/platform/files/common/files');
import {IFileService, IFilesConfiguration, IResolveFileOptions, IFileStat, IContent, IImportResult, IResolveContentOptions, IUpdateContentOptions} from 'vs/platform/files/common/files';
import {FileService as NodeFileService, IFileServiceOptions, IEncodingOverride} from 'vs/workbench/services/files/node/fileService';
import {IConfigurationService, IConfigurationServiceEvent, ConfigurationServiceEventTypes} from 'vs/platform/configuration/common/configuration';
import {IEventService} from 'vs/platform/event/common/event';
......@@ -20,10 +20,11 @@ import {IWorkspaceContextService} from 'vs/platform/workspace/common/workspace';
import {shell} from 'electron';
export class FileService implements files.IFileService {
public serviceId = files.IFileService;
export class FileService implements IFileService {
private raw: TPromise<files.IFileService>;
public serviceId = IFileService;
private raw: IFileService;
private configurationChangeListenerUnbind: () => void;
......@@ -32,40 +33,35 @@ export class FileService implements files.IFileService {
private eventService: IEventService,
private contextService: IWorkspaceContextService
) {
const configuration = this.configurationService.getConfiguration<IFilesConfiguration>();
// Init raw implementation
this.raw = this.configurationService.loadConfiguration().then((configuration: files.IFilesConfiguration) => {
// adjust encodings (TODO@Ben knowledge on settings location ('.vscode') is hardcoded)
let encodingOverride: IEncodingOverride[] = [];
encodingOverride.push({ resource: uri.file(this.contextService.getConfiguration().env.appSettingsHome), encoding: encoding.UTF8 });
if (this.contextService.getWorkspace()) {
encodingOverride.push({ resource: uri.file(paths.join(this.contextService.getWorkspace().resource.fsPath, '.vscode')), encoding: encoding.UTF8 });
}
let watcherIgnoredPatterns:string[] = [];
if (configuration.files && configuration.files.watcherExclude) {
watcherIgnoredPatterns = Object.keys(configuration.files.watcherExclude).filter(k => !!configuration.files.watcherExclude[k]);
}
// build config
let fileServiceConfig: IFileServiceOptions = {
errorLogger: (msg: string) => errors.onUnexpectedError(msg),
encoding: configuration.files && configuration.files.encoding,
encodingOverride: encodingOverride,
watcherIgnoredPatterns: watcherIgnoredPatterns,
verboseLogging: this.contextService.getConfiguration().env.verboseLogging
};
// adjust encodings (TODO@Ben knowledge on settings location ('.vscode') is hardcoded)
let encodingOverride: IEncodingOverride[] = [];
encodingOverride.push({ resource: uri.file(this.contextService.getConfiguration().env.appSettingsHome), encoding: encoding.UTF8 });
if (this.contextService.getWorkspace()) {
encodingOverride.push({ resource: uri.file(paths.join(this.contextService.getWorkspace().resource.fsPath, '.vscode')), encoding: encoding.UTF8 });
}
// create service
let workspace = this.contextService.getWorkspace();
return new NodeFileService(workspace ? workspace.resource.fsPath : void 0, this.eventService, fileServiceConfig);
});
let watcherIgnoredPatterns: string[] = [];
if (configuration.files && configuration.files.watcherExclude) {
watcherIgnoredPatterns = Object.keys(configuration.files.watcherExclude).filter(k => !!configuration.files.watcherExclude[k]);
}
// build config
let fileServiceConfig: IFileServiceOptions = {
errorLogger: (msg: string) => errors.onUnexpectedError(msg),
encoding: configuration.files && configuration.files.encoding,
encodingOverride: encodingOverride,
watcherIgnoredPatterns: watcherIgnoredPatterns,
verboseLogging: this.contextService.getConfiguration().env.verboseLogging
};
// create service
let workspace = this.contextService.getWorkspace();
this.raw = new NodeFileService(workspace ? workspace.resource.fsPath : void 0, this.eventService, fileServiceConfig);
// Listeners
this.raw.done((raw) => {
this.registerListeners();
}, errors.onUnexpectedError);
this.registerListeners();
}
private registerListeners(): void {
......@@ -74,85 +70,65 @@ export class FileService implements files.IFileService {
this.configurationChangeListenerUnbind = this.configurationService.addListener(ConfigurationServiceEventTypes.UPDATED, (e: IConfigurationServiceEvent) => this.onConfigurationChange(e.config));
}
private onConfigurationChange(configuration: files.IFilesConfiguration): void {
private onConfigurationChange(configuration: IFilesConfiguration): void {
this.updateOptions(configuration.files);
}
public updateOptions(options: any): void {
this.raw.done((raw) => {
raw.updateOptions(options);
}, errors.onUnexpectedError);
this.raw.updateOptions(options);
}
public resolveFile(resource: uri, options?: files.IResolveFileOptions): TPromise<files.IFileStat> {
return this.raw.then((raw) => {
return raw.resolveFile(resource, options);
});
public resolveFile(resource: uri, options?: IResolveFileOptions): TPromise<IFileStat> {
return this.raw.resolveFile(resource, options);
}
public resolveContent(resource: uri, options?: files.IResolveContentOptions): TPromise<files.IContent> {
public resolveContent(resource: uri, options?: IResolveContentOptions): TPromise<IContent> {
let contentId = resource.toString();
let timerEvent = timer.start(timer.Topic.WORKBENCH, strings.format('Load {0}', contentId));
return this.raw.then((raw) => {
return raw.resolveContent(resource, options).then((result) => {
timerEvent.stop();
return this.raw.resolveContent(resource, options).then((result) => {
timerEvent.stop();
return result;
});
return result;
});
}
public resolveContents(resources: uri[]): TPromise<files.IContent[]> {
return this.raw.then((raw) => {
return raw.resolveContents(resources);
});
public resolveContents(resources: uri[]): TPromise<IContent[]> {
return this.raw.resolveContents(resources);
}
public updateContent(resource: uri, value: string, options?: files.IUpdateContentOptions): TPromise<files.IFileStat> {
public updateContent(resource: uri, value: string, options?: IUpdateContentOptions): TPromise<IFileStat> {
let timerEvent = timer.start(timer.Topic.WORKBENCH, strings.format('Save {0}', resource.toString()));
return this.raw.then((raw) => {
return raw.updateContent(resource, value, options).then((result) => {
timerEvent.stop();
return this.raw.updateContent(resource, value, options).then((result) => {
timerEvent.stop();
return result;
}, (error) => {
timerEvent.stop();
return result;
}, (error) => {
timerEvent.stop();
return TPromise.wrapError(error);
});
return TPromise.wrapError(error);
});
}
public moveFile(source: uri, target: uri, overwrite?: boolean): TPromise<files.IFileStat> {
return this.raw.then((raw) => {
return raw.moveFile(source, target, overwrite);
});
public moveFile(source: uri, target: uri, overwrite?: boolean): TPromise<IFileStat> {
return this.raw.moveFile(source, target, overwrite);
}
public copyFile(source: uri, target: uri, overwrite?: boolean): TPromise<files.IFileStat> {
return this.raw.then((raw) => {
return raw.copyFile(source, target, overwrite);
});
public copyFile(source: uri, target: uri, overwrite?: boolean): TPromise<IFileStat> {
return this.raw.copyFile(source, target, overwrite);
}
public createFile(resource: uri, content?: string): TPromise<files.IFileStat> {
return this.raw.then((raw) => {
return raw.createFile(resource, content);
});
public createFile(resource: uri, content?: string): TPromise<IFileStat> {
return this.raw.createFile(resource, content);
}
public createFolder(resource: uri): TPromise<files.IFileStat> {
return this.raw.then((raw) => {
return raw.createFolder(resource);
});
public createFolder(resource: uri): TPromise<IFileStat> {
return this.raw.createFolder(resource);
}
public rename(resource: uri, newName: string): TPromise<files.IFileStat> {
return this.raw.then((raw) => {
return raw.rename(resource, newName);
});
public rename(resource: uri, newName: string): TPromise<IFileStat> {
return this.raw.rename(resource, newName);
}
public del(resource: uri, useTrash?: boolean): TPromise<void> {
......@@ -160,9 +136,7 @@ export class FileService implements files.IFileService {
return this.doMoveItemToTrash(resource);
}
return this.raw.then((raw) => {
return raw.del(resource);
});
return this.raw.del(resource);
}
private doMoveItemToTrash(resource: uri): TPromise<void> {
......@@ -181,14 +155,12 @@ export class FileService implements files.IFileService {
return TPromise.as(null);
}
public importFile(source: uri, targetFolder: uri): TPromise<files.IImportResult> {
return this.raw.then((raw) => {
return raw.importFile(source, targetFolder).then((result) => {
return <files.IImportResult> {
isNew: result && result.isNew,
stat: result && result.stat
};
});
public importFile(source: uri, targetFolder: uri): TPromise<IImportResult> {
return this.raw.importFile(source, targetFolder).then((result) => {
return <IImportResult>{
isNew: result && result.isNew,
stat: result && result.stat
};
});
}
......@@ -206,17 +178,13 @@ export class FileService implements files.IFileService {
return;
}
this.raw.then((raw) => {
raw.watchFileChanges(resource);
});
this.raw.watchFileChanges(resource);
}
public unwatchFileChanges(resource: uri): void;
public unwatchFileChanges(path: string): void;
public unwatchFileChanges(arg1: any): void {
this.raw.then((raw) => {
raw.unwatchFileChanges(arg1);
});
this.raw.unwatchFileChanges(arg1);
}
public dispose(): void {
......@@ -228,6 +196,6 @@ export class FileService implements files.IFileService {
}
// Dispose service
this.raw.done((raw) => raw.dispose());
this.raw.dispose();
}
}
\ No newline at end of file
......@@ -51,10 +51,10 @@ export class RequestService extends BaseRequestService {
private _rawHttpServicePromise: TPromise<IRawHttpService>;
private get rawHttpServicePromise(): TPromise<IRawHttpService> {
if (!this._rawHttpServicePromise) {
this._rawHttpServicePromise = this.configurationService.loadConfiguration().then((configuration: any) => {
rawHttpService.configure(configuration.http && configuration.http.proxy, configuration.http.proxyStrictSSL);
return rawHttpService;
});
const configuration = this.configurationService.getConfiguration<any>();
rawHttpService.configure(configuration.http && configuration.http.proxy, configuration.http.proxyStrictSSL);
return TPromise.as(rawHttpService);
}
return this._rawHttpServicePromise;
......
......@@ -34,71 +34,70 @@ export class SearchService implements ISearchService {
}
public search(query: ISearchQuery): PPromise<ISearchComplete, ISearchProgressItem> {
return this.configurationService.loadConfiguration().then((configuration: ISearchConfiguration) => {
const configuration = this.configurationService.getConfiguration<ISearchConfiguration>();
// Configuration: Encoding
if (!query.fileEncoding) {
let fileEncoding = configuration && configuration.files && configuration.files.encoding;
query.fileEncoding = fileEncoding;
}
// Configuration: Encoding
if (!query.fileEncoding) {
let fileEncoding = configuration && configuration.files && configuration.files.encoding;
query.fileEncoding = fileEncoding;
}
// Configuration: File Excludes
let fileExcludes = configuration && configuration.files && configuration.files.exclude;
if (fileExcludes) {
if (!query.excludePattern) {
query.excludePattern = fileExcludes;
} else {
objects.mixin(query.excludePattern, fileExcludes, false /* no overwrite */);
}
// Configuration: File Excludes
let fileExcludes = configuration && configuration.files && configuration.files.exclude;
if (fileExcludes) {
if (!query.excludePattern) {
query.excludePattern = fileExcludes;
} else {
objects.mixin(query.excludePattern, fileExcludes, false /* no overwrite */);
}
}
let rawSearchQuery: PPromise<void, ISearchProgressItem>;
return new PPromise<ISearchComplete, ISearchProgressItem>((onComplete, onError, onProgress) => {
let rawSearchQuery: PPromise<void, ISearchProgressItem>;
return new PPromise<ISearchComplete, ISearchProgressItem>((onComplete, onError, onProgress) => {
// Get local results from dirty/untitled
let localResultsFlushed = false;
let localResults = this.getLocalResults(query);
// Get local results from dirty/untitled
let localResultsFlushed = false;
let localResults = this.getLocalResults(query);
let flushLocalResultsOnce = function() {
if (!localResultsFlushed) {
localResultsFlushed = true;
Object.keys(localResults).map((key) => localResults[key]).filter((res) => !!res).forEach(onProgress);
}
};
// Delegate to parent for real file results
rawSearchQuery = this.diskSearch.search(query).then(
// on Complete
(complete) => {
flushLocalResultsOnce();
onComplete({ results: complete.results.filter((match) => typeof localResults[match.resource.toString()] === 'undefined'), limitHit: complete.limitHit }); // dont override local results
},
// on Error
(error) => {
flushLocalResultsOnce();
onError(error);
},
// on Progress
(progress) => {
flushLocalResultsOnce();
// Match
if (progress.resource) {
if (typeof localResults[progress.resource.toString()] === 'undefined') { // don't override local results
onProgress(progress);
}
let flushLocalResultsOnce = function () {
if (!localResultsFlushed) {
localResultsFlushed = true;
Object.keys(localResults).map((key) => localResults[key]).filter((res) => !!res).forEach(onProgress);
}
};
// Delegate to parent for real file results
rawSearchQuery = this.diskSearch.search(query).then(
// on Complete
(complete) => {
flushLocalResultsOnce();
onComplete({ results: complete.results.filter((match) => typeof localResults[match.resource.toString()] === 'undefined'), limitHit: complete.limitHit }); // dont override local results
},
// on Error
(error) => {
flushLocalResultsOnce();
onError(error);
},
// on Progress
(progress) => {
flushLocalResultsOnce();
// Match
if (progress.resource) {
if (typeof localResults[progress.resource.toString()] === 'undefined') { // don't override local results
onProgress(progress);
}
}
// Progress
else {
onProgress(<IProgress>progress);
}
});
}, () => rawSearchQuery && rawSearchQuery.cancel());
});
// Progress
else {
onProgress(<IProgress>progress);
}
});
}, () => rawSearchQuery && rawSearchQuery.cancel());
}
private getLocalResults(query: ISearchQuery): { [resourcePath: string]: IFileMatch; } {
......
......@@ -498,8 +498,8 @@ export const TestFileService = {
export class TestConfigurationService extends EventEmitter.EventEmitter implements IConfigurationService {
public serviceId = IConfigurationService;
public loadConfiguration(section?:string):TPromise<any> {
return TPromise.as({});
public getConfiguration(): any {
return {};
}
public hasWorkspaceConfiguration():boolean {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册