mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-24 18:49:00 +01:00
Merge remote-tracking branch 'origin/master' into treeExplorerAPI
This commit is contained in:
@@ -37,27 +37,34 @@ import Severity from 'vs/base/common/severity';
|
||||
import EditorCommon = require('vs/editor/common/editorCommon');
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService';
|
||||
import { ExtensionsRegistry } from 'vs/platform/extensions/common/extensionsRegistry';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import * as vscode from 'vscode';
|
||||
import * as paths from 'vs/base/common/paths';
|
||||
import { realpathSync } from 'fs';
|
||||
import { ITelemetryService, ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { MainContext, ExtHostContext, InstanceCollection } from './extHost.protocol';
|
||||
import { ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { MainContext, ExtHostContext, InstanceCollection, IInitConfiguration } from './extHost.protocol';
|
||||
|
||||
|
||||
export interface IExtensionApiFactory {
|
||||
(extension: IExtensionDescription): typeof vscode;
|
||||
}
|
||||
|
||||
function proposedApiFunction<T>(extension: IExtensionDescription, fn: T): T {
|
||||
if (extension.enableProposedApi) {
|
||||
return fn;
|
||||
} else {
|
||||
return <any>(() => {
|
||||
throw new Error(`${extension.id} cannot access proposed api`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method instantiates and returns the extension API surface
|
||||
*/
|
||||
export function createApiFactory(threadService: IThreadService, extensionService: ExtHostExtensionService, contextService: IWorkspaceContextService, telemetryService: ITelemetryService): IExtensionApiFactory {
|
||||
|
||||
|
||||
export function createApiFactory(initDataConfiguration: IInitConfiguration, initTelemetryInfo: ITelemetryInfo, threadService: IThreadService, extensionService: ExtHostExtensionService, contextService: IWorkspaceContextService): IExtensionApiFactory {
|
||||
|
||||
// Addressable instances
|
||||
const col = new InstanceCollection();
|
||||
@@ -67,7 +74,7 @@ export function createApiFactory(threadService: IThreadService, extensionService
|
||||
const extHostEditors = col.define(ExtHostContext.ExtHostEditors).set<ExtHostEditors>(new ExtHostEditors(threadService, extHostDocuments));
|
||||
const extHostCommands = col.define(ExtHostContext.ExtHostCommands).set<ExtHostCommands>(new ExtHostCommands(threadService, extHostEditors, extHostHeapService));
|
||||
const extHostExplorers = col.define(ExtHostContext.ExtHostExplorers).set<ExtHostTreeExplorers>(new ExtHostTreeExplorers(threadService, extHostCommands));
|
||||
const extHostConfiguration = col.define(ExtHostContext.ExtHostConfiguration).set<ExtHostConfiguration>(new ExtHostConfiguration(threadService.get(MainContext.MainThreadConfiguration)));
|
||||
const extHostConfiguration = col.define(ExtHostContext.ExtHostConfiguration).set<ExtHostConfiguration>(new ExtHostConfiguration(threadService.get(MainContext.MainThreadConfiguration), initDataConfiguration));
|
||||
const extHostDiagnostics = col.define(ExtHostContext.ExtHostDiagnostics).set<ExtHostDiagnostics>(new ExtHostDiagnostics(threadService));
|
||||
const languageFeatures = col.define(ExtHostContext.ExtHostLanguageFeatures).set<ExtHostLanguageFeatures>(new ExtHostLanguageFeatures(threadService, extHostDocuments, extHostCommands, extHostHeapService, extHostDiagnostics));
|
||||
const extHostFileSystemEvent = col.define(ExtHostContext.ExtHostFileSystemEventService).set<ExtHostFileSystemEventService>(new ExtHostFileSystemEventService());
|
||||
@@ -84,22 +91,15 @@ export function createApiFactory(threadService: IThreadService, extensionService
|
||||
const extHostWorkspace = new ExtHostWorkspace(threadService, workspacePath);
|
||||
const extHostLanguages = new ExtHostLanguages(threadService);
|
||||
|
||||
// Error forwarding
|
||||
const mainThreadErrors = threadService.get(MainContext.MainThreadErrors);
|
||||
errors.setUnexpectedErrorHandler((err) => {
|
||||
mainThreadErrors.onUnexpectedExtHostError(errors.transformErrorForSerialization(err));
|
||||
});
|
||||
|
||||
// Register API-ish commands
|
||||
ExtHostApiCommands.register(extHostCommands);
|
||||
|
||||
// TODO@joh,alex - this is lifecycle critical
|
||||
// fetch and store telemetry info
|
||||
let telemetryInfo: ITelemetryInfo;
|
||||
telemetryService.getTelemetryInfo().then(info => telemetryInfo = info, errors.onUnexpectedError);
|
||||
|
||||
return function (extension: IExtensionDescription): typeof vscode {
|
||||
|
||||
if (extension.enableProposedApi) {
|
||||
console.warn(`${extension.name} (${extension.id}) uses PROPOSED API which is subject to change and removal without notice`);
|
||||
}
|
||||
|
||||
// namespace: commands
|
||||
const commands: typeof vscode.commands = {
|
||||
registerCommand<T>(id: string, command: <T>(...args: any[]) => T | Thenable<T>, thisArgs?: any): vscode.Disposable {
|
||||
@@ -136,8 +136,8 @@ export function createApiFactory(threadService: IThreadService, extensionService
|
||||
|
||||
// namespace: env
|
||||
const env: typeof vscode.env = Object.freeze({
|
||||
get machineId() { return telemetryInfo.machineId; },
|
||||
get sessionId() { return telemetryInfo.sessionId; },
|
||||
get machineId() { return initTelemetryInfo.machineId; },
|
||||
get sessionId() { return initTelemetryInfo.sessionId; },
|
||||
get language() { return Platform.language; },
|
||||
get appName() { return product.nameLong; }
|
||||
});
|
||||
@@ -145,13 +145,13 @@ export function createApiFactory(threadService: IThreadService, extensionService
|
||||
// namespace: extensions
|
||||
const extensions: typeof vscode.extensions = {
|
||||
getExtension(extensionId: string): Extension<any> {
|
||||
let desc = ExtensionsRegistry.getExtensionDescription(extensionId);
|
||||
let desc = extensionService.getExtensionDescription(extensionId);
|
||||
if (desc) {
|
||||
return new Extension(extensionService, desc);
|
||||
}
|
||||
},
|
||||
get all(): Extension<any>[] {
|
||||
return ExtensionsRegistry.getAllExtensionDescriptions().map((desc) => new Extension(extensionService, desc));
|
||||
return extensionService.getAllExtensionDescriptions().map((desc) => new Extension(extensionService, desc));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -230,30 +230,34 @@ export function createApiFactory(threadService: IThreadService, extensionService
|
||||
createTextEditorDecorationType(options: vscode.DecorationRenderOptions): vscode.TextEditorDecorationType {
|
||||
return extHostEditors.createTextEditorDecorationType(options);
|
||||
},
|
||||
onDidChangeActiveTextEditor: extHostEditors.onDidChangeActiveTextEditor.bind(extHostEditors),
|
||||
onDidChangeActiveTextEditor(listener, thisArg?, disposables?) {
|
||||
return extHostEditors.onDidChangeActiveTextEditor(listener, thisArg, disposables);
|
||||
},
|
||||
onDidChangeVisibleTextEditors(listener, thisArg, disposables) {
|
||||
return extHostEditors.onDidChangeVisibleTextEditors(listener, thisArg, disposables);
|
||||
},
|
||||
onDidChangeTextEditorSelection: (listener: (e: vscode.TextEditorSelectionChangeEvent) => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) => {
|
||||
onDidChangeTextEditorSelection(listener: (e: vscode.TextEditorSelectionChangeEvent) => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) {
|
||||
return extHostEditors.onDidChangeTextEditorSelection(listener, thisArgs, disposables);
|
||||
},
|
||||
onDidChangeTextEditorOptions: (listener: (e: vscode.TextEditorOptionsChangeEvent) => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) => {
|
||||
onDidChangeTextEditorOptions(listener: (e: vscode.TextEditorOptionsChangeEvent) => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) {
|
||||
return extHostEditors.onDidChangeTextEditorOptions(listener, thisArgs, disposables);
|
||||
},
|
||||
onDidChangeTextEditorViewColumn(listener, thisArg?, disposables?) {
|
||||
return extHostEditors.onDidChangeTextEditorViewColumn(listener, thisArg, disposables);
|
||||
},
|
||||
onDidCloseTerminal: extHostTerminalService.onDidCloseTerminal.bind(extHostTerminalService),
|
||||
showInformationMessage: (message, ...items) => {
|
||||
onDidCloseTerminal(listener, thisArg?, disposables?) {
|
||||
return extHostTerminalService.onDidCloseTerminal(listener, thisArg, disposables);
|
||||
},
|
||||
showInformationMessage(message, ...items) {
|
||||
return extHostMessageService.showMessage(Severity.Info, message, items);
|
||||
},
|
||||
showWarningMessage: (message, ...items) => {
|
||||
showWarningMessage(message, ...items) {
|
||||
return extHostMessageService.showMessage(Severity.Warning, message, items);
|
||||
},
|
||||
showErrorMessage: (message, ...items) => {
|
||||
showErrorMessage(message, ...items) {
|
||||
return extHostMessageService.showMessage(Severity.Error, message, items);
|
||||
},
|
||||
showQuickPick: (items: any, options: vscode.QuickPickOptions, token?: vscode.CancellationToken) => {
|
||||
showQuickPick(items: any, options: vscode.QuickPickOptions, token?: vscode.CancellationToken) {
|
||||
return extHostQuickOpen.showQuickPick(items, options, token);
|
||||
},
|
||||
showInputBox(options?: vscode.InputBoxOptions, token?: vscode.CancellationToken) {
|
||||
@@ -270,7 +274,11 @@ export function createApiFactory(threadService: IThreadService, extensionService
|
||||
},
|
||||
createTerminal(name?: string, shellPath?: string, shellArgs?: string[]): vscode.Terminal {
|
||||
return extHostTerminalService.createTerminal(name, shellPath, shellArgs);
|
||||
}
|
||||
},
|
||||
// proposed API
|
||||
sampleFunction: proposedApiFunction(extension, () => {
|
||||
return extHostMessageService.showMessage(Severity.Info, 'Hello Proposed Api!', []);
|
||||
})
|
||||
};
|
||||
|
||||
// namespace: workspace
|
||||
@@ -422,7 +430,7 @@ class Extension<T> implements vscode.Extension<T> {
|
||||
}
|
||||
}
|
||||
|
||||
export function defineAPI(factory: IExtensionApiFactory, extensions: IExtensionDescription[]): void {
|
||||
export function defineAPI(factory: IExtensionApiFactory, extensionService: ExtHostExtensionService): void {
|
||||
|
||||
// each extension is meant to get its own api implementation
|
||||
const extApiImpl: { [id: string]: typeof vscode } = Object.create(null);
|
||||
@@ -430,6 +438,7 @@ export function defineAPI(factory: IExtensionApiFactory, extensions: IExtensionD
|
||||
|
||||
// create trie to enable fast 'filename -> extension id' look up
|
||||
const trie = new TrieMap<IExtensionDescription>(TrieMap.PathSplitter);
|
||||
const extensions = extensionService.getAllExtensionDescriptions();
|
||||
for (const ext of extensions) {
|
||||
if (ext.name) {
|
||||
const path = realpathSync(ext.extensionFolderPath);
|
||||
|
||||
@@ -18,10 +18,11 @@ import { TPromise } from 'vs/base/common/winjs.base';
|
||||
|
||||
import { IMarkerData } from 'vs/platform/markers/common/markers';
|
||||
import { Position as EditorPosition } from 'vs/platform/editor/common/editor';
|
||||
import { IMessage, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { StatusbarAlignment as MainThreadStatusBarAlignment } from 'vs/platform/statusbar/common/statusbar';
|
||||
import { ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
|
||||
import { IWorkspace } from 'vs/platform/workspace/common/workspace';
|
||||
|
||||
import * as editorCommon from 'vs/editor/common/editorCommon';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
@@ -36,6 +37,29 @@ import { IApplyEditsOptions, TextEditorRevealType, ITextEditorConfigurationUpdat
|
||||
|
||||
import { InternalTreeExplorerNode } from 'vs/workbench/parts/explorers/common/treeExplorerViewModel';
|
||||
|
||||
export interface IEnvironment {
|
||||
appSettingsHome: string;
|
||||
disableExtensions: boolean;
|
||||
userExtensionsHome: string;
|
||||
extensionDevelopmentPath: string;
|
||||
extensionTestsPath: string;
|
||||
}
|
||||
|
||||
export interface IInitConfiguration {
|
||||
_initConfigurationBrand: void;
|
||||
}
|
||||
|
||||
export interface IInitData {
|
||||
parentPid: number;
|
||||
environment: IEnvironment;
|
||||
contextService: {
|
||||
workspace: IWorkspace;
|
||||
};
|
||||
extensions: IExtensionDescription[];
|
||||
configuration: IInitConfiguration;
|
||||
telemetryInfo: ITelemetryInfo;
|
||||
}
|
||||
|
||||
export interface InstanceSetter<T> {
|
||||
set<R extends T>(instance: T): R;
|
||||
}
|
||||
@@ -202,7 +226,6 @@ export abstract class MainThreadWorkspaceShape {
|
||||
}
|
||||
|
||||
export abstract class MainProcessExtensionServiceShape {
|
||||
$onExtensionHostReady(extensionDescriptions: IExtensionDescription[], messages: IMessage[]): TPromise<void> { throw ni(); }
|
||||
$localShowMessage(severity: Severity, msg: string): void { throw ni(); }
|
||||
$onExtensionActivated(extensionId: string): void { throw ni(); }
|
||||
$onExtensionActivationFailed(extensionId: string): void { throw ni(); }
|
||||
@@ -242,7 +265,7 @@ export abstract class ExtHostDocumentsShape {
|
||||
}
|
||||
|
||||
export abstract class ExtHostDocumentSaveParticipantShape {
|
||||
$participateInSave(resource: URI, reason: SaveReason): TPromise<any[]> { throw ni(); }
|
||||
$participateInSave(resource: URI, reason: SaveReason): TPromise<boolean[]> { throw ni(); }
|
||||
}
|
||||
|
||||
export interface ITextEditorAddData {
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
'use strict';
|
||||
|
||||
import { mixin } from 'vs/base/common/objects';
|
||||
import { illegalState } from 'vs/base/common/errors';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { WorkspaceConfiguration } from 'vscode';
|
||||
import { ExtHostConfigurationShape, MainThreadConfigurationShape } from './extHost.protocol';
|
||||
@@ -14,13 +13,13 @@ import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/
|
||||
export class ExtHostConfiguration extends ExtHostConfigurationShape {
|
||||
|
||||
private _proxy: MainThreadConfigurationShape;
|
||||
private _hasConfig: boolean;
|
||||
private _config: any;
|
||||
private _onDidChangeConfiguration = new Emitter<void>();
|
||||
|
||||
constructor(proxy: MainThreadConfigurationShape) {
|
||||
constructor(proxy: MainThreadConfigurationShape, configuration: any) {
|
||||
super();
|
||||
this._proxy = proxy;
|
||||
this._config = configuration;
|
||||
}
|
||||
|
||||
get onDidChangeConfiguration(): Event<void> {
|
||||
@@ -29,14 +28,10 @@ export class ExtHostConfiguration extends ExtHostConfigurationShape {
|
||||
|
||||
public $acceptConfigurationChanged(config: any) {
|
||||
this._config = config;
|
||||
this._hasConfig = true;
|
||||
this._onDidChangeConfiguration.fire(undefined);
|
||||
}
|
||||
|
||||
public getConfiguration(section?: string): WorkspaceConfiguration {
|
||||
if (!this._hasConfig) {
|
||||
throw illegalState('missing config');
|
||||
}
|
||||
|
||||
const config = section
|
||||
? ExtHostConfiguration._lookUp(section, this._config)
|
||||
|
||||
@@ -10,8 +10,7 @@ import * as paths from 'vs/base/common/paths';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { AbstractExtensionService, ActivatedExtension } from 'vs/platform/extensions/common/abstractExtensionService';
|
||||
import { IMessage, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionsRegistry } from 'vs/platform/extensions/common/extensionsRegistry';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtHostStorage } from 'vs/workbench/api/node/extHostStorage';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
|
||||
@@ -119,8 +118,9 @@ export class ExtHostExtensionService extends AbstractExtensionService<ExtHostExt
|
||||
/**
|
||||
* This class is constructed manually because it is a service, so it doesn't use any ctor injection
|
||||
*/
|
||||
constructor(threadService: IThreadService, telemetryService: ITelemetryService, args: { _serviceBrand: any; workspaceStoragePath: string; }) {
|
||||
super(false);
|
||||
constructor(availableExtensions: IExtensionDescription[], threadService: IThreadService, telemetryService: ITelemetryService, args: { _serviceBrand: any; workspaceStoragePath: string; }) {
|
||||
super(true);
|
||||
this._registry.registerExtensions(availableExtensions);
|
||||
this._threadService = threadService;
|
||||
this._storage = new ExtHostStorage(threadService);
|
||||
this._proxy = this._threadService.get(MainContext.MainProcessExtensionService);
|
||||
@@ -128,6 +128,14 @@ export class ExtHostExtensionService extends AbstractExtensionService<ExtHostExt
|
||||
this._workspaceStoragePath = args.workspaceStoragePath;
|
||||
}
|
||||
|
||||
public getAllExtensionDescriptions(): IExtensionDescription[] {
|
||||
return this._registry.getAllExtensionDescriptions();
|
||||
}
|
||||
|
||||
public getExtensionDescription(extensionId: string): IExtensionDescription {
|
||||
return this._registry.getExtensionDescription(extensionId);
|
||||
}
|
||||
|
||||
public $localShowMessage(severity: Severity, msg: string): void {
|
||||
switch (severity) {
|
||||
case Severity.Error:
|
||||
@@ -178,14 +186,6 @@ export class ExtHostExtensionService extends AbstractExtensionService<ExtHostExt
|
||||
return result;
|
||||
}
|
||||
|
||||
public registrationDone(messages: IMessage[]): void {
|
||||
this._proxy.$onExtensionHostReady(ExtensionsRegistry.getAllExtensionDescriptions(), messages).then(() => {
|
||||
// Wait for the main process to acknowledge its receival of the extensions descriptions
|
||||
// before allowing extensions to be activated
|
||||
this._triggerOnReady();
|
||||
});
|
||||
}
|
||||
|
||||
// -- overwriting AbstractExtensionService
|
||||
|
||||
protected _showMessage(severity: Severity, msg: string): void {
|
||||
|
||||
@@ -113,22 +113,12 @@ class DefinitionAdapter {
|
||||
let pos = TypeConverters.toPosition(position);
|
||||
return asWinJsPromise(token => this._provider.provideDefinition(doc, pos, token)).then(value => {
|
||||
if (Array.isArray(value)) {
|
||||
return value.map(DefinitionAdapter._convertLocation);
|
||||
return value.map(TypeConverters.location.from);
|
||||
} else if (value) {
|
||||
return DefinitionAdapter._convertLocation(value);
|
||||
return TypeConverters.location.from(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static _convertLocation(location: vscode.Location): modes.Location {
|
||||
if (!location) {
|
||||
return;
|
||||
}
|
||||
return <modes.Location>{
|
||||
uri: location.uri,
|
||||
range: TypeConverters.fromRange(location.range)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class HoverAdapter {
|
||||
@@ -208,17 +198,10 @@ class ReferenceAdapter {
|
||||
|
||||
return asWinJsPromise(token => this._provider.provideReferences(doc, pos, context, token)).then(value => {
|
||||
if (Array.isArray(value)) {
|
||||
return value.map(ReferenceAdapter._convertLocation);
|
||||
return value.map(TypeConverters.location.from);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static _convertLocation(location: vscode.Location): modes.Location {
|
||||
return <modes.Location>{
|
||||
uri: location.uri,
|
||||
range: TypeConverters.fromRange(location.range)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class QuickFixAdapter {
|
||||
|
||||
@@ -68,7 +68,7 @@ export class ExtHostTerminal implements vscode.Terminal {
|
||||
}
|
||||
}
|
||||
|
||||
public setProcessId(processId: number): void {
|
||||
public _setProcessId(processId: number): void {
|
||||
this._pidPromiseComplete(processId);
|
||||
this._pidPromiseComplete = null;
|
||||
}
|
||||
@@ -123,7 +123,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
|
||||
public $acceptTerminalProcessId(id: number, processId: number): void {
|
||||
let terminal = this._getTerminalById(id);
|
||||
terminal.setProcessId(processId);
|
||||
terminal._setProcessId(processId);
|
||||
}
|
||||
|
||||
private _getTerminalById(id: number): ExtHostTerminal {
|
||||
|
||||
@@ -248,10 +248,10 @@ export function toSymbolInformation(bearing: IWorkspaceSymbol): types.SymbolInfo
|
||||
|
||||
|
||||
export const location = {
|
||||
from(value: types.Location): modes.Location {
|
||||
from(value: vscode.Location): modes.Location {
|
||||
return {
|
||||
range: fromRange(value.range),
|
||||
uri: value.uri
|
||||
range: value.range && fromRange(value.range),
|
||||
uri: <URI>value.uri
|
||||
};
|
||||
},
|
||||
to(value: modes.Location): types.Location {
|
||||
|
||||
@@ -25,7 +25,6 @@ export class MainThreadConfiguration extends MainThreadConfigurationShape {
|
||||
this._configurationEditingService = configurationEditingService;
|
||||
const proxy = threadService.get(ExtHostContext.ExtHostConfiguration);
|
||||
this._toDispose = configurationService.onDidUpdateConfiguration(event => proxy.$acceptConfigurationChanged(event.config));
|
||||
proxy.$acceptConfigurationChanged(configurationService.getConfiguration());
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { AbstractExtensionService, ActivatedExtension } from 'vs/platform/extensions/common/abstractExtensionService';
|
||||
import { IMessage, IExtensionDescription, IExtensionsStatus } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionsRegistry } from 'vs/platform/extensions/common/extensionsRegistry';
|
||||
import { IExtensionsRuntimeService, IMessage, IExtensionDescription, IExtensionsStatus } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtensionsRegistry, ExtensionPoint, IExtensionPointUser, ExtensionMessageCollector } from 'vs/platform/extensions/common/extensionsRegistry';
|
||||
import { IMessageService } from 'vs/platform/message/common/message';
|
||||
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
|
||||
import { ExtHostContext, ExtHostExtensionServiceShape } from './extHost.protocol';
|
||||
@@ -37,6 +37,8 @@ function messageWithSource(msg: IMessage): string {
|
||||
return (msg.source ? '[' + msg.source + ']: ' : '') + msg.message;
|
||||
}
|
||||
|
||||
const hasOwnProperty = Object.hasOwnProperty;
|
||||
|
||||
export class MainProcessExtensionService extends AbstractExtensionService<ActivatedExtension> {
|
||||
|
||||
private _threadService: IThreadService;
|
||||
@@ -51,7 +53,8 @@ export class MainProcessExtensionService extends AbstractExtensionService<Activa
|
||||
constructor(
|
||||
@IThreadService threadService: IThreadService,
|
||||
@IMessageService messageService: IMessageService,
|
||||
@IEnvironmentService private environmentService: IEnvironmentService
|
||||
@IEnvironmentService private environmentService: IEnvironmentService,
|
||||
@IExtensionsRuntimeService extensionsRuntimeService: IExtensionsRuntimeService
|
||||
) {
|
||||
super(false);
|
||||
this._isDev = !environmentService.isBuilt || !!environmentService.extensionDevelopmentPath;
|
||||
@@ -61,7 +64,7 @@ export class MainProcessExtensionService extends AbstractExtensionService<Activa
|
||||
this._proxy = this._threadService.get(ExtHostContext.ExtHostExtensionService);
|
||||
this._extensionsStatus = {};
|
||||
|
||||
ExtensionsRegistry.handleExtensionPoints((msg) => this._handleMessage(msg));
|
||||
extensionsRuntimeService.getExtensions().then((extensionDescriptions) => this._onExtensionDescriptions(extensionDescriptions));
|
||||
}
|
||||
|
||||
private _handleMessage(msg: IMessage) {
|
||||
@@ -124,11 +127,36 @@ export class MainProcessExtensionService extends AbstractExtensionService<Activa
|
||||
|
||||
// -- called by extension host
|
||||
|
||||
public $onExtensionHostReady(extensionDescriptions: IExtensionDescription[], messages: IMessage[]): TPromise<void> {
|
||||
ExtensionsRegistry.registerExtensions(extensionDescriptions);
|
||||
messages.forEach((entry) => this._handleMessage(entry));
|
||||
private _onExtensionDescriptions(extensionDescriptions: IExtensionDescription[]): void {
|
||||
this._registry.registerExtensions(extensionDescriptions);
|
||||
|
||||
let availableExtensions = this._registry.getAllExtensionDescriptions();
|
||||
let extensionPoints = ExtensionsRegistry.getExtensionPoints();
|
||||
|
||||
for (let i = 0, len = extensionPoints.length; i < len; i++) {
|
||||
this._handleExtensionPoint(extensionPoints[i], availableExtensions);
|
||||
}
|
||||
|
||||
this._triggerOnReady();
|
||||
return;
|
||||
}
|
||||
|
||||
private _handleExtensionPoint<T>(extensionPoint: ExtensionPoint<T>, availableExtensions: IExtensionDescription[]): void {
|
||||
let messageHandler = (msg: IMessage) => this._handleMessage(msg);
|
||||
|
||||
let users: IExtensionPointUser<T>[] = [], usersLen = 0;
|
||||
for (let i = 0, len = availableExtensions.length; i < len; i++) {
|
||||
let desc = availableExtensions[i];
|
||||
|
||||
if (desc.contributes && hasOwnProperty.call(desc.contributes, extensionPoint.name)) {
|
||||
users[usersLen++] = {
|
||||
description: desc,
|
||||
value: desc.contributes[extensionPoint.name],
|
||||
collector: new ExtensionMessageCollector(messageHandler, desc.extensionFolderPath)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
extensionPoint.acceptUsers(users);
|
||||
}
|
||||
|
||||
public $onExtensionActivated(extensionId: string): void {
|
||||
|
||||
@@ -11,6 +11,7 @@ import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService'
|
||||
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
|
||||
import { ISaveParticipant, ITextFileEditorModel, SaveReason } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IPosition, IModel, ICommonCodeEditor, ISingleEditOperation, IIdentifiedSingleEditOperation } from 'vs/editor/common/editorCommon';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
@@ -21,7 +22,13 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
|
||||
import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel';
|
||||
import { ExtHostContext, ExtHostDocumentSaveParticipantShape } from './extHost.protocol';
|
||||
|
||||
class TrimWhitespaceParticipant implements ISaveParticipant {
|
||||
interface INamedSaveParticpant extends ISaveParticipant {
|
||||
readonly name: string;
|
||||
}
|
||||
|
||||
class TrimWhitespaceParticipant implements INamedSaveParticpant {
|
||||
|
||||
readonly name = 'TrimWhitespaceParticipant';
|
||||
|
||||
constructor(
|
||||
@IConfigurationService private configurationService: IConfigurationService,
|
||||
@@ -75,7 +82,9 @@ class TrimWhitespaceParticipant implements ISaveParticipant {
|
||||
}
|
||||
}
|
||||
|
||||
class FormatOnSaveParticipant implements ISaveParticipant {
|
||||
class FormatOnSaveParticipant implements INamedSaveParticpant {
|
||||
|
||||
readonly name = 'FormatOnSaveParticipant';
|
||||
|
||||
constructor(
|
||||
@ICodeEditorService private _editorService: ICodeEditorService,
|
||||
@@ -97,7 +106,7 @@ class FormatOnSaveParticipant implements ISaveParticipant {
|
||||
const {tabSize, insertSpaces} = model.getOptions();
|
||||
|
||||
return new TPromise<ISingleEditOperation[]>((resolve, reject) => {
|
||||
setTimeout(resolve, 750);
|
||||
setTimeout(reject, 750);
|
||||
getDocumentFormattingEdits(model, { tabSize, insertSpaces }).then(resolve, reject);
|
||||
|
||||
}).then(edits => {
|
||||
@@ -158,25 +167,37 @@ class FormatOnSaveParticipant implements ISaveParticipant {
|
||||
}
|
||||
}
|
||||
|
||||
class ExtHostSaveParticipant implements ISaveParticipant {
|
||||
class ExtHostSaveParticipant implements INamedSaveParticpant {
|
||||
|
||||
private _proxy: ExtHostDocumentSaveParticipantShape;
|
||||
|
||||
readonly name = 'ExtHostSaveParticipant';
|
||||
|
||||
constructor( @IThreadService threadService: IThreadService) {
|
||||
this._proxy = threadService.get(ExtHostContext.ExtHostDocumentSaveParticipant);
|
||||
}
|
||||
|
||||
participate(editorModel: ITextFileEditorModel, env: { reason: SaveReason }): TPromise<any> {
|
||||
return this._proxy.$participateInSave(editorModel.getResource(), env.reason);
|
||||
return new TPromise<any>((resolve, reject) => {
|
||||
setTimeout(reject, 1750);
|
||||
this._proxy.$participateInSave(editorModel.getResource(), env.reason).then(values => {
|
||||
for (const success of values) {
|
||||
if (!success) {
|
||||
return TPromise.wrapError('listener failed');
|
||||
}
|
||||
}
|
||||
}).then(resolve, reject);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// The save participant can change a model before its saved to support various scenarios like trimming trailing whitespace
|
||||
export class SaveParticipant implements ISaveParticipant {
|
||||
|
||||
private _saveParticipants: ISaveParticipant[];
|
||||
private _saveParticipants: INamedSaveParticpant[];
|
||||
|
||||
constructor(
|
||||
@ITelemetryService private _telemetryService: ITelemetryService,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IThreadService threadService: IThreadService
|
||||
) {
|
||||
@@ -191,11 +212,24 @@ export class SaveParticipant implements ISaveParticipant {
|
||||
TextFileEditorModel.setSaveParticipant(this);
|
||||
}
|
||||
participate(model: ITextFileEditorModel, env: { reason: SaveReason }): TPromise<any> {
|
||||
|
||||
const stats: { [name: string]: number } = Object.create(null);
|
||||
|
||||
const promiseFactory = this._saveParticipants.map(p => () => {
|
||||
return TPromise.as(p.participate(model, env)).then(undefined, err => {
|
||||
|
||||
const {name} = p;
|
||||
const t1 = Date.now();
|
||||
|
||||
return TPromise.as(p.participate(model, env)).then(() => {
|
||||
stats[`Success-${name}`] = Date.now() - t1;
|
||||
}, err => {
|
||||
stats[`Failure-${name}`] = Date.now() - t1;
|
||||
// console.error(err);
|
||||
});
|
||||
});
|
||||
return sequence(promiseFactory);
|
||||
|
||||
return sequence(promiseFactory).then(() => {
|
||||
this._telemetryService.publicLog('saveParticipantStats', stats);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user