mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-30 17:23:29 -05:00
Merge from vscode 52dcb723a39ae75bee1bd56b3312d7fcdc87aeed (#6719)
This commit is contained in:
@@ -1,956 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import * as path from 'vs/base/common/path';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { TextEditorCursorStyle } from 'vs/editor/common/config/editorOptions';
|
||||
import { OverviewRulerLane } from 'vs/editor/common/model';
|
||||
import * as languageConfiguration from 'vs/editor/common/modes/languageConfiguration';
|
||||
import { score } from 'vs/editor/common/modes/languageSelector';
|
||||
import * as files from 'vs/platform/files/common/files';
|
||||
import { ExtHostContext, IInitData, IMainContext, MainContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostApiCommands } from 'vs/workbench/api/common/extHostApiCommands';
|
||||
import { ExtHostClipboard } from 'vs/workbench/api/common/extHostClipboard';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { ExtHostComments } from 'vs/workbench/api/common/extHostComments';
|
||||
import { ExtHostConfiguration, ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
|
||||
// {{SQL CARBON EDIT}} - Remove ExtHostDebugService
|
||||
// import { ExtHostDebugService } from 'vs/workbench/api/node/extHostDebugService';
|
||||
// {{SQL CARBON EDIT}} - Import product
|
||||
import product from 'vs/platform/product/node/product';
|
||||
import { ExtHostDecorations } from 'vs/workbench/api/common/extHostDecorations';
|
||||
import { ExtHostDiagnostics } from 'vs/workbench/api/common/extHostDiagnostics';
|
||||
import { ExtHostDialogs } from 'vs/workbench/api/common/extHostDialogs';
|
||||
import { ExtHostDocumentContentProvider } from 'vs/workbench/api/common/extHostDocumentContentProviders';
|
||||
import { ExtHostDocumentSaveParticipant } from 'vs/workbench/api/common/extHostDocumentSaveParticipant';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { ExtensionActivatedByAPI } from 'vs/workbench/api/common/extHostExtensionActivator';
|
||||
import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService';
|
||||
import { ExtHostFileSystem } from 'vs/workbench/api/common/extHostFileSystem';
|
||||
import { ExtHostFileSystemEventService } from 'vs/workbench/api/common/extHostFileSystemEventService';
|
||||
import { ExtHostLanguageFeatures } from 'vs/workbench/api/common/extHostLanguageFeatures';
|
||||
import { ExtHostLanguages } from 'vs/workbench/api/common/extHostLanguages';
|
||||
import { ExtHostLogService } from 'vs/workbench/api/common/extHostLogService';
|
||||
import { ExtHostMessageService } from 'vs/workbench/api/common/extHostMessageService';
|
||||
import { ExtHostOutputService } from 'vs/workbench/api/common/extHostOutput';
|
||||
import { LogOutputChannelFactory } from 'vs/workbench/api/node/extHostOutputService';
|
||||
import { ExtHostProgress } from 'vs/workbench/api/common/extHostProgress';
|
||||
import { ExtHostQuickOpen } from 'vs/workbench/api/common/extHostQuickOpen';
|
||||
import { ExtHostSCM } from 'vs/workbench/api/common/extHostSCM';
|
||||
import { ExtHostSearch, registerEHSearchProviders } from 'vs/workbench/api/node/extHostSearch';
|
||||
import { ExtHostStatusBar } from 'vs/workbench/api/common/extHostStatusBar';
|
||||
import { ExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
|
||||
import { ExtHostTask } from 'vs/workbench/api/node/extHostTask';
|
||||
import { ExtHostTerminalService } from 'vs/workbench/api/node/extHostTerminalService';
|
||||
import { ExtHostEditors } from 'vs/workbench/api/common/extHostTextEditors';
|
||||
import { ExtHostTreeViews } from 'vs/workbench/api/common/extHostTreeViews';
|
||||
import { ExtHostDownloadService } from 'vs/workbench/api/node/extHostDownloadService';
|
||||
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
|
||||
import { ExtHostUrls } from 'vs/workbench/api/common/extHostUrls';
|
||||
import { ExtHostWebviews } from 'vs/workbench/api/common/extHostWebview';
|
||||
import { ExtHostWindow } from 'vs/workbench/api/common/extHostWindow';
|
||||
import { ExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import { throwProposedApiError, checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ProxyIdentifier } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
||||
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
|
||||
import * as vscode from 'vscode';
|
||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { originalFSPath } from 'vs/base/common/resources';
|
||||
import { CLIServer } from 'vs/workbench/api/node/extHostCLIServer';
|
||||
import { values } from 'vs/base/common/collections';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { IURITransformer } from 'vs/base/common/uriIpc';
|
||||
import { ExtHostEditorInsets } from 'vs/workbench/api/common/extHostCodeInsets';
|
||||
import { ExtHostLabelService } from 'vs/workbench/api/common/extHostLabelService';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
|
||||
import { getSingletonServiceDescriptors } from 'vs/platform/instantiation/common/extensions';
|
||||
import { getRemoteName } from 'vs/platform/remote/common/remoteHosts';
|
||||
|
||||
export interface IExtensionApiFactory {
|
||||
(extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode;
|
||||
}
|
||||
|
||||
function proposedApiFunction<T>(extension: IExtensionDescription, fn: T): T {
|
||||
if (extension.enableProposedApi) {
|
||||
return fn;
|
||||
} else {
|
||||
return throwProposedApiError.bind(null, extension) as any as T;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method instantiates and returns the extension API surface
|
||||
*/
|
||||
export function createApiFactory(
|
||||
initData: IInitData,
|
||||
rpcProtocol: IMainContext,
|
||||
extHostWorkspace: ExtHostWorkspace,
|
||||
extHostConfiguration: ExtHostConfiguration,
|
||||
extensionService: ExtHostExtensionService,
|
||||
extHostLogService: ExtHostLogService,
|
||||
extHostStorage: ExtHostStorage,
|
||||
uriTransformer: IURITransformer | null
|
||||
): IExtensionApiFactory {
|
||||
|
||||
// bootstrap services
|
||||
const services = new ServiceCollection(...getSingletonServiceDescriptors());
|
||||
const instaService = new InstantiationService(services);
|
||||
|
||||
// Addressable instances
|
||||
rpcProtocol.set(ExtHostContext.ExtHostLogService, extHostLogService);
|
||||
const extHostDecorations = rpcProtocol.set(ExtHostContext.ExtHostDecorations, new ExtHostDecorations(rpcProtocol));
|
||||
const extHostWebviews = rpcProtocol.set(ExtHostContext.ExtHostWebviews, new ExtHostWebviews(rpcProtocol, initData.environment));
|
||||
const extHostUrls = rpcProtocol.set(ExtHostContext.ExtHostUrls, new ExtHostUrls(rpcProtocol));
|
||||
const extHostDocumentsAndEditors = rpcProtocol.set(ExtHostContext.ExtHostDocumentsAndEditors, new ExtHostDocumentsAndEditors(rpcProtocol));
|
||||
const extHostDocuments = rpcProtocol.set(ExtHostContext.ExtHostDocuments, new ExtHostDocuments(rpcProtocol, extHostDocumentsAndEditors));
|
||||
const extHostDocumentContentProviders = rpcProtocol.set(ExtHostContext.ExtHostDocumentContentProviders, new ExtHostDocumentContentProvider(rpcProtocol, extHostDocumentsAndEditors, extHostLogService));
|
||||
const extHostDocumentSaveParticipant = rpcProtocol.set(ExtHostContext.ExtHostDocumentSaveParticipant, new ExtHostDocumentSaveParticipant(extHostLogService, extHostDocuments, rpcProtocol.getProxy(MainContext.MainThreadTextEditors)));
|
||||
const extHostEditors = rpcProtocol.set(ExtHostContext.ExtHostEditors, new ExtHostEditors(rpcProtocol, extHostDocumentsAndEditors));
|
||||
const extHostCommands = rpcProtocol.set(ExtHostContext.ExtHostCommands, new ExtHostCommands(rpcProtocol, extHostLogService));
|
||||
const extHostTreeViews = rpcProtocol.set(ExtHostContext.ExtHostTreeViews, new ExtHostTreeViews(rpcProtocol.getProxy(MainContext.MainThreadTreeViews), extHostCommands, extHostLogService));
|
||||
rpcProtocol.set(ExtHostContext.ExtHostDownloadService, new ExtHostDownloadService(rpcProtocol.getProxy(MainContext.MainThreadDownloadService), extHostCommands));
|
||||
rpcProtocol.set(ExtHostContext.ExtHostWorkspace, extHostWorkspace);
|
||||
rpcProtocol.set(ExtHostContext.ExtHostConfiguration, extHostConfiguration);
|
||||
const extHostEditorInsets = rpcProtocol.set(ExtHostContext.ExtHostEditorInsets, new ExtHostEditorInsets(rpcProtocol.getProxy(MainContext.MainThreadEditorInsets), extHostEditors, initData.environment));
|
||||
const extHostDiagnostics = rpcProtocol.set(ExtHostContext.ExtHostDiagnostics, new ExtHostDiagnostics(rpcProtocol));
|
||||
const extHostLanguageFeatures = rpcProtocol.set(ExtHostContext.ExtHostLanguageFeatures, new ExtHostLanguageFeatures(rpcProtocol, uriTransformer, extHostDocuments, extHostCommands, extHostDiagnostics, extHostLogService));
|
||||
const extHostFileSystem = rpcProtocol.set(ExtHostContext.ExtHostFileSystem, new ExtHostFileSystem(rpcProtocol, extHostLanguageFeatures));
|
||||
const extHostFileSystemEvent = rpcProtocol.set(ExtHostContext.ExtHostFileSystemEventService, new ExtHostFileSystemEventService(rpcProtocol, extHostDocumentsAndEditors));
|
||||
const extHostQuickOpen = rpcProtocol.set(ExtHostContext.ExtHostQuickOpen, new ExtHostQuickOpen(rpcProtocol, extHostWorkspace, extHostCommands));
|
||||
const extHostTerminalService = rpcProtocol.set(ExtHostContext.ExtHostTerminalService, new ExtHostTerminalService(rpcProtocol, extHostConfiguration, extHostWorkspace, extHostDocumentsAndEditors, extHostLogService));
|
||||
// const extHostDebugService = rpcProtocol.set(ExtHostContext.ExtHostDebugService, instaService.createInstance(ExtHostDebugService, rpcProtocol, extHostWorkspace, extensionService, extHostDocumentsAndEditors, extHostConfiguration, extHostTerminalService, extHostCommands)); {{SQL CARBON EDIT}} remove debug service
|
||||
const extHostSCM = rpcProtocol.set(ExtHostContext.ExtHostSCM, new ExtHostSCM(rpcProtocol, extHostCommands, extHostLogService));
|
||||
const extHostComment = rpcProtocol.set(ExtHostContext.ExtHostComments, new ExtHostComments(rpcProtocol, extHostCommands, extHostDocuments));
|
||||
const extHostSearch = rpcProtocol.set(ExtHostContext.ExtHostSearch, new ExtHostSearch(rpcProtocol, uriTransformer, extHostLogService));
|
||||
const extHostTask = rpcProtocol.set(ExtHostContext.ExtHostTask, new ExtHostTask(rpcProtocol, extHostWorkspace, extHostDocumentsAndEditors, extHostConfiguration, extHostTerminalService));
|
||||
const extHostWindow = rpcProtocol.set(ExtHostContext.ExtHostWindow, new ExtHostWindow(rpcProtocol));
|
||||
rpcProtocol.set(ExtHostContext.ExtHostExtensionService, extensionService);
|
||||
const extHostProgress = rpcProtocol.set(ExtHostContext.ExtHostProgress, new ExtHostProgress(rpcProtocol.getProxy(MainContext.MainThreadProgress)));
|
||||
const extHostOutputService = rpcProtocol.set(ExtHostContext.ExtHostOutputService, new ExtHostOutputService(LogOutputChannelFactory, initData.logsLocation, rpcProtocol));
|
||||
rpcProtocol.set(ExtHostContext.ExtHostStorage, extHostStorage);
|
||||
const extHostLabelService = rpcProtocol.set(ExtHostContext.ExtHosLabelService, new ExtHostLabelService(rpcProtocol));
|
||||
|
||||
if (initData.remote.isRemote && initData.remote.authority) {
|
||||
extHostTask.registerTaskSystem(Schemas.vscodeRemote, {
|
||||
scheme: Schemas.vscodeRemote,
|
||||
authority: initData.remote.authority,
|
||||
platform: process.platform
|
||||
});
|
||||
|
||||
registerEHSearchProviders(extHostSearch, extHostLogService);
|
||||
|
||||
const cliServer = new CLIServer(extHostCommands);
|
||||
process.env['VSCODE_IPC_HOOK_CLI'] = cliServer.ipcHandlePath;
|
||||
}
|
||||
|
||||
// Check that no named customers are missing
|
||||
// {{SQL CARBON EDIT}} filter out the services we don't expose
|
||||
const filtered: ProxyIdentifier<any>[] = [ExtHostContext.ExtHostDebugService, ExtHostContext.ExtHostTask];
|
||||
const expected: ProxyIdentifier<any>[] = values(ExtHostContext).filter(v => !filtered.includes(v));
|
||||
rpcProtocol.assertRegistered(expected);
|
||||
|
||||
// Other instances
|
||||
const extHostClipboard = new ExtHostClipboard(rpcProtocol);
|
||||
const extHostMessageService = new ExtHostMessageService(rpcProtocol);
|
||||
const extHostDialogs = new ExtHostDialogs(rpcProtocol);
|
||||
const extHostStatusBar = new ExtHostStatusBar(rpcProtocol);
|
||||
const extHostLanguages = new ExtHostLanguages(rpcProtocol, extHostDocuments);
|
||||
|
||||
// Register an output channel for exthost log
|
||||
const outputChannelName = initData.remote.isRemote ? nls.localize('remote extension host Log', "Remote Extension Host") : nls.localize('extension host Log', "Extension Host");
|
||||
extHostOutputService.createOutputChannelFromLogFile(outputChannelName, extHostLogService.logFile);
|
||||
|
||||
// Register API-ish commands
|
||||
ExtHostApiCommands.register(extHostCommands);
|
||||
|
||||
return function (extension: IExtensionDescription, extensionRegistry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode {
|
||||
|
||||
// Check document selectors for being overly generic. Technically this isn't a problem but
|
||||
// in practice many extensions say they support `fooLang` but need fs-access to do so. Those
|
||||
// extension should specify then the `file`-scheme, e.g. `{ scheme: 'fooLang', language: 'fooLang' }`
|
||||
// We only inform once, it is not a warning because we just want to raise awareness and because
|
||||
// we cannot say if the extension is doing it right or wrong...
|
||||
const checkSelector = (function () {
|
||||
let done = (!extension.isUnderDevelopment);
|
||||
function informOnce(selector: vscode.DocumentSelector) {
|
||||
if (!done) {
|
||||
console.info(`Extension '${extension.identifier.value}' uses a document selector without scheme. Learn more about this: https://go.microsoft.com/fwlink/?linkid=872305`);
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
return function perform(selector: vscode.DocumentSelector): vscode.DocumentSelector {
|
||||
if (Array.isArray(selector)) {
|
||||
selector.forEach(perform);
|
||||
} else if (typeof selector === 'string') {
|
||||
informOnce(selector);
|
||||
} else {
|
||||
if (typeof selector.scheme === 'undefined') {
|
||||
informOnce(selector);
|
||||
}
|
||||
if (!extension.enableProposedApi && typeof selector.exclusive === 'boolean') {
|
||||
throwProposedApiError(extension);
|
||||
}
|
||||
}
|
||||
return selector;
|
||||
};
|
||||
})();
|
||||
|
||||
|
||||
// namespace: commands
|
||||
const commands: typeof vscode.commands = {
|
||||
registerCommand(id: string, command: <T>(...args: any[]) => T | Thenable<T>, thisArgs?: any): vscode.Disposable {
|
||||
return extHostCommands.registerCommand(true, id, command, thisArgs);
|
||||
},
|
||||
registerTextEditorCommand(id: string, callback: (textEditor: vscode.TextEditor, edit: vscode.TextEditorEdit, ...args: any[]) => void, thisArg?: any): vscode.Disposable {
|
||||
return extHostCommands.registerCommand(true, id, (...args: any[]): any => {
|
||||
const activeTextEditor = extHostEditors.getActiveTextEditor();
|
||||
if (!activeTextEditor) {
|
||||
console.warn('Cannot execute ' + id + ' because there is no active text editor.');
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return activeTextEditor.edit((edit: vscode.TextEditorEdit) => {
|
||||
args.unshift(activeTextEditor, edit);
|
||||
callback.apply(thisArg, args);
|
||||
|
||||
}).then((result) => {
|
||||
if (!result) {
|
||||
console.warn('Edits from command ' + id + ' were not applied.');
|
||||
}
|
||||
}, (err) => {
|
||||
console.warn('An error occurred while running command ' + id, err);
|
||||
});
|
||||
});
|
||||
},
|
||||
registerDiffInformationCommand: proposedApiFunction(extension, (id: string, callback: (diff: vscode.LineChange[], ...args: any[]) => any, thisArg?: any): vscode.Disposable => {
|
||||
return extHostCommands.registerCommand(true, id, async (...args: any[]): Promise<any> => {
|
||||
const activeTextEditor = extHostEditors.getActiveTextEditor();
|
||||
if (!activeTextEditor) {
|
||||
console.warn('Cannot execute ' + id + ' because there is no active text editor.');
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const diff = await extHostEditors.getDiffInformation(activeTextEditor.id);
|
||||
callback.apply(thisArg, [diff, ...args]);
|
||||
});
|
||||
}),
|
||||
executeCommand<T>(id: string, ...args: any[]): Thenable<T> {
|
||||
return extHostCommands.executeCommand<T>(id, ...args);
|
||||
},
|
||||
getCommands(filterInternal: boolean = false): Thenable<string[]> {
|
||||
return extHostCommands.getCommands(filterInternal);
|
||||
},
|
||||
onDidExecuteCommand: proposedApiFunction(extension, (listener, thisArgs?, disposables?) => {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostCommands.onDidExecuteCommand(listener, thisArgs, disposables);
|
||||
}),
|
||||
};
|
||||
|
||||
// namespace: env
|
||||
const env: typeof vscode.env = {
|
||||
get machineId() { return initData.telemetryInfo.machineId; },
|
||||
get sessionId() { return initData.telemetryInfo.sessionId; },
|
||||
get language() { return initData.environment.appLanguage; },
|
||||
get appName() { return initData.environment.appName; },
|
||||
get appRoot() { return initData.environment.appRoot!.fsPath; },
|
||||
get uriScheme() { return initData.environment.appUriScheme; },
|
||||
get logLevel() {
|
||||
checkProposedApiEnabled(extension);
|
||||
return typeConverters.LogLevel.to(extHostLogService.getLevel());
|
||||
},
|
||||
get onDidChangeLogLevel() {
|
||||
checkProposedApiEnabled(extension);
|
||||
return Event.map(extHostLogService.onDidChangeLogLevel, l => typeConverters.LogLevel.to(l));
|
||||
},
|
||||
get clipboard(): vscode.Clipboard {
|
||||
return extHostClipboard;
|
||||
},
|
||||
get shell() {
|
||||
return extHostTerminalService.getDefaultShell(configProvider);
|
||||
},
|
||||
openExternal(uri: URI) {
|
||||
return extHostWindow.openUri(uri, { allowTunneling: !!initData.remote.isRemote });
|
||||
},
|
||||
get remoteName() {
|
||||
return getRemoteName(initData.remote.authority);
|
||||
}
|
||||
};
|
||||
if (!initData.environment.extensionTestsLocationURI) {
|
||||
// allow to patch env-function when running tests
|
||||
Object.freeze(env);
|
||||
}
|
||||
|
||||
const extensionKind = initData.remote.isRemote
|
||||
? extHostTypes.ExtensionKind.Workspace
|
||||
: extHostTypes.ExtensionKind.UI;
|
||||
|
||||
// namespace: extensions
|
||||
const extensions: typeof vscode.extensions = {
|
||||
getExtension(extensionId: string): Extension<any> | undefined {
|
||||
const desc = extensionRegistry.getExtensionDescription(extensionId);
|
||||
if (desc) {
|
||||
return new Extension(extensionService, desc, extensionKind);
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
get all(): Extension<any>[] {
|
||||
return extensionRegistry.getAllExtensionDescriptions().map((desc) => new Extension(extensionService, desc, extensionKind));
|
||||
},
|
||||
get onDidChange() {
|
||||
return extensionRegistry.onDidChange;
|
||||
}
|
||||
};
|
||||
|
||||
// namespace: languages
|
||||
const languages: typeof vscode.languages = {
|
||||
createDiagnosticCollection(name?: string): vscode.DiagnosticCollection {
|
||||
return extHostDiagnostics.createDiagnosticCollection(name);
|
||||
},
|
||||
get onDidChangeDiagnostics() {
|
||||
return extHostDiagnostics.onDidChangeDiagnostics;
|
||||
},
|
||||
getDiagnostics: (resource?: vscode.Uri) => {
|
||||
return <any>extHostDiagnostics.getDiagnostics(resource);
|
||||
},
|
||||
getLanguages(): Thenable<string[]> {
|
||||
return extHostLanguages.getLanguages();
|
||||
},
|
||||
setTextDocumentLanguage(document: vscode.TextDocument, languageId: string): Thenable<vscode.TextDocument> {
|
||||
return extHostLanguages.changeLanguage(document.uri, languageId);
|
||||
},
|
||||
match(selector: vscode.DocumentSelector, document: vscode.TextDocument): number {
|
||||
return score(typeConverters.LanguageSelector.from(selector), document.uri, document.languageId, true);
|
||||
},
|
||||
registerCodeActionsProvider(selector: vscode.DocumentSelector, provider: vscode.CodeActionProvider, metadata?: vscode.CodeActionProviderMetadata): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerCodeActionProvider(extension, checkSelector(selector), provider, metadata);
|
||||
},
|
||||
registerCodeLensProvider(selector: vscode.DocumentSelector, provider: vscode.CodeLensProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerCodeLensProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
registerDefinitionProvider(selector: vscode.DocumentSelector, provider: vscode.DefinitionProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerDefinitionProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
registerDeclarationProvider(selector: vscode.DocumentSelector, provider: vscode.DeclarationProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerDeclarationProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
registerImplementationProvider(selector: vscode.DocumentSelector, provider: vscode.ImplementationProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerImplementationProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
registerTypeDefinitionProvider(selector: vscode.DocumentSelector, provider: vscode.TypeDefinitionProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerTypeDefinitionProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
registerHoverProvider(selector: vscode.DocumentSelector, provider: vscode.HoverProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerHoverProvider(extension, checkSelector(selector), provider, extension.identifier);
|
||||
},
|
||||
registerDocumentHighlightProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentHighlightProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerDocumentHighlightProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
registerReferenceProvider(selector: vscode.DocumentSelector, provider: vscode.ReferenceProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerReferenceProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
registerRenameProvider(selector: vscode.DocumentSelector, provider: vscode.RenameProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerRenameProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
registerDocumentSymbolProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentSymbolProvider, metadata?: vscode.DocumentSymbolProviderMetadata): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerDocumentSymbolProvider(extension, checkSelector(selector), provider, metadata);
|
||||
},
|
||||
registerWorkspaceSymbolProvider(provider: vscode.WorkspaceSymbolProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerWorkspaceSymbolProvider(extension, provider);
|
||||
},
|
||||
registerDocumentFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentFormattingEditProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerDocumentFormattingEditProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
registerDocumentRangeFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentRangeFormattingEditProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerDocumentRangeFormattingEditProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
registerOnTypeFormattingEditProvider(selector: vscode.DocumentSelector, provider: vscode.OnTypeFormattingEditProvider, firstTriggerCharacter: string, ...moreTriggerCharacters: string[]): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerOnTypeFormattingEditProvider(extension, checkSelector(selector), provider, [firstTriggerCharacter].concat(moreTriggerCharacters));
|
||||
},
|
||||
registerSignatureHelpProvider(selector: vscode.DocumentSelector, provider: vscode.SignatureHelpProvider, firstItem?: string | vscode.SignatureHelpProviderMetadata, ...remaining: string[]): vscode.Disposable {
|
||||
if (typeof firstItem === 'object') {
|
||||
return extHostLanguageFeatures.registerSignatureHelpProvider(extension, checkSelector(selector), provider, firstItem);
|
||||
}
|
||||
return extHostLanguageFeatures.registerSignatureHelpProvider(extension, checkSelector(selector), provider, typeof firstItem === 'undefined' ? [] : [firstItem, ...remaining]);
|
||||
},
|
||||
registerCompletionItemProvider(selector: vscode.DocumentSelector, provider: vscode.CompletionItemProvider, ...triggerCharacters: string[]): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerCompletionItemProvider(extension, checkSelector(selector), provider, triggerCharacters);
|
||||
},
|
||||
registerDocumentLinkProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentLinkProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerDocumentLinkProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
registerColorProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentColorProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerColorProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
registerFoldingRangeProvider(selector: vscode.DocumentSelector, provider: vscode.FoldingRangeProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerFoldingRangeProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
registerSelectionRangeProvider(selector: vscode.DocumentSelector, provider: vscode.SelectionRangeProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerSelectionRangeProvider(extension, selector, provider);
|
||||
},
|
||||
registerCallHierarchyProvider(selector: vscode.DocumentSelector, provider: vscode.CallHierarchyItemProvider): vscode.Disposable {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostLanguageFeatures.registerCallHierarchyProvider(extension, selector, provider);
|
||||
},
|
||||
setLanguageConfiguration: (language: string, configuration: vscode.LanguageConfiguration): vscode.Disposable => {
|
||||
return extHostLanguageFeatures.setLanguageConfiguration(language, configuration);
|
||||
}
|
||||
};
|
||||
|
||||
// namespace: window
|
||||
const window: typeof vscode.window = {
|
||||
get activeTextEditor() {
|
||||
return extHostEditors.getActiveTextEditor();
|
||||
},
|
||||
get visibleTextEditors() {
|
||||
return extHostEditors.getVisibleTextEditors();
|
||||
},
|
||||
get activeTerminal() {
|
||||
return extHostTerminalService.activeTerminal;
|
||||
},
|
||||
get terminals() {
|
||||
return extHostTerminalService.terminals;
|
||||
},
|
||||
showTextDocument(documentOrUri: vscode.TextDocument | vscode.Uri, columnOrOptions?: vscode.ViewColumn | vscode.TextDocumentShowOptions, preserveFocus?: boolean): Thenable<vscode.TextEditor> {
|
||||
let documentPromise: Promise<vscode.TextDocument>;
|
||||
if (URI.isUri(documentOrUri)) {
|
||||
documentPromise = Promise.resolve(workspace.openTextDocument(documentOrUri));
|
||||
} else {
|
||||
documentPromise = Promise.resolve(<vscode.TextDocument>documentOrUri);
|
||||
}
|
||||
return documentPromise.then(document => {
|
||||
return extHostEditors.showTextDocument(document, columnOrOptions, preserveFocus);
|
||||
});
|
||||
},
|
||||
createTextEditorDecorationType(options: vscode.DecorationRenderOptions): vscode.TextEditorDecorationType {
|
||||
return extHostEditors.createTextEditorDecorationType(options);
|
||||
},
|
||||
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[]) {
|
||||
return extHostEditors.onDidChangeTextEditorSelection(listener, thisArgs, disposables);
|
||||
},
|
||||
onDidChangeTextEditorOptions(listener: (e: vscode.TextEditorOptionsChangeEvent) => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) {
|
||||
return extHostEditors.onDidChangeTextEditorOptions(listener, thisArgs, disposables);
|
||||
},
|
||||
onDidChangeTextEditorVisibleRanges(listener: (e: vscode.TextEditorVisibleRangesChangeEvent) => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) {
|
||||
return extHostEditors.onDidChangeTextEditorVisibleRanges(listener, thisArgs, disposables);
|
||||
},
|
||||
onDidChangeTextEditorViewColumn(listener, thisArg?, disposables?) {
|
||||
return extHostEditors.onDidChangeTextEditorViewColumn(listener, thisArg, disposables);
|
||||
},
|
||||
onDidCloseTerminal(listener, thisArg?, disposables?) {
|
||||
return extHostTerminalService.onDidCloseTerminal(listener, thisArg, disposables);
|
||||
},
|
||||
onDidOpenTerminal(listener, thisArg?, disposables?) {
|
||||
return extHostTerminalService.onDidOpenTerminal(listener, thisArg, disposables);
|
||||
},
|
||||
onDidChangeActiveTerminal(listener, thisArg?, disposables?) {
|
||||
return extHostTerminalService.onDidChangeActiveTerminal(listener, thisArg, disposables);
|
||||
},
|
||||
onDidChangeTerminalDimensions(listener, thisArg?, disposables?) {
|
||||
return extHostTerminalService.onDidChangeTerminalDimensions(listener, thisArg, disposables);
|
||||
},
|
||||
get state() {
|
||||
return extHostWindow.state;
|
||||
},
|
||||
onDidChangeWindowState(listener, thisArg?, disposables?) {
|
||||
return extHostWindow.onDidChangeWindowState(listener, thisArg, disposables);
|
||||
},
|
||||
// {{SQL CARBON EDIT}} Typing needs to be disabled; enabled strict null checks allows the typing once we get there
|
||||
showInformationMessage(message, first, ...rest) {
|
||||
return extHostMessageService.showMessage(extension, Severity.Info, message, first, rest);
|
||||
},
|
||||
// {{SQL CARBON EDIT}} Typing needs to be disabled; enabled strict null checks allows the typing once we get there
|
||||
showWarningMessage(message, first, ...rest) {
|
||||
return extHostMessageService.showMessage(extension, Severity.Warning, message, first, rest);
|
||||
},
|
||||
// {{SQL CARBON EDIT}} Typing needs to be disabled; enabled strict null checks allows the typing once we get there
|
||||
showErrorMessage(message, first, ...rest) {
|
||||
return extHostMessageService.showMessage(extension, Severity.Error, message, first, rest);
|
||||
},
|
||||
showQuickPick(items: any, options: vscode.QuickPickOptions, token?: vscode.CancellationToken): any {
|
||||
return extHostQuickOpen.showQuickPick(items, !!extension.enableProposedApi, options, token);
|
||||
},
|
||||
showWorkspaceFolderPick(options: vscode.WorkspaceFolderPickOptions) {
|
||||
return extHostQuickOpen.showWorkspaceFolderPick(options);
|
||||
},
|
||||
showInputBox(options?: vscode.InputBoxOptions, token?: vscode.CancellationToken) {
|
||||
return extHostQuickOpen.showInput(options, token);
|
||||
},
|
||||
showOpenDialog(options) {
|
||||
return extHostDialogs.showOpenDialog(options);
|
||||
},
|
||||
showSaveDialog(options) {
|
||||
return extHostDialogs.showSaveDialog(options);
|
||||
},
|
||||
createStatusBarItem(alignmentOrOptions?: vscode.StatusBarAlignment | vscode.window.StatusBarItemOptions, priority?: number): vscode.StatusBarItem {
|
||||
let id: string;
|
||||
let name: string;
|
||||
let alignment: number | undefined;
|
||||
|
||||
if (alignmentOrOptions && typeof alignmentOrOptions !== 'number') {
|
||||
id = alignmentOrOptions.id;
|
||||
name = alignmentOrOptions.name;
|
||||
alignment = alignmentOrOptions.alignment;
|
||||
priority = alignmentOrOptions.priority;
|
||||
} else {
|
||||
id = extension.identifier.value;
|
||||
name = nls.localize('extensionLabel', "{0} (Extension)", extension.displayName || extension.name);
|
||||
alignment = alignmentOrOptions as number; // {{SQL CARBON EDIT}} strict-null-check
|
||||
priority = priority;
|
||||
}
|
||||
|
||||
return extHostStatusBar.createStatusBarEntry(id, name, alignment, priority);
|
||||
},
|
||||
setStatusBarMessage(text: string, timeoutOrThenable?: number | Thenable<any>): vscode.Disposable {
|
||||
return extHostStatusBar.setStatusBarMessage(text, timeoutOrThenable);
|
||||
},
|
||||
withScmProgress<R>(task: (progress: vscode.Progress<number>) => Thenable<R>) {
|
||||
console.warn(`[Deprecation Warning] function 'withScmProgress' is deprecated and should no longer be used. Use 'withProgress' instead.`);
|
||||
return extHostProgress.withProgress(extension, { location: extHostTypes.ProgressLocation.SourceControl }, (progress, token) => task({ report(n: number) { /*noop*/ } }));
|
||||
},
|
||||
withProgress<R>(options: vscode.ProgressOptions, task: (progress: vscode.Progress<{ message?: string; worked?: number }>, token: vscode.CancellationToken) => Thenable<R>) {
|
||||
return extHostProgress.withProgress(extension, options, task);
|
||||
},
|
||||
createOutputChannel(name: string): vscode.OutputChannel {
|
||||
return extHostOutputService.createOutputChannel(name);
|
||||
},
|
||||
createWebviewPanel(viewType: string, title: string, showOptions: vscode.ViewColumn | { viewColumn: vscode.ViewColumn, preserveFocus?: boolean }, options: vscode.WebviewPanelOptions & vscode.WebviewOptions): vscode.WebviewPanel {
|
||||
return extHostWebviews.createWebviewPanel(extension, viewType, title, showOptions, options);
|
||||
},
|
||||
createWebviewTextEditorInset(editor: vscode.TextEditor, line: number, height: number, options: vscode.WebviewOptions): vscode.WebviewEditorInset {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostEditorInsets.createWebviewEditorInset(editor, line, height, options, extension);
|
||||
},
|
||||
createTerminal(nameOrOptions?: vscode.TerminalOptions | vscode.ExtensionTerminalOptions | string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal {
|
||||
if (typeof nameOrOptions === 'object') {
|
||||
if ('pty' in nameOrOptions) {
|
||||
return extHostTerminalService.createExtensionTerminal(nameOrOptions);
|
||||
} else {
|
||||
nameOrOptions.hideFromUser = nameOrOptions.hideFromUser || (nameOrOptions.runInBackground && extension.enableProposedApi);
|
||||
return extHostTerminalService.createTerminalFromOptions(nameOrOptions);
|
||||
}
|
||||
}
|
||||
return extHostTerminalService.createTerminal(<string>nameOrOptions, shellPath, shellArgs);
|
||||
},
|
||||
createTerminalRenderer(name: string): vscode.TerminalRenderer {
|
||||
return extHostTerminalService.createTerminalRenderer(name);
|
||||
},
|
||||
registerTreeDataProvider(viewId: string, treeDataProvider: vscode.TreeDataProvider<any>): vscode.Disposable {
|
||||
return extHostTreeViews.registerTreeDataProvider(viewId, treeDataProvider, extension);
|
||||
},
|
||||
createTreeView(viewId: string, options: { treeDataProvider: vscode.TreeDataProvider<any> }): vscode.TreeView<any> {
|
||||
return extHostTreeViews.createTreeView(viewId, options, extension);
|
||||
},
|
||||
registerWebviewPanelSerializer: (viewType: string, serializer: vscode.WebviewPanelSerializer) => {
|
||||
return extHostWebviews.registerWebviewPanelSerializer(viewType, serializer);
|
||||
},
|
||||
registerDecorationProvider: proposedApiFunction(extension, (provider: vscode.DecorationProvider) => {
|
||||
return extHostDecorations.registerDecorationProvider(provider, extension.identifier);
|
||||
}),
|
||||
registerUriHandler(handler: vscode.UriHandler) {
|
||||
return extHostUrls.registerUriHandler(extension.identifier, handler);
|
||||
},
|
||||
createQuickPick<T extends vscode.QuickPickItem>(): vscode.QuickPick<T> {
|
||||
return extHostQuickOpen.createQuickPick(extension.identifier, !!extension.enableProposedApi);
|
||||
},
|
||||
createInputBox(): vscode.InputBox {
|
||||
return extHostQuickOpen.createInputBox(extension.identifier);
|
||||
}
|
||||
};
|
||||
|
||||
// namespace: workspace
|
||||
const workspace: typeof vscode.workspace = {
|
||||
get rootPath() {
|
||||
return extHostWorkspace.getPath();
|
||||
},
|
||||
set rootPath(value) {
|
||||
throw errors.readonly();
|
||||
},
|
||||
getWorkspaceFolder(resource) {
|
||||
return extHostWorkspace.getWorkspaceFolder(resource);
|
||||
},
|
||||
get workspaceFolders() {
|
||||
return extHostWorkspace.getWorkspaceFolders();
|
||||
},
|
||||
get name() {
|
||||
return extHostWorkspace.name;
|
||||
},
|
||||
set name(value) {
|
||||
throw errors.readonly();
|
||||
},
|
||||
get workspaceFile() {
|
||||
return extHostWorkspace.workspaceFile;
|
||||
},
|
||||
set workspaceFile(value) {
|
||||
throw errors.readonly();
|
||||
},
|
||||
updateWorkspaceFolders: (index, deleteCount, ...workspaceFoldersToAdd) => {
|
||||
return extHostWorkspace.updateWorkspaceFolders(extension, index, deleteCount || 0, ...workspaceFoldersToAdd);
|
||||
},
|
||||
onDidChangeWorkspaceFolders: function (listener, thisArgs?, disposables?) {
|
||||
return extHostWorkspace.onDidChangeWorkspace(listener, thisArgs, disposables);
|
||||
},
|
||||
asRelativePath: (pathOrUri, includeWorkspace?) => {
|
||||
return extHostWorkspace.getRelativePath(pathOrUri, includeWorkspace);
|
||||
},
|
||||
findFiles: (include, exclude, maxResults?, token?) => {
|
||||
// Note, undefined/null have different meanings on "exclude"
|
||||
return extHostWorkspace.findFiles(typeConverters.GlobPattern.from(include), typeConverters.GlobPattern.from(exclude), maxResults, extension.identifier, token);
|
||||
},
|
||||
findTextInFiles: (query: vscode.TextSearchQuery, optionsOrCallback: vscode.FindTextInFilesOptions | ((result: vscode.TextSearchResult) => void), callbackOrToken?: vscode.CancellationToken | ((result: vscode.TextSearchResult) => void), token?: vscode.CancellationToken) => {
|
||||
let options: vscode.FindTextInFilesOptions;
|
||||
let callback: (result: vscode.TextSearchResult) => void;
|
||||
|
||||
if (typeof optionsOrCallback === 'object') {
|
||||
options = optionsOrCallback;
|
||||
callback = callbackOrToken as (result: vscode.TextSearchResult) => void;
|
||||
} else {
|
||||
options = {};
|
||||
callback = optionsOrCallback;
|
||||
token = callbackOrToken as vscode.CancellationToken;
|
||||
}
|
||||
|
||||
return extHostWorkspace.findTextInFiles(query, options || {}, callback, extension.identifier, token);
|
||||
},
|
||||
saveAll: (includeUntitled?) => {
|
||||
return extHostWorkspace.saveAll(includeUntitled);
|
||||
},
|
||||
applyEdit(edit: vscode.WorkspaceEdit): Thenable<boolean> {
|
||||
return extHostEditors.applyWorkspaceEdit(edit);
|
||||
},
|
||||
createFileSystemWatcher: (pattern, ignoreCreate, ignoreChange, ignoreDelete): vscode.FileSystemWatcher => {
|
||||
return extHostFileSystemEvent.createFileSystemWatcher(typeConverters.GlobPattern.from(pattern), ignoreCreate, ignoreChange, ignoreDelete);
|
||||
},
|
||||
get textDocuments() {
|
||||
return extHostDocuments.getAllDocumentData().map(data => data.document);
|
||||
},
|
||||
set textDocuments(value) {
|
||||
throw errors.readonly();
|
||||
},
|
||||
openTextDocument(uriOrFileNameOrOptions?: vscode.Uri | string | { language?: string; content?: string; }) {
|
||||
let uriPromise: Thenable<URI>;
|
||||
|
||||
const options = uriOrFileNameOrOptions as { language?: string; content?: string; };
|
||||
if (typeof uriOrFileNameOrOptions === 'string') {
|
||||
uriPromise = Promise.resolve(URI.file(uriOrFileNameOrOptions));
|
||||
} else if (uriOrFileNameOrOptions instanceof URI) {
|
||||
uriPromise = Promise.resolve(uriOrFileNameOrOptions);
|
||||
} else if (!options || typeof options === 'object') {
|
||||
uriPromise = extHostDocuments.createDocumentData(options);
|
||||
} else {
|
||||
throw new Error('illegal argument - uriOrFileNameOrOptions');
|
||||
}
|
||||
|
||||
return uriPromise.then(uri => {
|
||||
return extHostDocuments.ensureDocumentData(uri).then(() => {
|
||||
return extHostDocuments.getDocument(uri);
|
||||
});
|
||||
});
|
||||
},
|
||||
onDidOpenTextDocument: (listener, thisArgs?, disposables?) => {
|
||||
return extHostDocuments.onDidAddDocument(listener, thisArgs, disposables);
|
||||
},
|
||||
onDidCloseTextDocument: (listener, thisArgs?, disposables?) => {
|
||||
return extHostDocuments.onDidRemoveDocument(listener, thisArgs, disposables);
|
||||
},
|
||||
onDidChangeTextDocument: (listener, thisArgs?, disposables?) => {
|
||||
return extHostDocuments.onDidChangeDocument(listener, thisArgs, disposables);
|
||||
},
|
||||
onDidSaveTextDocument: (listener, thisArgs?, disposables?) => {
|
||||
return extHostDocuments.onDidSaveDocument(listener, thisArgs, disposables);
|
||||
},
|
||||
onWillSaveTextDocument: (listener, thisArgs?, disposables?) => {
|
||||
return extHostDocumentSaveParticipant.getOnWillSaveTextDocumentEvent(extension)(listener, thisArgs, disposables);
|
||||
},
|
||||
onDidChangeConfiguration: (listener: (_: any) => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) => {
|
||||
return configProvider.onDidChangeConfiguration(listener, thisArgs, disposables);
|
||||
},
|
||||
getConfiguration(section?: string, resource?: vscode.Uri): vscode.WorkspaceConfiguration {
|
||||
resource = arguments.length === 1 ? undefined : resource;
|
||||
return configProvider.getConfiguration(section, resource, extension.identifier);
|
||||
},
|
||||
registerTextDocumentContentProvider(scheme: string, provider: vscode.TextDocumentContentProvider) {
|
||||
return extHostDocumentContentProviders.registerTextDocumentContentProvider(scheme, provider);
|
||||
},
|
||||
registerTaskProvider: (type: string, provider: vscode.TaskProvider) => {
|
||||
return extHostTask.registerTaskProvider(extension, type, provider);
|
||||
},
|
||||
registerFileSystemProvider(scheme, provider, options) {
|
||||
return extHostFileSystem.registerFileSystemProvider(scheme, provider, options);
|
||||
},
|
||||
get fs() {
|
||||
return extHostFileSystem.fileSystem;
|
||||
},
|
||||
registerFileSearchProvider: proposedApiFunction(extension, (scheme: string, provider: vscode.FileSearchProvider) => {
|
||||
return extHostSearch.registerFileSearchProvider(scheme, provider);
|
||||
}),
|
||||
registerTextSearchProvider: proposedApiFunction(extension, (scheme: string, provider: vscode.TextSearchProvider) => {
|
||||
return extHostSearch.registerTextSearchProvider(scheme, provider);
|
||||
}),
|
||||
registerRemoteAuthorityResolver: proposedApiFunction(extension, (authorityPrefix: string, resolver: vscode.RemoteAuthorityResolver) => {
|
||||
return extensionService.registerRemoteAuthorityResolver(authorityPrefix, resolver);
|
||||
}),
|
||||
registerResourceLabelFormatter: proposedApiFunction(extension, (formatter: vscode.ResourceLabelFormatter) => {
|
||||
return extHostLabelService.$registerResourceLabelFormatter(formatter);
|
||||
}),
|
||||
onDidRenameFile: proposedApiFunction(extension, (listener: (e: vscode.FileRenameEvent) => any, thisArg?: any, disposables?: vscode.Disposable[]) => {
|
||||
return extHostFileSystemEvent.onDidRenameFile(listener, thisArg, disposables);
|
||||
}),
|
||||
onWillRenameFile: proposedApiFunction(extension, (listener: (e: vscode.FileWillRenameEvent) => any, thisArg?: any, disposables?: vscode.Disposable[]) => {
|
||||
return extHostFileSystemEvent.getOnWillRenameFileEvent(extension)(listener, thisArg, disposables);
|
||||
})
|
||||
};
|
||||
|
||||
// namespace: scm
|
||||
const scm: typeof vscode.scm = {
|
||||
get inputBox() {
|
||||
return extHostSCM.getLastInputBox(extension)!; // Strict null override - Deprecated api
|
||||
},
|
||||
createSourceControl(id: string, label: string, rootUri?: vscode.Uri) {
|
||||
return extHostSCM.createSourceControl(extension, id, label, rootUri);
|
||||
}
|
||||
};
|
||||
|
||||
const comment: typeof vscode.comments = {
|
||||
createCommentController(id: string, label: string) {
|
||||
return extHostComment.createCommentController(extension, id, label);
|
||||
}
|
||||
};
|
||||
|
||||
const comments = comment;
|
||||
|
||||
// {{SQL CARBON EDIT}} -- no-op debug extensibility API
|
||||
// namespace: debug
|
||||
const debug: typeof vscode.debug = {
|
||||
get activeDebugSession() {
|
||||
return undefined;
|
||||
},
|
||||
get activeDebugConsole() {
|
||||
return undefined;
|
||||
},
|
||||
get breakpoints() {
|
||||
return [];
|
||||
},
|
||||
onDidStartDebugSession(listener, thisArg?, disposables?) {
|
||||
return undefined;
|
||||
},
|
||||
onDidTerminateDebugSession(listener, thisArg?, disposables?) {
|
||||
return undefined;
|
||||
},
|
||||
onDidChangeActiveDebugSession(listener, thisArg?, disposables?) {
|
||||
return undefined;
|
||||
},
|
||||
onDidReceiveDebugSessionCustomEvent(listener, thisArg?, disposables?) {
|
||||
return undefined;
|
||||
},
|
||||
onDidChangeBreakpoints(listener, thisArgs?, disposables?) {
|
||||
return undefined;
|
||||
},
|
||||
registerDebugConfigurationProvider(debugType: string, provider: vscode.DebugConfigurationProvider) {
|
||||
return undefined;
|
||||
},
|
||||
registerDebugAdapterDescriptorFactory(debugType: string, factory: vscode.DebugAdapterDescriptorFactory) {
|
||||
return undefined;
|
||||
},
|
||||
registerDebugAdapterTrackerFactory(debugType: string, factory: vscode.DebugAdapterTrackerFactory) {
|
||||
return undefined;
|
||||
},
|
||||
startDebugging(folder: vscode.WorkspaceFolder | undefined, nameOrConfig: string | vscode.DebugConfiguration, parentSession?: vscode.DebugSession) {
|
||||
return undefined;
|
||||
},
|
||||
addBreakpoints(breakpoints: vscode.Breakpoint[]) {
|
||||
return undefined;
|
||||
},
|
||||
removeBreakpoints(breakpoints: vscode.Breakpoint[]) {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
const tasks: typeof vscode.tasks = {
|
||||
registerTaskProvider: (type: string, provider: vscode.TaskProvider) => {
|
||||
return extHostTask.registerTaskProvider(extension, type, provider);
|
||||
},
|
||||
fetchTasks: (filter?: vscode.TaskFilter): Thenable<vscode.Task[]> => {
|
||||
return extHostTask.fetchTasks(filter);
|
||||
},
|
||||
executeTask: (task: vscode.Task): Thenable<vscode.TaskExecution> => {
|
||||
return extHostTask.executeTask(extension, task);
|
||||
},
|
||||
get taskExecutions(): vscode.TaskExecution[] {
|
||||
return extHostTask.taskExecutions;
|
||||
},
|
||||
onDidStartTask: (listeners, thisArgs?, disposables?) => {
|
||||
return extHostTask.onDidStartTask(listeners, thisArgs, disposables);
|
||||
},
|
||||
onDidEndTask: (listeners, thisArgs?, disposables?) => {
|
||||
return extHostTask.onDidEndTask(listeners, thisArgs, disposables);
|
||||
},
|
||||
onDidStartTaskProcess: (listeners, thisArgs?, disposables?) => {
|
||||
return extHostTask.onDidStartTaskProcess(listeners, thisArgs, disposables);
|
||||
},
|
||||
onDidEndTaskProcess: (listeners, thisArgs?, disposables?) => {
|
||||
return extHostTask.onDidEndTaskProcess(listeners, thisArgs, disposables);
|
||||
}
|
||||
};
|
||||
|
||||
return <typeof vscode>{
|
||||
// {{SQL CARBON EDIT}} - Expose the VS Code version here for extensions that rely on it
|
||||
version: product.vscodeVersion,
|
||||
// namespaces
|
||||
commands,
|
||||
debug,
|
||||
env,
|
||||
extensions,
|
||||
languages,
|
||||
scm,
|
||||
comment,
|
||||
comments,
|
||||
tasks,
|
||||
window,
|
||||
workspace,
|
||||
// types
|
||||
Breakpoint: extHostTypes.Breakpoint,
|
||||
CancellationTokenSource: CancellationTokenSource,
|
||||
CodeAction: extHostTypes.CodeAction,
|
||||
CodeActionKind: extHostTypes.CodeActionKind,
|
||||
CodeActionTrigger: extHostTypes.CodeActionTrigger,
|
||||
CodeLens: extHostTypes.CodeLens,
|
||||
CodeInset: extHostTypes.CodeInset,
|
||||
Color: extHostTypes.Color,
|
||||
ColorInformation: extHostTypes.ColorInformation,
|
||||
ColorPresentation: extHostTypes.ColorPresentation,
|
||||
CommentThreadCollapsibleState: extHostTypes.CommentThreadCollapsibleState,
|
||||
CommentMode: extHostTypes.CommentMode,
|
||||
CompletionItem: extHostTypes.CompletionItem,
|
||||
CompletionItemKind: extHostTypes.CompletionItemKind,
|
||||
CompletionList: extHostTypes.CompletionList,
|
||||
CompletionTriggerKind: extHostTypes.CompletionTriggerKind,
|
||||
ConfigurationTarget: extHostTypes.ConfigurationTarget,
|
||||
DebugAdapterExecutable: extHostTypes.DebugAdapterExecutable,
|
||||
DebugAdapterServer: extHostTypes.DebugAdapterServer,
|
||||
DecorationRangeBehavior: extHostTypes.DecorationRangeBehavior,
|
||||
Diagnostic: extHostTypes.Diagnostic,
|
||||
DiagnosticRelatedInformation: extHostTypes.DiagnosticRelatedInformation,
|
||||
DiagnosticSeverity: extHostTypes.DiagnosticSeverity,
|
||||
DiagnosticTag: extHostTypes.DiagnosticTag,
|
||||
Disposable: extHostTypes.Disposable,
|
||||
DocumentHighlight: extHostTypes.DocumentHighlight,
|
||||
DocumentHighlightKind: extHostTypes.DocumentHighlightKind,
|
||||
DocumentLink: extHostTypes.DocumentLink,
|
||||
DocumentSymbol: extHostTypes.DocumentSymbol,
|
||||
EndOfLine: extHostTypes.EndOfLine,
|
||||
EventEmitter: Emitter,
|
||||
ExtensionExecutionContext: extHostTypes.ExtensionExecutionContext,
|
||||
ExtensionKind: extHostTypes.ExtensionKind,
|
||||
CustomExecution: extHostTypes.CustomExecution,
|
||||
CustomExecution2: extHostTypes.CustomExecution2,
|
||||
FileChangeType: extHostTypes.FileChangeType,
|
||||
FileSystemError: extHostTypes.FileSystemError,
|
||||
FileType: files.FileType,
|
||||
FoldingRange: extHostTypes.FoldingRange,
|
||||
FoldingRangeKind: extHostTypes.FoldingRangeKind,
|
||||
FunctionBreakpoint: extHostTypes.FunctionBreakpoint,
|
||||
Hover: extHostTypes.Hover,
|
||||
IndentAction: languageConfiguration.IndentAction,
|
||||
Location: extHostTypes.Location,
|
||||
LogLevel: extHostTypes.LogLevel,
|
||||
MarkdownString: extHostTypes.MarkdownString,
|
||||
OverviewRulerLane: OverviewRulerLane,
|
||||
ParameterInformation: extHostTypes.ParameterInformation,
|
||||
Position: extHostTypes.Position,
|
||||
ProcessExecution: extHostTypes.ProcessExecution,
|
||||
ProgressLocation: extHostTypes.ProgressLocation,
|
||||
QuickInputButtons: extHostTypes.QuickInputButtons,
|
||||
Range: extHostTypes.Range,
|
||||
RelativePattern: extHostTypes.RelativePattern,
|
||||
ResolvedAuthority: extHostTypes.ResolvedAuthority,
|
||||
RemoteAuthorityResolverError: extHostTypes.RemoteAuthorityResolverError,
|
||||
Selection: extHostTypes.Selection,
|
||||
SelectionRange: extHostTypes.SelectionRange,
|
||||
ShellExecution: extHostTypes.ShellExecution,
|
||||
ShellQuoting: extHostTypes.ShellQuoting,
|
||||
SignatureHelpTriggerKind: extHostTypes.SignatureHelpTriggerKind,
|
||||
SignatureHelp: extHostTypes.SignatureHelp,
|
||||
SignatureInformation: extHostTypes.SignatureInformation,
|
||||
SnippetString: extHostTypes.SnippetString,
|
||||
SourceBreakpoint: extHostTypes.SourceBreakpoint,
|
||||
SourceControlInputBoxValidationType: extHostTypes.SourceControlInputBoxValidationType,
|
||||
StatusBarAlignment: extHostTypes.StatusBarAlignment,
|
||||
SymbolInformation: extHostTypes.SymbolInformation,
|
||||
SymbolKind: extHostTypes.SymbolKind,
|
||||
Task: extHostTypes.Task,
|
||||
Task2: extHostTypes.Task,
|
||||
TaskGroup: extHostTypes.TaskGroup,
|
||||
TaskPanelKind: extHostTypes.TaskPanelKind,
|
||||
TaskRevealKind: extHostTypes.TaskRevealKind,
|
||||
TaskScope: extHostTypes.TaskScope,
|
||||
TextDocumentSaveReason: extHostTypes.TextDocumentSaveReason,
|
||||
TextEdit: extHostTypes.TextEdit,
|
||||
TextEditorCursorStyle: TextEditorCursorStyle,
|
||||
TextEditorLineNumbersStyle: extHostTypes.TextEditorLineNumbersStyle,
|
||||
TextEditorRevealType: extHostTypes.TextEditorRevealType,
|
||||
TextEditorSelectionChangeKind: extHostTypes.TextEditorSelectionChangeKind,
|
||||
ThemeColor: extHostTypes.ThemeColor,
|
||||
ThemeIcon: extHostTypes.ThemeIcon,
|
||||
TreeItem: extHostTypes.TreeItem,
|
||||
TreeItem2: extHostTypes.TreeItem,
|
||||
TreeItemCollapsibleState: extHostTypes.TreeItemCollapsibleState,
|
||||
Uri: URI,
|
||||
ViewColumn: extHostTypes.ViewColumn,
|
||||
WorkspaceEdit: extHostTypes.WorkspaceEdit,
|
||||
// proposed
|
||||
CallHierarchyDirection: extHostTypes.CallHierarchyDirection,
|
||||
CallHierarchyItem: extHostTypes.CallHierarchyItem
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
class Extension<T> implements vscode.Extension<T> {
|
||||
|
||||
private _extensionService: ExtHostExtensionService;
|
||||
private _identifier: ExtensionIdentifier;
|
||||
|
||||
readonly id: string;
|
||||
readonly extensionPath: string;
|
||||
readonly packageJSON: IExtensionDescription;
|
||||
readonly extensionKind: vscode.ExtensionKind;
|
||||
|
||||
constructor(extensionService: ExtHostExtensionService, description: IExtensionDescription, kind: extHostTypes.ExtensionKind) {
|
||||
this._extensionService = extensionService;
|
||||
this._identifier = description.identifier;
|
||||
this.id = description.identifier.value;
|
||||
this.extensionPath = path.normalize(originalFSPath(description.extensionLocation));
|
||||
this.packageJSON = description;
|
||||
this.extensionKind = kind;
|
||||
}
|
||||
|
||||
get isActive(): boolean {
|
||||
return this._extensionService.isActivated(this._identifier);
|
||||
}
|
||||
|
||||
get exports(): T {
|
||||
if (this.packageJSON.api === 'none') {
|
||||
return undefined!; // Strict nulloverride - Public api
|
||||
}
|
||||
return <T>this._extensionService.getExtensionExports(this._identifier);
|
||||
}
|
||||
|
||||
activate(): Thenable<T> {
|
||||
return this._extensionService.activateByIdWithErrors(this._identifier, new ExtensionActivatedByAPI(false)).then(() => this.exports);
|
||||
}
|
||||
}
|
||||
41
src/vs/workbench/api/node/extHost.services.ts
Normal file
41
src/vs/workbench/api/node/extHost.services.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IExtHostOutputService } from 'vs/workbench/api/common/extHostOutput';
|
||||
import { ExtHostOutputService2 } from 'vs/workbench/api/node/extHostOutputService';
|
||||
import { IExtHostWorkspace, ExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import { IExtHostDecorations, ExtHostDecorations } from 'vs/workbench/api/common/extHostDecorations';
|
||||
import { IExtHostConfiguration, ExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
|
||||
import { IExtHostCommands, ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { IExtHostDocumentsAndEditors, ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { ExtHostTerminalService } from 'vs/workbench/api/node/extHostTerminalService';
|
||||
import { IExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService';
|
||||
import { IExtHostTask } from 'vs/workbench/api/common/extHostTask';
|
||||
import { ExtHostTask } from 'vs/workbench/api/node/extHostTask';
|
||||
import { ExtHostDebugService } from 'vs/workbench/api/node/extHostDebugService';
|
||||
import { IExtHostDebugService } from 'vs/workbench/api/common/extHostDebugService';
|
||||
import { IExtHostSearch } from 'vs/workbench/api/common/extHostSearch';
|
||||
import { ExtHostSearch } from 'vs/workbench/api/node/extHostSearch';
|
||||
import { ExtensionStoragePaths } from 'vs/workbench/api/node/extHostStoragePaths';
|
||||
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
|
||||
import { IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
|
||||
import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService';
|
||||
import { IExtHostStorage, ExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
|
||||
|
||||
// register singleton services
|
||||
registerSingleton(IExtHostOutputService, ExtHostOutputService2);
|
||||
registerSingleton(IExtHostWorkspace, ExtHostWorkspace);
|
||||
registerSingleton(IExtHostDecorations, ExtHostDecorations);
|
||||
registerSingleton(IExtHostConfiguration, ExtHostConfiguration);
|
||||
registerSingleton(IExtHostCommands, ExtHostCommands);
|
||||
registerSingleton(IExtHostDocumentsAndEditors, ExtHostDocumentsAndEditors);
|
||||
registerSingleton(IExtHostTerminalService, ExtHostTerminalService);
|
||||
registerSingleton(IExtHostTask, ExtHostTask);
|
||||
registerSingleton(IExtHostDebugService, ExtHostDebugService);
|
||||
registerSingleton(IExtHostSearch, ExtHostSearch);
|
||||
registerSingleton(IExtensionStoragePaths, ExtensionStoragePaths);
|
||||
registerSingleton(IExtHostExtensionService, ExtHostExtensionService);
|
||||
registerSingleton(IExtHostStorage, ExtHostStorage);
|
||||
@@ -6,7 +6,7 @@
|
||||
import { generateRandomPipeName } from 'vs/base/parts/ipc/node/ipc.net';
|
||||
import * as http from 'http';
|
||||
import * as fs from 'fs';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { IExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { IURIToOpen, IOpenSettings } from 'vs/platform/windows/common/windows';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces';
|
||||
@@ -38,7 +38,7 @@ export class CLIServer {
|
||||
private _server: http.Server;
|
||||
private _ipcHandlePath: string | undefined;
|
||||
|
||||
constructor(private _commands: ExtHostCommands) {
|
||||
constructor(@IExtHostCommands private _commands: IExtHostCommands) {
|
||||
this._server = http.createServer((req, res) => this.onRequest(req, res));
|
||||
this.setup().catch(err => {
|
||||
console.error(err);
|
||||
@@ -179,4 +179,4 @@ export class CLIServer {
|
||||
fs.unlinkSync(this._ipcHandlePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,33 +11,37 @@ import { asPromise } from 'vs/base/common/async';
|
||||
import * as nls from 'vs/nls';
|
||||
import {
|
||||
MainContext, MainThreadDebugServiceShape, ExtHostDebugServiceShape, DebugSessionUUID,
|
||||
IMainContext, IBreakpointsDeltaDto, ISourceMultiBreakpointDto, IFunctionBreakpointDto, IDebugSessionDto
|
||||
IBreakpointsDeltaDto, ISourceMultiBreakpointDto, IFunctionBreakpointDto, IDebugSessionDto
|
||||
} from 'vs/workbench/api/common/extHost.protocol';
|
||||
import * as vscode from 'vscode';
|
||||
import { Disposable, Position, Location, SourceBreakpoint, FunctionBreakpoint, DebugAdapterServer, DebugAdapterExecutable } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { ExecutableDebugAdapter, SocketDebugAdapter } from 'vs/workbench/contrib/debug/node/debugAdapter';
|
||||
import { AbstractDebugAdapter } from 'vs/workbench/contrib/debug/common/abstractDebugAdapter';
|
||||
import { IExtHostWorkspaceProvider } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import { IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
|
||||
import { ExtHostDocumentsAndEditors, IExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { IDebuggerContribution, IConfig, IDebugAdapter, IDebugAdapterServer, IDebugAdapterExecutable, IAdapterDescriptor } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { hasChildProcesses, prepareCommand, runInExternalTerminal } from 'vs/workbench/contrib/debug/node/terminals';
|
||||
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/common/variableResolver';
|
||||
import { ExtHostConfiguration, ExtHostConfigProvider } from '../common/extHostConfiguration';
|
||||
import { ExtHostConfigProvider, IExtHostConfiguration } from '../common/extHostConfiguration';
|
||||
import { convertToVSCPaths, convertToDAPaths, isDebuggerMainContribution } from 'vs/workbench/contrib/debug/common/debugUtils';
|
||||
import { ExtHostTerminalService } from 'vs/workbench/api/node/extHostTerminalService';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { IExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
|
||||
import { IProcessEnvironment } from 'vs/base/common/platform';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { SignService } from 'vs/platform/sign/node/signService';
|
||||
import { ISignService } from 'vs/platform/sign/common/sign';
|
||||
import { IExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService';
|
||||
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
import { IExtHostDebugService } from 'vs/workbench/api/common/extHostDebugService';
|
||||
|
||||
export class ExtHostDebugService implements ExtHostDebugServiceShape {
|
||||
export class ExtHostDebugService implements IExtHostDebugService, ExtHostDebugServiceShape {
|
||||
|
||||
readonly _serviceBrand: any;
|
||||
|
||||
private _configProviderHandleCounter: number;
|
||||
private _configProviders: ConfigProviderTuple[];
|
||||
@@ -86,13 +90,14 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
|
||||
private _signService: ISignService;
|
||||
|
||||
|
||||
constructor(mainContext: IMainContext,
|
||||
private _workspaceService: IExtHostWorkspaceProvider,
|
||||
private _extensionService: ExtHostExtensionService,
|
||||
private _editorsService: ExtHostDocumentsAndEditors,
|
||||
private _configurationService: ExtHostConfiguration,
|
||||
private _terminalService: ExtHostTerminalService,
|
||||
private _commandService: ExtHostCommands
|
||||
constructor(
|
||||
@IExtHostRpcService extHostRpcService: IExtHostRpcService,
|
||||
@IExtHostWorkspace private _workspaceService: IExtHostWorkspace,
|
||||
@IExtHostExtensionService private _extensionService: IExtHostExtensionService,
|
||||
@IExtHostDocumentsAndEditors private _editorsService: IExtHostDocumentsAndEditors,
|
||||
@IExtHostConfiguration private _configurationService: IExtHostConfiguration,
|
||||
@IExtHostTerminalService private _terminalService: IExtHostTerminalService,
|
||||
@IExtHostCommands private _commandService: IExtHostCommands
|
||||
) {
|
||||
this._configProviderHandleCounter = 0;
|
||||
this._configProviders = [];
|
||||
@@ -112,7 +117,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
|
||||
this._onDidChangeActiveDebugSession = new Emitter<vscode.DebugSession>();
|
||||
this._onDidReceiveDebugSessionCustomEvent = new Emitter<vscode.DebugSessionCustomEvent>();
|
||||
|
||||
this._debugServiceProxy = mainContext.getProxy(MainContext.MainThreadDebugService);
|
||||
this._debugServiceProxy = extHostRpcService.getProxy(MainContext.MainThreadDebugService);
|
||||
|
||||
this._onDidChangeBreakpoints = new Emitter<vscode.BreakpointsChangeEvent>({
|
||||
onFirstListenerAdd: () => {
|
||||
@@ -344,7 +349,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
|
||||
}).then(async needNewTerminal => {
|
||||
|
||||
const configProvider = await this._configurationService.getConfigProvider();
|
||||
const shell = this._terminalService.getDefaultShell(configProvider);
|
||||
const shell = this._terminalService.getDefaultShell(true, configProvider);
|
||||
|
||||
if (needNewTerminal || !this._integratedTerminalInstance) {
|
||||
const options: vscode.TerminalOptions = {
|
||||
@@ -599,7 +604,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
|
||||
this.fireBreakpointChanges(a, r, c);
|
||||
}
|
||||
|
||||
public $provideDebugConfigurations(configProviderHandle: number, folderUri: UriComponents | undefined): Promise<vscode.DebugConfiguration[]> {
|
||||
public $provideDebugConfigurations(configProviderHandle: number, folderUri: UriComponents | undefined, token: CancellationToken): Promise<vscode.DebugConfiguration[]> {
|
||||
return asPromise(async () => {
|
||||
const provider = this.getConfigProviderByHandle(configProviderHandle);
|
||||
if (!provider) {
|
||||
@@ -609,7 +614,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
|
||||
throw new Error('DebugConfigurationProvider has no method provideDebugConfigurations');
|
||||
}
|
||||
const folder = await this.getFolder(folderUri);
|
||||
return provider.provideDebugConfigurations(folder, CancellationToken.None);
|
||||
return provider.provideDebugConfigurations(folder, token);
|
||||
}).then(debugConfigurations => {
|
||||
if (!debugConfigurations) {
|
||||
throw new Error('nothing returned from DebugConfigurationProvider.provideDebugConfigurations');
|
||||
@@ -618,7 +623,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
|
||||
});
|
||||
}
|
||||
|
||||
public $resolveDebugConfiguration(configProviderHandle: number, folderUri: UriComponents | undefined, debugConfiguration: vscode.DebugConfiguration): Promise<vscode.DebugConfiguration | null | undefined> {
|
||||
public $resolveDebugConfiguration(configProviderHandle: number, folderUri: UriComponents | undefined, debugConfiguration: vscode.DebugConfiguration, token: CancellationToken): Promise<vscode.DebugConfiguration | null | undefined> {
|
||||
return asPromise(async () => {
|
||||
const provider = this.getConfigProviderByHandle(configProviderHandle);
|
||||
if (!provider) {
|
||||
@@ -628,7 +633,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape {
|
||||
throw new Error('DebugConfigurationProvider has no method resolveDebugConfiguration');
|
||||
}
|
||||
const folder = await this.getFolder(folderUri);
|
||||
return provider.resolveDebugConfiguration(folder, debugConfiguration, CancellationToken.None);
|
||||
return provider.resolveDebugConfiguration(folder, debugConfiguration, token);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -6,23 +6,26 @@
|
||||
import { join } from 'vs/base/common/path';
|
||||
import { tmpdir } from 'os';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { IExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { MainThreadDownloadServiceShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { MainContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
|
||||
export class ExtHostDownloadService extends Disposable {
|
||||
|
||||
constructor(
|
||||
proxy: MainThreadDownloadServiceShape,
|
||||
commands: ExtHostCommands
|
||||
@IExtHostRpcService extHostRpc: IExtHostRpcService,
|
||||
@IExtHostCommands commands: IExtHostCommands
|
||||
) {
|
||||
super();
|
||||
|
||||
const proxy = extHostRpc.getProxy(MainContext.MainThreadDownloadService);
|
||||
|
||||
commands.registerCommand(false, '_workbench.downloadResource', async (resource: URI): Promise<any> => {
|
||||
const location = URI.file(join(tmpdir(), generateUuid()));
|
||||
await proxy.$download(resource, location);
|
||||
return location;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,768 +3,63 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import * as path from 'vs/base/common/path';
|
||||
// {{SQL CARBON EDIT}}
|
||||
import { createApiFactory, initializeExtensionApi, ISqlExtensionApiFactory } from 'sql/workbench/api/node/sqlExtHost.api.impl';
|
||||
import { originalFSPath } from 'vs/base/common/resources';
|
||||
import { Barrier } from 'vs/base/common/async';
|
||||
import { dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { TernarySearchTree } from 'vs/base/common/map';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
// {{SQL CARBON EDIT}} - Remove createApiFactory initializeExtensionApi, and IExtensionApiFactory imports
|
||||
// import { createApiFactory, IExtensionApiFactory } from 'vs/workbench/api/node/extHost.api.impl';
|
||||
import { createApiFactoryAndRegisterActors } from 'vs/workbench/api/common/extHost.api.impl';
|
||||
import { NodeModuleRequireInterceptor, VSCodeNodeModuleFactory, KeytarNodeModuleFactory, OpenNodeModuleFactory } from 'vs/workbench/api/node/extHostRequireInterceptor';
|
||||
import { ExtHostExtensionServiceShape, IEnvironment, IInitData, IMainContext, MainContext, MainThreadExtensionServiceShape, MainThreadTelemetryShape, MainThreadWorkspaceShape, IResolveAuthorityResult } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
|
||||
import { ActivatedExtension, EmptyExtension, ExtensionActivatedByAPI, ExtensionActivatedByEvent, ExtensionActivationReason, ExtensionActivationTimes, ExtensionActivationTimesBuilder, ExtensionsActivator, IExtensionAPI, IExtensionContext, IExtensionModule, HostExtension, ExtensionActivationTimesFragment } from 'vs/workbench/api/common/extHostExtensionActivator';
|
||||
import { ExtHostLogService } from 'vs/workbench/api/common/extHostLogService';
|
||||
import { ExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
|
||||
import { ExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import { ExtensionActivationError } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
|
||||
import { MainContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtensionActivationTimesBuilder } from 'vs/workbench/api/common/extHostExtensionActivator';
|
||||
import { connectProxyResolver } from 'vs/workbench/services/extensions/node/proxyResolver';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import * as vscode from 'vscode';
|
||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { ExtensionMemento } from 'vs/workbench/api/common/extHostMemento';
|
||||
import { ExtensionStoragePaths } from 'vs/workbench/api/node/extHostStoragePaths';
|
||||
import { RemoteAuthorityResolverError, ExtensionExecutionContext } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { IURITransformer } from 'vs/base/common/uriIpc';
|
||||
import { ResolvedAuthority, ResolvedOptions } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { AbstractExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
|
||||
import { ExtHostDownloadService } from 'vs/workbench/api/node/extHostDownloadService';
|
||||
import { CLIServer } from 'vs/workbench/api/node/extHostCLIServer';
|
||||
import { initializeExtensionApi, createApiFactory } from 'sql/workbench/api/common/sqlExtHost.api.impl'; // {{SQL CARBON EDIT}} use our extension initalizer
|
||||
|
||||
interface ITestRunner {
|
||||
/** Old test runner API, as exported from `vscode/lib/testrunner` */
|
||||
run(testsRoot: string, clb: (error: Error, failures?: number) => void): void;
|
||||
}
|
||||
export class ExtHostExtensionService extends AbstractExtHostExtensionService {
|
||||
|
||||
interface INewTestRunner {
|
||||
/** New test runner API, as explained in the extension test doc */
|
||||
run(): Promise<void>;
|
||||
}
|
||||
protected async _beforeAlmostReadyToRunExtensions(): Promise<void> {
|
||||
// initialize API and register actors
|
||||
const extensionApiFactory = this._instaService.invokeFunction(createApiFactory);
|
||||
|
||||
export interface IHostUtils {
|
||||
exit(code?: number): void;
|
||||
exists(path: string): Promise<boolean>;
|
||||
realpath(path: string): Promise<string>;
|
||||
}
|
||||
// Register Download command
|
||||
this._instaService.createInstance(ExtHostDownloadService);
|
||||
|
||||
type TelemetryActivationEventFragment = {
|
||||
id: { classification: 'PublicNonPersonalData', purpose: 'FeatureInsight' };
|
||||
name: { classification: 'PublicNonPersonalData', purpose: 'FeatureInsight' };
|
||||
extensionVersion: { classification: 'PublicNonPersonalData', purpose: 'FeatureInsight' };
|
||||
publisherDisplayName: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||
activationEvents: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||
isBuiltin: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true };
|
||||
reason: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||
};
|
||||
|
||||
export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
|
||||
private static readonly WORKSPACE_CONTAINS_TIMEOUT = 7000;
|
||||
|
||||
private readonly _hostUtils: IHostUtils;
|
||||
private readonly _initData: IInitData;
|
||||
private readonly _extHostContext: IMainContext;
|
||||
private readonly _extHostWorkspace: ExtHostWorkspace;
|
||||
private readonly _extHostConfiguration: ExtHostConfiguration;
|
||||
private readonly _environment: IEnvironment;
|
||||
private readonly _extHostLogService: ExtHostLogService;
|
||||
|
||||
private readonly _mainThreadWorkspaceProxy: MainThreadWorkspaceShape;
|
||||
private readonly _mainThreadTelemetryProxy: MainThreadTelemetryShape;
|
||||
private readonly _mainThreadExtensionsProxy: MainThreadExtensionServiceShape;
|
||||
|
||||
private readonly _almostReadyToRunExtensions: Barrier;
|
||||
private readonly _readyToStartExtensionHost: Barrier;
|
||||
private readonly _readyToRunExtensions: Barrier;
|
||||
private readonly _registry: ExtensionDescriptionRegistry;
|
||||
private readonly _storage: ExtHostStorage;
|
||||
private readonly _storagePath: ExtensionStoragePaths;
|
||||
private readonly _activator: ExtensionsActivator;
|
||||
private _extensionPathIndex: Promise<TernarySearchTree<IExtensionDescription>> | null;
|
||||
private readonly _extensionApiFactory: ISqlExtensionApiFactory;
|
||||
|
||||
private readonly _resolvers: { [authorityPrefix: string]: vscode.RemoteAuthorityResolver; };
|
||||
|
||||
private _started: boolean;
|
||||
|
||||
private readonly _disposables: DisposableStore;
|
||||
|
||||
constructor(
|
||||
hostUtils: IHostUtils,
|
||||
initData: IInitData,
|
||||
extHostContext: IMainContext,
|
||||
extHostWorkspace: ExtHostWorkspace,
|
||||
extHostConfiguration: ExtHostConfiguration,
|
||||
environment: IEnvironment,
|
||||
extHostLogService: ExtHostLogService,
|
||||
uriTransformer: IURITransformer | null
|
||||
) {
|
||||
this._hostUtils = hostUtils;
|
||||
this._initData = initData;
|
||||
this._extHostContext = extHostContext;
|
||||
this._extHostWorkspace = extHostWorkspace;
|
||||
this._extHostConfiguration = extHostConfiguration;
|
||||
this._environment = environment;
|
||||
this._extHostLogService = extHostLogService;
|
||||
this._disposables = new DisposableStore();
|
||||
|
||||
this._mainThreadWorkspaceProxy = this._extHostContext.getProxy(MainContext.MainThreadWorkspace);
|
||||
this._mainThreadTelemetryProxy = this._extHostContext.getProxy(MainContext.MainThreadTelemetry);
|
||||
this._mainThreadExtensionsProxy = this._extHostContext.getProxy(MainContext.MainThreadExtensionService);
|
||||
|
||||
this._almostReadyToRunExtensions = new Barrier();
|
||||
this._readyToStartExtensionHost = new Barrier();
|
||||
this._readyToRunExtensions = new Barrier();
|
||||
this._registry = new ExtensionDescriptionRegistry(initData.extensions);
|
||||
this._storage = new ExtHostStorage(this._extHostContext);
|
||||
this._storagePath = new ExtensionStoragePaths(withNullAsUndefined(initData.workspace), initData.environment);
|
||||
|
||||
const hostExtensions = new Set<string>();
|
||||
initData.hostExtensions.forEach((extensionId) => hostExtensions.add(ExtensionIdentifier.toKey(extensionId)));
|
||||
|
||||
this._activator = new ExtensionsActivator(this._registry, initData.resolvedExtensions, initData.hostExtensions, {
|
||||
onExtensionActivationError: (extensionId: ExtensionIdentifier, error: ExtensionActivationError): void => {
|
||||
this._mainThreadExtensionsProxy.$onExtensionActivationError(extensionId, error);
|
||||
},
|
||||
|
||||
actualActivateExtension: async (extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<ActivatedExtension> => {
|
||||
if (hostExtensions.has(ExtensionIdentifier.toKey(extensionId))) {
|
||||
const activationEvent = (reason instanceof ExtensionActivatedByEvent ? reason.activationEvent : null);
|
||||
await this._mainThreadExtensionsProxy.$activateExtension(extensionId, activationEvent);
|
||||
return new HostExtension();
|
||||
}
|
||||
const extensionDescription = this._registry.getExtensionDescription(extensionId)!;
|
||||
return this._activateExtension(extensionDescription, reason);
|
||||
}
|
||||
});
|
||||
this._extensionPathIndex = null;
|
||||
|
||||
// initialize API first (i.e. do not release barrier until the API is initialized)
|
||||
this._extensionApiFactory = createApiFactory(
|
||||
this._initData,
|
||||
this._extHostContext,
|
||||
this._extHostWorkspace,
|
||||
this._extHostConfiguration,
|
||||
this,
|
||||
this._extHostLogService,
|
||||
this._storage,
|
||||
uriTransformer
|
||||
);
|
||||
|
||||
this._resolvers = Object.create(null);
|
||||
|
||||
this._started = false;
|
||||
|
||||
this._initialize();
|
||||
|
||||
if (this._initData.autoStart) {
|
||||
this._startExtensionHost();
|
||||
// Register CLI Server for ipc
|
||||
if (this._initData.remote.isRemote && this._initData.remote.authority) {
|
||||
const cliServer = this._instaService.createInstance(CLIServer);
|
||||
process.env['VSCODE_IPC_HOOK_CLI'] = cliServer.ipcHandlePath;
|
||||
}
|
||||
|
||||
// Module loading tricks
|
||||
const configProvider = await this._extHostConfiguration.getConfigProvider();
|
||||
const extensionPaths = await this.getExtensionPathIndex();
|
||||
// {{SQL CARBON EDIT}} - disable VSCodeNodeModuleFactory and use older initializeExtensionApi
|
||||
// NodeModuleRequireInterceptor.INSTANCE.register(new VSCodeNodeModuleFactory(this._extensionApiFactory, extensionPaths, this._registry, configProvider));
|
||||
await initializeExtensionApi(this, extensionApiFactory, this._registry, configProvider);
|
||||
NodeModuleRequireInterceptor.INSTANCE.register(new KeytarNodeModuleFactory(this._extHostContext.getProxy(MainContext.MainThreadKeytar), this._initData.environment));
|
||||
if (this._initData.remote.isRemote) {
|
||||
NodeModuleRequireInterceptor.INSTANCE.register(new OpenNodeModuleFactory(
|
||||
this._extHostContext.getProxy(MainContext.MainThreadWindow),
|
||||
this._extHostContext.getProxy(MainContext.MainThreadTelemetry),
|
||||
extensionPaths
|
||||
));
|
||||
}
|
||||
|
||||
// Do this when extension service exists, but extensions are not being activated yet.
|
||||
await connectProxyResolver(this._extHostWorkspace, configProvider, this, this._extHostLogService, this._mainThreadTelemetryProxy);
|
||||
|
||||
}
|
||||
|
||||
private async _initialize(): Promise<void> {
|
||||
protected _loadCommonJSModule<T>(modulePath: string, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<T> {
|
||||
let r: T | null = null;
|
||||
activationTimesBuilder.codeLoadingStart();
|
||||
this._extHostLogService.info(`ExtensionService#loadCommonJSModule ${modulePath}`);
|
||||
try {
|
||||
const configProvider = await this._extHostConfiguration.getConfigProvider();
|
||||
const extensionPaths = await this.getExtensionPathIndex();
|
||||
// {{SQL CARBON EDIT}} - disable VSCodeNodeModuleFactory and use older initializeExtensionApi
|
||||
// NodeModuleRequireInterceptor.INSTANCE.register(new VSCodeNodeModuleFactory(this._extensionApiFactory, extensionPaths, this._registry, configProvider));
|
||||
await initializeExtensionApi(this, this._extensionApiFactory, this._registry, configProvider);
|
||||
NodeModuleRequireInterceptor.INSTANCE.register(new KeytarNodeModuleFactory(this._extHostContext.getProxy(MainContext.MainThreadKeytar), this._environment));
|
||||
if (this._initData.remote.isRemote) {
|
||||
NodeModuleRequireInterceptor.INSTANCE.register(new OpenNodeModuleFactory(
|
||||
this._extHostContext.getProxy(MainContext.MainThreadWindow),
|
||||
this._extHostContext.getProxy(MainContext.MainThreadTelemetry),
|
||||
extensionPaths
|
||||
));
|
||||
}
|
||||
|
||||
// Do this when extension service exists, but extensions are not being activated yet.
|
||||
await connectProxyResolver(this._extHostWorkspace, configProvider, this, this._extHostLogService, this._mainThreadTelemetryProxy);
|
||||
this._almostReadyToRunExtensions.open();
|
||||
|
||||
await this._extHostWorkspace.waitForInitializeCall();
|
||||
this._readyToStartExtensionHost.open();
|
||||
} catch (err) {
|
||||
errors.onUnexpectedError(err);
|
||||
r = require.__$__nodeRequire<T>(modulePath);
|
||||
} catch (e) {
|
||||
return Promise.reject(e);
|
||||
} finally {
|
||||
activationTimesBuilder.codeLoadingStop();
|
||||
}
|
||||
}
|
||||
|
||||
public async deactivateAll(): Promise<void> {
|
||||
let allPromises: Promise<void>[] = [];
|
||||
try {
|
||||
const allExtensions = this._registry.getAllExtensionDescriptions();
|
||||
const allExtensionsIds = allExtensions.map(ext => ext.identifier);
|
||||
const activatedExtensions = allExtensionsIds.filter(id => this.isActivated(id));
|
||||
|
||||
allPromises = activatedExtensions.map((extensionId) => {
|
||||
return this._deactivate(extensionId);
|
||||
});
|
||||
} catch (err) {
|
||||
// TODO: write to log once we have one
|
||||
}
|
||||
await allPromises;
|
||||
}
|
||||
|
||||
public isActivated(extensionId: ExtensionIdentifier): boolean {
|
||||
if (this._readyToRunExtensions.isOpen()) {
|
||||
return this._activator.isActivated(extensionId);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private _activateByEvent(activationEvent: string, startup: boolean): Promise<void> {
|
||||
const reason = new ExtensionActivatedByEvent(startup, activationEvent);
|
||||
return this._activator.activateByEvent(activationEvent, reason);
|
||||
}
|
||||
|
||||
private _activateById(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<void> {
|
||||
return this._activator.activateById(extensionId, reason);
|
||||
}
|
||||
|
||||
public activateByIdWithErrors(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<void> {
|
||||
return this._activateById(extensionId, reason).then(() => {
|
||||
const extension = this._activator.getActivatedExtension(extensionId);
|
||||
if (extension.activationFailed) {
|
||||
// activation failed => bubble up the error as the promise result
|
||||
return Promise.reject(extension.activationFailedError);
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
public getExtensionRegistry(): Promise<ExtensionDescriptionRegistry> {
|
||||
return this._readyToRunExtensions.wait().then(_ => this._registry);
|
||||
}
|
||||
|
||||
public getExtensionExports(extensionId: ExtensionIdentifier): IExtensionAPI | null | undefined {
|
||||
if (this._readyToRunExtensions.isOpen()) {
|
||||
return this._activator.getActivatedExtension(extensionId).exports;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// create trie to enable fast 'filename -> extension id' look up
|
||||
public getExtensionPathIndex(): Promise<TernarySearchTree<IExtensionDescription>> {
|
||||
if (!this._extensionPathIndex) {
|
||||
const tree = TernarySearchTree.forPaths<IExtensionDescription>();
|
||||
const extensions = this._registry.getAllExtensionDescriptions().map(ext => {
|
||||
if (!ext.main) {
|
||||
return undefined;
|
||||
}
|
||||
return this._hostUtils.realpath(ext.extensionLocation.fsPath).then(value => tree.set(URI.file(value).fsPath, ext));
|
||||
});
|
||||
this._extensionPathIndex = Promise.all(extensions).then(() => tree);
|
||||
}
|
||||
return this._extensionPathIndex;
|
||||
}
|
||||
|
||||
private _deactivate(extensionId: ExtensionIdentifier): Promise<void> {
|
||||
let result = Promise.resolve(undefined);
|
||||
|
||||
if (!this._readyToRunExtensions.isOpen()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!this._activator.isActivated(extensionId)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const extension = this._activator.getActivatedExtension(extensionId);
|
||||
if (!extension) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// call deactivate if available
|
||||
try {
|
||||
if (typeof extension.module.deactivate === 'function') {
|
||||
result = Promise.resolve(extension.module.deactivate()).then(undefined, (err) => {
|
||||
// TODO: Do something with err if this is not the shutdown case
|
||||
return Promise.resolve(undefined);
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
// TODO: Do something with err if this is not the shutdown case
|
||||
}
|
||||
|
||||
// clean up subscriptions
|
||||
try {
|
||||
dispose(extension.subscriptions);
|
||||
} catch (err) {
|
||||
// TODO: Do something with err if this is not the shutdown case
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// --- impl
|
||||
|
||||
private _activateExtension(extensionDescription: IExtensionDescription, reason: ExtensionActivationReason): Promise<ActivatedExtension> {
|
||||
this._mainThreadExtensionsProxy.$onWillActivateExtension(extensionDescription.identifier);
|
||||
return this._doActivateExtension(extensionDescription, reason).then((activatedExtension) => {
|
||||
const activationTimes = activatedExtension.activationTimes;
|
||||
const activationEvent = (reason instanceof ExtensionActivatedByEvent ? reason.activationEvent : null);
|
||||
this._mainThreadExtensionsProxy.$onDidActivateExtension(extensionDescription.identifier, activationTimes.startup, activationTimes.codeLoadingTime, activationTimes.activateCallTime, activationTimes.activateResolvedTime, activationEvent);
|
||||
this._logExtensionActivationTimes(extensionDescription, reason, 'success', activationTimes);
|
||||
return activatedExtension;
|
||||
}, (err) => {
|
||||
this._logExtensionActivationTimes(extensionDescription, reason, 'failure');
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
private _logExtensionActivationTimes(extensionDescription: IExtensionDescription, reason: ExtensionActivationReason, outcome: string, activationTimes?: ExtensionActivationTimes) {
|
||||
const event = getTelemetryActivationEvent(extensionDescription, reason);
|
||||
type ExtensionActivationTimesClassification = {
|
||||
outcome: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
|
||||
} & TelemetryActivationEventFragment & ExtensionActivationTimesFragment;
|
||||
|
||||
type ExtensionActivationTimesEvent = {
|
||||
outcome: string
|
||||
} & ActivationTimesEvent & TelemetryActivationEvent;
|
||||
|
||||
type ActivationTimesEvent = {
|
||||
startup?: boolean;
|
||||
codeLoadingTime?: number;
|
||||
activateCallTime?: number;
|
||||
activateResolvedTime?: number;
|
||||
};
|
||||
|
||||
this._mainThreadTelemetryProxy.$publicLog2<ExtensionActivationTimesEvent, ExtensionActivationTimesClassification>('extensionActivationTimes', {
|
||||
...event,
|
||||
...(activationTimes || {}),
|
||||
outcome
|
||||
});
|
||||
}
|
||||
|
||||
private _doActivateExtension(extensionDescription: IExtensionDescription, reason: ExtensionActivationReason): Promise<ActivatedExtension> {
|
||||
const event = getTelemetryActivationEvent(extensionDescription, reason);
|
||||
type ActivatePluginClassification = {} & TelemetryActivationEventFragment;
|
||||
this._mainThreadTelemetryProxy.$publicLog2<TelemetryActivationEvent, ActivatePluginClassification>('activatePlugin', event);
|
||||
if (!extensionDescription.main) {
|
||||
// Treat the extension as being empty => NOT AN ERROR CASE
|
||||
return Promise.resolve(new EmptyExtension(ExtensionActivationTimes.NONE));
|
||||
}
|
||||
|
||||
this._extHostLogService.info(`ExtensionService#_doActivateExtension ${extensionDescription.identifier.value} ${JSON.stringify(reason)}`);
|
||||
|
||||
const activationTimesBuilder = new ExtensionActivationTimesBuilder(reason.startup);
|
||||
return Promise.all<any>([
|
||||
loadCommonJSModule(this._extHostLogService, extensionDescription.main, activationTimesBuilder),
|
||||
this._loadExtensionContext(extensionDescription)
|
||||
]).then(values => {
|
||||
return ExtHostExtensionService._callActivate(this._extHostLogService, extensionDescription.identifier, <IExtensionModule>values[0], <IExtensionContext>values[1], activationTimesBuilder);
|
||||
});
|
||||
}
|
||||
|
||||
private _loadExtensionContext(extensionDescription: IExtensionDescription): Promise<vscode.ExtensionContext> {
|
||||
|
||||
const globalState = new ExtensionMemento(extensionDescription.identifier.value, true, this._storage);
|
||||
const workspaceState = new ExtensionMemento(extensionDescription.identifier.value, false, this._storage);
|
||||
|
||||
this._extHostLogService.trace(`ExtensionService#loadExtensionContext ${extensionDescription.identifier.value}`);
|
||||
return Promise.all([
|
||||
globalState.whenReady,
|
||||
workspaceState.whenReady,
|
||||
this._storagePath.whenReady
|
||||
]).then(() => {
|
||||
const that = this;
|
||||
return Object.freeze(<IExtensionContext>{
|
||||
globalState,
|
||||
workspaceState,
|
||||
subscriptions: [],
|
||||
get extensionPath() { return extensionDescription.extensionLocation.fsPath; },
|
||||
storagePath: this._storagePath.workspaceValue(extensionDescription),
|
||||
globalStoragePath: this._storagePath.globalValue(extensionDescription),
|
||||
asAbsolutePath: (relativePath: string) => { return path.join(extensionDescription.extensionLocation.fsPath, relativePath); },
|
||||
logPath: that._extHostLogService.getLogDirectory(extensionDescription.identifier),
|
||||
executionContext: this._initData.remote.isRemote ? ExtensionExecutionContext.Remote : ExtensionExecutionContext.Local,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private static _callActivate(logService: ILogService, extensionId: ExtensionIdentifier, extensionModule: IExtensionModule, context: IExtensionContext, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<ActivatedExtension> {
|
||||
// Make sure the extension's surface is not undefined
|
||||
extensionModule = extensionModule || {
|
||||
activate: undefined,
|
||||
deactivate: undefined
|
||||
};
|
||||
|
||||
return this._callActivateOptional(logService, extensionId, extensionModule, context, activationTimesBuilder).then((extensionExports) => {
|
||||
return new ActivatedExtension(false, null, activationTimesBuilder.build(), extensionModule, extensionExports, context.subscriptions);
|
||||
});
|
||||
}
|
||||
|
||||
private static _callActivateOptional(logService: ILogService, extensionId: ExtensionIdentifier, extensionModule: IExtensionModule, context: IExtensionContext, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<IExtensionAPI> {
|
||||
if (typeof extensionModule.activate === 'function') {
|
||||
try {
|
||||
activationTimesBuilder.activateCallStart();
|
||||
logService.trace(`ExtensionService#_callActivateOptional ${extensionId.value}`);
|
||||
const activateResult: Promise<IExtensionAPI> = extensionModule.activate.apply(global, [context]);
|
||||
activationTimesBuilder.activateCallStop();
|
||||
|
||||
activationTimesBuilder.activateResolveStart();
|
||||
return Promise.resolve(activateResult).then((value) => {
|
||||
activationTimesBuilder.activateResolveStop();
|
||||
return value;
|
||||
});
|
||||
} catch (err) {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
} else {
|
||||
// No activate found => the module is the extension's exports
|
||||
return Promise.resolve<IExtensionAPI>(extensionModule);
|
||||
}
|
||||
}
|
||||
|
||||
// -- eager activation
|
||||
|
||||
// Handle "eager" activation extensions
|
||||
private async _handleEagerExtensions(): Promise<void> {
|
||||
// {{SQL CARBON EDIT}} - load MSSQL extension first so it doesn't get delayed by other extensions
|
||||
try {
|
||||
await this._activateById(new ExtensionIdentifier('microsoft.mssql'), new ExtensionActivatedByEvent(true, `Load MSSQL extension first on startup`));
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
return this._defaultHandleEagerExtensions();
|
||||
}
|
||||
|
||||
|
||||
// Handle "eager" activation extensions
|
||||
private _defaultHandleEagerExtensions(): Promise<void> {
|
||||
this._activateByEvent('*', true).then(undefined, (err) => {
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
this._disposables.add(this._extHostWorkspace.onDidChangeWorkspace((e) => this._handleWorkspaceContainsEagerExtensions(e.added)));
|
||||
const folders = this._extHostWorkspace.workspace ? this._extHostWorkspace.workspace.folders : [];
|
||||
return this._handleWorkspaceContainsEagerExtensions(folders);
|
||||
}
|
||||
|
||||
private _handleWorkspaceContainsEagerExtensions(folders: ReadonlyArray<vscode.WorkspaceFolder>): Promise<void> {
|
||||
if (folders.length === 0) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
return Promise.all(
|
||||
this._registry.getAllExtensionDescriptions().map((desc) => {
|
||||
return this._handleWorkspaceContainsEagerExtension(folders, desc);
|
||||
})
|
||||
).then(() => { });
|
||||
}
|
||||
|
||||
private _handleWorkspaceContainsEagerExtension(folders: ReadonlyArray<vscode.WorkspaceFolder>, desc: IExtensionDescription): Promise<void> {
|
||||
const activationEvents = desc.activationEvents;
|
||||
if (!activationEvents) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
if (this.isActivated(desc.identifier)) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
const fileNames: string[] = [];
|
||||
const globPatterns: string[] = [];
|
||||
|
||||
for (const activationEvent of activationEvents) {
|
||||
if (/^workspaceContains:/.test(activationEvent)) {
|
||||
const fileNameOrGlob = activationEvent.substr('workspaceContains:'.length);
|
||||
if (fileNameOrGlob.indexOf('*') >= 0 || fileNameOrGlob.indexOf('?') >= 0) {
|
||||
globPatterns.push(fileNameOrGlob);
|
||||
} else {
|
||||
fileNames.push(fileNameOrGlob);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fileNames.length === 0 && globPatterns.length === 0) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
const fileNamePromise = Promise.all(fileNames.map((fileName) => this._activateIfFileName(folders, desc.identifier, fileName))).then(() => { });
|
||||
const globPatternPromise = this._activateIfGlobPatterns(folders, desc.identifier, globPatterns);
|
||||
|
||||
return Promise.all([fileNamePromise, globPatternPromise]).then(() => { });
|
||||
}
|
||||
|
||||
private async _activateIfFileName(folders: ReadonlyArray<vscode.WorkspaceFolder>, extensionId: ExtensionIdentifier, fileName: string): Promise<void> {
|
||||
|
||||
// find exact path
|
||||
for (const { uri } of folders) {
|
||||
if (await this._hostUtils.exists(path.join(URI.revive(uri).fsPath, fileName))) {
|
||||
// the file was found
|
||||
return (
|
||||
this._activateById(extensionId, new ExtensionActivatedByEvent(true, `workspaceContains:${fileName}`))
|
||||
.then(undefined, err => console.error(err))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private async _activateIfGlobPatterns(folders: ReadonlyArray<vscode.WorkspaceFolder>, extensionId: ExtensionIdentifier, globPatterns: string[]): Promise<void> {
|
||||
this._extHostLogService.trace(`extensionHostMain#activateIfGlobPatterns: fileSearch, extension: ${extensionId.value}, entryPoint: workspaceContains`);
|
||||
|
||||
if (globPatterns.length === 0) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
const tokenSource = new CancellationTokenSource();
|
||||
const searchP = this._mainThreadWorkspaceProxy.$checkExists(folders.map(folder => folder.uri), globPatterns, tokenSource.token);
|
||||
|
||||
const timer = setTimeout(async () => {
|
||||
tokenSource.cancel();
|
||||
this._activateById(extensionId, new ExtensionActivatedByEvent(true, `workspaceContainsTimeout:${globPatterns.join(',')}`))
|
||||
.then(undefined, err => console.error(err));
|
||||
}, ExtHostExtensionService.WORKSPACE_CONTAINS_TIMEOUT);
|
||||
|
||||
let exists: boolean = false;
|
||||
try {
|
||||
exists = await searchP;
|
||||
} catch (err) {
|
||||
if (!errors.isPromiseCanceledError(err)) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
tokenSource.dispose();
|
||||
clearTimeout(timer);
|
||||
|
||||
if (exists) {
|
||||
// a file was found matching one of the glob patterns
|
||||
return (
|
||||
this._activateById(extensionId, new ExtensionActivatedByEvent(true, `workspaceContains:${globPatterns.join(',')}`))
|
||||
.then(undefined, err => console.error(err))
|
||||
);
|
||||
}
|
||||
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
private _handleExtensionTests(): Promise<void> {
|
||||
return this._doHandleExtensionTests().then(undefined, error => {
|
||||
console.error(error); // ensure any error message makes it onto the console
|
||||
|
||||
return Promise.reject(error);
|
||||
});
|
||||
}
|
||||
|
||||
private _doHandleExtensionTests(): Promise<void> {
|
||||
const { extensionDevelopmentLocationURI: extensionDevelopmentLocationURI, extensionTestsLocationURI } = this._initData.environment;
|
||||
if (!(extensionDevelopmentLocationURI && extensionTestsLocationURI && extensionTestsLocationURI.scheme === Schemas.file)) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
const extensionTestsPath = originalFSPath(extensionTestsLocationURI);
|
||||
|
||||
// Require the test runner via node require from the provided path
|
||||
let testRunner: ITestRunner | INewTestRunner | undefined;
|
||||
let requireError: Error | undefined;
|
||||
try {
|
||||
testRunner = <any>require.__$__nodeRequire(extensionTestsPath);
|
||||
} catch (error) {
|
||||
requireError = error;
|
||||
}
|
||||
|
||||
// Execute the runner if it follows the old `run` spec
|
||||
if (testRunner && typeof testRunner.run === 'function') {
|
||||
return new Promise<void>((c, e) => {
|
||||
const oldTestRunnerCallback = (error: Error, failures: number | undefined) => {
|
||||
if (error) {
|
||||
e(error.toString());
|
||||
} else {
|
||||
c(undefined);
|
||||
}
|
||||
|
||||
// after tests have run, we shutdown the host
|
||||
this._gracefulExit(error || (typeof failures === 'number' && failures > 0) ? 1 /* ERROR */ : 0 /* OK */);
|
||||
};
|
||||
|
||||
const runResult = testRunner!.run(extensionTestsPath, oldTestRunnerCallback);
|
||||
|
||||
// Using the new API `run(): Promise<void>`
|
||||
if (runResult && runResult.then) {
|
||||
runResult
|
||||
.then(() => {
|
||||
c();
|
||||
this._gracefulExit(0);
|
||||
})
|
||||
.catch((err: Error) => {
|
||||
e(err.toString());
|
||||
this._gracefulExit(1);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Otherwise make sure to shutdown anyway even in case of an error
|
||||
else {
|
||||
this._gracefulExit(1 /* ERROR */);
|
||||
}
|
||||
|
||||
return Promise.reject(new Error(requireError ? requireError.toString() : nls.localize('extensionTestError', "Path {0} does not point to a valid extension test runner.", extensionTestsPath)));
|
||||
}
|
||||
|
||||
private _gracefulExit(code: number): void {
|
||||
// to give the PH process a chance to flush any outstanding console
|
||||
// messages to the main process, we delay the exit() by some time
|
||||
setTimeout(() => {
|
||||
// If extension tests are running, give the exit code to the renderer
|
||||
if (this._initData.remote.isRemote && !!this._initData.environment.extensionTestsLocationURI) {
|
||||
this._mainThreadExtensionsProxy.$onExtensionHostExit(code);
|
||||
return;
|
||||
}
|
||||
|
||||
this._hostUtils.exit(code);
|
||||
}, 500);
|
||||
}
|
||||
|
||||
private _startExtensionHost(): Promise<void> {
|
||||
if (this._started) {
|
||||
throw new Error(`Extension host is already started!`);
|
||||
}
|
||||
this._started = true;
|
||||
|
||||
return this._readyToStartExtensionHost.wait()
|
||||
.then(() => this._readyToRunExtensions.open())
|
||||
.then(() => this._handleEagerExtensions())
|
||||
.then(() => this._handleExtensionTests())
|
||||
.then(() => {
|
||||
this._extHostLogService.info(`eager extensions activated`);
|
||||
});
|
||||
}
|
||||
|
||||
// -- called by extensions
|
||||
|
||||
public registerRemoteAuthorityResolver(authorityPrefix: string, resolver: vscode.RemoteAuthorityResolver): vscode.Disposable {
|
||||
this._resolvers[authorityPrefix] = resolver;
|
||||
return toDisposable(() => {
|
||||
delete this._resolvers[authorityPrefix];
|
||||
});
|
||||
}
|
||||
|
||||
// -- called by main thread
|
||||
|
||||
public async $resolveAuthority(remoteAuthority: string, resolveAttempt: number): Promise<IResolveAuthorityResult> {
|
||||
const authorityPlusIndex = remoteAuthority.indexOf('+');
|
||||
if (authorityPlusIndex === -1) {
|
||||
throw new Error(`Not an authority that can be resolved!`);
|
||||
}
|
||||
const authorityPrefix = remoteAuthority.substr(0, authorityPlusIndex);
|
||||
|
||||
await this._almostReadyToRunExtensions.wait();
|
||||
await this._activateByEvent(`onResolveRemoteAuthority:${authorityPrefix}`, false);
|
||||
|
||||
const resolver = this._resolvers[authorityPrefix];
|
||||
if (!resolver) {
|
||||
throw new Error(`No remote extension installed to resolve ${authorityPrefix}.`);
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await resolver.resolve(remoteAuthority, { resolveAttempt });
|
||||
|
||||
// Split merged API result into separate authority/options
|
||||
const authority: ResolvedAuthority = {
|
||||
authority: remoteAuthority,
|
||||
host: result.host,
|
||||
port: result.port
|
||||
};
|
||||
const options: ResolvedOptions = {
|
||||
extensionHostEnv: result.extensionHostEnv
|
||||
};
|
||||
|
||||
return {
|
||||
type: 'ok',
|
||||
value: {
|
||||
authority,
|
||||
options
|
||||
}
|
||||
};
|
||||
} catch (err) {
|
||||
if (err instanceof RemoteAuthorityResolverError) {
|
||||
return {
|
||||
type: 'error',
|
||||
error: {
|
||||
code: err._code,
|
||||
message: err._message,
|
||||
detail: err._detail
|
||||
}
|
||||
};
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
public $startExtensionHost(enabledExtensionIds: ExtensionIdentifier[]): Promise<void> {
|
||||
this._registry.keepOnly(enabledExtensionIds);
|
||||
return this._startExtensionHost();
|
||||
}
|
||||
|
||||
public $activateByEvent(activationEvent: string): Promise<void> {
|
||||
return (
|
||||
this._readyToRunExtensions.wait()
|
||||
.then(_ => this._activateByEvent(activationEvent, false))
|
||||
);
|
||||
}
|
||||
|
||||
public async $activate(extensionId: ExtensionIdentifier, activationEvent: string): Promise<boolean> {
|
||||
await this._readyToRunExtensions.wait();
|
||||
if (!this._registry.getExtensionDescription(extensionId)) {
|
||||
// unknown extension => ignore
|
||||
return false;
|
||||
}
|
||||
await this._activateById(extensionId, new ExtensionActivatedByEvent(false, activationEvent));
|
||||
return true;
|
||||
}
|
||||
|
||||
public async $deltaExtensions(toAdd: IExtensionDescription[], toRemove: ExtensionIdentifier[]): Promise<void> {
|
||||
toAdd.forEach((extension) => (<any>extension).extensionLocation = URI.revive(extension.extensionLocation));
|
||||
|
||||
const trie = await this.getExtensionPathIndex();
|
||||
|
||||
await Promise.all(toRemove.map(async (extensionId) => {
|
||||
const extensionDescription = this._registry.getExtensionDescription(extensionId);
|
||||
if (!extensionDescription) {
|
||||
return;
|
||||
}
|
||||
const realpathValue = await this._hostUtils.realpath(extensionDescription.extensionLocation.fsPath);
|
||||
trie.delete(URI.file(realpathValue).fsPath);
|
||||
}));
|
||||
|
||||
await Promise.all(toAdd.map(async (extensionDescription) => {
|
||||
const realpathValue = await this._hostUtils.realpath(extensionDescription.extensionLocation.fsPath);
|
||||
trie.set(URI.file(realpathValue).fsPath, extensionDescription);
|
||||
}));
|
||||
|
||||
this._registry.deltaExtensions(toAdd, toRemove);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
public async $test_latency(n: number): Promise<number> {
|
||||
return n;
|
||||
}
|
||||
|
||||
public async $test_up(b: VSBuffer): Promise<number> {
|
||||
return b.byteLength;
|
||||
}
|
||||
|
||||
public async $test_down(size: number): Promise<VSBuffer> {
|
||||
let buff = VSBuffer.alloc(size);
|
||||
let value = Math.random() % 256;
|
||||
for (let i = 0; i < size; i++) {
|
||||
buff.writeUInt8(value, i);
|
||||
}
|
||||
return buff;
|
||||
return Promise.resolve(r);
|
||||
}
|
||||
|
||||
public async $setRemoteEnvironment(env: { [key: string]: string | null }): Promise<void> {
|
||||
@@ -782,44 +77,3 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function loadCommonJSModule<T>(logService: ILogService, modulePath: string, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<T> {
|
||||
let r: T | null = null;
|
||||
activationTimesBuilder.codeLoadingStart();
|
||||
logService.info(`ExtensionService#loadCommonJSModule ${modulePath}`);
|
||||
try {
|
||||
r = require.__$__nodeRequire<T>(modulePath);
|
||||
} catch (e) {
|
||||
return Promise.reject(e);
|
||||
} finally {
|
||||
activationTimesBuilder.codeLoadingStop();
|
||||
}
|
||||
return Promise.resolve(r);
|
||||
}
|
||||
|
||||
type TelemetryActivationEvent = {
|
||||
id: string;
|
||||
name: string;
|
||||
extensionVersion: string;
|
||||
publisherDisplayName: string;
|
||||
activationEvents: string | null;
|
||||
isBuiltin: boolean;
|
||||
reason: string;
|
||||
};
|
||||
|
||||
function getTelemetryActivationEvent(extensionDescription: IExtensionDescription, reason: ExtensionActivationReason): TelemetryActivationEvent {
|
||||
const reasonStr = reason instanceof ExtensionActivatedByEvent ? reason.activationEvent :
|
||||
reason instanceof ExtensionActivatedByAPI ? 'api' :
|
||||
'';
|
||||
const event = {
|
||||
id: extensionDescription.identifier.value,
|
||||
name: extensionDescription.name,
|
||||
extensionVersion: extensionDescription.version,
|
||||
publisherDisplayName: extensionDescription.publisher,
|
||||
activationEvents: extensionDescription.activationEvents ? extensionDescription.activationEvents.join(',') : null,
|
||||
isBuiltin: extensionDescription.isBuiltin,
|
||||
reason: reasonStr
|
||||
};
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,9 @@ import { join } from 'vs/base/common/path';
|
||||
import { OutputAppender } from 'vs/workbench/services/output/node/outputAppender';
|
||||
import { toLocalISOString } from 'vs/base/common/date';
|
||||
import { dirExists, mkdirp } from 'vs/base/node/pfs';
|
||||
import { AbstractExtHostOutputChannel, IOutputChannelFactory, ExtHostPushOutputChannel } from 'vs/workbench/api/common/extHostOutput';
|
||||
import { AbstractExtHostOutputChannel, ExtHostPushOutputChannel, ExtHostOutputService, LazyOutputChannel } from 'vs/workbench/api/common/extHostOutput';
|
||||
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
|
||||
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
|
||||
export class ExtHostOutputChannelBackedByFile extends AbstractExtHostOutputChannel {
|
||||
|
||||
@@ -43,23 +45,39 @@ export class ExtHostOutputChannelBackedByFile extends AbstractExtHostOutputChann
|
||||
}
|
||||
}
|
||||
|
||||
export const LogOutputChannelFactory = new class implements IOutputChannelFactory {
|
||||
export class ExtHostOutputService2 extends ExtHostOutputService {
|
||||
|
||||
_namePool = 1;
|
||||
private _logsLocation: URI;
|
||||
private _namePool: number = 1;
|
||||
|
||||
async createOutputChannel(name: string, logsLocation: URI, proxy: MainThreadOutputServiceShape): Promise<AbstractExtHostOutputChannel> {
|
||||
constructor(
|
||||
@IExtHostRpcService extHostRpc: IExtHostRpcService,
|
||||
@IExtHostInitDataService initData: IExtHostInitDataService,
|
||||
) {
|
||||
super(extHostRpc);
|
||||
this._logsLocation = initData.logsLocation;
|
||||
}
|
||||
|
||||
createOutputChannel(name: string): vscode.OutputChannel {
|
||||
name = name.trim();
|
||||
if (!name) {
|
||||
throw new Error('illegal argument `name`. must not be falsy');
|
||||
}
|
||||
return new LazyOutputChannel(name, this._doCreateOutChannel(name));
|
||||
}
|
||||
|
||||
private async _doCreateOutChannel(name: string): Promise<AbstractExtHostOutputChannel> {
|
||||
try {
|
||||
const outputDirPath = join(logsLocation.fsPath, `output_logging_${toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')}`);
|
||||
const outputDir = await dirExists(outputDirPath).then(exists => exists ? exists : mkdirp(outputDirPath).then(() => true)).then(() => outputDirPath);
|
||||
const outputDirPath = join(this._logsLocation.fsPath, `output_logging_${toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')}`);
|
||||
const outputDir = await dirExists(outputDirPath).then(exists => exists || mkdirp(outputDirPath).then(() => true)).then(() => outputDirPath);
|
||||
const fileName = `${this._namePool++}-${name.replace(/[\\/:\*\?"<>\|]/g, '')}`;
|
||||
const file = URI.file(join(outputDir, `${fileName}.log`));
|
||||
const appender = new OutputAppender(fileName, file.fsPath);
|
||||
return new ExtHostOutputChannelBackedByFile(name, appender, proxy);
|
||||
return new ExtHostOutputChannelBackedByFile(name, appender, this._proxy);
|
||||
} catch (error) {
|
||||
// Do not crash if logger cannot be created
|
||||
console.log(error);
|
||||
return new ExtHostPushOutputChannel(name, proxy);
|
||||
return new ExtHostPushOutputChannel(name, this._proxy);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/c
|
||||
import * as vscode from 'vscode';
|
||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { endsWith } from 'vs/base/common/strings';
|
||||
import { IExtensionApiFactory } from 'vs/workbench/api/node/extHost.api.impl';
|
||||
import { IExtensionApiFactory } from 'vs/workbench/api/common/extHost.api.impl';
|
||||
|
||||
|
||||
interface LoadFunction {
|
||||
@@ -75,7 +75,7 @@ export class VSCodeNodeModuleFactory implements INodeModuleFactory {
|
||||
public readonly nodeModuleName = 'vscode';
|
||||
|
||||
private readonly _extApiImpl = new Map<string, typeof vscode>();
|
||||
private _defaultApiImpl: typeof vscode;
|
||||
private _defaultApiImpl?: typeof vscode;
|
||||
|
||||
constructor(
|
||||
private readonly _apiFactory: IExtensionApiFactory,
|
||||
@@ -191,7 +191,7 @@ export class OpenNodeModuleFactory implements INodeModuleFactory {
|
||||
public readonly nodeModuleName: string[] = ['open', 'opn'];
|
||||
|
||||
private _extensionId: string | undefined;
|
||||
private _original: IOriginalOpen;
|
||||
private _original?: IOriginalOpen;
|
||||
private _impl: IOpenModule;
|
||||
|
||||
constructor(mainThreadWindow: MainThreadWindowShape, private _mainThreadTelemerty: MainThreadTelemetryShape, private readonly _extensionPaths: TernarySearchTree<IExtensionDescription>) {
|
||||
@@ -224,7 +224,7 @@ export class OpenNodeModuleFactory implements INodeModuleFactory {
|
||||
|
||||
private callOriginal(target: string, options: OpenOptions | undefined): Thenable<any> {
|
||||
this.sendNoForwardTelemetry();
|
||||
return this._original(target, options);
|
||||
return this._original!(target, options);
|
||||
}
|
||||
|
||||
private sendShimmingTelemetry(): void {
|
||||
|
||||
@@ -15,8 +15,10 @@ import { RipgrepSearchProvider } from 'vs/workbench/services/search/node/ripgrep
|
||||
import { OutputChannel } from 'vs/workbench/services/search/node/ripgrepSearchUtils';
|
||||
import { TextSearchManager } from 'vs/workbench/services/search/node/textSearchManager';
|
||||
import * as vscode from 'vscode';
|
||||
import { ExtHostSearchShape, IMainContext, MainContext, MainThreadSearchShape } from '../common/extHost.protocol';
|
||||
import { IURITransformer } from 'vs/base/common/uriIpc';
|
||||
import { ExtHostSearchShape, MainContext, MainThreadSearchShape } from '../common/extHost.protocol';
|
||||
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
import { IURITransformerService } from 'vs/workbench/api/common/extHostUriTransformerService';
|
||||
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
|
||||
|
||||
export class ExtHostSearch implements ExtHostSearchShape {
|
||||
|
||||
@@ -32,16 +34,30 @@ export class ExtHostSearch implements ExtHostSearchShape {
|
||||
|
||||
private _fileSearchManager: FileSearchManager;
|
||||
|
||||
constructor(mainContext: IMainContext, private _uriTransformer: IURITransformer | null, private _logService: ILogService, private _pfs = pfs) {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadSearch);
|
||||
protected _pfs: typeof pfs = pfs; // allow extending for tests
|
||||
|
||||
constructor(
|
||||
@IExtHostRpcService extHostRpc: IExtHostRpcService,
|
||||
@IExtHostInitDataService initData: IExtHostInitDataService,
|
||||
@IURITransformerService private _uriTransformer: IURITransformerService,
|
||||
@ILogService private _logService: ILogService,
|
||||
) {
|
||||
this._proxy = extHostRpc.getProxy(MainContext.MainThreadSearch);
|
||||
this._fileSearchManager = new FileSearchManager();
|
||||
|
||||
if (initData.remote.isRemote && initData.remote.authority) {
|
||||
this._registerEHSearchProviders();
|
||||
}
|
||||
}
|
||||
|
||||
private _registerEHSearchProviders(): void {
|
||||
const outputChannel = new OutputChannel(this._logService);
|
||||
this.registerTextSearchProvider('file', new RipgrepSearchProvider(outputChannel));
|
||||
this.registerInternalFileSearchProvider('file', new SearchService());
|
||||
}
|
||||
|
||||
private _transformScheme(scheme: string): string {
|
||||
if (this._uriTransformer) {
|
||||
return this._uriTransformer.transformOutgoingScheme(scheme);
|
||||
}
|
||||
return scheme;
|
||||
return this._uriTransformer.transformOutgoingScheme(scheme);
|
||||
}
|
||||
|
||||
registerTextSearchProvider(scheme: string, provider: vscode.TextSearchProvider): IDisposable {
|
||||
@@ -148,12 +164,6 @@ export class ExtHostSearch implements ExtHostSearchShape {
|
||||
}
|
||||
}
|
||||
|
||||
export function registerEHSearchProviders(extHostSearch: ExtHostSearch, logService: ILogService): void {
|
||||
const outputChannel = new OutputChannel(logService);
|
||||
extHostSearch.registerTextSearchProvider('file', new RipgrepSearchProvider(outputChannel));
|
||||
extHostSearch.registerInternalFileSearchProvider('file', new SearchService());
|
||||
}
|
||||
|
||||
function reviveQuery<U extends IRawQuery>(rawQuery: U): U extends IRawTextQuery ? ITextQuery : IFileQuery {
|
||||
return {
|
||||
...<any>rawQuery, // TODO
|
||||
|
||||
@@ -8,23 +8,24 @@ import { URI } from 'vs/base/common/uri';
|
||||
import * as pfs from 'vs/base/node/pfs';
|
||||
import { IEnvironment, IStaticWorkspaceData } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
|
||||
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
|
||||
export class ExtensionStoragePaths {
|
||||
export class ExtensionStoragePaths implements IExtensionStoragePaths {
|
||||
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
private readonly _workspace?: IStaticWorkspaceData;
|
||||
private readonly _environment: IEnvironment;
|
||||
|
||||
private readonly _ready: Promise<string | undefined>;
|
||||
readonly whenReady: Promise<string | undefined>;
|
||||
private _value?: string;
|
||||
|
||||
constructor(workspace: IStaticWorkspaceData | undefined, environment: IEnvironment) {
|
||||
this._workspace = workspace;
|
||||
this._environment = environment;
|
||||
this._ready = this._getOrCreateWorkspaceStoragePath().then(value => this._value = value);
|
||||
}
|
||||
|
||||
get whenReady(): Promise<any> {
|
||||
return this._ready;
|
||||
constructor(@IExtHostInitDataService initData: IExtHostInitDataService) {
|
||||
this._workspace = withNullAsUndefined(initData.workspace);
|
||||
this._environment = initData.environment;
|
||||
this.whenReady = this._getOrCreateWorkspaceStoragePath().then(value => this._value = value);
|
||||
}
|
||||
|
||||
workspaceValue(extension: IExtensionDescription): string | undefined {
|
||||
|
||||
@@ -12,28 +12,28 @@ import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { win32 } from 'vs/base/node/processes';
|
||||
|
||||
|
||||
import { MainContext, MainThreadTaskShape, ExtHostTaskShape, IMainContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { MainContext, MainThreadTaskShape, ExtHostTaskShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
|
||||
import * as types from 'vs/workbench/api/common/extHostTypes';
|
||||
import { ExtHostWorkspace, IExtHostWorkspaceProvider } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import { IExtHostWorkspaceProvider, IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import * as vscode from 'vscode';
|
||||
import {
|
||||
TaskDefinitionDTO, TaskExecutionDTO, TaskPresentationOptionsDTO,
|
||||
ProcessExecutionOptionsDTO, ProcessExecutionDTO,
|
||||
ShellExecutionOptionsDTO, ShellExecutionDTO,
|
||||
CustomExecutionDTO,
|
||||
CustomExecution2DTO,
|
||||
TaskDTO, TaskHandleDTO, TaskFilterDTO, TaskProcessStartedDTO, TaskProcessEndedDTO, TaskSystemInfoDTO, TaskSetDTO
|
||||
} from '../common/shared/tasks';
|
||||
// {{SQL CARBON EDIT}}
|
||||
// import { ExtHostVariableResolverService } from 'vs/workbench/api/node/extHostDebugService';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { ExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
|
||||
import { ExtHostTerminalService, ExtHostTerminal } from 'vs/workbench/api/node/extHostTerminalService';
|
||||
import { ExtHostVariableResolverService } from 'vs/workbench/api/node/extHostDebugService';
|
||||
import { IExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { IExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
|
||||
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { IExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService';
|
||||
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
|
||||
namespace TaskDefinitionDTO {
|
||||
export function from(value: vscode.TaskDefinition): TaskDefinitionDTO | undefined {
|
||||
@@ -81,7 +81,7 @@ namespace ProcessExecutionOptionsDTO {
|
||||
}
|
||||
|
||||
namespace ProcessExecutionDTO {
|
||||
export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO | CustomExecution2DTO | undefined): value is ProcessExecutionDTO {
|
||||
export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecution2DTO | undefined): value is ProcessExecutionDTO {
|
||||
if (value) {
|
||||
const candidate = value as ProcessExecutionDTO;
|
||||
return candidate && !!candidate.process;
|
||||
@@ -126,7 +126,7 @@ namespace ShellExecutionOptionsDTO {
|
||||
}
|
||||
|
||||
namespace ShellExecutionDTO {
|
||||
export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO | CustomExecution2DTO | undefined): value is ShellExecutionDTO {
|
||||
export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecution2DTO | undefined): value is ShellExecutionDTO {
|
||||
if (value) {
|
||||
const candidate = value as ShellExecutionDTO;
|
||||
return candidate && (!!candidate.commandLine || !!candidate.command);
|
||||
@@ -163,25 +163,8 @@ namespace ShellExecutionDTO {
|
||||
}
|
||||
}
|
||||
|
||||
namespace CustomExecutionDTO {
|
||||
export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO | CustomExecution2DTO | undefined): value is CustomExecutionDTO {
|
||||
if (value) {
|
||||
let candidate = value as CustomExecutionDTO;
|
||||
return candidate && candidate.customExecution === 'customExecution';
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function from(value: vscode.CustomExecution): CustomExecutionDTO {
|
||||
return {
|
||||
customExecution: 'customExecution'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
namespace CustomExecution2DTO {
|
||||
export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO | CustomExecution2DTO | undefined): value is CustomExecution2DTO {
|
||||
export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecution2DTO | undefined): value is CustomExecution2DTO {
|
||||
if (value) {
|
||||
let candidate = value as CustomExecution2DTO;
|
||||
return candidate && candidate.customExecution === 'customExecution2';
|
||||
@@ -230,13 +213,11 @@ namespace TaskDTO {
|
||||
if (value === undefined || value === null) {
|
||||
return undefined;
|
||||
}
|
||||
let execution: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO | CustomExecution2DTO | undefined;
|
||||
let execution: ShellExecutionDTO | ProcessExecutionDTO | CustomExecution2DTO | undefined;
|
||||
if (value.execution instanceof types.ProcessExecution) {
|
||||
execution = ProcessExecutionDTO.from(value.execution);
|
||||
} else if (value.execution instanceof types.ShellExecution) {
|
||||
execution = ShellExecutionDTO.from(value.execution);
|
||||
} else if ((<vscode.Task2>value).execution2 && (<vscode.Task2>value).execution2 instanceof types.CustomExecution) {
|
||||
execution = CustomExecutionDTO.from(<types.CustomExecution>(<vscode.Task2>value).execution2);
|
||||
} else if ((<vscode.Task2>value).execution2 && (<vscode.Task2>value).execution2 instanceof types.CustomExecution2) {
|
||||
execution = CustomExecution2DTO.from(<types.CustomExecution2>(<vscode.Task2>value).execution2);
|
||||
}
|
||||
@@ -374,122 +355,18 @@ interface HandlerData {
|
||||
extension: IExtensionDescription;
|
||||
}
|
||||
|
||||
class CustomExecutionData implements IDisposable {
|
||||
private static waitForDimensionsTimeoutInMs: number = 5000;
|
||||
private _cancellationSource?: CancellationTokenSource;
|
||||
private readonly _onTaskExecutionComplete: Emitter<CustomExecutionData> = new Emitter<CustomExecutionData>();
|
||||
private readonly _disposables = new DisposableStore();
|
||||
private terminal?: vscode.Terminal;
|
||||
private terminalId?: number;
|
||||
public result: number | undefined;
|
||||
|
||||
constructor(
|
||||
private readonly customExecution: vscode.CustomExecution,
|
||||
private readonly terminalService: ExtHostTerminalService) {
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._cancellationSource = undefined;
|
||||
this._disposables.dispose();
|
||||
}
|
||||
|
||||
public get onTaskExecutionComplete(): Event<CustomExecutionData> {
|
||||
return this._onTaskExecutionComplete.event;
|
||||
}
|
||||
|
||||
private onDidCloseTerminal(terminal: vscode.Terminal): void {
|
||||
if ((this.terminal === terminal) && this._cancellationSource) {
|
||||
this._cancellationSource.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
private onDidOpenTerminal(terminal: vscode.Terminal): void {
|
||||
if (!(terminal instanceof ExtHostTerminal)) {
|
||||
throw new Error('How could this not be a extension host terminal?');
|
||||
}
|
||||
|
||||
if (this.terminalId && terminal._id === this.terminalId) {
|
||||
this.startCallback(this.terminalId);
|
||||
}
|
||||
}
|
||||
|
||||
public async startCallback(terminalId: number): Promise<void> {
|
||||
this.terminalId = terminalId;
|
||||
|
||||
// If we have already started the extension task callback, then
|
||||
// do not start it again.
|
||||
// It is completely valid for multiple terminals to be opened
|
||||
// before the one for our task.
|
||||
if (this._cancellationSource) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const callbackTerminals: vscode.Terminal[] = this.terminalService.terminals.filter((terminal) => terminal._id === terminalId);
|
||||
|
||||
if (!callbackTerminals || callbackTerminals.length === 0) {
|
||||
this._disposables.add(this.terminalService.onDidOpenTerminal(this.onDidOpenTerminal.bind(this)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (callbackTerminals.length !== 1) {
|
||||
throw new Error(`Expected to only have one terminal at this point`);
|
||||
}
|
||||
|
||||
this.terminal = callbackTerminals[0];
|
||||
const terminalRenderer: vscode.TerminalRenderer = await this.terminalService.resolveTerminalRenderer(terminalId);
|
||||
|
||||
// If we don't have the maximum dimensions yet, then we need to wait for them (but not indefinitely).
|
||||
// Custom executions will expect the dimensions to be set properly before they are launched.
|
||||
// BUT, due to the API contract VSCode has for terminals and dimensions, they are still responsible for
|
||||
// handling cases where they are not set.
|
||||
if (!terminalRenderer.maximumDimensions) {
|
||||
const dimensionTimeout: Promise<void> = new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve();
|
||||
}, CustomExecutionData.waitForDimensionsTimeoutInMs);
|
||||
});
|
||||
|
||||
let dimensionsRegistration: IDisposable | undefined;
|
||||
const dimensionsPromise: Promise<void> = new Promise((resolve) => {
|
||||
dimensionsRegistration = terminalRenderer.onDidChangeMaximumDimensions((newDimensions) => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
await Promise.race([dimensionTimeout, dimensionsPromise]);
|
||||
if (dimensionsRegistration) {
|
||||
dimensionsRegistration.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
this._cancellationSource = new CancellationTokenSource();
|
||||
this._disposables.add(this._cancellationSource);
|
||||
|
||||
this._disposables.add(this.terminalService.onDidCloseTerminal(this.onDidCloseTerminal.bind(this)));
|
||||
|
||||
// Regardless of how the task completes, we are done with this custom execution task.
|
||||
this.customExecution.callback(terminalRenderer, this._cancellationSource.token).then(
|
||||
(success) => {
|
||||
this.result = success;
|
||||
this._onTaskExecutionComplete.fire(this);
|
||||
}, (rejected) => {
|
||||
this._onTaskExecutionComplete.fire(this);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostTask implements ExtHostTaskShape {
|
||||
|
||||
private _proxy: MainThreadTaskShape;
|
||||
private _workspaceProvider: IExtHostWorkspaceProvider;
|
||||
private _editorService: ExtHostDocumentsAndEditors;
|
||||
private _configurationService: ExtHostConfiguration;
|
||||
private _terminalService: ExtHostTerminalService;
|
||||
readonly _serviceBrand: any;
|
||||
|
||||
private readonly _proxy: MainThreadTaskShape;
|
||||
private readonly _workspaceProvider: IExtHostWorkspaceProvider;
|
||||
private readonly _editorService: IExtHostDocumentsAndEditors;
|
||||
private readonly _configurationService: IExtHostConfiguration;
|
||||
private readonly _terminalService: IExtHostTerminalService;
|
||||
private _handleCounter: number;
|
||||
private _handlers: Map<number, HandlerData>;
|
||||
private _taskExecutions: Map<string, TaskExecutionImpl>;
|
||||
private _providedCustomExecutions: Map<string, CustomExecutionData>;
|
||||
private _activeCustomExecutions: Map<string, CustomExecutionData>;
|
||||
private _providedCustomExecutions2: Map<string, vscode.CustomExecution2>;
|
||||
private _activeCustomExecutions2: Map<string, vscode.CustomExecution2>;
|
||||
|
||||
@@ -500,12 +377,14 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
private readonly _onDidTaskProcessEnded: Emitter<vscode.TaskProcessEndEvent> = new Emitter<vscode.TaskProcessEndEvent>();
|
||||
|
||||
constructor(
|
||||
mainContext: IMainContext,
|
||||
workspaceService: ExtHostWorkspace,
|
||||
editorService: ExtHostDocumentsAndEditors,
|
||||
configurationService: ExtHostConfiguration,
|
||||
extHostTerminalService: ExtHostTerminalService) {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadTask);
|
||||
@IExtHostRpcService extHostRpc: IExtHostRpcService,
|
||||
@IExtHostInitDataService initData: IExtHostInitDataService,
|
||||
@IExtHostWorkspace workspaceService: IExtHostWorkspace,
|
||||
@IExtHostDocumentsAndEditors editorService: IExtHostDocumentsAndEditors,
|
||||
@IExtHostConfiguration configurationService: IExtHostConfiguration,
|
||||
@IExtHostTerminalService extHostTerminalService: IExtHostTerminalService
|
||||
) {
|
||||
this._proxy = extHostRpc.getProxy(MainContext.MainThreadTask);
|
||||
this._workspaceProvider = workspaceService;
|
||||
this._editorService = editorService;
|
||||
this._configurationService = configurationService;
|
||||
@@ -513,10 +392,16 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
this._handleCounter = 0;
|
||||
this._handlers = new Map<number, HandlerData>();
|
||||
this._taskExecutions = new Map<string, TaskExecutionImpl>();
|
||||
this._providedCustomExecutions = new Map<string, CustomExecutionData>();
|
||||
this._activeCustomExecutions = new Map<string, CustomExecutionData>();
|
||||
this._providedCustomExecutions2 = new Map<string, vscode.CustomExecution2>();
|
||||
this._activeCustomExecutions2 = new Map<string, vscode.CustomExecution2>();
|
||||
|
||||
if (initData.remote.isRemote && initData.remote.authority) {
|
||||
this.registerTaskSystem(Schemas.vscodeRemote, {
|
||||
scheme: Schemas.vscodeRemote,
|
||||
authority: initData.remote.authority,
|
||||
platform: process.platform
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public registerTaskProvider(extension: IExtensionDescription, type: string, provider: vscode.TaskProvider): vscode.Disposable {
|
||||
@@ -589,26 +474,7 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
|
||||
// Clone the custom execution to keep the original untouched. This is important for multiple runs of the same task.
|
||||
this._activeCustomExecutions2.set(execution.id, execution2);
|
||||
await this._terminalService.attachPtyToTerminal(terminalId, await execution2.callback());
|
||||
}
|
||||
|
||||
// Once a terminal is spun up for the custom execution task this event will be fired.
|
||||
// At that point, we need to actually start the callback, but
|
||||
// only if it hasn't already begun.
|
||||
const extensionCallback: CustomExecutionData | undefined = this._providedCustomExecutions.get(execution.id);
|
||||
if (extensionCallback) {
|
||||
if (this._activeCustomExecutions.get(execution.id) !== undefined) {
|
||||
throw new Error('We should not be trying to start the same custom task executions twice.');
|
||||
}
|
||||
|
||||
this._activeCustomExecutions.set(execution.id, extensionCallback);
|
||||
|
||||
const taskExecutionComplete: IDisposable = extensionCallback.onTaskExecutionComplete(() => {
|
||||
this.customExecutionComplete(execution);
|
||||
taskExecutionComplete.dispose();
|
||||
});
|
||||
|
||||
extensionCallback.startCallback(terminalId);
|
||||
this._terminalService.attachPtyToTerminal(terminalId, await execution2.callback());
|
||||
}
|
||||
|
||||
this._onDidExecuteTask.fire({
|
||||
@@ -666,7 +532,6 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
// For custom execution tasks, we need to store the execution objects locally
|
||||
// since we obviously cannot send callback functions through the proxy.
|
||||
// So, clear out any existing ones.
|
||||
this._providedCustomExecutions.clear();
|
||||
this._providedCustomExecutions2.clear();
|
||||
|
||||
// Set up a list of task ID promises that we can wait on
|
||||
@@ -690,14 +555,11 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
if (taskDTO) {
|
||||
taskDTOs.push(taskDTO);
|
||||
|
||||
if (CustomExecutionDTO.is(taskDTO.execution)) {
|
||||
if (CustomExecution2DTO.is(taskDTO.execution)) {
|
||||
// The ID is calculated on the main thread task side, so, let's call into it here.
|
||||
// We need the task id's pre-computed for custom task executions because when OnDidStartTask
|
||||
// is invoked, we have to be able to map it back to our data.
|
||||
taskIdPromises.push(this.addCustomExecution(taskDTO, <vscode.Task2>task));
|
||||
} else if (CustomExecution2DTO.is(taskDTO.execution)) {
|
||||
taskIdPromises.push(this.addCustomExecution2(taskDTO, <vscode.Task2>task));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -747,10 +609,6 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
throw new Error('Unexpected: The resolved task definition must be the same object as the original task definition. The task definition cannot be changed.');
|
||||
}
|
||||
|
||||
if (CustomExecutionDTO.is(resolvedTaskDTO.execution)) {
|
||||
await this.addCustomExecution(resolvedTaskDTO, <vscode.Task2>resolvedTask);
|
||||
}
|
||||
|
||||
if (CustomExecution2DTO.is(resolvedTaskDTO.execution)) {
|
||||
await this.addCustomExecution2(resolvedTaskDTO, <vscode.Task2>resolvedTask);
|
||||
}
|
||||
@@ -805,11 +663,6 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
return this._handleCounter++;
|
||||
}
|
||||
|
||||
private async addCustomExecution(taskDTO: TaskDTO, task: vscode.Task2): Promise<void> {
|
||||
const taskId = await this._proxy.$createTaskId(taskDTO);
|
||||
this._providedCustomExecutions.set(taskId, new CustomExecutionData(<vscode.CustomExecution>(<vscode.Task2>task).execution2, this._terminalService));
|
||||
}
|
||||
|
||||
private async addCustomExecution2(taskDTO: TaskDTO, task: vscode.Task2): Promise<void> {
|
||||
const taskId = await this._proxy.$createTaskId(taskDTO);
|
||||
this._providedCustomExecutions2.set(taskId, <vscode.CustomExecution2>(<vscode.Task2>task).execution2);
|
||||
@@ -838,12 +691,6 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
}
|
||||
|
||||
private customExecutionComplete(execution: TaskExecutionDTO): void {
|
||||
const extensionCallback: CustomExecutionData | undefined = this._activeCustomExecutions.get(execution.id);
|
||||
if (extensionCallback) {
|
||||
this._activeCustomExecutions.delete(execution.id);
|
||||
this._proxy.$customExecutionComplete(execution.id, extensionCallback.result);
|
||||
extensionCallback.dispose();
|
||||
}
|
||||
const extensionCallback2: vscode.CustomExecution2 | undefined = this._activeCustomExecutions2.get(execution.id);
|
||||
if (extensionCallback2) {
|
||||
this._activeCustomExecutions2.delete(execution.id);
|
||||
|
||||
@@ -10,26 +10,25 @@ import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IMainContext, ShellLaunchConfigDto, IShellDefinitionDto, IShellAndArgsDto, ITerminalDimensionsDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostConfiguration, ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
|
||||
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IShellLaunchConfigDto, IShellDefinitionDto, IShellAndArgsDto, ITerminalDimensionsDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostConfiguration, ExtHostConfigProvider, IExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { EXT_HOST_CREATION_DELAY, IShellLaunchConfig, ITerminalEnvironment, ITerminalChildProcess, ITerminalDimensions } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { TerminalProcess } from 'vs/workbench/contrib/terminal/node/terminalProcess';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
import { ExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import { ExtHostWorkspace, IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { ExtHostVariableResolverService } from 'vs/workbench/api/node/extHostDebugService';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { ExtHostDocumentsAndEditors, IExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { getSystemShell, detectAvailableShells } from 'vs/workbench/contrib/terminal/node/terminal';
|
||||
import { getMainProcessParentEnv } from 'vs/workbench/contrib/terminal/node/terminalEnvironment';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
const RENDERER_NO_PROCESS_ID = -1;
|
||||
import { IExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService';
|
||||
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
|
||||
export class BaseExtHostTerminal {
|
||||
public _id: number;
|
||||
public _id: number | undefined;
|
||||
protected _idPromise: Promise<number>;
|
||||
private _idPromiseComplete: (value: number) => any;
|
||||
private _idPromiseComplete: ((value: number) => any) | undefined;
|
||||
private _disposed: boolean = false;
|
||||
private _queuedRequests: ApiRequest[] = [];
|
||||
|
||||
@@ -71,9 +70,12 @@ export class BaseExtHostTerminal {
|
||||
|
||||
public _runQueuedRequests(id: number): void {
|
||||
this._id = id;
|
||||
this._idPromiseComplete(id);
|
||||
if (this._idPromiseComplete) {
|
||||
this._idPromiseComplete(id);
|
||||
this._idPromiseComplete = undefined;
|
||||
}
|
||||
this._queuedRequests.forEach((r) => {
|
||||
r.run(this._proxy, this._id);
|
||||
r.run(this._proxy, id);
|
||||
});
|
||||
this._queuedRequests.length = 0;
|
||||
}
|
||||
@@ -82,32 +84,29 @@ export class BaseExtHostTerminal {
|
||||
export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Terminal {
|
||||
private _pidPromise: Promise<number | undefined>;
|
||||
private _cols: number | undefined;
|
||||
private _pidPromiseComplete: ((value: number | undefined) => any) | null;
|
||||
private _pidPromiseComplete: ((value: number | undefined) => any) | undefined;
|
||||
private _rows: number | undefined;
|
||||
|
||||
/** @deprecated */
|
||||
private readonly _onData = new Emitter<string>();
|
||||
/** @deprecated */
|
||||
public get onDidWriteData(): Event<string> {
|
||||
// Tell the main side to start sending data if it's not already
|
||||
this._idPromise.then(c => {
|
||||
this._proxy.$registerOnDataListener(this._id);
|
||||
this._idPromise.then(id => {
|
||||
this._proxy.$registerOnDataListener(id);
|
||||
});
|
||||
return this._onData.event;
|
||||
}
|
||||
|
||||
public isOpen: boolean = false;
|
||||
|
||||
constructor(
|
||||
proxy: MainThreadTerminalServiceShape,
|
||||
private _name?: string,
|
||||
id?: number,
|
||||
pid?: number
|
||||
id?: number
|
||||
) {
|
||||
super(proxy, id);
|
||||
this._pidPromise = new Promise<number>(c => {
|
||||
if (pid === RENDERER_NO_PROCESS_ID) {
|
||||
c(undefined);
|
||||
} else {
|
||||
this._pidPromiseComplete = c;
|
||||
}
|
||||
});
|
||||
this._pidPromise = new Promise<number>(c => this._pidPromiseComplete = c);
|
||||
}
|
||||
|
||||
public async create(
|
||||
@@ -124,10 +123,11 @@ export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Termi
|
||||
this._runQueuedRequests(terminal.id);
|
||||
}
|
||||
|
||||
public async createExtensionTerminal(): Promise<void> {
|
||||
public async createExtensionTerminal(): Promise<number> {
|
||||
const terminal = await this._proxy.$createTerminal({ name: this._name, isExtensionTerminal: true });
|
||||
this._name = terminal.name;
|
||||
this._runQueuedRequests(terminal.id);
|
||||
return terminal.id;
|
||||
}
|
||||
|
||||
public get name(): string {
|
||||
@@ -181,7 +181,7 @@ export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Termi
|
||||
// The event may fire 2 times when the panel is restored
|
||||
if (this._pidPromiseComplete) {
|
||||
this._pidPromiseComplete(processId);
|
||||
this._pidPromiseComplete = null;
|
||||
this._pidPromiseComplete = undefined;
|
||||
} else {
|
||||
// Recreate the promise if this is the nth processId set (e.g. reused task terminals)
|
||||
this._pidPromise.then(pid => {
|
||||
@@ -197,92 +197,14 @@ export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Termi
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostTerminalRenderer extends BaseExtHostTerminal implements vscode.TerminalRenderer {
|
||||
public get name(): string { return this._name; }
|
||||
public set name(newName: string) {
|
||||
this._name = newName;
|
||||
this._checkDisposed();
|
||||
this._queueApiRequest(this._proxy.$terminalRendererSetName, [this._name]);
|
||||
}
|
||||
export class ExtHostTerminalService implements IExtHostTerminalService, ExtHostTerminalServiceShape {
|
||||
|
||||
private readonly _onInput = new Emitter<string>();
|
||||
public get onDidAcceptInput(): Event<string> {
|
||||
this._checkDisposed();
|
||||
this._queueApiRequest(this._proxy.$terminalRendererRegisterOnInputListener, [this._id]);
|
||||
// Tell the main side to start sending data if it's not already
|
||||
// this._proxy.$terminalRendererRegisterOnDataListener(this._id);
|
||||
return this._onInput && this._onInput.event;
|
||||
}
|
||||
readonly _serviceBrand: any;
|
||||
|
||||
private _dimensions: vscode.TerminalDimensions | undefined;
|
||||
public get dimensions(): vscode.TerminalDimensions | undefined { return this._dimensions; }
|
||||
public set dimensions(dimensions: vscode.TerminalDimensions | undefined) {
|
||||
this._checkDisposed();
|
||||
this._dimensions = dimensions;
|
||||
this._queueApiRequest(this._proxy.$terminalRendererSetDimensions, [dimensions]);
|
||||
}
|
||||
|
||||
private _maximumDimensions: vscode.TerminalDimensions | undefined;
|
||||
public get maximumDimensions(): vscode.TerminalDimensions | undefined {
|
||||
if (!this._maximumDimensions) {
|
||||
return undefined;
|
||||
}
|
||||
return {
|
||||
rows: this._maximumDimensions.rows,
|
||||
columns: this._maximumDimensions.columns
|
||||
};
|
||||
}
|
||||
|
||||
private readonly _onDidChangeMaximumDimensions: Emitter<vscode.TerminalDimensions> = new Emitter<vscode.TerminalDimensions>();
|
||||
public get onDidChangeMaximumDimensions(): Event<vscode.TerminalDimensions> {
|
||||
return this._onDidChangeMaximumDimensions && this._onDidChangeMaximumDimensions.event;
|
||||
}
|
||||
|
||||
public get terminal(): ExtHostTerminal {
|
||||
return this._terminal;
|
||||
}
|
||||
|
||||
constructor(
|
||||
proxy: MainThreadTerminalServiceShape,
|
||||
private _name: string,
|
||||
private _terminal: ExtHostTerminal,
|
||||
id?: number
|
||||
) {
|
||||
super(proxy, id);
|
||||
|
||||
if (!id) {
|
||||
this._proxy.$createTerminalRenderer(this._name).then(id => {
|
||||
this._runQueuedRequests(id);
|
||||
(<any>this._terminal)._runQueuedRequests(id);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public write(data: string): void {
|
||||
this._checkDisposed();
|
||||
this._queueApiRequest(this._proxy.$terminalRendererWrite, [data]);
|
||||
}
|
||||
|
||||
public _fireOnInput(data: string): void {
|
||||
this._onInput.fire(data);
|
||||
}
|
||||
|
||||
public _setMaximumDimensions(columns: number, rows: number): void {
|
||||
if (this._maximumDimensions && this._maximumDimensions.columns === columns && this._maximumDimensions.rows === rows) {
|
||||
return;
|
||||
}
|
||||
const newValue = { columns, rows };
|
||||
this._maximumDimensions = newValue;
|
||||
this._onDidChangeMaximumDimensions.fire(newValue);
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
private _proxy: MainThreadTerminalServiceShape;
|
||||
private _activeTerminal: ExtHostTerminal | undefined;
|
||||
private _terminals: ExtHostTerminal[] = [];
|
||||
private _terminalProcesses: { [id: number]: ITerminalChildProcess } = {};
|
||||
private _terminalRenderers: ExtHostTerminalRenderer[] = [];
|
||||
private _getTerminalPromises: { [id: number]: Promise<ExtHostTerminal> } = {};
|
||||
private _variableResolver: ExtHostVariableResolverService | undefined;
|
||||
private _lastActiveWorkspace: IWorkspaceFolder | undefined;
|
||||
@@ -301,15 +223,21 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
public get onDidChangeActiveTerminal(): Event<vscode.Terminal | undefined> { return this._onDidChangeActiveTerminal && this._onDidChangeActiveTerminal.event; }
|
||||
private readonly _onDidChangeTerminalDimensions: Emitter<vscode.TerminalDimensionsChangeEvent> = new Emitter<vscode.TerminalDimensionsChangeEvent>();
|
||||
public get onDidChangeTerminalDimensions(): Event<vscode.TerminalDimensionsChangeEvent> { return this._onDidChangeTerminalDimensions && this._onDidChangeTerminalDimensions.event; }
|
||||
private readonly _onDidWriteTerminalData: Emitter<vscode.TerminalDataWriteEvent>;
|
||||
public get onDidWriteTerminalData(): Event<vscode.TerminalDataWriteEvent> { return this._onDidWriteTerminalData && this._onDidWriteTerminalData.event; }
|
||||
|
||||
constructor(
|
||||
mainContext: IMainContext,
|
||||
private _extHostConfiguration: ExtHostConfiguration,
|
||||
private _extHostWorkspace: ExtHostWorkspace,
|
||||
private _extHostDocumentsAndEditors: ExtHostDocumentsAndEditors,
|
||||
private _logService: ILogService
|
||||
@IExtHostRpcService extHostRpc: IExtHostRpcService,
|
||||
@IExtHostConfiguration private _extHostConfiguration: ExtHostConfiguration,
|
||||
@IExtHostWorkspace private _extHostWorkspace: ExtHostWorkspace,
|
||||
@IExtHostDocumentsAndEditors private _extHostDocumentsAndEditors: ExtHostDocumentsAndEditors,
|
||||
@ILogService private _logService: ILogService
|
||||
) {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadTerminalService);
|
||||
this._proxy = extHostRpc.getProxy(MainContext.MainThreadTerminalService);
|
||||
this._onDidWriteTerminalData = new Emitter<vscode.TerminalDataWriteEvent>({
|
||||
onFirstListenerAdd: () => this._proxy.$startSendingDataEvents(),
|
||||
onLastListenerRemove: () => this._proxy.$stopSendingDataEvents()
|
||||
});
|
||||
this._updateLastActiveWorkspace();
|
||||
this._updateVariableResolver();
|
||||
this._registerListeners();
|
||||
@@ -332,12 +260,12 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
public createExtensionTerminal(options: vscode.ExtensionTerminalOptions): vscode.Terminal {
|
||||
const terminal = new ExtHostTerminal(this._proxy, options.name);
|
||||
const p = new ExtHostPseudoterminal(options.pty);
|
||||
terminal.createExtensionTerminal().then(() => this._setupExtHostProcessListeners(terminal._id, p));
|
||||
terminal.createExtensionTerminal().then(id => this._setupExtHostProcessListeners(id, p));
|
||||
this._terminals.push(terminal);
|
||||
return terminal;
|
||||
}
|
||||
|
||||
public async attachPtyToTerminal(id: number, pty: vscode.Pseudoterminal): Promise<void> {
|
||||
public attachPtyToTerminal(id: number, pty: vscode.Pseudoterminal): void {
|
||||
const terminal = this._getTerminalByIdEventually(id);
|
||||
if (!terminal) {
|
||||
throw new Error(`Cannot resolve terminal with id ${id} for virtual process`);
|
||||
@@ -346,18 +274,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
this._setupExtHostProcessListeners(id, p);
|
||||
}
|
||||
|
||||
public createTerminalRenderer(name: string): vscode.TerminalRenderer {
|
||||
const terminal = new ExtHostTerminal(this._proxy, name);
|
||||
terminal._setProcessId(undefined);
|
||||
this._terminals.push(terminal);
|
||||
|
||||
const renderer = new ExtHostTerminalRenderer(this._proxy, name, terminal);
|
||||
this._terminalRenderers.push(renderer);
|
||||
|
||||
return renderer;
|
||||
}
|
||||
|
||||
public getDefaultShell(configProvider: ExtHostConfigProvider): string {
|
||||
public getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string {
|
||||
const fetchSetting = (key: string) => {
|
||||
const setting = configProvider
|
||||
.getConfiguration(key.substr(0, key.lastIndexOf('.')))
|
||||
@@ -372,11 +289,12 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
process.env.windir,
|
||||
this._lastActiveWorkspace,
|
||||
this._variableResolver,
|
||||
this._logService
|
||||
this._logService,
|
||||
useAutomationShell
|
||||
);
|
||||
}
|
||||
|
||||
private _getDefaultShellArgs(configProvider: ExtHostConfigProvider): string[] | string {
|
||||
private _getDefaultShellArgs(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string[] | string {
|
||||
const fetchSetting = (key: string) => {
|
||||
const setting = configProvider
|
||||
.getConfiguration(key.substr(0, key.lastIndexOf('.')))
|
||||
@@ -384,28 +302,10 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
return this._apiInspectConfigToPlain<string | string[]>(setting);
|
||||
};
|
||||
|
||||
return terminalEnvironment.getDefaultShellArgs(fetchSetting, this._isWorkspaceShellAllowed, this._lastActiveWorkspace, this._variableResolver, this._logService);
|
||||
return terminalEnvironment.getDefaultShellArgs(fetchSetting, this._isWorkspaceShellAllowed, useAutomationShell, this._lastActiveWorkspace, this._variableResolver, this._logService);
|
||||
}
|
||||
|
||||
public async resolveTerminalRenderer(id: number): Promise<vscode.TerminalRenderer> {
|
||||
// Check to see if the extension host already knows about this terminal.
|
||||
for (const terminalRenderer of this._terminalRenderers) {
|
||||
if (terminalRenderer._id === id) {
|
||||
return terminalRenderer;
|
||||
}
|
||||
}
|
||||
|
||||
const terminal = this._getTerminalById(id);
|
||||
if (!terminal) {
|
||||
throw new Error(`Cannot resolve terminal renderer for terminal id ${id}`);
|
||||
}
|
||||
const renderer = new ExtHostTerminalRenderer(this._proxy, terminal.name, terminal, terminal._id);
|
||||
this._terminalRenderers.push(renderer);
|
||||
|
||||
return renderer;
|
||||
}
|
||||
|
||||
public $acceptActiveTerminalChanged(id: number | null): void {
|
||||
public async $acceptActiveTerminalChanged(id: number | null): Promise<void> {
|
||||
const original = this._activeTerminal;
|
||||
if (id === null) {
|
||||
this._activeTerminal = undefined;
|
||||
@@ -414,69 +314,62 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.performTerminalIdAction(id, terminal => {
|
||||
if (terminal) {
|
||||
this._activeTerminal = terminal;
|
||||
if (original !== this._activeTerminal) {
|
||||
this._onDidChangeActiveTerminal.fire(this._activeTerminal);
|
||||
}
|
||||
const terminal = await this._getTerminalByIdEventually(id);
|
||||
if (terminal) {
|
||||
this._activeTerminal = terminal;
|
||||
if (original !== this._activeTerminal) {
|
||||
this._onDidChangeActiveTerminal.fire(this._activeTerminal);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public $acceptTerminalProcessData(id: number, data: string): void {
|
||||
this._getTerminalByIdEventually(id).then(terminal => {
|
||||
if (terminal) {
|
||||
terminal._fireOnData(data);
|
||||
}
|
||||
});
|
||||
/** @deprecated */
|
||||
public async $acceptTerminalProcessData(id: number, data: string): Promise<void> {
|
||||
const terminal = await this._getTerminalByIdEventually(id);
|
||||
if (terminal) {
|
||||
terminal._fireOnData(data);
|
||||
}
|
||||
}
|
||||
|
||||
public $acceptTerminalDimensions(id: number, cols: number, rows: number): void {
|
||||
this._getTerminalByIdEventually(id).then(terminal => {
|
||||
if (terminal) {
|
||||
if (terminal.setDimensions(cols, rows)) {
|
||||
this._onDidChangeTerminalDimensions.fire({
|
||||
terminal: terminal,
|
||||
dimensions: terminal.dimensions as vscode.TerminalDimensions
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
public async $acceptTerminalProcessData2(id: number, data: string): Promise<void> {
|
||||
const terminal = await this._getTerminalByIdEventually(id);
|
||||
if (terminal) {
|
||||
this._onDidWriteTerminalData.fire({ terminal, data });
|
||||
}
|
||||
}
|
||||
|
||||
public $acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): void {
|
||||
public async $acceptTerminalDimensions(id: number, cols: number, rows: number): Promise<void> {
|
||||
const terminal = await this._getTerminalByIdEventually(id);
|
||||
if (terminal) {
|
||||
if (terminal.setDimensions(cols, rows)) {
|
||||
this._onDidChangeTerminalDimensions.fire({
|
||||
terminal: terminal,
|
||||
dimensions: terminal.dimensions as vscode.TerminalDimensions
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async $acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): Promise<void> {
|
||||
await this._getTerminalByIdEventually(id);
|
||||
|
||||
if (this._terminalProcesses[id]) {
|
||||
// Virtual processes only - when virtual process resize fires it means that the
|
||||
// Extension pty terminal only - when virtual process resize fires it means that the
|
||||
// terminal's maximum dimensions changed
|
||||
this._terminalProcesses[id].resize(cols, rows);
|
||||
} else {
|
||||
// Terminal renderer
|
||||
this._getTerminalByIdEventually(id).then(() => {
|
||||
// When a terminal's dimensions change, a renderer's _maximum_ dimensions change
|
||||
const renderer = this._getTerminalRendererById(id);
|
||||
if (renderer) {
|
||||
renderer._setMaximumDimensions(cols, rows);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public $acceptTerminalRendererInput(id: number, data: string): void {
|
||||
const renderer = this._getTerminalRendererById(id);
|
||||
if (renderer) {
|
||||
renderer._fireOnInput(data);
|
||||
}
|
||||
}
|
||||
|
||||
public $acceptTerminalTitleChange(id: number, name: string): void {
|
||||
public async $acceptTerminalTitleChange(id: number, name: string): Promise<void> {
|
||||
await this._getTerminalByIdEventually(id);
|
||||
const extHostTerminal = this._getTerminalObjectById(this.terminals, id);
|
||||
if (extHostTerminal) {
|
||||
extHostTerminal.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
public $acceptTerminalClosed(id: number): void {
|
||||
public async $acceptTerminalClosed(id: number): Promise<void> {
|
||||
await this._getTerminalByIdEventually(id);
|
||||
const index = this._getTerminalObjectIndexById(this.terminals, id);
|
||||
if (index !== null) {
|
||||
const terminal = this._terminals.splice(index, 1)[0];
|
||||
@@ -489,20 +382,25 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
if (index !== null) {
|
||||
// The terminal has already been created (via createTerminal*), only fire the event
|
||||
this._onDidOpenTerminal.fire(this.terminals[index]);
|
||||
this.terminals[index].isOpen = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const renderer = this._getTerminalRendererById(id);
|
||||
const terminal = new ExtHostTerminal(this._proxy, name, id, renderer ? RENDERER_NO_PROCESS_ID : undefined);
|
||||
const terminal = new ExtHostTerminal(this._proxy, name, id);
|
||||
this._terminals.push(terminal);
|
||||
this._onDidOpenTerminal.fire(terminal);
|
||||
terminal.isOpen = true;
|
||||
}
|
||||
|
||||
public $acceptTerminalProcessId(id: number, processId: number): void {
|
||||
this.performTerminalIdAction(id, terminal => terminal._setProcessId(processId));
|
||||
public async $acceptTerminalProcessId(id: number, processId: number): Promise<void> {
|
||||
const terminal = await this._getTerminalByIdEventually(id);
|
||||
if (terminal) {
|
||||
terminal._setProcessId(processId);
|
||||
}
|
||||
}
|
||||
|
||||
public performTerminalIdAction(id: number, callback: (terminal: ExtHostTerminal) => void): void {
|
||||
// TODO: Use await this._getTerminalByIdEventually(id);
|
||||
let terminal = this._getTerminalById(id);
|
||||
if (terminal) {
|
||||
callback(terminal);
|
||||
@@ -551,7 +449,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
this._variableResolver = new ExtHostVariableResolverService(workspaceFolders || [], this._extHostDocumentsAndEditors, configProvider);
|
||||
}
|
||||
|
||||
public async $spawnExtHostProcess(id: number, shellLaunchConfigDto: ShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise<void> {
|
||||
public async $spawnExtHostProcess(id: number, shellLaunchConfigDto: IShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise<void> {
|
||||
const shellLaunchConfig: IShellLaunchConfig = {
|
||||
name: shellLaunchConfigDto.name,
|
||||
executable: shellLaunchConfigDto.executable,
|
||||
@@ -564,8 +462,8 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
const platformKey = platform.isWindows ? 'windows' : (platform.isMacintosh ? 'osx' : 'linux');
|
||||
const configProvider = await this._extHostConfiguration.getConfigProvider();
|
||||
if (!shellLaunchConfig.executable) {
|
||||
shellLaunchConfig.executable = this.getDefaultShell(configProvider);
|
||||
shellLaunchConfig.args = this._getDefaultShellArgs(configProvider);
|
||||
shellLaunchConfig.executable = this.getDefaultShell(false, configProvider);
|
||||
shellLaunchConfig.args = this._getDefaultShellArgs(false, configProvider);
|
||||
} else {
|
||||
if (this._variableResolver) {
|
||||
shellLaunchConfig.executable = this._variableResolver.resolve(this._lastActiveWorkspace, shellLaunchConfig.executable);
|
||||
@@ -625,7 +523,27 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
public async $startExtensionTerminal(id: number, initialDimensions: ITerminalDimensionsDto | undefined): Promise<void> {
|
||||
// Make sure the ExtHostTerminal exists so onDidOpenTerminal has fired before we call
|
||||
// Pseudoterminal.start
|
||||
await this._getTerminalByIdEventually(id);
|
||||
const terminal = await this._getTerminalByIdEventually(id);
|
||||
if (!terminal) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait for onDidOpenTerminal to fire
|
||||
let openPromise: Promise<void>;
|
||||
if (terminal.isOpen) {
|
||||
openPromise = Promise.resolve();
|
||||
} else {
|
||||
openPromise = new Promise<void>(r => {
|
||||
// Ensure open is called after onDidOpenTerminal
|
||||
const listener = this.onDidOpenTerminal(async e => {
|
||||
if (e === terminal) {
|
||||
listener.dispose();
|
||||
r();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
await openPromise;
|
||||
|
||||
// Processes should be initialized here for normal virtual process terminals, however for
|
||||
// tasks they are responsible for attaching the virtual process to a terminal so this
|
||||
@@ -686,11 +604,11 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
return detectAvailableShells();
|
||||
}
|
||||
|
||||
public async $requestDefaultShellAndArgs(): Promise<IShellAndArgsDto> {
|
||||
public async $requestDefaultShellAndArgs(useAutomationShell: boolean): Promise<IShellAndArgsDto> {
|
||||
const configProvider = await this._extHostConfiguration.getConfigProvider();
|
||||
return Promise.resolve({
|
||||
shell: this.getDefaultShell(configProvider),
|
||||
args: this._getDefaultShellArgs(configProvider)
|
||||
shell: this.getDefaultShell(useAutomationShell, configProvider),
|
||||
args: this._getDefaultShellArgs(useAutomationShell, configProvider)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -702,7 +620,8 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
this._proxy.$sendProcessExit(id, exitCode);
|
||||
}
|
||||
|
||||
private _getTerminalByIdEventually(id: number, retries: number = 5): Promise<ExtHostTerminal> {
|
||||
// TODO: This could be improved by using a single promise and resolve it when the terminal is ready
|
||||
private _getTerminalByIdEventually(id: number, retries: number = 5): Promise<ExtHostTerminal | undefined> {
|
||||
if (!this._getTerminalPromises[id]) {
|
||||
this._getTerminalPromises[id] = this._createGetTerminalPromise(id, retries);
|
||||
} else {
|
||||
@@ -735,16 +654,12 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
return this._getTerminalObjectById(this._terminals, id);
|
||||
}
|
||||
|
||||
private _getTerminalRendererById(id: number): ExtHostTerminalRenderer | null {
|
||||
return this._getTerminalObjectById(this._terminalRenderers, id);
|
||||
}
|
||||
|
||||
private _getTerminalObjectById<T extends ExtHostTerminal | ExtHostTerminalRenderer>(array: T[], id: number): T | null {
|
||||
private _getTerminalObjectById<T extends ExtHostTerminal>(array: T[], id: number): T | null {
|
||||
const index = this._getTerminalObjectIndexById(array, id);
|
||||
return index !== null ? array[index] : null;
|
||||
}
|
||||
|
||||
private _getTerminalObjectIndexById<T extends ExtHostTerminal | ExtHostTerminalRenderer>(array: T[], id: number): number | null {
|
||||
private _getTerminalObjectIndexById<T extends ExtHostTerminal>(array: T[], id: number): number | null {
|
||||
let index: number | null = null;
|
||||
array.some((item, i) => {
|
||||
const thisId = item._id;
|
||||
@@ -777,9 +692,6 @@ class ApiRequest {
|
||||
}
|
||||
|
||||
class ExtHostPseudoterminal implements ITerminalChildProcess {
|
||||
private _queuedEvents: (IQueuedEvent<string> | IQueuedEvent<number> | IQueuedEvent<{ pid: number, cwd: string }> | IQueuedEvent<ITerminalDimensions | undefined>)[] = [];
|
||||
private _queueDisposables: IDisposable[] | undefined;
|
||||
|
||||
private readonly _onProcessData = new Emitter<string>();
|
||||
public readonly onProcessData: Event<string> = this._onProcessData.event;
|
||||
private readonly _onProcessExit = new Emitter<number>();
|
||||
@@ -791,23 +703,10 @@ class ExtHostPseudoterminal implements ITerminalChildProcess {
|
||||
private readonly _onProcessOverrideDimensions = new Emitter<ITerminalDimensions | undefined>();
|
||||
public get onProcessOverrideDimensions(): Event<ITerminalDimensions | undefined> { return this._onProcessOverrideDimensions.event; }
|
||||
|
||||
constructor(
|
||||
private readonly _pty: vscode.Pseudoterminal
|
||||
) {
|
||||
this._queueDisposables = [];
|
||||
this._queueDisposables.push(this._pty.onDidWrite(e => this._queuedEvents.push({ emitter: this._onProcessData, data: e })));
|
||||
if (this._pty.onDidClose) {
|
||||
this._queueDisposables.push(this._pty.onDidClose(e => this._queuedEvents.push({ emitter: this._onProcessExit, data: 0 })));
|
||||
}
|
||||
if (this._pty.onDidOverrideDimensions) {
|
||||
this._queueDisposables.push(this._pty.onDidOverrideDimensions(e => this._queuedEvents.push({ emitter: this._onProcessOverrideDimensions, data: e ? { cols: e.columns, rows: e.rows } : undefined })));
|
||||
}
|
||||
}
|
||||
constructor(private readonly _pty: vscode.Pseudoterminal) { }
|
||||
|
||||
shutdown(): void {
|
||||
if (this._pty.close) {
|
||||
this._pty.close();
|
||||
}
|
||||
this._pty.close();
|
||||
}
|
||||
|
||||
input(data: string): void {
|
||||
@@ -835,12 +734,7 @@ class ExtHostPseudoterminal implements ITerminalChildProcess {
|
||||
}
|
||||
|
||||
startSendingEvents(initialDimensions: ITerminalDimensionsDto | undefined): void {
|
||||
// Flush all buffered events
|
||||
this._queuedEvents.forEach(e => (<any>e.emitter.fire)(e.data));
|
||||
this._queuedEvents = [];
|
||||
this._queueDisposables = undefined;
|
||||
|
||||
// Attach the real listeners
|
||||
// Attach the listeners
|
||||
this._pty.onDidWrite(e => this._onProcessData.fire(e));
|
||||
if (this._pty.onDidClose) {
|
||||
this._pty.onDidClose(e => this._onProcessExit.fire(0));
|
||||
@@ -849,13 +743,7 @@ class ExtHostPseudoterminal implements ITerminalChildProcess {
|
||||
this._pty.onDidOverrideDimensions(e => this._onProcessOverrideDimensions.fire(e ? { cols: e.columns, rows: e.rows } : undefined)); // {{SQL CARBON EDIT}} strict-null-checks
|
||||
}
|
||||
|
||||
if (this._pty.open) {
|
||||
this._pty.open(initialDimensions);
|
||||
}
|
||||
this._pty.open(initialDimensions ? initialDimensions : undefined);
|
||||
}
|
||||
}
|
||||
|
||||
interface IQueuedEvent<T> {
|
||||
emitter: Emitter<T>;
|
||||
data: T;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user