Merge from vscode a348d103d1256a06a2c9b3f9b406298a9fef6898 (#15681)

* Merge from vscode a348d103d1256a06a2c9b3f9b406298a9fef6898

* Fixes and cleanup

* Distro

* Fix hygiene yarn

* delete no yarn lock changes file

* Fix hygiene

* Fix layer check

* Fix CI

* Skip lib checks

* Remove tests deleted in vs code

* Fix tests

* Distro

* Fix tests and add removed extension point

* Skip failing notebook tests for now

* Disable broken tests and cleanup build folder

* Update yarn.lock and fix smoke tests

* Bump sqlite

* fix contributed actions and file spacing

* Fix user data path

* Update yarn.locks

Co-authored-by: ADS Merger <karlb@microsoft.com>
This commit is contained in:
Charles Gagnon
2021-06-17 08:17:11 -07:00
committed by GitHub
parent fdcb97c7f7
commit 3cb2f552a6
2582 changed files with 124827 additions and 87099 deletions

View File

@@ -32,7 +32,11 @@ function adjustHandler(handler: (executor: ICommandsExecutor, ...args: any[]) =>
interface INewWindowAPICommandOptions {
reuseWindow?: boolean;
remoteAuthority?: string;
/**
* If set, defines the remoteAuthority of the new window. `null` will open a local window.
* If not set, defaults to remoteAuthority of the current window.
*/
remoteAuthority?: string | null;
}
export class NewWindowAPICommand {
@@ -95,6 +99,7 @@ interface RecentEntry {
uri: URI;
type: 'workspace' | 'folder' | 'file';
label?: string;
remoteAuthority?: string;
}
CommandsRegistry.registerCommand('_workbench.addToRecentlyOpened', async function (accessor: ServicesAccessor, recentEntry: RecentEntry) {
@@ -102,13 +107,14 @@ CommandsRegistry.registerCommand('_workbench.addToRecentlyOpened', async functio
let recent: IRecent | undefined = undefined;
const uri = recentEntry.uri;
const label = recentEntry.label;
const remoteAuthority = recentEntry.remoteAuthority;
if (recentEntry.type === 'workspace') {
const workspace = await workspacesService.getWorkspaceIdentifier(uri);
recent = { workspace, label };
recent = { workspace, label, remoteAuthority };
} else if (recentEntry.type === 'folder') {
recent = { folderUri: uri, label };
recent = { folderUri: uri, label, remoteAuthority };
} else {
recent = { fileUri: uri, label };
recent = { fileUri: uri, label, remoteAuthority };
}
return workspacesService.addRecentlyOpened([recent]);
});

View File

@@ -170,7 +170,7 @@ configurationExtPoint.setHandler((extensions, { added, removed }) => {
validateProperties(configuration, extension);
configuration.id = node.id || extension.description.identifier.value;
configuration.extensionInfo = { id: extension.description.identifier.value };
configuration.extensionInfo = { id: extension.description.identifier.value, restrictedConfigurations: extension.description.capabilities?.untrustedWorkspaces?.supported === 'limited' ? extension.description.capabilities?.untrustedWorkspaces.restrictedConfigurations : undefined };
configuration.title = configuration.title || extension.description.displayName || extension.description.identifier.value;
configurations.push(configuration);
return configurations;
@@ -181,10 +181,10 @@ configurationExtPoint.setHandler((extensions, { added, removed }) => {
for (let extension of added) {
const configurations: IConfigurationNode[] = [];
const value = <IConfigurationNode | IConfigurationNode[]>extension.value;
if (!Array.isArray(value)) {
configurations.push(...handleConfiguration(value, extension));
} else {
if (Array.isArray(value)) {
value.forEach(v => configurations.push(...handleConfiguration(v, extension)));
} else {
configurations.push(...handleConfiguration(value, extension));
}
extensionConfigurations.set(ExtensionIdentifier.toKey(extension.description.identifier), configurations);
addedConfigurations.push(...configurations);
@@ -213,7 +213,7 @@ function validateProperties(configuration: IConfigurationNode, extension: IExten
const propertyConfiguration = properties[key];
if (!isObject(propertyConfiguration)) {
delete properties[key];
extension.collector.error(nls.localize('invalid.property', "'configuration.property' must be an object"));
extension.collector.error(nls.localize('invalid.property', "configuration.properties property '{0}' must be an object", key));
continue;
}
if (propertyConfiguration.scope) {
@@ -320,7 +320,7 @@ jsonRegistry.registerSchema('vscode://schemas/workspaceConfig', {
'remoteAuthority': {
type: 'string',
doNotSuggest: true,
description: nls.localize('workspaceConfig.remoteAuthority', "The remote server where the workspace is located. Only used by unsaved remote workspaces."),
description: nls.localize('workspaceConfig.remoteAuthority', "The remote server where the workspace is located."),
}
},
errorMessage: nls.localize('unknownWorkspaceProperty', "Unknown workspace configuration property")

View File

@@ -7,7 +7,6 @@ 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';
@@ -15,7 +14,7 @@ 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, MainContext, ExtHostLogServiceShape, UIKind } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostContext, MainContext, ExtHostLogServiceShape, UIKind, CandidatePortSource } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostApiCommands } from 'vs/workbench/api/common/extHostApiCommands';
import { ExtHostClipboard } from 'vs/workbench/api/common/extHostClipboard';
import { IExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
@@ -27,7 +26,7 @@ import { ExtHostDocumentContentProvider } from 'vs/workbench/api/common/extHostD
import { ExtHostDocumentSaveParticipant } from 'vs/workbench/api/common/extHostDocumentSaveParticipant';
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
import { IExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
import { Extension, IExtHostExtensionService } from 'vs/workbench/api/common/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';
@@ -35,7 +34,7 @@ import { ExtHostLanguages } from 'vs/workbench/api/common/extHostLanguages';
import { ExtHostMessageService } from 'vs/workbench/api/common/extHostMessageService';
import { IExtHostOutputService } from 'vs/workbench/api/common/extHostOutput';
import { ExtHostProgress } from 'vs/workbench/api/common/extHostProgress';
import { ExtHostQuickOpen } from 'vs/workbench/api/common/extHostQuickOpen';
import { createExtHostQuickOpen } from 'vs/workbench/api/common/extHostQuickOpen';
import { ExtHostSCM } from 'vs/workbench/api/common/extHostSCM';
import { ExtHostStatusBar } from 'vs/workbench/api/common/extHostStatusBar';
import { IExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
@@ -52,8 +51,7 @@ import { throwProposedApiError, checkProposedApiEnabled } from 'vs/workbench/ser
import { ProxyIdentifier } from 'vs/workbench/services/extensions/common/proxyIdentifier';
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
import type * as vscode from 'vscode';
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { originalFSPath } from 'vs/base/common/resources';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { values } from 'vs/base/common/collections';
import { ExtHostEditorInsets } from 'vs/workbench/api/common/extHostCodeInsets';
import { ExtHostLabelService } from 'vs/workbench/api/common/extHostLabelService';
@@ -85,6 +83,10 @@ import { ExtHostTesting } from 'vs/workbench/api/common/extHostTesting';
import { ExtHostUriOpeners } from 'vs/workbench/api/common/extHostUriOpener';
import { IExtHostSecretState } from 'vs/workbench/api/common/exHostSecretState';
import { ExtHostEditorTabs } from 'vs/workbench/api/common/extHostEditorTabs';
import { IExtHostTelemetry } from 'vs/workbench/api/common/extHostTelemetry';
import { ExtHostNotebookKernels } from 'vs/workbench/api/common/extHostNotebookKernels';
import { RemoteTrustOption } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { TextSearchCompleteMessageType } from 'vs/workbench/services/search/common/searchExtTypes';
export interface IExtensionApiFactory {
(extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode;
@@ -101,6 +103,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
const extHostConsumerFileSystem = accessor.get(IExtHostConsumerFileSystem);
const extensionService = accessor.get(IExtHostExtensionService);
const extHostWorkspace = accessor.get(IExtHostWorkspace);
const extHostTelemetry = accessor.get(IExtHostTelemetry);
const extHostConfiguration = accessor.get(IExtHostConfiguration);
const uriTransformer = accessor.get(IURITransformerService);
const rpcProtocol = accessor.get(IExtHostRpcService);
@@ -122,6 +125,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
rpcProtocol.set(ExtHostContext.ExtHostTunnelService, extHostTunnelService);
rpcProtocol.set(ExtHostContext.ExtHostWindow, extHostWindow);
rpcProtocol.set(ExtHostContext.ExtHostSecretState, extHostSecretState);
rpcProtocol.set(ExtHostContext.ExtHostTelemetry, extHostTelemetry);
// automatically create and register addressable instances
const extHostDecorations = rpcProtocol.set(ExtHostContext.ExtHostDecorations, accessor.get(IExtHostDecorations));
@@ -139,7 +143,8 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
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.MainThreadBulkEdits)));
const extHostNotebook = rpcProtocol.set(ExtHostContext.ExtHostNotebook, new ExtHostNotebookController(rpcProtocol, extHostCommands, extHostDocumentsAndEditors, initData.environment, extHostLogService, extensionStoragePaths));
const extHostNotebook = rpcProtocol.set(ExtHostContext.ExtHostNotebook, new ExtHostNotebookController(rpcProtocol, extHostCommands, extHostDocumentsAndEditors, extHostDocuments, extHostLogService, extensionStoragePaths));
const extHostNotebookKernels = rpcProtocol.set(ExtHostContext.ExtHostNotebookKernels, new ExtHostNotebookKernels(rpcProtocol, initData, extHostNotebook));
const extHostEditors = rpcProtocol.set(ExtHostContext.ExtHostEditors, new ExtHostEditors(rpcProtocol, extHostDocumentsAndEditors));
const extHostTreeViews = rpcProtocol.set(ExtHostContext.ExtHostTreeViews, new ExtHostTreeViews(rpcProtocol.getProxy(MainContext.MainThreadTreeViews), extHostCommands, extHostLogService));
const extHostEditorInsets = rpcProtocol.set(ExtHostContext.ExtHostEditorInsets, new ExtHostEditorInsets(rpcProtocol.getProxy(MainContext.MainThreadEditorInsets), extHostEditors, initData.environment));
@@ -147,7 +152,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
const extHostLanguageFeatures = rpcProtocol.set(ExtHostContext.ExtHostLanguageFeatures, new ExtHostLanguageFeatures(rpcProtocol, uriTransformer, extHostDocuments, extHostCommands, extHostDiagnostics, extHostLogService, extHostApiDeprecation));
const extHostFileSystem = rpcProtocol.set(ExtHostContext.ExtHostFileSystem, new ExtHostFileSystem(rpcProtocol, extHostLanguageFeatures));
const extHostFileSystemEvent = rpcProtocol.set(ExtHostContext.ExtHostFileSystemEventService, new ExtHostFileSystemEventService(rpcProtocol, extHostLogService, extHostDocumentsAndEditors));
const extHostQuickOpen = rpcProtocol.set(ExtHostContext.ExtHostQuickOpen, new ExtHostQuickOpen(rpcProtocol, extHostWorkspace, extHostCommands));
const extHostQuickOpen = rpcProtocol.set(ExtHostContext.ExtHostQuickOpen, createExtHostQuickOpen(rpcProtocol, extHostWorkspace, extHostCommands));
const extHostSCM = rpcProtocol.set(ExtHostContext.ExtHostSCM, new ExtHostSCM(rpcProtocol, extHostCommands, extHostLogService));
const extHostComment = rpcProtocol.set(ExtHostContext.ExtHostComments, new ExtHostComments(rpcProtocol, extHostCommands, extHostDocuments));
const extHostProgress = rpcProtocol.set(ExtHostContext.ExtHostProgress, new ExtHostProgress(rpcProtocol.getProxy(MainContext.MainThreadProgress)));
@@ -170,7 +175,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
rpcProtocol.assertRegistered(expected);
// Other instances
const extHostBulkEdits = new ExtHostBulkEdits(rpcProtocol, extHostDocumentsAndEditors, extHostNotebook);
const extHostBulkEdits = new ExtHostBulkEdits(rpcProtocol, extHostDocumentsAndEditors);
const extHostClipboard = new ExtHostClipboard(rpcProtocol);
const extHostMessageService = new ExtHostMessageService(rpcProtocol, extHostLogService);
const extHostDialogs = new ExtHostDialogs(rpcProtocol);
@@ -201,10 +206,11 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
} else if (typeof selector === 'string') {
informOnce(selector);
} else {
if (typeof selector.scheme === 'undefined') {
const filter = selector as vscode.DocumentFilter; // TODO: microsoft/TypeScript#42768
if (typeof filter.scheme === 'undefined') {
informOnce(selector);
}
if (!extension.enableProposedApi && typeof selector.exclusive === 'boolean') {
if (!extension.enableProposedApi && typeof filter.exclusive === 'boolean') {
throwProposedApiError(extension);
}
}
@@ -220,7 +226,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
return extHostAuthentication.onDidChangeSessions;
},
registerAuthenticationProvider(id: string, label: string, provider: vscode.AuthenticationProvider, options?: vscode.AuthenticationProviderOptions): vscode.Disposable {
checkProposedApiEnabled(extension);
return extHostAuthentication.registerAuthenticationProvider(id, label, provider, options);
},
get onDidChangeAuthenticationProviders(): Event<vscode.AuthenticationProvidersChangeEvent> {
@@ -233,7 +238,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
},
logout(providerId: string, sessionId: string): Thenable<void> {
checkProposedApiEnabled(extension);
return extHostAuthentication.logout(providerId, sessionId);
return extHostAuthentication.removeSession(providerId, sessionId);
}
};
@@ -295,6 +300,16 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
get shell() {
return extHostTerminalService.getDefaultShell(false, configProvider);
},
get isTelemetryEnabled() {
return extHostTelemetry.getTelemetryEnabled();
},
get onDidChangeTelemetryEnabled(): Event<boolean> {
return extHostTelemetry.onDidChangeTelemetryEnabled;
},
get isNewAppInstall() {
const installAge = Date.now() - new Date(initData.telemetryInfo.firstSessionDate).getTime();
return isNaN(installAge) ? false : installAge < 1000 * 60 * 60 * 24; // install age is less than a day
},
openExternal(uri: URI, options?: { allowContributedOpeners?: boolean | string; }) {
return extHostWindow.openUri(uri, {
allowTunneling: !!initData.remote.authority,
@@ -325,9 +340,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
: extHostTypes.ExtensionKind.UI;
const test: typeof vscode.test = {
registerTestProvider(provider) {
registerTestController(provider) {
checkProposedApiEnabled(extension);
return extHostTesting.registerTestProvider(provider);
return extHostTesting.registerTestController(extension.identifier.value, provider);
},
createDocumentTestObserver(document) {
checkProposedApiEnabled(extension);
@@ -341,26 +356,36 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
checkProposedApiEnabled(extension);
return extHostTesting.runTests(provider);
},
createTestItem<T>(options: vscode.TestItemOptions, data?: T) {
return new extHostTypes.TestItemImpl(options.id, options.label, options.uri, data);
},
createTestRun(request, name, persist) {
checkProposedApiEnabled(extension);
return extHostTesting.createTestRun(extension.identifier.value, request, name, persist);
},
get onDidChangeTestResults() {
checkProposedApiEnabled(extension);
return extHostTesting.onLastResultsChanged;
return extHostTesting.onResultsChanged;
},
get testResults() {
checkProposedApiEnabled(extension);
return extHostTesting.lastResults;
return extHostTesting.results;
},
};
// todo@connor4312: backwards compatibility for a short period
(test as any).createTestRunTask = test.createTestRun;
// namespace: extensions
const extensions: typeof vscode.extensions = {
getExtension(extensionId: string): Extension<any> | undefined {
getExtension(extensionId: string): vscode.Extension<any> | undefined {
const desc = extensionRegistry.getExtensionDescription(extensionId);
if (desc) {
return new Extension(extensionService, extension.identifier, desc, extensionKind);
}
return undefined;
},
get all(): Extension<any>[] {
get all(): vscode.Extension<any>[] {
return extensionRegistry.getAllExtensionDescriptions().map((desc) => new Extension(extensionService, extension.identifier, desc, extensionKind));
},
get onDidChange() {
@@ -412,6 +437,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
registerEvaluatableExpressionProvider(selector: vscode.DocumentSelector, provider: vscode.EvaluatableExpressionProvider): vscode.Disposable {
return extHostLanguageFeatures.registerEvaluatableExpressionProvider(extension, checkSelector(selector), provider, extension.identifier);
},
registerInlineValuesProvider(selector: vscode.DocumentSelector, provider: vscode.InlineValuesProvider): vscode.Disposable {
return extHostLanguageFeatures.registerInlineValuesProvider(extension, checkSelector(selector), provider, extension.identifier);
},
registerDocumentHighlightProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentHighlightProvider): vscode.Disposable {
return extHostLanguageFeatures.registerDocumentHighlightProvider(extension, checkSelector(selector), provider);
},
@@ -571,7 +599,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
showSaveDialog(options) {
return extHostDialogs.showSaveDialog(options);
},
createStatusBarItem(alignmentOrOptions?: vscode.StatusBarAlignment | vscode.window.StatusBarItemOptions, priority?: number): vscode.StatusBarItem {
createStatusBarItem(alignmentOrOptions?: vscode.StatusBarAlignment | vscode.StatusBarItemOptions, priority?: number): vscode.StatusBarItem {
let id: string;
let name: string;
let alignment: number | undefined;
@@ -619,6 +647,12 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
if ('pty' in nameOrOptions) {
return extHostTerminalService.createExtensionTerminal(nameOrOptions);
}
if (nameOrOptions.message) {
checkProposedApiEnabled(extension);
}
if (nameOrOptions.icon) {
checkProposedApiEnabled(extension);
}
return extHostTerminalService.createTerminalFromOptions(nameOrOptions);
}
return extHostTerminalService.createTerminal(nameOrOptions, shellPath, shellArgs);
@@ -687,9 +721,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
checkProposedApiEnabled(extension);
return extHostNotebook.onDidChangeNotebookEditorVisibleRanges(listener, thisArgs, disposables);
},
showNotebookDocument(document, options?) {
showNotebookDocument(uriOrDocument, options?) {
checkProposedApiEnabled(extension);
return extHostNotebook.showNotebookDocument(document, options);
return extHostNotebook.showNotebookDocument(uriOrDocument, options);
},
registerExternalUriOpener(id: string, opener: vscode.ExternalUriOpener, metadata: vscode.ExternalUriOpenerMetadata) {
checkProposedApiEnabled(extension);
@@ -885,11 +919,24 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
onDidChangeTunnels: (listener, thisArg?, disposables?) => {
checkProposedApiEnabled(extension);
return extHostTunnelService.onDidChangeTunnels(listener, thisArg, disposables);
},
registerPortAttributesProvider: (portSelector: { pid?: number, portRange?: [number, number], commandMatcher?: RegExp }, provider: vscode.PortAttributesProvider) => {
checkProposedApiEnabled(extension);
return extHostTunnelService.registerPortsAttributesProvider(portSelector, provider);
},
registerTimelineProvider: (scheme: string | string[], provider: vscode.TimelineProvider) => {
checkProposedApiEnabled(extension);
return extHostTimeline.registerTimelineProvider(scheme, provider, extension.identifier, extHostCommands.converter);
},
get isTrusted() {
return extHostWorkspace.trusted;
},
requestWorkspaceTrust: (options?: vscode.WorkspaceTrustRequestOptions) => {
checkProposedApiEnabled(extension);
return extHostWorkspace.requestWorkspaceTrust(options);
},
onDidGrantWorkspaceTrust: (listener, thisArgs?, disposables?) => {
return extHostWorkspace.onDidGrantWorkspaceTrust(listener, thisArgs, disposables);
}
};
@@ -1009,18 +1056,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
};
// namespace: notebook
const notebook: (typeof vscode.notebook & {
// to ensure that notebook extensions not break before they update APIs.
visibleNotebookEditors: vscode.NotebookEditor[];
onDidChangeVisibleNotebookEditors: Event<vscode.NotebookEditor[]>;
activeNotebookEditor: vscode.NotebookEditor | undefined;
onDidChangeActiveNotebookEditor: Event<vscode.NotebookEditor | undefined>;
onDidChangeNotebookEditorSelection: Event<vscode.NotebookEditorSelectionChangeEvent>;
onDidChangeNotebookEditorVisibleRanges: Event<vscode.NotebookEditorVisibleRangesChangeEvent>;
}) = {
openNotebookDocument: (uriComponents, viewType) => {
const notebook: typeof vscode.notebook = {
openNotebookDocument: (uriComponents) => {
checkProposedApiEnabled(extension);
return extHostNotebook.openNotebookDocument(uriComponents, viewType);
return extHostNotebook.openNotebookDocument(uriComponents);
},
get onDidOpenNotebookDocument(): Event<vscode.NotebookDocument> {
checkProposedApiEnabled(extension);
@@ -1036,43 +1075,24 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
},
get notebookDocuments(): vscode.NotebookDocument[] {
checkProposedApiEnabled(extension);
return extHostNotebook.notebookDocuments.map(d => d.notebookDocument);
return extHostNotebook.notebookDocuments.map(d => d.apiNotebook);
},
get visibleNotebookEditors(): vscode.NotebookEditor[] {
registerNotebookSerializer(viewType, serializer, options) {
checkProposedApiEnabled(extension);
return extHostNotebook.visibleNotebookEditors;
return extHostNotebook.registerNotebookSerializer(extension, viewType, serializer, options);
},
get onDidChangeVisibleNotebookEditors() {
checkProposedApiEnabled(extension);
return extHostNotebook.onDidChangeVisibleNotebookEditors;
},
get onDidChangeActiveNotebookKernel() {
checkProposedApiEnabled(extension);
return extHostNotebook.onDidChangeActiveNotebookKernel;
},
registerNotebookContentProvider: (viewType: string, provider: vscode.NotebookContentProvider, options?: {
transientOutputs: boolean;
transientMetadata: { [K in keyof vscode.NotebookCellMetadata]?: boolean }
}) => {
registerNotebookContentProvider: (viewType, provider, options) => {
checkProposedApiEnabled(extension);
return extHostNotebook.registerNotebookContentProvider(extension, viewType, provider, options);
},
registerNotebookKernelProvider: (selector: vscode.NotebookDocumentFilter, provider: vscode.NotebookKernelProvider) => {
registerNotebookCellStatusBarItemProvider: (selector: vscode.NotebookSelector, provider: vscode.NotebookCellStatusBarItemProvider) => {
checkProposedApiEnabled(extension);
return extHostNotebook.registerNotebookKernelProvider(extension, selector, provider);
return extHostNotebook.registerNotebookCellStatusBarItemProvider(extension, selector, provider);
},
createNotebookEditorDecorationType(options: vscode.NotebookDecorationRenderOptions): vscode.NotebookEditorDecorationType {
checkProposedApiEnabled(extension);
return extHostNotebook.createNotebookEditorDecorationType(options);
},
get activeNotebookEditor(): vscode.NotebookEditor | undefined {
checkProposedApiEnabled(extension);
return extHostNotebook.activeNotebookEditor;
},
onDidChangeActiveNotebookEditor(listener, thisArgs?, disposables?) {
checkProposedApiEnabled(extension);
return extHostNotebook.onDidChangeActiveNotebookEditor(listener, thisArgs, disposables);
},
onDidChangeNotebookDocumentMetadata(listener, thisArgs?, disposables?) {
checkProposedApiEnabled(extension);
return extHostNotebook.onDidChangeNotebookDocumentMetadata(listener, thisArgs, disposables);
@@ -1081,22 +1101,14 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
checkProposedApiEnabled(extension);
return extHostNotebook.onDidChangeNotebookCells(listener, thisArgs, disposables);
},
onDidChangeNotebookEditorSelection(listener, thisArgs?, disposables?) {
onDidChangeCellExecutionState(listener, thisArgs?, disposables?) {
checkProposedApiEnabled(extension);
return extHostNotebook.onDidChangeNotebookEditorSelection(listener, thisArgs, disposables);
},
onDidChangeNotebookEditorVisibleRanges(listener, thisArgs?, disposables?) {
checkProposedApiEnabled(extension);
return extHostNotebook.onDidChangeNotebookEditorVisibleRanges(listener, thisArgs, disposables);
return extHostNotebook.onDidChangeNotebookCellExecutionState(listener, thisArgs, disposables);
},
onDidChangeCellOutputs(listener, thisArgs?, disposables?) {
checkProposedApiEnabled(extension);
return extHostNotebook.onDidChangeCellOutputs(listener, thisArgs, disposables);
},
onDidChangeCellLanguage(listener, thisArgs?, disposables?) {
checkProposedApiEnabled(extension);
return extHostNotebook.onDidChangeCellLanguage(listener, thisArgs, disposables);
},
onDidChangeCellMetadata(listener, thisArgs?, disposables?) {
checkProposedApiEnabled(extension);
return extHostNotebook.onDidChangeCellMetadata(listener, thisArgs, disposables);
@@ -1105,9 +1117,13 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
checkProposedApiEnabled(extension);
return new ExtHostNotebookConcatDocument(extHostNotebook, extHostDocuments, notebook, selector);
},
createCellStatusBarItem(cell: vscode.NotebookCell, alignment?: vscode.NotebookCellStatusBarAlignment, priority?: number): vscode.NotebookCellStatusBarItem {
createNotebookCellExecutionTask(uri: vscode.Uri, index: number, kernelId: string): vscode.NotebookCellExecutionTask | undefined {
checkProposedApiEnabled(extension);
return extHostNotebook.createNotebookCellStatusBarItemInternal(cell, alignment, priority);
return extHostNotebook.createNotebookCellExecution(uri, index, kernelId);
},
createNotebookController(id, viewType, label, executeHandler, preloads) {
checkProposedApiEnabled(extension);
return extHostNotebookKernels.createNotebookController(extension, id, viewType, label, executeHandler, preloads);
}
};
@@ -1135,9 +1151,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
CallHierarchyOutgoingCall: extHostTypes.CallHierarchyOutgoingCall,
CancellationError: errors.CancellationError,
CancellationTokenSource: CancellationTokenSource,
CandidatePortSource: CandidatePortSource,
CodeAction: extHostTypes.CodeAction,
CodeActionKind: extHostTypes.CodeActionKind,
CodeActionTrigger: extHostTypes.CodeActionTrigger,
CodeActionTriggerKind: extHostTypes.CodeActionTriggerKind,
CodeLens: extHostTypes.CodeLens,
Color: extHostTypes.Color,
ColorInformation: extHostTypes.ColorInformation,
@@ -1171,6 +1188,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
EndOfLine: extHostTypes.EndOfLine,
EnvironmentVariableMutatorType: extHostTypes.EnvironmentVariableMutatorType,
EvaluatableExpression: extHostTypes.EvaluatableExpression,
InlineValueText: extHostTypes.InlineValueText,
InlineValueVariableLookup: extHostTypes.InlineValueVariableLookup,
InlineValueEvaluatableExpression: extHostTypes.InlineValueEvaluatableExpression,
EventEmitter: Emitter,
ExtensionKind: extHostTypes.ExtensionKind,
ExtensionMode: extHostTypes.ExtensionMode,
@@ -1184,11 +1204,11 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
FunctionBreakpoint: extHostTypes.FunctionBreakpoint,
Hover: extHostTypes.Hover,
IndentAction: languageConfiguration.IndentAction,
InlineHint: extHostTypes.InlineHint,
Location: extHostTypes.Location,
MarkdownString: extHostTypes.MarkdownString,
OverviewRulerLane: OverviewRulerLane,
ParameterInformation: extHostTypes.ParameterInformation,
PortAutoForwardAction: extHostTypes.PortAutoForwardAction,
Position: extHostTypes.Position,
ProcessExecution: extHostTypes.ProcessExecution,
ProgressLocation: extHostTypes.ProgressLocation,
@@ -1234,113 +1254,34 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
ViewColumn: extHostTypes.ViewColumn,
WorkspaceEdit: extHostTypes.WorkspaceEdit,
// proposed api types
get RemoteAuthorityResolverError() {
// checkProposedApiEnabled(extension);
return extHostTypes.RemoteAuthorityResolverError;
},
get ResolvedAuthority() {
// checkProposedApiEnabled(extension);
return extHostTypes.ResolvedAuthority;
},
get SourceControlInputBoxValidationType() {
// checkProposedApiEnabled(extension);
return extHostTypes.SourceControlInputBoxValidationType;
},
get ExtensionRuntime() {
// checkProposedApiEnabled(extension);
return extHostTypes.ExtensionRuntime;
},
get TimelineItem() {
// checkProposedApiEnabled(extension);
return extHostTypes.TimelineItem;
},
get CellKind() {
// checkProposedApiEnabled(extension);
return extHostTypes.CellKind;
},
get CellOutputKind() {
// checkProposedApiEnabled(extension);
return extHostTypes.CellOutputKind;
},
get NotebookCellRunState() {
// checkProposedApiEnabled(extension);
return extHostTypes.NotebookCellRunState;
},
get NotebookRunState() {
// checkProposedApiEnabled(extension);
return extHostTypes.NotebookRunState;
},
get NotebookCellStatusBarAlignment() {
// checkProposedApiEnabled(extension);
return extHostTypes.NotebookCellStatusBarAlignment;
},
get NotebookEditorRevealType() {
// checkProposedApiEnabled(extension);
return extHostTypes.NotebookEditorRevealType;
},
get NotebookCellOutput() {
// checkProposedApiEnabled(extension);
return extHostTypes.NotebookCellOutput;
},
get NotebookCellOutputItem() {
// checkProposedApiEnabled(extension);
return extHostTypes.NotebookCellOutputItem;
},
get LinkedEditingRanges() {
// checkProposedApiEnabled(extension);
return extHostTypes.LinkedEditingRanges;
},
get TestRunState() {
// checkProposedApiEnabled(extension);
return extHostTypes.TestRunState;
},
get TestMessageSeverity() {
// checkProposedApiEnabled(extension);
return extHostTypes.TestMessageSeverity;
},
get TestState() {
// checkProposedApiEnabled(extension);
return extHostTypes.TestState;
},
InlineHint: extHostTypes.InlineHint,
InlineHintKind: extHostTypes.InlineHintKind,
RemoteAuthorityResolverError: extHostTypes.RemoteAuthorityResolverError,
RemoteTrustOption: RemoteTrustOption,
ResolvedAuthority: extHostTypes.ResolvedAuthority,
SourceControlInputBoxValidationType: extHostTypes.SourceControlInputBoxValidationType,
ExtensionRuntime: extHostTypes.ExtensionRuntime,
TimelineItem: extHostTypes.TimelineItem,
NotebookRange: extHostTypes.NotebookRange,
NotebookCellKind: extHostTypes.NotebookCellKind,
NotebookCellExecutionState: extHostTypes.NotebookCellExecutionState,
NotebookDocumentMetadata: extHostTypes.NotebookDocumentMetadata,
NotebookCellMetadata: extHostTypes.NotebookCellMetadata,
NotebookCellData: extHostTypes.NotebookCellData,
NotebookData: extHostTypes.NotebookData,
NotebookCellStatusBarAlignment: extHostTypes.NotebookCellStatusBarAlignment,
NotebookEditorRevealType: extHostTypes.NotebookEditorRevealType,
NotebookCellOutput: extHostTypes.NotebookCellOutput,
NotebookCellOutputItem: extHostTypes.NotebookCellOutputItem,
NotebookCellStatusBarItem: extHostTypes.NotebookCellStatusBarItem,
NotebookControllerAffinity: extHostTypes.NotebookControllerAffinity,
LinkedEditingRanges: extHostTypes.LinkedEditingRanges,
TestItemStatus: extHostTypes.TestItemStatus,
TestResultState: extHostTypes.TestResultState,
TestMessage: extHostTypes.TestMessage,
TextSearchCompleteMessageType: TextSearchCompleteMessageType,
TestMessageSeverity: extHostTypes.TestMessageSeverity,
WorkspaceTrustState: extHostTypes.WorkspaceTrustState
};
};
}
class Extension<T> implements vscode.Extension<T> {
#extensionService: IExtHostExtensionService;
#originExtensionId: ExtensionIdentifier;
#identifier: ExtensionIdentifier;
readonly id: string;
readonly extensionUri: URI;
readonly extensionPath: string;
readonly packageJSON: IExtensionDescription;
readonly extensionKind: vscode.ExtensionKind;
constructor(extensionService: IExtHostExtensionService, originExtensionId: ExtensionIdentifier, description: IExtensionDescription, kind: extHostTypes.ExtensionKind) {
this.#extensionService = extensionService;
this.#originExtensionId = originExtensionId;
this.#identifier = description.identifier;
this.id = description.identifier.value;
this.extensionUri = description.extensionLocation;
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, { startup: false, extensionId: this.#originExtensionId, activationEvent: 'api' }).then(() => this.exports);
}
}

View File

@@ -22,6 +22,7 @@ import { IExtHostWindow, ExtHostWindow } from 'vs/workbench/api/common/extHostWi
import { IExtHostConsumerFileSystem, ExtHostConsumerFileSystem } from 'vs/workbench/api/common/extHostFileSystemConsumer';
import { IExtHostFileSystemInfo, ExtHostFileSystemInfo } from 'vs/workbench/api/common/extHostFileSystemInfo';
import { IExtHostSecretState, ExtHostSecretState } from 'vs/workbench/api/common/exHostSecretState';
import { ExtHostTelemetry, IExtHostTelemetry } from 'vs/workbench/api/common/extHostTelemetry';
registerSingleton(IExtensionStoragePaths, ExtensionStoragePaths);
registerSingleton(IExtHostApiDeprecationService, ExtHostApiDeprecationService);
@@ -41,3 +42,4 @@ registerSingleton(IExtHostTunnelService, ExtHostTunnelService);
registerSingleton(IExtHostWindow, ExtHostWindow);
registerSingleton(IExtHostWorkspace, ExtHostWorkspace);
registerSingleton(IExtHostSecretState, ExtHostSecretState);
registerSingleton(IExtHostTelemetry, ExtHostTelemetry);

View File

@@ -41,25 +41,30 @@ import * as tasks from 'vs/workbench/api/common/shared/tasks';
import { IRevealOptions, ITreeItem } from 'vs/workbench/common/views';
import { IAdapterDescriptor, IConfig, IDebugSessionReplMode } from 'vs/workbench/contrib/debug/common/debug';
import { ITextQueryBuilderOptions } from 'vs/workbench/contrib/search/common/queryBuilder';
import { ITerminalDimensions, IShellLaunchConfig, ITerminalLaunchError } from 'vs/workbench/contrib/terminal/common/terminal';
import { ActivationKind, ExtensionActivationError, ExtensionHostKind } from 'vs/workbench/services/extensions/common/extensions';
import { ActivationKind, MissingExtensionDependency, ExtensionHostKind } from 'vs/workbench/services/extensions/common/extensions';
import { createExtHostContextProxyIdentifier as createExtId, createMainContextProxyIdentifier as createMainId, IRPCProtocol } from 'vs/workbench/services/extensions/common/proxyIdentifier';
import * as search from 'vs/workbench/services/search/common/search';
import { EditorGroupColumn, SaveReason } from 'vs/workbench/common/editor';
import { ExtensionActivationReason } from 'vs/workbench/api/common/extHostExtensionActivator';
import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService';
import { TunnelCreationOptions, TunnelProviderFeatures, TunnelOptions } from 'vs/platform/remote/common/tunnel';
import { TunnelCreationOptions, TunnelProviderFeatures, TunnelOptions, ProvidedPortAttributes } from 'vs/platform/remote/common/tunnel';
import { Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor, InternalTimelineOptions } from 'vs/workbench/contrib/timeline/common/timeline';
import { revive } from 'vs/base/common/marshalling';
import { IProcessedOutput, INotebookDisplayOrder, NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEventDto, NotebookDataDto, IMainCellDto, INotebookDocumentFilter, INotebookKernelInfoDto2, TransientMetadata, INotebookCellStatusBarEntry, ICellRange, INotebookDecorationRenderOptions, INotebookExclusiveDocumentFilter } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEventDto, NotebookDataDto, IMainCellDto, TransientCellMetadata, INotebookDecorationRenderOptions, INotebookExclusiveDocumentFilter, IOutputDto, TransientOptions, IImmediateCellEditOperation, INotebookCellStatusBarItem, TransientDocumentMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange';
import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
import { Dto } from 'vs/base/common/types';
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { DebugConfigurationProviderTriggerKind } from 'vs/workbench/api/common/extHostTypes';
import { DebugConfigurationProviderTriggerKind, TestResultState } from 'vs/workbench/api/common/extHostTypes';
import { IAccessibilityInformation } from 'vs/platform/accessibility/common/accessibility';
import { IExtensionIdWithVersion } from 'vs/platform/userDataSync/common/extensionsStorageSync';
import { InternalTestItem, InternalTestResults, RunTestForProviderRequest, RunTestsRequest, RunTestsResult, TestIdWithProvider, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection';
import { InternalTestItem, RunTestForProviderRequest, RunTestsRequest, TestIdWithSrc, TestsDiff, ISerializedTestResults, ITestMessage, ITestItem, ITestRunTask, ExtensionRunTestsRequest } from 'vs/workbench/contrib/testing/common/testCollection';
import { CandidatePort } from 'vs/workbench/services/remote/common/remoteExplorerService';
import { WorkspaceTrustRequestOptions } from 'vs/platform/workspace/common/workspaceTrust';
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { IShellLaunchConfig, IShellLaunchConfigDto, ITerminalDimensions, ITerminalEnvironment, ITerminalLaunchError } from 'vs/platform/terminal/common/terminal';
import { ITerminalProfile } from 'vs/workbench/contrib/terminal/common/terminal';
import { NotebookSelector } from 'vs/workbench/contrib/notebook/common/notebookSelector';
import { InputValidationType } from 'vs/workbench/contrib/scm/common/scm';
// {{SQL CARBON EDIT}}
import { ITreeItem as sqlITreeItem } from 'sql/workbench/common/views';
@@ -171,7 +176,7 @@ export interface MainThreadAuthenticationShape extends IDisposable {
$ensureProvider(id: string): Promise<void>;
$sendDidChangeSessions(providerId: string, event: modes.AuthenticationSessionsChangeEvent): void;
$getSession(providerId: string, scopes: string[], extensionId: string, extensionName: string, options: { createIfNone?: boolean, clearSessionPreference?: boolean }): Promise<modes.AuthenticationSession | undefined>;
$logout(providerId: string, sessionId: string): Promise<void>;
$removeSession(providerId: string, sessionId: string): Promise<void>;
}
export interface MainThreadSecretStateShape extends IDisposable {
@@ -288,7 +293,7 @@ export interface MainThreadTextEditorsShape extends IDisposable {
}
export interface MainThreadTreeViewsShape extends IDisposable {
$registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean, canSelectMany: boolean; }): void;
$registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean, canSelectMany: boolean; }): Promise<void>;
$refresh(treeViewId: string, itemsToRefresh?: { [treeItemHandle: string]: ITreeItem; }): Promise<void>;
$reveal(treeViewId: string, itemInfo: { item: ITreeItem, parentChain: ITreeItem[] } | undefined, options: IRevealOptions): Promise<void>;
$setMessage(treeViewId: string, message: string): void;
@@ -381,6 +386,8 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable {
$registerTypeDefinitionSupport(handle: number, selector: IDocumentFilterDto[]): void;
$registerHoverProvider(handle: number, selector: IDocumentFilterDto[]): void;
$registerEvaluatableExpressionProvider(handle: number, selector: IDocumentFilterDto[]): void;
$registerInlineValuesProvider(handle: number, selector: IDocumentFilterDto[], eventHandle: number | undefined): void;
$emitInlineValuesEvent(eventHandle: number, event?: any): void;
$registerDocumentHighlightProvider(handle: number, selector: IDocumentFilterDto[]): void;
$registerLinkedEditingRangeProvider(handle: number, selector: IDocumentFilterDto[]): void;
$registerReferenceSupport(handle: number, selector: IDocumentFilterDto[]): void;
@@ -454,12 +461,15 @@ export interface TerminalLaunchConfig {
shellPath?: string;
shellArgs?: string[] | string;
cwd?: string | UriComponents;
env?: { [key: string]: string | null; };
env?: ITerminalEnvironment;
icon?: string;
initialText?: string;
waitOnExit?: boolean;
strictEnv?: boolean;
hideFromUser?: boolean;
isExtensionTerminal?: boolean;
isExtensionCustomPtyTerminal?: boolean;
isFeatureTerminal?: boolean;
isExtensionOwnedTerminal?: boolean;
}
export interface MainThreadTerminalServiceShape extends IDisposable {
@@ -504,6 +514,8 @@ export interface BaseTransferQuickInput {
id: number;
title?: string;
type?: 'quickPick' | 'inputBox';
enabled?: boolean;
@@ -558,6 +570,7 @@ export interface TransferInputBox extends BaseTransferQuickInput {
}
export interface IInputBoxOptions {
title?: string;
value?: string;
valueSelection?: [number, number];
prompt?: string;
@@ -592,11 +605,11 @@ export interface MainThreadTelemetryShape extends IDisposable {
}
export interface MainThreadEditorInsetsShape extends IDisposable {
$createEditorInset(handle: number, id: string, uri: UriComponents, line: number, height: number, options: modes.IWebviewOptions, extensionId: ExtensionIdentifier, extensionLocation: UriComponents): Promise<void>;
$createEditorInset(handle: number, id: string, uri: UriComponents, line: number, height: number, options: IWebviewOptions, extensionId: ExtensionIdentifier, extensionLocation: UriComponents): Promise<void>;
$disposeEditorInset(handle: number): void;
$setHtml(handle: number, value: string): void;
$setOptions(handle: number, options: modes.IWebviewOptions): void;
$setOptions(handle: number, options: IWebviewOptions): void;
$postMessage(handle: number, value: any): Promise<boolean>;
}
@@ -646,30 +659,87 @@ export enum WebviewEditorCapabilities {
SupportsHotExit,
}
export interface IWebviewPortMapping {
readonly webviewPort: number;
readonly extensionHostPort: number;
}
export interface IWebviewOptions {
readonly enableScripts?: boolean;
readonly enableCommandUris?: boolean;
readonly localResourceRoots?: ReadonlyArray<UriComponents>;
readonly portMapping?: ReadonlyArray<IWebviewPortMapping>;
}
export interface IWebviewPanelOptions {
readonly enableFindWidget?: boolean;
readonly retainContextWhenHidden?: boolean;
}
export interface CustomTextEditorCapabilities {
readonly supportsMove?: boolean;
}
export const enum WebviewMessageArrayBufferViewType {
Int8Array = 1,
Uint8Array = 2,
Uint8ClampedArray = 3,
Int16Array = 4,
Uint16Array = 5,
Int32Array = 6,
Uint32Array = 7,
Float32Array = 8,
Float64Array = 9,
BigInt64Array = 10,
BigUint64Array = 11,
}
export interface WebviewMessageArrayBufferReference {
readonly $$vscode_array_buffer_reference$$: true,
readonly index: number;
/**
* Tracks if the reference is to a view instead of directly to an ArrayBuffer.
*/
readonly view?: {
readonly type: WebviewMessageArrayBufferViewType;
readonly byteLength: number;
readonly byteOffset: number;
};
}
export interface MainThreadWebviewsShape extends IDisposable {
$setHtml(handle: WebviewHandle, value: string): void;
$setOptions(handle: WebviewHandle, options: modes.IWebviewOptions): void;
$postMessage(handle: WebviewHandle, value: any): Promise<boolean>
$setOptions(handle: WebviewHandle, options: IWebviewOptions): void;
$postMessage(handle: WebviewHandle, value: any, ...buffers: VSBuffer[]): Promise<boolean>
}
export interface MainThreadWebviewPanelsShape extends IDisposable {
$createWebviewPanel(extension: WebviewExtensionDescription, handle: WebviewHandle, viewType: string, title: string, showOptions: WebviewPanelShowOptions, options: modes.IWebviewPanelOptions & modes.IWebviewOptions): void;
$createWebviewPanel(
extension: WebviewExtensionDescription,
handle: WebviewHandle,
viewType: string,
initData: {
title: string;
webviewOptions: IWebviewOptions;
panelOptions: IWebviewPanelOptions;
serializeBuffersForPostMessage: boolean;
},
showOptions: WebviewPanelShowOptions,
): void;
$disposeWebview(handle: WebviewHandle): void;
$reveal(handle: WebviewHandle, showOptions: WebviewPanelShowOptions): void;
$setTitle(handle: WebviewHandle, value: string): void;
$setIconPath(handle: WebviewHandle, value: { light: UriComponents, dark: UriComponents; } | undefined): void;
$registerSerializer(viewType: string): void;
$registerSerializer(viewType: string, options: { serializeBuffersForPostMessage: boolean }): void;
$unregisterSerializer(viewType: string): void;
}
export interface MainThreadCustomEditorsShape extends IDisposable {
$registerTextEditorProvider(extension: WebviewExtensionDescription, viewType: string, options: modes.IWebviewPanelOptions, capabilities: CustomTextEditorCapabilities): void;
$registerCustomEditorProvider(extension: WebviewExtensionDescription, viewType: string, options: modes.IWebviewPanelOptions, supportsMultipleEditorsPerDocument: boolean): void;
$registerTextEditorProvider(extension: WebviewExtensionDescription, viewType: string, options: IWebviewPanelOptions, capabilities: CustomTextEditorCapabilities, serializeBuffersForPostMessage: boolean): void;
$registerCustomEditorProvider(extension: WebviewExtensionDescription, viewType: string, options: IWebviewPanelOptions, supportsMultipleEditorsPerDocument: boolean, serializeBuffersForPostMessage: boolean): void;
$unregisterEditorProvider(viewType: string): void;
$onDidEdit(resource: UriComponents, viewType: string, editId: number, label: string | undefined): void;
@@ -677,7 +747,7 @@ export interface MainThreadCustomEditorsShape extends IDisposable {
}
export interface MainThreadWebviewViewsShape extends IDisposable {
$registerWebviewViewProvider(extension: WebviewExtensionDescription, viewType: string, options?: { retainContextWhenHidden?: boolean }): void;
$registerWebviewViewProvider(extension: WebviewExtensionDescription, viewType: string, options: { retainContextWhenHidden?: boolean, serializeBuffersForPostMessage: boolean }): void;
$unregisterWebviewViewProvider(viewType: string): void;
$setWebviewViewTitle(handle: WebviewHandle, value: string | undefined): void;
@@ -695,19 +765,40 @@ export interface WebviewPanelViewStateData {
}
export interface ExtHostWebviewsShape {
$onMessage(handle: WebviewHandle, message: any): void;
$onMessage(handle: WebviewHandle, jsonSerializedMessage: string, ...buffers: VSBuffer[]): void;
$onMissingCsp(handle: WebviewHandle, extensionId: string): void;
}
export interface ExtHostWebviewPanelsShape {
$onDidChangeWebviewPanelViewStates(newState: WebviewPanelViewStateData): void;
$onDidDisposeWebviewPanel(handle: WebviewHandle): Promise<void>;
$deserializeWebviewPanel(newWebviewHandle: WebviewHandle, viewType: string, title: string, state: any, position: EditorGroupColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions): Promise<void>;
$deserializeWebviewPanel(
newWebviewHandle: WebviewHandle,
viewType: string,
initData: {
title: string;
state: any;
webviewOptions: IWebviewOptions;
panelOptions: IWebviewPanelOptions;
},
position: EditorGroupColumn,
): Promise<void>;
}
export interface ExtHostCustomEditorsShape {
$resolveWebviewEditor(resource: UriComponents, newWebviewHandle: WebviewHandle, viewType: string, title: string, position: EditorGroupColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions, cancellation: CancellationToken): Promise<void>;
$createCustomDocument(resource: UriComponents, viewType: string, backupId: string | undefined, cancellation: CancellationToken): Promise<{ editable: boolean }>;
$resolveWebviewEditor(
resource: UriComponents,
newWebviewHandle: WebviewHandle,
viewType: string,
initData: {
title: string;
webviewOptions: IWebviewOptions;
panelOptions: IWebviewPanelOptions;
},
position: EditorGroupColumn,
cancellation: CancellationToken
): Promise<void>;
$createCustomDocument(resource: UriComponents, viewType: string, backupId: string | undefined, untitledDocumentData: VSBuffer | undefined, cancellation: CancellationToken): Promise<{ editable: boolean }>;
$disposeCustomDocument(resource: UriComponents, viewType: string): Promise<void>;
$undo(resource: UriComponents, viewType: string, editId: number, isDirty: boolean): Promise<void>;
@@ -748,7 +839,7 @@ export interface ICellDto {
source: string[];
language: string;
cellKind: CellKind;
outputs: IProcessedOutput[];
outputs: IOutputDto[];
metadata?: NotebookCellMetadata;
}
@@ -761,7 +852,7 @@ export type NotebookCellsSplice = [
export type NotebookCellOutputsSplice = [
number /* start */,
number /* delete count */,
IProcessedOutput[]
IOutputDto[]
];
export enum NotebookEditorRevealType {
@@ -775,33 +866,69 @@ export interface INotebookDocumentShowOptions {
position?: EditorGroupColumn;
preserveFocus?: boolean;
pinned?: boolean;
selection?: ICellRange;
selections?: ICellRange[];
}
export type INotebookCellStatusBarEntryDto = Dto<INotebookCellStatusBarEntry>;
export type INotebookCellStatusBarEntryDto = Dto<INotebookCellStatusBarItem>;
export interface INotebookCellStatusBarListDto {
items: INotebookCellStatusBarEntryDto[];
cacheId: number;
}
export interface MainThreadNotebookShape extends IDisposable {
$registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, supportBackup: boolean, options: {
$registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, options: {
transientOutputs: boolean;
transientMetadata: TransientMetadata;
transientCellMetadata: TransientCellMetadata;
transientDocumentMetadata: TransientDocumentMetadata;
viewOptions?: { displayName: string; filenamePattern: (string | IRelativePattern | INotebookExclusiveDocumentFilter)[]; exclusive: boolean; };
}): Promise<void>;
$updateNotebookProviderOptions(viewType: string, options?: { transientOutputs: boolean; transientMetadata: TransientMetadata; }): Promise<void>;
$updateNotebookProviderOptions(viewType: string, options?: { transientOutputs: boolean; transientCellMetadata: TransientCellMetadata; transientDocumentMetadata: TransientDocumentMetadata; }): Promise<void>;
$unregisterNotebookProvider(viewType: string): Promise<void>;
$registerNotebookKernelProvider(extension: NotebookExtensionDescription, handle: number, documentFilter: INotebookDocumentFilter): Promise<void>;
$unregisterNotebookKernelProvider(handle: number): Promise<void>;
$onNotebookKernelChange(handle: number, uri: UriComponents | undefined): void;
$tryApplyEdits(viewType: string, resource: UriComponents, modelVersionId: number, edits: ICellEditOperation[]): Promise<boolean>;
$updateNotebookLanguages(viewType: string, resource: UriComponents, languages: string[]): Promise<void>;
$spliceNotebookCellOutputs(viewType: string, resource: UriComponents, cellHandle: number, splices: NotebookCellOutputsSplice[]): Promise<void>;
$postMessage(editorId: string, forRendererId: string | undefined, value: any): Promise<boolean>;
$setStatusBarEntry(id: number, statusBarEntry: INotebookCellStatusBarEntryDto): Promise<void>;
$tryOpenDocument(uriComponents: UriComponents, viewType?: string): Promise<URI>;
$registerNotebookSerializer(handle: number, extension: NotebookExtensionDescription, viewType: string, options: TransientOptions): void;
$unregisterNotebookSerializer(handle: number): void;
$registerNotebookCellStatusBarItemProvider(handle: number, eventHandle: number | undefined, selector: NotebookSelector): Promise<void>;
$unregisterNotebookCellStatusBarItemProvider(handle: number, eventHandle: number | undefined): Promise<void>;
$emitCellStatusBarEvent(eventHandle: number): void;
}
export interface MainThreadNotebookEditorsShape extends IDisposable {
$tryShowNotebookDocument(uriComponents: UriComponents, viewType: string, options: INotebookDocumentShowOptions): Promise<string>;
$tryRevealRange(id: string, range: ICellRange, revealType: NotebookEditorRevealType): Promise<void>;
$registerNotebookEditorDecorationType(key: string, options: INotebookDecorationRenderOptions): void;
$removeNotebookEditorDecorationType(key: string): void;
$trySetDecorations(id: string, range: ICellRange, decorationKey: string): void;
$tryApplyEdits(editorId: string, modelVersionId: number, cellEdits: ICellEditOperation[]): Promise<boolean>
}
export interface MainThreadNotebookDocumentsShape extends IDisposable {
$tryOpenDocument(uriComponents: UriComponents): Promise<UriComponents>;
$trySaveDocument(uri: UriComponents): Promise<boolean>;
$applyEdits(resource: UriComponents, edits: IImmediateCellEditOperation[], computeUndoRedo?: boolean): Promise<void>;
}
export interface INotebookKernelDto2 {
id: string;
viewType: string;
extensionId: ExtensionIdentifier;
extensionLocation: UriComponents;
label: string;
detail?: string;
description?: string;
supportedLanguages?: string[];
supportsInterrupt?: boolean;
hasExecutionOrder?: boolean;
preloads?: { uri: UriComponents; provides: string[] }[];
}
export interface MainThreadNotebookKernelsShape extends IDisposable {
$postMessage(handle: number, editorId: string | undefined, message: any): Promise<boolean>;
$addKernel(handle: number, data: INotebookKernelDto2): Promise<void>;
$updateKernel(handle: number, data: Partial<INotebookKernelDto2>): void;
$removeKernel(handle: number): void;
$updateNotebookPriority(handle: number, uri: UriComponents, value: number | undefined): void;
}
export interface MainThreadUrlsShape extends IDisposable {
@@ -835,6 +962,7 @@ export interface MainThreadWorkspaceShape extends IDisposable {
$saveAll(includeUntitled?: boolean): Promise<boolean>;
$updateWorkspaceFolders(extensionName: string, index: number, deleteCount: number, workspaceFoldersToAdd: { uri: UriComponents, name?: string; }[]): Promise<void>;
$resolveProxy(url: string): Promise<string | undefined>;
$requestWorkspaceTrust(options?: WorkspaceTrustRequestOptions): Promise<boolean | undefined>;
}
export interface IFileChangeDto {
@@ -888,9 +1016,8 @@ export interface MainThreadExtensionServiceShape extends IDisposable {
$activateExtension(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<void>;
$onWillActivateExtension(extensionId: ExtensionIdentifier): Promise<void>;
$onDidActivateExtension(extensionId: ExtensionIdentifier, codeLoadingTime: number, activateCallTime: number, activateResolvedTime: number, activationReason: ExtensionActivationReason): void;
$onExtensionActivationError(extensionId: ExtensionIdentifier, error: ExtensionActivationError): Promise<void>;
$onExtensionActivationError(extensionId: ExtensionIdentifier, error: SerializedError, missingExtensionDependency: MissingExtensionDependency | null): Promise<void>;
$onExtensionRuntimeError(extensionId: ExtensionIdentifier, error: SerializedError): void;
$onExtensionHostExit(code: number): Promise<void>;
$setPerformanceMarks(marks: performance.PerformanceMark[]): Promise<void>;
}
@@ -943,6 +1070,8 @@ export interface MainThreadSCMShape extends IDisposable {
$setInputBoxValue(sourceControlHandle: number, value: string): void;
$setInputBoxPlaceholder(sourceControlHandle: number, placeholder: string): void;
$setInputBoxVisibility(sourceControlHandle: number, visible: boolean): void;
$setInputBoxFocus(sourceControlHandle: number): void;
$showValidationMessage(sourceControlHandle: number, message: string, type: InputValidationType): void;
$setValidationProviderIsEnabled(sourceControlHandle: number, enabled: boolean): void;
}
@@ -994,14 +1123,29 @@ export interface MainThreadWindowShape extends IDisposable {
$asExternalUri(uri: UriComponents, options: IOpenUriOptions): Promise<UriComponents>;
}
export enum CandidatePortSource {
None = 0,
Process = 1,
Output = 2
}
export interface PortAttributesProviderSelector {
pid?: number;
portRange?: [number, number];
commandMatcher?: RegExp;
}
export interface MainThreadTunnelServiceShape extends IDisposable {
$openTunnel(tunnelOptions: TunnelOptions, source: string | undefined): Promise<TunnelDto | undefined>;
$closeTunnel(remote: { host: string, port: number }): Promise<void>;
$getTunnels(): Promise<TunnelDescription[]>;
$setTunnelProvider(features: TunnelProviderFeatures): Promise<void>;
$setCandidateFinder(): Promise<void>;
$setRemoteTunnelService(processId: number): Promise<void>;
$setCandidateFilter(): Promise<void>;
$onFoundNewCandidates(candidates: { host: string, port: number, detail: string }[]): Promise<void>;
$onFoundNewCandidates(candidates: CandidatePort[]): Promise<void>;
$setCandidatePortSource(source: CandidatePortSource): Promise<void>;
$registerPortsAttributesProvider(selector: PortAttributesProviderSelector, providerHandle: number): Promise<void>;
$unregisterPortsAttributesProvider(providerHandle: number): Promise<void>;
}
export interface MainThreadTimelineShape extends IDisposable {
@@ -1039,7 +1183,7 @@ export interface IModelAddedData {
isDirty: boolean;
}
export interface ExtHostDocumentsShape {
$acceptModelModeChanged(strURL: UriComponents, oldModeId: string, newModeId: string): void;
$acceptModelModeChanged(strURL: UriComponents, newModeId: string): void;
$acceptModelSaved(strURL: UriComponents): void;
$acceptDirtyStateChanged(strURL: UriComponents, isDirty: boolean): void;
$acceptModelChanged(strURL: UriComponents, e: IModelChangedEvent, isDirty: boolean): void;
@@ -1098,9 +1242,10 @@ export interface ExtHostTreeViewsShape {
}
export interface ExtHostWorkspaceShape {
$initializeWorkspace(workspace: IWorkspaceData | null): void;
$initializeWorkspace(workspace: IWorkspaceData | null, trusted: boolean): void;
$acceptWorkspaceData(workspace: IWorkspaceData | null): void;
$handleTextSearchResult(result: search.IRawFileMatch2, requestId: number): void;
$onDidGrantWorkspaceTrust(): void;
}
export interface ExtHostFileSystemInfoShape {
@@ -1129,11 +1274,10 @@ export interface ExtHostLabelServiceShape {
}
export interface ExtHostAuthenticationShape {
$getSessions(id: string): Promise<ReadonlyArray<modes.AuthenticationSession>>;
$getSessionAccessToken(id: string, sessionId: string): Promise<string>;
$login(id: string, scopes: string[]): Promise<modes.AuthenticationSession>;
$logout(id: string, sessionId: string): Promise<void>;
$onDidChangeAuthenticationSessions(id: string, label: string, event: modes.AuthenticationSessionsChangeEvent): Promise<void>;
$getSessions(id: string, scopes?: string[]): Promise<ReadonlyArray<modes.AuthenticationSession>>;
$createSession(id: string, scopes: string[]): Promise<modes.AuthenticationSession>;
$removeSession(id: string, sessionId: string): Promise<void>;
$onDidChangeAuthenticationSessions(id: string, label: string): Promise<void>;
$onDidChangeAuthenticationProviders(added: modes.AuthenticationProviderInformation[], removed: modes.AuthenticationProviderInformation[]): Promise<void>;
$setProviders(providers: modes.AuthenticationProviderInformation[]): Promise<void>;
}
@@ -1167,6 +1311,8 @@ export type IResolveAuthorityResult = IResolveAuthorityErrorResult | IResolveAut
export interface ExtHostExtensionServiceShape {
$resolveAuthority(remoteAuthority: string, resolveAttempt: number): Promise<IResolveAuthorityResult>;
$startExtensionHost(enabledExtensionIds: ExtensionIdentifier[]): Promise<void>;
$extensionTestsExecute(): Promise<number>;
$extensionTestsExit(code: number): Promise<void>;
$activateByEvent(activationEvent: string, activationKind: ActivationKind): Promise<void>;
$activate(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<boolean>;
$setRemoteEnvironment(env: { [key: string]: string | null; }): Promise<void>;
@@ -1197,8 +1343,8 @@ export interface IWillRunFileOperationParticipation {
export interface ExtHostFileSystemEventServiceShape {
$onFileEvent(events: FileSystemEvents): void;
$onWillRunFileOperation(operation: files.FileOperation, files: SourceTargetPair[], timeout: number, token: CancellationToken): Promise<IWillRunFileOperationParticipation | undefined>;
$onDidRunFileOperation(operation: files.FileOperation, files: SourceTargetPair[]): void;
$onWillRunFileOperation(operation: files.FileOperation, files: readonly SourceTargetPair[], timeout: number, token: CancellationToken): Promise<IWillRunFileOperationParticipation | undefined>;
$onDidRunFileOperation(operation: files.FileOperation, files: readonly SourceTargetPair[]): void;
}
export interface ObjectIdentifier {
@@ -1305,9 +1451,10 @@ export interface ISignatureHelpContextDto {
export interface IInlineHintDto {
text: string;
range: IRange;
hoverMessage?: string;
kind: modes.InlineHintKind;
whitespaceBefore?: boolean;
whitespaceAfter?: boolean;
hoverMessage?: string;
}
export interface IInlineHintsDto {
@@ -1376,9 +1523,6 @@ export interface IWorkspaceCellEditDto {
export interface IWorkspaceEditDto {
edits: Array<IWorkspaceFileEditDto | IWorkspaceTextEditDto | IWorkspaceCellEditDto>;
// todo@jrieken reject should go into rename
rejectReason?: string;
}
export function reviveWorkspaceEditDto(data: IWorkspaceEditDto | undefined): modes.WorkspaceEdit {
@@ -1470,6 +1614,11 @@ export interface ILinkedEditingRangesDto {
wordPattern?: IRegExpDto;
}
export interface IInlineValueContextDto {
frameId: number;
stoppedLocation: IRange;
}
export interface ExtHostLanguageFeaturesShape {
$provideDocumentSymbols(handle: number, resource: UriComponents, token: CancellationToken): Promise<modes.DocumentSymbol[] | undefined>;
$provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Promise<ICodeLensListDto | undefined>;
@@ -1481,6 +1630,7 @@ export interface ExtHostLanguageFeaturesShape {
$provideTypeDefinition(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<IDefinitionLinkDto[]>;
$provideHover(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<modes.Hover | undefined>;
$provideEvaluatableExpression(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<modes.EvaluatableExpression | undefined>;
$provideInlineValues(handle: number, resource: UriComponents, range: IRange, context: modes.InlineValueContext, token: CancellationToken): Promise<modes.InlineValue[] | undefined>;
$provideDocumentHighlights(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<modes.DocumentHighlight[] | undefined>;
$provideLinkedEditingRanges(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<ILinkedEditingRangesDto | undefined>;
$provideReferences(handle: number, resource: UriComponents, position: IPosition, context: modes.ReferenceContext, token: CancellationToken): Promise<ILocationDto[] | undefined>;
@@ -1493,7 +1643,7 @@ export interface ExtHostLanguageFeaturesShape {
$provideWorkspaceSymbols(handle: number, search: string, token: CancellationToken): Promise<IWorkspaceSymbolsDto>;
$resolveWorkspaceSymbol(handle: number, symbol: IWorkspaceSymbolDto, token: CancellationToken): Promise<IWorkspaceSymbolDto | undefined>;
$releaseWorkspaceSymbols(handle: number, id: number): void;
$provideRenameEdits(handle: number, resource: UriComponents, position: IPosition, newName: string, token: CancellationToken): Promise<IWorkspaceEditDto | undefined>;
$provideRenameEdits(handle: number, resource: UriComponents, position: IPosition, newName: string, token: CancellationToken): Promise<IWorkspaceEditDto & { rejectReason?: string } | undefined>;
$resolveRenameLocation(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<modes.RenameLocation | undefined>;
$provideDocumentSemanticTokens(handle: number, resource: UriComponents, previousResultId: number, token: CancellationToken): Promise<VSBuffer | null>;
$releaseDocumentSemanticTokens(handle: number, semanticColoringResultId: number): void;
@@ -1529,19 +1679,9 @@ export interface ExtHostQuickOpenShape {
$onDidHide(sessionId: number): void;
}
export interface IShellLaunchConfigDto {
name?: string;
executable?: string;
args?: string[] | string;
cwd?: string | UriComponents;
env?: { [key: string]: string | null; };
hideFromUser?: boolean;
flowControl?: boolean;
}
export interface IShellDefinitionDto {
label: string;
path: string;
export interface ExtHostTelemetryShape {
$initializeTelemetryEnabled(enabled: boolean): void;
$onDidChangeTelemetryEnabled(enabled: boolean): void;
}
export interface IShellAndArgsDto {
@@ -1574,7 +1714,6 @@ export interface ExtHostTerminalServiceShape {
$acceptTerminalTitleChange(id: number, name: string): void;
$acceptTerminalDimensions(id: number, cols: number, rows: number): void;
$acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): void;
$spawnExtHostProcess(id: number, shellLaunchConfig: IShellLaunchConfigDto, activeWorkspaceRootUri: UriComponents | undefined, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise<ITerminalLaunchError | undefined>;
$startExtensionTerminal(id: number, initialDimensions: ITerminalDimensionsDto | undefined): Promise<ITerminalLaunchError | undefined>;
$acceptProcessAckDataEvent(id: number, charCount: number): void;
$acceptProcessInput(id: number, data: string): void;
@@ -1583,8 +1722,7 @@ export interface ExtHostTerminalServiceShape {
$acceptProcessRequestInitialCwd(id: number): void;
$acceptProcessRequestCwd(id: number): void;
$acceptProcessRequestLatency(id: number): number;
$acceptWorkspacePermissionsChanged(isAllowed: boolean): void;
$getAvailableShells(): Promise<IShellDefinitionDto[]>;
$getAvailableProfiles(configuredProfilesOnly: boolean): Promise<ITerminalProfile[]>;
$getDefaultShellAndArgs(useAutomationShell: boolean): Promise<IShellAndArgsDto>;
$provideLinks(id: number, line: string): Promise<ITerminalLinkDto[]>;
$activateLink(id: number, linkId: number): void;
@@ -1632,6 +1770,7 @@ export interface IDataBreakpointDto extends IBreakpointDto {
canPersist: boolean;
label: string;
accessTypes?: DebugProtocol.DataBreakpointAccessType[];
accessType: DebugProtocol.DataBreakpointAccessType;
}
export interface ISourceBreakpointDto extends IBreakpointDto {
@@ -1731,26 +1870,20 @@ export interface ExtHostCommentsShape {
}
export interface INotebookSelectionChangeEvent {
// handles
selections: number[];
}
export interface INotebookCellVisibleRange {
start: number;
end: number;
selections: ICellRange[];
}
export interface INotebookVisibleRangesEvent {
ranges: INotebookCellVisibleRange[];
ranges: ICellRange[];
}
export interface INotebookEditorPropertiesChangeData {
visibleRanges: INotebookVisibleRangesEvent | null;
selections: INotebookSelectionChangeEvent | null;
visibleRanges?: INotebookVisibleRangesEvent;
selections?: INotebookSelectionChangeEvent;
}
export interface INotebookDocumentPropertiesChangeData {
metadata: NotebookDocumentMetadata | null;
metadata?: NotebookDocumentMetadata;
}
export interface INotebookModelAddedData {
@@ -1759,15 +1892,14 @@ export interface INotebookModelAddedData {
cells: IMainCellDto[],
viewType: string;
metadata?: NotebookDocumentMetadata;
attachedEditor?: { id: string; selections: number[]; visibleRanges: ICellRange[] }
contentOptions: { transientOutputs: boolean; transientMetadata: TransientMetadata; }
}
export interface INotebookEditorAddData {
id: string;
documentUri: UriComponents;
selections: number[];
selections: ICellRange[];
visibleRanges: ICellRange[];
viewColumn?: number
}
export interface INotebookDocumentsAndEditorsDelta {
@@ -1779,26 +1911,59 @@ export interface INotebookDocumentsAndEditorsDelta {
visibleEditors?: string[];
}
export interface ExtHostNotebookShape {
$resolveNotebookData(viewType: string, uri: UriComponents, backupId?: string): Promise<NotebookDataDto>;
$resolveNotebookEditor(viewType: string, uri: UriComponents, editorId: string): Promise<void>;
$provideNotebookKernels(handle: number, uri: UriComponents, token: CancellationToken): Promise<INotebookKernelInfoDto2[]>;
$resolveNotebookKernel(handle: number, editorId: string, uri: UriComponents, kernelId: string, token: CancellationToken): Promise<void>;
$executeNotebookKernelFromProvider(handle: number, uri: UriComponents, kernelId: string, cellHandle: number | undefined): Promise<void>;
$cancelNotebookKernelFromProvider(handle: number, uri: UriComponents, kernelId: string, cellHandle: number | undefined): Promise<void>;
export interface INotebookKernelInfoDto2 {
id?: string;
friendlyId: string;
label: string;
extension: ExtensionIdentifier;
extensionLocation: UriComponents;
providerHandle?: number;
description?: string;
detail?: string;
isPreferred?: boolean;
preloads?: { uri: UriComponents; provides: string[] }[];
supportedLanguages?: string[]
implementsInterrupt?: boolean;
}
export interface ExtHostNotebookShape extends ExtHostNotebookDocumentsAndEditorsShape, ExtHostNotebookDocumentsShape, ExtHostNotebookEditorsShape {
$provideNotebookCellStatusBarItems(handle: number, uri: UriComponents, index: number, token: CancellationToken): Promise<INotebookCellStatusBarListDto | undefined>;
$releaseNotebookCellStatusBarItems(id: number): void;
$openNotebook(viewType: string, uri: UriComponents, backupId: string | undefined, untitledDocumentData: VSBuffer | undefined, token: CancellationToken): Promise<NotebookDataDto>;
$saveNotebook(viewType: string, uri: UriComponents, token: CancellationToken): Promise<boolean>;
$saveNotebookAs(viewType: string, uri: UriComponents, target: UriComponents, token: CancellationToken): Promise<boolean>;
$backup(viewType: string, uri: UriComponents, cancellation: CancellationToken): Promise<string | undefined>;
$acceptDisplayOrder(displayOrder: INotebookDisplayOrder): void;
$acceptNotebookActiveKernelChange(event: { uri: UriComponents, providerHandle: number | undefined, kernelFriendlyId: string | undefined }): void;
$onDidReceiveMessage(editorId: string, rendererId: string | undefined, message: unknown): void;
$acceptModelChanged(uriComponents: UriComponents, event: NotebookCellsChangedEventDto, isDirty: boolean): void;
$acceptModelSaved(uriComponents: UriComponents): void;
$acceptEditorPropertiesChanged(id: string, data: INotebookEditorPropertiesChangeData): void;
$acceptDocumentPropertiesChanged(uriComponents: UriComponents, data: INotebookDocumentPropertiesChangeData): void;
$backupNotebook(viewType: string, uri: UriComponents, cancellation: CancellationToken): Promise<string>;
$dataToNotebook(handle: number, data: VSBuffer, token: CancellationToken): Promise<NotebookDataDto>;
$notebookToData(handle: number, data: NotebookDataDto, token: CancellationToken): Promise<VSBuffer>;
}
export interface ExtHostNotebookDocumentsAndEditorsShape {
$acceptDocumentAndEditorsDelta(delta: INotebookDocumentsAndEditorsDelta): void;
}
export interface ExtHostNotebookDocumentsShape {
$acceptModelChanged(uriComponents: UriComponents, event: NotebookCellsChangedEventDto, isDirty: boolean): void;
$acceptDirtyStateChanged(uriComponents: UriComponents, isDirty: boolean): void;
$acceptModelSaved(uriComponents: UriComponents): void;
$acceptDocumentPropertiesChanged(uriComponents: UriComponents, data: INotebookDocumentPropertiesChangeData): void;
}
export type INotebookEditorViewColumnInfo = Record<string, number>;
export interface ExtHostNotebookEditorsShape {
$acceptEditorPropertiesChanged(id: string, data: INotebookEditorPropertiesChangeData): void;
$acceptEditorViewColumns(data: INotebookEditorViewColumnInfo): void;
}
export interface ExtHostNotebookKernelsShape {
$acceptSelection(handle: number, uri: UriComponents, value: boolean): void;
$executeCells(handle: number, uri: UriComponents, handles: number[]): Promise<void>;
$cancelCells(handle: number, uri: UriComponents, handles: number[]): Promise<void>;
$acceptRendererMessage(handle: number, editorId: string, message: any): void;
}
export interface ExtHostStorageShape {
$acceptValue(shared: boolean, key: string, value: object | undefined): void;
}
@@ -1816,6 +1981,7 @@ export interface ExtHostTunnelServiceShape {
$onDidTunnelsChange(): Promise<void>;
$registerCandidateFinder(enable: boolean): Promise<void>;
$applyCandidateFilter(candidates: CandidatePort[]): Promise<CandidatePort[]>;
$providePortAttributes(handles: number[], ports: number[], pid: number | undefined, commandline: string | undefined, cancellationToken: CancellationToken): Promise<ProvidedPortAttributes[]>;
}
export interface ExtHostTimelineShape {
@@ -1828,21 +1994,49 @@ export const enum ExtHostTestingResource {
}
export interface ExtHostTestingShape {
$runTestsForProvider(req: RunTestForProviderRequest, token: CancellationToken): Promise<RunTestsResult>;
$runTestsForProvider(req: RunTestForProviderRequest, token: CancellationToken): Promise<void>;
$subscribeToTests(resource: ExtHostTestingResource, uri: UriComponents): void;
$unsubscribeFromTests(resource: ExtHostTestingResource, uri: UriComponents): void;
$lookupTest(test: TestIdWithProvider): Promise<InternalTestItem | undefined>;
$lookupTest(test: TestIdWithSrc): Promise<InternalTestItem | undefined>;
$acceptDiff(resource: ExtHostTestingResource, uri: UriComponents, diff: TestsDiff): void;
$publishTestResults(results: InternalTestResults): void;
$publishTestResults(results: ISerializedTestResults[]): void;
$expandTest(src: TestIdWithSrc, levels: number): Promise<void>;
}
export interface MainThreadTestingShape {
$registerTestProvider(id: string): void;
$unregisterTestProvider(id: string): void;
/** Registeres that there's a test controller with the given ID */
$registerTestController(id: string): void;
/** Diposes of the test controller with the given ID */
$unregisterTestController(id: string): void;
/** Requests tests from the given resource/uri, from the observer API. */
$subscribeToDiffs(resource: ExtHostTestingResource, uri: UriComponents): void;
/** Stops requesting tests from the given resource/uri, from the observer API. */
$unsubscribeFromDiffs(resource: ExtHostTestingResource, uri: UriComponents): void;
/** Publishes that new tests were available on the given source. */
$publishDiff(resource: ExtHostTestingResource, uri: UriComponents, diff: TestsDiff): void;
$runTests(req: RunTestsRequest, token: CancellationToken): Promise<RunTestsResult>;
/** Request by an extension to run tests. */
$runTests(req: RunTestsRequest, token: CancellationToken): Promise<string>;
// --- test run handling:
/**
* Adds tests to the run. The tests are given in descending depth. The first
* item will be a previously-known test, or a test root.
*/
$addTestsToRun(runId: string, tests: ITestItem[]): void;
/** Updates the state of a test run in the given run. */
$updateTestStateInRun(runId: string, taskId: string, testId: string, state: TestResultState, duration?: number): void;
/** Appends a message to a test in the run. */
$appendTestMessageInRun(runId: string, taskId: string, testId: string, message: ITestMessage): void;
/** Appends raw output to the test run.. */
$appendOutputToRun(runId: string, taskId: string, output: VSBuffer): void;
/** Signals a task in a test run started. */
$startedTestRunTask(runId: string, task: ITestRunTask): void;
/** Signals a task in a test run ended. */
$finishedTestRunTask(runId: string, taskId: string): void;
/** Start a new extension-provided test run. */
$startedExtensionTestRun(req: ExtensionRunTestsRequest): void;
/** Signals that an extension-provided test run finished. */
$finishedExtensionTestRun(runId: string): void;
}
// --- proxy identifiers
@@ -1895,6 +2089,9 @@ export const MainContext = {
MainThreadWindow: createMainId<MainThreadWindowShape>('MainThreadWindow'),
MainThreadLabelService: createMainId<MainThreadLabelServiceShape>('MainThreadLabelService'),
MainThreadNotebook: createMainId<MainThreadNotebookShape>('MainThreadNotebook'),
MainThreadNotebookDocuments: createMainId<MainThreadNotebookDocumentsShape>('MainThreadNotebookDocumentsShape'),
MainThreadNotebookEditors: createMainId<MainThreadNotebookEditorsShape>('MainThreadNotebookEditorsShape'),
MainThreadNotebookKernels: createMainId<MainThreadNotebookKernelsShape>('MainThreadNotebookKernels'),
MainThreadTheming: createMainId<MainThreadThemingShape>('MainThreadTheming'),
MainThreadTunnelService: createMainId<MainThreadTunnelServiceShape>('MainThreadTunnelService'),
MainThreadTimeline: createMainId<MainThreadTimelineShape>('MainThreadTimeline'),
@@ -1941,9 +2138,11 @@ export const ExtHostContext = {
ExtHostOutputService: createMainId<ExtHostOutputServiceShape>('ExtHostOutputService'),
ExtHosLabelService: createMainId<ExtHostLabelServiceShape>('ExtHostLabelService'),
ExtHostNotebook: createMainId<ExtHostNotebookShape>('ExtHostNotebook'),
ExtHostNotebookKernels: createMainId<ExtHostNotebookKernelsShape>('ExtHostNotebookKernels'),
ExtHostTheming: createMainId<ExtHostThemingShape>('ExtHostTheming'),
ExtHostTunnelService: createMainId<ExtHostTunnelServiceShape>('ExtHostTunnelService'),
ExtHostAuthentication: createMainId<ExtHostAuthenticationShape>('ExtHostAuthentication'),
ExtHostTimeline: createMainId<ExtHostTimelineShape>('ExtHostTimeline'),
ExtHostTesting: createMainId<ExtHostTestingShape>('ExtHostTesting'),
ExtHostTelemetry: createMainId<ExtHostTelemetryShape>('ExtHostTelemetry'),
};

View File

@@ -18,7 +18,7 @@ import { ICommandsExecutor, RemoveFromRecentlyOpenedAPICommand, OpenIssueReporte
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
import { IRange } from 'vs/editor/common/core/range';
import { IPosition } from 'vs/editor/common/core/position';
import { TransientMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { TransientCellMetadata, TransientDocumentMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { ITextEditorOptions } from 'vs/platform/editor/common/editor';
import { VSBuffer } from 'vs/base/common/buffer';
import { decodeSemanticTokensDto } from 'vs/editor/common/services/semanticTokensDto';
@@ -30,13 +30,13 @@ const newCommands: ApiCommand[] = [
new ApiCommand(
'vscode.executeDocumentHighlights', '_executeDocumentHighlights', 'Execute document highlight provider.',
[ApiCommandArgument.Uri, ApiCommandArgument.Position],
new ApiCommandResult<modes.DocumentHighlight[], types.DocumentHighlight[] | undefined>('A promise that resolves to an array of SymbolInformation and DocumentSymbol instances.', tryMapWith(typeConverters.DocumentHighlight.to))
new ApiCommandResult<modes.DocumentHighlight[], types.DocumentHighlight[] | undefined>('A promise that resolves to an array of DocumentHighlight-instances.', tryMapWith(typeConverters.DocumentHighlight.to))
),
// -- document symbols
new ApiCommand(
'vscode.executeDocumentSymbolProvider', '_executeDocumentSymbolProvider', 'Execute document symbol provider.',
[ApiCommandArgument.Uri],
new ApiCommandResult<modes.DocumentSymbol[], vscode.SymbolInformation[] | undefined>('A promise that resolves to an array of DocumentHighlight-instances.', (value, apiArgs) => {
new ApiCommandResult<modes.DocumentSymbol[], vscode.SymbolInformation[] | undefined>('A promise that resolves to an array of SymbolInformation and DocumentSymbol instances.', (value, apiArgs) => {
if (isFalsyOrEmpty(value)) {
return undefined;
@@ -60,7 +60,7 @@ const newCommands: ApiCommand[] = [
range!: vscode.Range;
selectionRange!: vscode.Range;
children!: vscode.DocumentSymbol[];
containerName!: string;
override containerName!: string;
}
return value.map(MergedInfo.to);
@@ -117,7 +117,7 @@ const newCommands: ApiCommand[] = [
// -- selection range
new ApiCommand(
'vscode.executeSelectionRangeProvider', '_executeSelectionRangeProvider', 'Execute selection range provider.',
[ApiCommandArgument.Uri, new ApiCommandArgument<types.Position[], IPosition[]>('position', 'A positions in a text document', v => Array.isArray(v) && v.every(v => types.Position.isPosition(v)), v => v.map(typeConverters.Position.from))],
[ApiCommandArgument.Uri, new ApiCommandArgument<types.Position[], IPosition[]>('position', 'A position in a text document', v => Array.isArray(v) && v.every(v => types.Position.isPosition(v)), v => v.map(typeConverters.Position.from))],
new ApiCommandResult<IRange[][], types.SelectionRange[]>('A promise that resolves to an array of ranges.', result => {
return result.map(ranges => {
let node: types.SelectionRange | undefined;
@@ -162,7 +162,7 @@ const newCommands: ApiCommand[] = [
new ApiCommand(
'vscode.executeDocumentRenameProvider', '_executeDocumentRenameProvider', 'Execute rename provider.',
[ApiCommandArgument.Uri, ApiCommandArgument.Position, ApiCommandArgument.String.with('newName', 'The new symbol name')],
new ApiCommandResult<IWorkspaceEditDto, types.WorkspaceEdit | undefined>('A promise that resolves to a WorkspaceEdit.', value => {
new ApiCommandResult<IWorkspaceEditDto & { rejectReason?: string }, types.WorkspaceEdit | undefined>('A promise that resolves to a WorkspaceEdit.', value => {
if (!value) {
return undefined;
}
@@ -343,25 +343,37 @@ const newCommands: ApiCommand[] = [
new ApiCommandResult<{
viewType: string;
displayName: string;
options: { transientOutputs: boolean; transientMetadata: TransientMetadata };
options: { transientOutputs: boolean; transientCellMetadata: TransientCellMetadata; transientDocumentMetadata: TransientDocumentMetadata; };
filenamePattern: (string | types.RelativePattern | { include: string | types.RelativePattern, exclude: string | types.RelativePattern })[]
}[], {
viewType: string;
displayName: string;
filenamePattern: vscode.NotebookFilenamePattern[];
filenamePattern: (vscode.GlobPattern | { include: vscode.GlobPattern; exclude: vscode.GlobPattern; })[];
options: vscode.NotebookDocumentContentOptions;
}[] | undefined>('A promise that resolves to an array of NotebookContentProvider static info objects.', tryMapWith(item => {
return {
viewType: item.viewType,
displayName: item.displayName,
options: { transientOutputs: item.options.transientOutputs, transientMetadata: item.options.transientMetadata },
options: {
transientOutputs: item.options.transientOutputs,
transientCellMetadata: item.options.transientCellMetadata,
transientDocumentMetadata: item.options.transientDocumentMetadata
},
filenamePattern: item.filenamePattern.map(pattern => typeConverters.NotebookExclusiveDocumentPattern.to(pattern))
};
}))
),
// --- debug support
new ApiCommand(
'vscode.executeInlineValueProvider', '_executeInlineValueProvider', 'Execute inline value provider',
[ApiCommandArgument.Uri, ApiCommandArgument.Range],
new ApiCommandResult<modes.InlineValue[], vscode.InlineValue[]>('A promise that resolves to an array of InlineValue objects', result => {
return result.map(typeConverters.InlineValue.to);
})
),
// --- open'ish commands
new ApiCommand(
'vscode.open', '_workbench.open', 'Opens the provided resource in the editor. Can be a text or binary file, or a http(s) url. If you need more control over the options for opening a text file, use vscode.window.showTextDocument instead.',
'vscode.open', '_workbench.open', 'Opens the provided resource in the editor. Can be a text or binary file, or an http(s) URL. If you need more control over the options for opening a text file, use vscode.window.showTextDocument instead.',
[
ApiCommandArgument.Uri,
new ApiCommandArgument<vscode.ViewColumn | typeConverters.TextEditorOpenOptions | undefined, [number?, ITextEditorOptions?] | undefined>('columnOrOptions', 'Either the column in which to open or editor options, see vscode.TextDocumentShowOptions',
@@ -388,7 +400,7 @@ const newCommands: ApiCommand[] = [
'vscode.diff', '_workbench.diff', 'Opens the provided resources in the diff editor to compare their contents.',
[
ApiCommandArgument.Uri.with('left', 'Left-hand side resource of the diff editor'),
ApiCommandArgument.Uri.with('right', 'Rigth-hand side resource of the diff editor'),
ApiCommandArgument.Uri.with('right', 'Right-hand side resource of the diff editor'),
ApiCommandArgument.String.with('title', 'Human readable title for the diff editor').optional(),
new ApiCommandArgument<typeConverters.TextEditorOpenOptions | undefined, [number?, ITextEditorOptions?] | undefined>('columnOrOptions', 'Either the column in which to open or editor options, see vscode.TextDocumentShowOptions',
v => v === undefined || typeof v === 'object',

View File

@@ -87,13 +87,13 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
return this._proxy.$getSession(providerId, scopes, extensionId, extensionName, options);
}
async logout(providerId: string, sessionId: string): Promise<void> {
async removeSession(providerId: string, sessionId: string): Promise<void> {
const providerData = this._authenticationProviders.get(providerId);
if (!providerData) {
return this._proxy.$logout(providerId, sessionId);
return this._proxy.$removeSession(providerId, sessionId);
}
return providerData.provider.logout(sessionId);
return providerData.provider.removeSession(sessionId);
}
registerAuthenticationProvider(id: string, label: string, provider: vscode.AuthenticationProvider, options?: vscode.AuthenticationProviderOptions): vscode.Disposable {
@@ -111,7 +111,11 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
}
const listener = provider.onDidChangeSessions(e => {
this._proxy.$sendDidChangeSessions(id, e);
this._proxy.$sendDidChangeSessions(id, {
added: e.added ?? [],
changed: e.changed ?? [],
removed: e.removed ?? []
});
});
this._proxy.$registerAuthenticationProvider(id, label, options?.supportsMultipleAccounts ?? false);
@@ -129,50 +133,35 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
});
}
$login(providerId: string, scopes: string[]): Promise<modes.AuthenticationSession> {
$createSession(providerId: string, scopes: string[]): Promise<modes.AuthenticationSession> {
const providerData = this._authenticationProviders.get(providerId);
if (providerData) {
return Promise.resolve(providerData.provider.login(scopes));
return Promise.resolve(providerData.provider.createSession(scopes));
}
throw new Error(`Unable to find authentication provider with handle: ${providerId}`);
}
$logout(providerId: string, sessionId: string): Promise<void> {
$removeSession(providerId: string, sessionId: string): Promise<void> {
const providerData = this._authenticationProviders.get(providerId);
if (providerData) {
return Promise.resolve(providerData.provider.logout(sessionId));
return Promise.resolve(providerData.provider.removeSession(sessionId));
}
throw new Error(`Unable to find authentication provider with handle: ${providerId}`);
}
$getSessions(providerId: string): Promise<ReadonlyArray<modes.AuthenticationSession>> {
$getSessions(providerId: string, scopes?: string[]): Promise<ReadonlyArray<modes.AuthenticationSession>> {
const providerData = this._authenticationProviders.get(providerId);
if (providerData) {
return Promise.resolve(providerData.provider.getSessions());
return Promise.resolve(providerData.provider.getSessions(scopes));
}
throw new Error(`Unable to find authentication provider with handle: ${providerId}`);
}
async $getSessionAccessToken(providerId: string, sessionId: string): Promise<string> {
const providerData = this._authenticationProviders.get(providerId);
if (providerData) {
const sessions = await providerData.provider.getSessions();
const session = sessions.find(session => session.id === sessionId);
if (session) {
return session.accessToken;
}
throw new Error(`Unable to find session with id: ${sessionId}`);
}
throw new Error(`Unable to find authentication provider with handle: ${providerId}`);
}
$onDidChangeAuthenticationSessions(id: string, label: string, event: modes.AuthenticationSessionsChangeEvent) {
this._onDidChangeSessions.fire({ provider: { id, label }, ...event });
$onDidChangeAuthenticationSessions(id: string, label: string) {
this._onDidChangeSessions.fire({ provider: { id, label } });
return Promise.resolve();
}

View File

@@ -5,7 +5,6 @@
import { MainContext, MainThreadBulkEditsShape } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { WorkspaceEdit } from 'vs/workbench/api/common/extHostTypeConverters';
import type * as vscode from 'vscode';
@@ -17,13 +16,12 @@ export class ExtHostBulkEdits {
constructor(
@IExtHostRpcService extHostRpc: IExtHostRpcService,
private readonly _extHostDocumentsAndEditors: ExtHostDocumentsAndEditors,
private readonly _extHostNotebooks: ExtHostNotebookController,
) {
this._proxy = extHostRpc.getProxy(MainContext.MainThreadBulkEdits);
}
applyWorkspaceEdit(edit: vscode.WorkspaceEdit): Promise<boolean> {
const dto = WorkspaceEdit.from(edit, this._extHostDocumentsAndEditors, this._extHostNotebooks);
const dto = WorkspaceEdit.from(edit, this._extHostDocumentsAndEditors);
return this._proxy.$tryApplyWorkspaceEdit(dto);
}
}

View File

@@ -217,6 +217,14 @@ export class ExtHostCommands implements ExtHostCommandsShape {
try {
return await callback.apply(thisArg, args);
} catch (err) {
// The indirection-command from the converter can fail when invoking the actual
// command and in that case it is better to blame the correct command
if (id === this.converter.delegatingCommandId) {
const actual = this.converter.getActualCommand(...args);
if (actual) {
id = actual.command;
}
}
this._logService.error(err, id);
throw new Error(`Running the contributed command: '${id}' failed.`);
}
@@ -261,7 +269,7 @@ export const IExtHostCommands = createDecorator<IExtHostCommands>('IExtHostComma
export class CommandsConverter {
private readonly _delegatingCommandId: string;
readonly delegatingCommandId: string = `_vscode_delegate_cmd_${Date.now().toString(36)}`;
private readonly _cache = new Map<number, vscode.Command>();
private _cachIdPool = 0;
@@ -271,8 +279,7 @@ export class CommandsConverter {
private readonly _lookupApiCommand: (id: string) => ApiCommand | undefined,
private readonly _logService: ILogService
) {
this._delegatingCommandId = `_vscode_delegate_cmd_${Date.now().toString(36)}`;
this._commands.registerCommand(true, this._delegatingCommandId, this._executeConvertedCommand, this);
this._commands.registerCommand(true, this.delegatingCommandId, this._executeConvertedCommand, this);
}
toInternal(command: vscode.Command, disposables: DisposableStore): ICommandDto;
@@ -315,7 +322,7 @@ export class CommandsConverter {
}));
result.$ident = id;
result.id = this._delegatingCommandId;
result.id = this.delegatingCommandId;
result.arguments = [id];
this._logService.trace('CommandsConverter#CREATE', command.command, id);
@@ -339,8 +346,13 @@ export class CommandsConverter {
}
}
getActualCommand(...args: any[]): vscode.Command | undefined {
return this._cache.get(args[0]);
}
private _executeConvertedCommand<R>(...args: any[]): Promise<R> {
const actualCmd = this._cache.get(args[0]);
const actualCmd = this.getActualCommand(...args);
this._logService.trace('CommandsConverter#EXECUTE', args[0], actualCmd ? actualCmd.command : 'MISSING');
if (!actualCmd) {

View File

@@ -3,18 +3,18 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { VSBuffer } from 'vs/base/common/buffer';
import { CancellationToken } from 'vs/base/common/cancellation';
import { hash } from 'vs/base/common/hash';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { Schemas } from 'vs/base/common/network';
import { joinPath } from 'vs/base/common/resources';
import { URI, UriComponents } from 'vs/base/common/uri';
import * as modes from 'vs/editor/common/modes';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import { ExtHostWebviews, toExtensionData } from 'vs/workbench/api/common/extHostWebview';
import { ExtHostWebviews, shouldSerializeBuffersForPostMessage, toExtensionData } from 'vs/workbench/api/common/extHostWebview';
import { ExtHostWebviewPanels } from 'vs/workbench/api/common/extHostWebviewPanels';
import { EditorGroupColumn } from 'vs/workbench/common/editor';
import type * as vscode from 'vscode';
@@ -183,7 +183,7 @@ export class ExtHostCustomEditors implements extHostProtocol.ExtHostCustomEditor
disposables.add(this._editorProviders.addTextProvider(viewType, extension, provider));
this._proxy.$registerTextEditorProvider(toExtensionData(extension), viewType, options.webviewOptions || {}, {
supportsMove: !!provider.moveCustomTextEditor,
});
}, shouldSerializeBuffersForPostMessage(extension));
} else {
disposables.add(this._editorProviders.addCustomProvider(viewType, extension, provider));
@@ -199,7 +199,7 @@ export class ExtHostCustomEditors implements extHostProtocol.ExtHostCustomEditor
}));
}
this._proxy.$registerCustomEditorProvider(toExtensionData(extension), viewType, options.webviewOptions || {}, !!options.supportsMultipleEditorsPerDocument);
this._proxy.$registerCustomEditorProvider(toExtensionData(extension), viewType, options.webviewOptions || {}, !!options.supportsMultipleEditorsPerDocument, shouldSerializeBuffersForPostMessage(extension));
}
return extHostTypes.Disposable.from(
@@ -209,7 +209,7 @@ export class ExtHostCustomEditors implements extHostProtocol.ExtHostCustomEditor
}));
}
async $createCustomDocument(resource: UriComponents, viewType: string, backupId: string | undefined, cancellation: CancellationToken) {
async $createCustomDocument(resource: UriComponents, viewType: string, backupId: string | undefined, untitledDocumentData: VSBuffer | undefined, cancellation: CancellationToken) {
const entry = this._editorProviders.get(viewType);
if (!entry) {
throw new Error(`No provider found for '${viewType}'`);
@@ -220,7 +220,7 @@ export class ExtHostCustomEditors implements extHostProtocol.ExtHostCustomEditor
}
const revivedResource = URI.revive(resource);
const document = await entry.provider.openCustomDocument(revivedResource, { backupId }, cancellation);
const document = await entry.provider.openCustomDocument(revivedResource, { backupId, untitledDocumentData: untitledDocumentData?.buffer }, cancellation);
let storageRoot: URI | undefined;
if (this.supportEditing(entry.provider) && this._extensionStoragePaths) {
@@ -251,9 +251,12 @@ export class ExtHostCustomEditors implements extHostProtocol.ExtHostCustomEditor
resource: UriComponents,
handle: extHostProtocol.WebviewHandle,
viewType: string,
title: string,
initData: {
title: string;
webviewOptions: extHostProtocol.IWebviewOptions;
panelOptions: extHostProtocol.IWebviewPanelOptions;
},
position: EditorGroupColumn,
options: modes.IWebviewOptions & modes.IWebviewPanelOptions,
cancellation: CancellationToken,
): Promise<void> {
const entry = this._editorProviders.get(viewType);
@@ -263,8 +266,8 @@ export class ExtHostCustomEditors implements extHostProtocol.ExtHostCustomEditor
const viewColumn = typeConverters.ViewColumn.to(position);
const webview = this._extHostWebview.createNewWebview(handle, options, entry.extension);
const panel = this._extHostWebviewPanels.createNewWebviewPanel(handle, viewType, title, viewColumn, options, webview);
const webview = this._extHostWebview.createNewWebview(handle, initData.webviewOptions, entry.extension);
const panel = this._extHostWebviewPanels.createNewWebviewPanel(handle, viewType, initData.title, viewColumn, initData.panelOptions, webview);
const revivedResource = URI.revive(resource);

View File

@@ -30,7 +30,7 @@ import type * as vscode from 'vscode';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { withNullAsUndefined } from 'vs/base/common/types';
import { IProcessEnvironment } from 'vs/base/common/platform';
import * as process from 'vs/base/common/process';
export const IExtHostDebugService = createDecorator<IExtHostDebugService>('IExtHostDebugService');
@@ -384,7 +384,7 @@ export abstract class ExtHostDebugServiceBase implements IExtHostDebugService, E
}
};
}
return this._variableResolver.resolveAny(ws, config);
return this._variableResolver.resolveAnyAsync(ws, config);
}
protected createDebugAdapter(adapter: IAdapterDescriptor, session: ExtHostDebugSession): AbstractDebugAdapter | undefined {
@@ -930,7 +930,7 @@ export class ExtHostDebugConsole {
export class ExtHostVariableResolverService extends AbstractVariableResolverService {
constructor(folders: vscode.WorkspaceFolder[], editorService: ExtHostDocumentsAndEditors | undefined, configurationService: ExtHostConfigProvider, env?: IProcessEnvironment, workspaceService?: IExtHostWorkspace) {
constructor(folders: vscode.WorkspaceFolder[], editorService: ExtHostDocumentsAndEditors | undefined, configurationService: ExtHostConfigProvider, workspaceService?: IExtHostWorkspace) {
super({
getFolderUri: (folderName: string): URI | undefined => {
const found = folders.filter(f => f.name === folderName);
@@ -945,8 +945,11 @@ export class ExtHostVariableResolverService extends AbstractVariableResolverServ
getConfigurationValue: (folderUri: URI | undefined, section: string): string | undefined => {
return configurationService.getConfiguration(undefined, folderUri).get<string>(section);
},
getAppRoot: (): string | undefined => {
return process.cwd();
},
getExecPath: (): string | undefined => {
return env ? env['VSCODE_EXEC_PATH'] : undefined;
return process.env['VSCODE_EXEC_PATH'];
},
getFilePath: (): string | undefined => {
if (editorService) {
@@ -987,7 +990,7 @@ export class ExtHostVariableResolverService extends AbstractVariableResolverServ
}
return undefined;
}
}, undefined, env);
}, undefined, Promise.resolve(process.env));
}
}

View File

@@ -10,7 +10,6 @@ import type * as vscode from 'vscode';
import { MainContext, MainThreadDiagnosticsShape, ExtHostDiagnosticsShape, IMainContext } from './extHost.protocol';
import { DiagnosticSeverity } from './extHostTypes';
import * as converter from './extHostTypeConverters';
import { mergeSort } from 'vs/base/common/arrays';
import { Event, Emitter } from 'vs/base/common/event';
import { ILogService } from 'vs/platform/log/common/log';
import { ResourceMap } from 'vs/base/common/map';
@@ -78,7 +77,7 @@ export class DiagnosticCollection implements vscode.DiagnosticCollection {
let lastUri: vscode.Uri | undefined;
// ensure stable-sort
first = mergeSort([...first], DiagnosticCollection._compareIndexedTuplesByUri);
first = [...first].sort(DiagnosticCollection._compareIndexedTuplesByUri);
for (const tuple of first) {
const [uri, diagnostics] = tuple;
@@ -289,7 +288,7 @@ export class ExtHostDiagnostics implements ExtHostDiagnosticsShape {
super(name!, owner, ExtHostDiagnostics._maxDiagnosticsPerFile, loggingProxy, _onDidChangeDiagnostics);
_collections.set(owner, this);
}
dispose() {
override dispose() {
super.dispose();
_collections.delete(owner);
}

View File

@@ -42,7 +42,7 @@ export class ExtHostDocumentData extends MirrorTextModel {
super(uri, lines, eol, versionId);
}
dispose(): void {
override dispose(): void {
// we don't really dispose documents but let
// extensions still read from them. some
// operations, live saving, will now error tho

View File

@@ -102,7 +102,7 @@ export class ExtHostDocuments implements ExtHostDocumentsShape {
return this._proxy.$tryCreateDocument(options).then(data => URI.revive(data));
}
public $acceptModelModeChanged(uriComponents: UriComponents, oldModeId: string, newModeId: string): void {
public $acceptModelModeChanged(uriComponents: UriComponents, newModeId: string): void {
const uri = URI.revive(uriComponents);
const data = this._documentsAndEditors.getDocument(uri);
if (!data) {

View File

@@ -3,12 +3,11 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import type * as vscode from 'vscode';
import { IDisposable } from 'vs/base/common/lifecycle';
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { ExtensionActivationError, MissingDependencyError } from 'vs/workbench/services/extensions/common/extensions';
import { MissingExtensionDependency } from 'vs/workbench/services/extensions/common/extensions';
import { ILogService } from 'vs/platform/log/common/log';
const NO_OP_VOID_PROMISE = Promise.resolve<void>(undefined);
@@ -158,7 +157,7 @@ export class FailedExtension extends ActivatedExtension {
}
export interface IExtensionsActivatorHost {
onExtensionActivationError(extensionId: ExtensionIdentifier, error: ExtensionActivationError): void;
onExtensionActivationError(extensionId: ExtensionIdentifier, error: Error | null, missingExtensionDependency: MissingExtensionDependency | null): void;
actualActivateExtension(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<ActivatedExtension>;
}
@@ -255,8 +254,12 @@ export class ExtensionsActivator {
const currentExtension = this._registry.getExtensionDescription(currentActivation.id);
if (!currentExtension) {
// Error condition 0: unknown extension
this._host.onExtensionActivationError(currentActivation.id, new MissingDependencyError(currentActivation.id.value));
const error = new Error(`Unknown dependency '${currentActivation.id.value}'`);
const error = new Error(`Cannot activate unknown extension '${currentActivation.id.value}'`);
this._host.onExtensionActivationError(
currentActivation.id,
error,
new MissingExtensionDependency(currentActivation.id.value)
);
this._activatedExtensions.set(ExtensionIdentifier.toKey(currentActivation.id), new FailedExtension(error));
return;
}
@@ -280,9 +283,16 @@ export class ExtensionsActivator {
if (dep && dep.activationFailed) {
// Error condition 2: a dependency has already failed activation
this._host.onExtensionActivationError(currentExtension.identifier, nls.localize('failedDep1', "Cannot activate extension '{0}' because it depends on extension '{1}', which failed to activate.", currentExtension.displayName || currentExtension.identifier.value, depId));
const error = new Error(`Dependency ${depId} failed to activate`);
const currentExtensionFriendlyName = currentExtension.displayName || currentExtension.identifier.value;
const depDesc = this._registry.getExtensionDescription(depId);
const depFriendlyName = (depDesc ? depDesc.displayName || depId : depId);
const error = new Error(`Cannot activate the '${currentExtensionFriendlyName}' extension because its dependency '${depFriendlyName}' failed to activate`);
(<any>error).detail = dep.activationFailedError;
this._host.onExtensionActivationError(
currentExtension.identifier,
error,
null
);
this._activatedExtensions.set(ExtensionIdentifier.toKey(currentExtension.identifier), new FailedExtension(error));
return;
}
@@ -309,8 +319,13 @@ export class ExtensionsActivator {
}
// Error condition 1: unknown dependency
this._host.onExtensionActivationError(currentExtension.identifier, new MissingDependencyError(depId));
const error = new Error(`Unknown dependency '${depId}'`);
const currentExtensionFriendlyName = currentExtension.displayName || currentExtension.identifier.value;
const error = new Error(`Cannot activate the '${currentExtensionFriendlyName}' extension because it depends on unknown extension '${depId}'`);
this._host.onExtensionActivationError(
currentExtension.identifier,
error,
new MissingExtensionDependency(depId)
);
this._activatedExtensions.set(ExtensionIdentifier.toKey(currentExtension.identifier), new FailedExtension(error));
return;
}
@@ -372,7 +387,25 @@ export class ExtensionsActivator {
}
const newlyActivatingExtension = this._host.actualActivateExtension(extensionId, reason).then(undefined, (err) => {
this._host.onExtensionActivationError(extensionId, nls.localize('activationError', "Activating extension '{0}' failed: {1}.", extensionId.value, err.message));
const error = new Error();
if (err && err.name) {
error.name = err.name;
}
if (err && err.message) {
error.message = `Activating extension '${extensionId.value}' failed: ${err.message}.`;
} else {
error.message = `Activating extension '${extensionId.value}' failed: ${err}.`;
}
if (err && err.stack) {
error.stack = err.stack;
}
this._host.onExtensionActivationError(
extensionId,
error,
null
);
this._logService.error(`Activating extension ${extensionId.value} failed due to an error:`);
this._logService.error(err);
// Treat the extension as being empty

View File

@@ -17,15 +17,14 @@ import { ExtHostConfiguration, IExtHostConfiguration } from 'vs/workbench/api/co
import { ActivatedExtension, EmptyExtension, ExtensionActivationReason, ExtensionActivationTimes, ExtensionActivationTimesBuilder, ExtensionsActivator, IExtensionAPI, IExtensionModule, HostExtension, ExtensionActivationTimesFragment } from 'vs/workbench/api/common/extHostExtensionActivator';
import { ExtHostStorage, IExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
import { ExtHostWorkspace, IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
import { ExtensionActivationError, checkProposedApiEnabled, ActivationKind } from 'vs/workbench/services/extensions/common/extensions';
import { MissingExtensionDependency, checkProposedApiEnabled, ActivationKind } from 'vs/workbench/services/extensions/common/extensions';
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
import * as errors from 'vs/base/common/errors';
import type * as vscode from 'vscode';
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { Schemas } from 'vs/base/common/network';
import { VSBuffer } from 'vs/base/common/buffer';
import { ExtensionGlobalMemento, ExtensionMemento } from 'vs/workbench/api/common/extHostMemento';
import { RemoteAuthorityResolverError, ExtensionMode, ExtensionRuntime } from 'vs/workbench/api/common/extHostTypes';
import { RemoteAuthorityResolverError, ExtensionKind, ExtensionMode, ExtensionRuntime } from 'vs/workbench/api/common/extHostTypes';
import { ResolvedAuthority, ResolvedOptions, RemoteAuthorityResolverErrorCode, IRemoteConnectionData } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { IInstantiationService, createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
@@ -95,6 +94,8 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
private readonly _almostReadyToRunExtensions: Barrier;
private readonly _readyToStartExtensionHost: Barrier;
private readonly _readyToRunExtensions: Barrier;
private readonly _eagerExtensionsActivated: Barrier;
protected readonly _registry: ExtensionDescriptionRegistry;
private readonly _storage: ExtHostStorage;
private readonly _secretState: ExtHostSecretState;
@@ -140,6 +141,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
this._almostReadyToRunExtensions = new Barrier();
this._readyToStartExtensionHost = new Barrier();
this._readyToRunExtensions = new Barrier();
this._eagerExtensionsActivated = new Barrier();
this._registry = new ExtensionDescriptionRegistry(this._initData.extensions);
this._storage = new ExtHostStorage(this._extHostContext);
this._secretState = new ExtHostSecretState(this._extHostContext);
@@ -158,8 +160,8 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
this._initData.resolvedExtensions,
this._initData.hostExtensions,
{
onExtensionActivationError: (extensionId: ExtensionIdentifier, error: ExtensionActivationError): void => {
this._mainThreadExtensionsProxy.$onExtensionActivationError(extensionId, error);
onExtensionActivationError: (extensionId: ExtensionIdentifier, error: Error, missingExtensionDependency: MissingExtensionDependency | null): void => {
this._mainThreadExtensionsProxy.$onExtensionActivationError(extensionId, errors.transformErrorForSerialization(error), missingExtensionDependency);
},
actualActivateExtension: async (extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<ActivatedExtension> => {
@@ -388,6 +390,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
const extensionMode = extensionDescription.isUnderDevelopment
? (this._initData.environment.extensionTestsLocationURI ? ExtensionMode.Test : ExtensionMode.Development)
: ExtensionMode.Production;
const extensionKind = this._initData.remote.isRemote ? ExtensionKind.Workspace : ExtensionKind.UI;
this._logService.trace(`ExtensionService#loadExtensionContext ${extensionDescription.identifier.value}`);
@@ -397,6 +400,8 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
this._storagePath.whenReady
]).then(() => {
const that = this;
let extension: vscode.Extension<any> | undefined;
return Object.freeze<vscode.ExtensionContext>({
globalState,
workspaceState,
@@ -412,6 +417,12 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
get storageUri() { return that._storagePath.workspaceValue(extensionDescription); },
get globalStorageUri() { return that._storagePath.globalValue(extensionDescription); },
get extensionMode() { return extensionMode; },
get extension() {
if (extension === undefined) {
extension = new Extension(that, extensionDescription.identifier, extensionDescription, extensionKind);
}
return extension;
},
get extensionRuntime() {
checkProposedApiEnabled(extensionDescription);
return that.extensionRuntime;
@@ -537,84 +548,61 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
);
}
private _handleExtensionTests(): Promise<void> {
return this._doHandleExtensionTests().then(undefined, error => {
public async $extensionTestsExecute(): Promise<number> {
await this._eagerExtensionsActivated.wait();
try {
return this._doHandleExtensionTests();
} catch (error) {
console.error(error); // ensure any error message makes it onto the console
return Promise.reject(error);
});
throw error;
}
}
private async _doHandleExtensionTests(): Promise<void> {
private async _doHandleExtensionTests(): Promise<number> {
const { extensionDevelopmentLocationURI, extensionTestsLocationURI } = this._initData.environment;
if (!(extensionDevelopmentLocationURI && extensionTestsLocationURI && extensionTestsLocationURI.scheme === Schemas.file)) {
return Promise.resolve(undefined);
if (!extensionDevelopmentLocationURI || !extensionTestsLocationURI) {
throw new Error(nls.localize('extensionTestError1', "Cannot load test runner."));
}
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 = await this._loadCommonJSModule(null, URI.file(extensionTestsPath), new ExtensionActivationTimesBuilder(false));
} catch (error) {
requireError = error;
const testRunner: ITestRunner | INewTestRunner | undefined = await this._loadCommonJSModule(null, extensionTestsLocationURI, new ExtensionActivationTimesBuilder(false));
if (!testRunner || typeof testRunner.run !== 'function') {
throw new Error(nls.localize('extensionTestError', "Path {0} does not point to a valid extension test runner.", extensionTestsLocationURI.toString()));
}
// 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._testRunnerExit(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._testRunnerExit(0);
})
.catch((err: Error) => {
e(err.toString());
this._testRunnerExit(1);
});
return new Promise<number>((resolve, reject) => {
const oldTestRunnerCallback = (error: Error, failures: number | undefined) => {
if (error) {
reject(error);
} else {
resolve((typeof failures === 'number' && failures > 0) ? 1 /* ERROR */ : 0 /* OK */);
}
});
}
};
// Otherwise make sure to shutdown anyway even in case of an error
else {
this._testRunnerExit(1 /* ERROR */);
}
const extensionTestsPath = originalFSPath(extensionTestsLocationURI); // for the old test runner API
return Promise.reject(new Error(requireError ? requireError.toString() : nls.localize('extensionTestError', "Path {0} does not point to a valid extension test runner.", extensionTestsPath)));
const runResult = testRunner.run(extensionTestsPath, oldTestRunnerCallback);
// Using the new API `run(): Promise<void>`
if (runResult && runResult.then) {
runResult
.then(() => {
resolve(0);
})
.catch((err: Error) => {
reject(err.toString());
});
}
});
}
private _testRunnerExit(code: number): void {
public async $extensionTestsExit(code: number): Promise<void> {
this._logService.info(`extension host terminating: test runner requested exit with code ${code}`);
this._logService.info(`exiting with code ${code}`);
this._logService.flush();
// wait at most 5000ms for the renderer to confirm our exit request and for the renderer socket to drain
// (this is to ensure all outstanding messages reach the renderer)
const exitPromise = this._mainThreadExtensionsProxy.$onExtensionHostExit(code);
const drainPromise = this._extHostContext.drain();
Promise.race([Promise.all([exitPromise, drainPromise]), timeout(5000)]).then(() => {
this._logService.info(`exiting with code ${code}`);
this._logService.flush();
this._hostUtils.exit(code);
});
this._hostUtils.exit(code);
}
private _startExtensionHost(): Promise<void> {
@@ -626,8 +614,8 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
return this._readyToStartExtensionHost.wait()
.then(() => this._readyToRunExtensions.open())
.then(() => this._handleEagerExtensions())
.then(() => this._handleExtensionTests())
.then(() => {
this._eagerExtensionsActivated.open();
this._logService.info(`eager extensions activated`);
});
}
@@ -666,10 +654,10 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
}
try {
this._disposables.add(await this._extHostTunnelService.setTunnelExtensionFunctions(resolver));
performance.mark(`code/extHost/willResolveAuthority/${authorityPrefix}`);
const result = await resolver.resolve(remoteAuthority, { resolveAttempt });
performance.mark(`code/extHost/didResolveAuthorityOK/${authorityPrefix}`);
this._disposables.add(await this._extHostTunnelService.setTunnelExtensionFunctions(resolver));
// Split merged API result into separate authority/options
const authority: ResolvedAuthority = {
@@ -679,7 +667,8 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
connectionToken: result.connectionToken
};
const options: ResolvedOptions = {
extensionHostEnv: result.extensionHostEnv
extensionHostEnv: result.extensionHostEnv,
trust: result.trust
};
return {
@@ -827,3 +816,42 @@ export interface IExtHostExtensionService extends AbstractExtHostExtensionServic
onDidChangeRemoteConnectionData: Event<void>;
getRemoteConnectionData(): IRemoteConnectionData | null;
}
export class Extension<T> implements vscode.Extension<T> {
#extensionService: IExtHostExtensionService;
#originExtensionId: ExtensionIdentifier;
#identifier: ExtensionIdentifier;
readonly id: string;
readonly extensionUri: URI;
readonly extensionPath: string;
readonly packageJSON: IExtensionDescription;
readonly extensionKind: vscode.ExtensionKind;
constructor(extensionService: IExtHostExtensionService, originExtensionId: ExtensionIdentifier, description: IExtensionDescription, kind: ExtensionKind) {
this.#extensionService = extensionService;
this.#originExtensionId = originExtensionId;
this.#identifier = description.identifier;
this.id = description.identifier.value;
this.extensionUri = description.extensionLocation;
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, { startup: false, extensionId: this.#originExtensionId, activationEvent: 'api' }).then(() => this.exports);
}
}

View File

@@ -291,6 +291,24 @@ class EvaluatableExpressionAdapter {
}
}
class InlineValuesAdapter {
constructor(
private readonly _documents: ExtHostDocuments,
private readonly _provider: vscode.InlineValuesProvider,
) { }
public provideInlineValues(resource: URI, viewPort: IRange, context: extHostProtocol.IInlineValueContextDto, token: CancellationToken): Promise<modes.InlineValue[] | undefined> {
const doc = this._documents.getDocument(resource);
return asPromise(() => this._provider.provideInlineValues(doc, typeConvert.Range.to(viewPort), typeConvert.InlineValueContext.to(context), token)).then(value => {
if (Array.isArray(value)) {
return value.map(iv => typeConvert.InlineValue.from(iv));
}
return undefined;
});
}
}
class DocumentHighlightAdapter {
constructor(
@@ -394,7 +412,8 @@ class CodeActionAdapter {
const codeActionContext: vscode.CodeActionContext = {
diagnostics: allDiagnostics,
only: context.only ? new CodeActionKind(context.only) : undefined
only: context.only ? new CodeActionKind(context.only) : undefined,
triggerKind: typeConvert.CodeActionTriggerKind.to(context.trigger),
};
return asPromise(() => this._provider.provideCodeActions(doc, ran, codeActionContext, token)).then((commandsOrActions): extHostProtocol.ICodeActionListDto | undefined => {
@@ -1334,7 +1353,8 @@ type Adapter = DocumentSymbolAdapter | CodeLensAdapter | DefinitionAdapter | Hov
| RangeFormattingAdapter | OnTypeFormattingAdapter | NavigateTypeAdapter | RenameAdapter
| SuggestAdapter | SignatureHelpAdapter | LinkProviderAdapter | ImplementationAdapter
| TypeDefinitionAdapter | ColorProviderAdapter | FoldingProviderAdapter | DeclarationAdapter
| SelectionRangeAdapter | CallHierarchyAdapter | DocumentSemanticTokensAdapter | DocumentRangeSemanticTokensAdapter | EvaluatableExpressionAdapter
| SelectionRangeAdapter | CallHierarchyAdapter | DocumentSemanticTokensAdapter | DocumentRangeSemanticTokensAdapter
| EvaluatableExpressionAdapter | InlineValuesAdapter
| LinkedEditingRangeAdapter | InlineHintsAdapter;
class AdapterData {
@@ -1568,6 +1588,27 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF
return this._withAdapter(handle, EvaluatableExpressionAdapter, adapter => adapter.provideEvaluatableExpression(URI.revive(resource), position, token), undefined);
}
// --- debug inline values
registerInlineValuesProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.InlineValuesProvider, extensionId?: ExtensionIdentifier): vscode.Disposable {
const eventHandle = typeof provider.onDidChangeInlineValues === 'function' ? this._nextHandle() : undefined;
const handle = this._addNewAdapter(new InlineValuesAdapter(this._documents, provider), extension);
this._proxy.$registerInlineValuesProvider(handle, this._transformDocumentSelector(selector), eventHandle);
let result = this._createDisposable(handle);
if (eventHandle !== undefined) {
const subscription = provider.onDidChangeInlineValues!(_ => this._proxy.$emitInlineValuesEvent(eventHandle));
result = Disposable.from(result, subscription);
}
return result;
}
$provideInlineValues(handle: number, resource: UriComponents, range: IRange, context: extHostProtocol.IInlineValueContextDto, token: CancellationToken): Promise<modes.InlineValue[] | undefined> {
return this._withAdapter(handle, InlineValuesAdapter, adapter => adapter.provideInlineValues(URI.revive(resource), range, context, token), undefined);
}
// --- occurrences
registerDocumentHighlightProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentHighlightProvider): vscode.Disposable {

View File

@@ -7,6 +7,7 @@ import type * as vscode from 'vscode';
import { IDisposable } from 'vs/base/common/lifecycle';
import { ExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { DeferredPromise, RunOnceScheduler } from 'vs/base/common/async';
export class ExtensionMemento implements vscode.Memento {
@@ -18,6 +19,9 @@ export class ExtensionMemento implements vscode.Memento {
private _value?: { [n: string]: any; };
private readonly _storageListener: IDisposable;
private _deferredPromises: Map<string, DeferredPromise<void>> = new Map();
private _scheduler: RunOnceScheduler;
constructor(id: string, global: boolean, storage: ExtHostStorage) {
this._id = id;
this._shared = global;
@@ -33,6 +37,23 @@ export class ExtensionMemento implements vscode.Memento {
this._value = e.value;
}
});
this._scheduler = new RunOnceScheduler(() => {
const records = this._deferredPromises;
this._deferredPromises = new Map();
(async () => {
try {
await this._storage.setValue(this._shared, this._id, this._value!);
for (const value of records.values()) {
value.complete();
}
} catch (e) {
for (const value of records.values()) {
value.error(e);
}
}
})();
}, 0);
}
get whenReady(): Promise<ExtensionMemento> {
@@ -51,7 +72,20 @@ export class ExtensionMemento implements vscode.Memento {
update(key: string, value: any): Promise<void> {
this._value![key] = value;
return this._storage.setValue(this._shared, this._id, this._value!);
let record = this._deferredPromises.get(key);
if (record !== undefined) {
return record.p;
}
const promise = new DeferredPromise<void>();
this._deferredPromises.set(key, promise);
if (!this._scheduler.isScheduled()) {
this._scheduler.schedule();
}
return promise.p;
}
dispose(): void {

File diff suppressed because it is too large Load Diff

View File

@@ -11,7 +11,6 @@ import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { score } from 'vs/editor/common/modes/languageSelector';
import { CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { ResourceMap } from 'vs/base/common/map';
import { URI } from 'vs/base/common/uri';
import { generateUuid } from 'vs/base/common/uuid';
@@ -57,7 +56,6 @@ export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextD
}
};
this._disposables.add(extHostNotebooks.onDidChangeCellLanguage(e => documentChange(e.document)));
this._disposables.add(extHostNotebooks.onDidChangeNotebookCells(e => documentChange(e.document)));
}
@@ -75,9 +73,9 @@ export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextD
this._cellUris = new ResourceMap();
const cellLengths: number[] = [];
const cellLineCounts: number[] = [];
for (const cell of this._notebook.cells) {
if (cell.cellKind === CellKind.Code && (!this._selector || score(this._selector, cell.uri, cell.language, true))) {
this._cellUris.set(cell.uri, this._cells.length);
for (const cell of this._notebook.getCells()) {
if (cell.kind === types.NotebookCellKind.Code && (!this._selector || score(this._selector, cell.document.uri, cell.document.languageId, true))) {
this._cellUris.set(cell.document.uri, this._cells.length);
this._cells.push(cell);
cellLengths.push(cell.document.getText().length + 1);
cellLineCounts.push(cell.document.lineCount);
@@ -163,7 +161,7 @@ export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextD
const range = new types.Range(startPos, endPos);
const startCell = this._cells[startIdx.index];
return new types.Location(startCell.uri, <types.Range>startCell.document.validateRange(range));
return new types.Location(startCell.document.uri, <types.Range>startCell.document.validateRange(range));
}
contains(uri: vscode.Uri): boolean {

View File

@@ -3,56 +3,34 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Emitter, Event } from 'vs/base/common/event';
import { hash } from 'vs/base/common/hash';
import { Disposable, DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle';
import { Schemas } from 'vs/base/common/network';
import { joinPath } from 'vs/base/common/resources';
import { ISplice } from 'vs/base/common/sequence';
import { deepFreeze, equals } from 'vs/base/common/objects';
import { URI } from 'vs/base/common/uri';
import * as UUID from 'vs/base/common/uuid';
import { CellKind, INotebookDocumentPropertiesChangeData, IWorkspaceCellEditDto, MainThreadBulkEditsShape, MainThreadNotebookShape, NotebookCellOutputsSplice, WorkspaceEditType } from 'vs/workbench/api/common/extHost.protocol';
import { CellKind, INotebookDocumentPropertiesChangeData, MainThreadNotebookDocumentsShape } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
import { ExtHostDocumentsAndEditors, IExtHostModelAddedData } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { CellEditType, CellOutputKind, diff, IMainCellDto, IProcessedOutput, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookCellsSplice2, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import * as extHostTypeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
import { IMainCellDto, IOutputDto, IOutputItemDto, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookCellsSplice2 } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import * as vscode from 'vscode';
interface IObservable<T> {
proxy: T;
onDidChange: Event<void>;
}
function getObservable<T extends Object>(obj: T): IObservable<T> {
const onDidChange = new Emitter<void>();
const proxy = new Proxy(obj, {
set(target: T, p: PropertyKey, value: any, _receiver: any): boolean {
target[p as keyof T] = value;
onDidChange.fire();
return true;
}
});
return {
proxy,
onDidChange: onDidChange.event
};
}
class RawContentChangeEvent {
constructor(readonly start: number, readonly deletedCount: number, readonly deletedItems: ExtHostCell[], readonly items: ExtHostCell[]) { }
constructor(readonly start: number, readonly deletedCount: number, readonly deletedItems: vscode.NotebookCell[], readonly items: ExtHostCell[]) { }
static asApiEvent(event: RawContentChangeEvent): vscode.NotebookCellsChangeData {
return Object.freeze({
start: event.start,
deletedCount: event.deletedCount,
deletedItems: event.deletedItems.map(data => data.cell),
items: event.items.map(data => data.cell)
static asApiEvents(events: RawContentChangeEvent[]): readonly vscode.NotebookCellsChangeData[] {
return events.map(event => {
return {
start: event.start,
deletedCount: event.deletedCount,
deletedItems: event.deletedItems,
items: event.items.map(data => data.apiCell)
};
});
}
}
export class ExtHostCell extends Disposable {
export class ExtHostCell {
static asModelAddData(notebook: vscode.NotebookDocument, cell: IMainCellDto): IExtHostModelAddedData {
return {
@@ -66,18 +44,11 @@ export class ExtHostCell extends Disposable {
};
}
private _onDidDispose = new Emitter<void>();
readonly onDidDispose: Event<void> = this._onDidDispose.event;
private _onDidChangeOutputs = new Emitter<ISplice<IProcessedOutput>[]>();
readonly onDidChangeOutputs: Event<ISplice<IProcessedOutput>[]> = this._onDidChangeOutputs.event;
private _outputs: any[];
private _outputMapping = new WeakMap<vscode.CellOutput, string | undefined /* output ID */>();
private _metadata: vscode.NotebookCellMetadata;
private _metadataChangeListener: IDisposable;
private _outputs: extHostTypes.NotebookCellOutput[];
private _metadata: extHostTypes.NotebookCellMetadata;
private _previousResult: vscode.NotebookCellExecutionSummary | undefined;
private _internalMetadata: NotebookCellMetadata;
readonly handle: number;
readonly uri: URI;
readonly cellKind: CellKind;
@@ -85,242 +56,128 @@ export class ExtHostCell extends Disposable {
private _cell: vscode.NotebookCell | undefined;
constructor(
private readonly _mainThreadBulkEdits: MainThreadBulkEditsShape,
private readonly _notebook: ExtHostNotebookDocument,
private readonly _extHostDocument: ExtHostDocumentsAndEditors,
private readonly _cellData: IMainCellDto,
) {
super();
this.handle = _cellData.handle;
this.uri = URI.revive(_cellData.uri);
this.cellKind = _cellData.cellKind;
this._outputs = _cellData.outputs;
for (const output of this._outputs) {
this._outputMapping.set(output, output.outputId);
delete output.outputId;
}
const observableMetadata = getObservable(_cellData.metadata ?? {});
this._metadata = observableMetadata.proxy;
this._metadataChangeListener = this._register(observableMetadata.onDidChange(() => {
this._updateMetadata();
}));
this._outputs = _cellData.outputs.map(extHostTypeConverters.NotebookCellOutput.to);
this._internalMetadata = _cellData.metadata ?? {};
this._metadata = extHostTypeConverters.NotebookCellMetadata.to(this._internalMetadata);
this._previousResult = extHostTypeConverters.NotebookCellPreviousExecutionResult.to(this._internalMetadata);
}
get cell(): vscode.NotebookCell {
get internalMetadata(): NotebookCellMetadata {
return this._internalMetadata;
}
get apiCell(): vscode.NotebookCell {
if (!this._cell) {
const that = this;
const data = this._extHostDocument.getDocument(this.uri);
if (!data) {
throw new Error(`MISSING extHostDocument for notebook cell: ${this.uri}`);
}
this._cell = Object.freeze({
this._cell = Object.freeze<vscode.NotebookCell>({
get index() { return that._notebook.getCellIndex(that); },
notebook: that._notebook.notebookDocument,
uri: that.uri,
cellKind: this._cellData.cellKind,
notebook: that._notebook.apiNotebook,
kind: extHostTypeConverters.NotebookCellKind.to(this._cellData.cellKind),
document: data.document,
get language() { return data!.document.languageId; },
get outputs() { return that._outputs; },
set outputs(value) { that._updateOutputs(value); },
get outputs() { return that._outputs.slice(0); },
get metadata() { return that._metadata; },
set metadata(value) {
that.setMetadata(value);
that._updateMetadata();
},
get latestExecutionSummary() { return that._previousResult; }
});
}
return this._cell;
}
dispose() {
super.dispose();
this._onDidDispose.fire();
setOutputs(newOutputs: IOutputDto[]): void {
this._outputs = newOutputs.map(extHostTypeConverters.NotebookCellOutput.to);
}
setOutputs(newOutputs: vscode.CellOutput[]): void {
this._outputs = newOutputs;
}
private _updateOutputs(newOutputs: vscode.CellOutput[]) {
const rawDiffs = diff<vscode.CellOutput>(this._outputs || [], newOutputs || [], (a) => {
return this._outputMapping.has(a);
});
const transformedDiffs: ISplice<IProcessedOutput>[] = rawDiffs.map(diff => {
for (let i = diff.start; i < diff.start + diff.deleteCount; i++) {
this._outputMapping.delete(this._outputs[i]);
setOutputItems(outputId: string, append: boolean, newOutputItems: IOutputItemDto[]) {
const newItems = newOutputItems.map(extHostTypeConverters.NotebookCellOutputItem.to);
const output = this._outputs.find(op => op.id === outputId);
if (output) {
if (!append) {
output.outputs.length = 0;
}
return {
deleteCount: diff.deleteCount,
start: diff.start,
toInsert: diff.toInsert.map((output): IProcessedOutput => {
if (output.outputKind === CellOutputKind.Rich) {
const uuid = UUID.generateUuid();
this._outputMapping.set(output, uuid);
return { ...output, outputId: uuid };
}
this._outputMapping.set(output, undefined);
return output;
})
};
});
this._outputs = newOutputs;
this._onDidChangeOutputs.fire(transformedDiffs);
output.outputs.push(...newItems);
}
}
setMetadata(newMetadata: vscode.NotebookCellMetadata): void {
// Don't apply metadata defaults here, 'undefined' means 'inherit from document metadata'
this._metadataChangeListener.dispose();
const observableMetadata = getObservable(newMetadata);
this._metadata = observableMetadata.proxy;
this._metadataChangeListener = this._register(observableMetadata.onDidChange(() => {
this._updateMetadata();
}));
}
private _updateMetadata(): Promise<boolean> {
const index = this._notebook.notebookDocument.cells.indexOf(this.cell);
const edit: IWorkspaceCellEditDto = {
_type: WorkspaceEditType.Cell,
metadata: undefined,
resource: this._notebook.uri,
notebookVersionId: this._notebook.notebookDocument.version,
edit: { editType: CellEditType.Metadata, index, metadata: this._metadata }
};
return this._mainThreadBulkEdits.$tryApplyWorkspaceEdit({ edits: [edit] });
setMetadata(newMetadata: NotebookCellMetadata): void {
this._internalMetadata = newMetadata;
this._metadata = extHostTypeConverters.NotebookCellMetadata.to(newMetadata);
this._previousResult = extHostTypeConverters.NotebookCellPreviousExecutionResult.to(newMetadata);
}
}
export interface INotebookEventEmitter {
emitModelChange(events: vscode.NotebookCellsChangeEvent): void;
emitDocumentMetadataChange(event: vscode.NotebookDocumentMetadataChangeEvent): void;
emitCellOutputsChange(event: vscode.NotebookCellOutputsChangeEvent): void;
emitCellLanguageChange(event: vscode.NotebookCellLanguageChangeEvent): void;
emitCellMetadataChange(event: vscode.NotebookCellMetadataChangeEvent): void;
emitCellExecutionStateChange(event: vscode.NotebookCellExecutionStateChangeEvent): void;
}
function hashPath(resource: URI): string {
const str = resource.scheme === Schemas.file || resource.scheme === Schemas.untitled ? resource.fsPath : resource.toString();
return hash(str) + '';
}
export class ExtHostNotebookDocument extends Disposable {
export class ExtHostNotebookDocument {
private static _handlePool: number = 0;
readonly handle = ExtHostNotebookDocument._handlePool++;
private _cells: ExtHostCell[] = [];
private _cellDisposableMapping = new Map<number, DisposableStore>();
private _notebook: vscode.NotebookDocument | undefined;
private _metadata: Required<vscode.NotebookDocumentMetadata>;
private _metadataChangeListener: IDisposable;
private _versionId = 0;
private _versionId: number = 0;
private _isDirty: boolean = false;
private _backupCounter = 1;
private _backup?: vscode.NotebookDocumentBackup;
private _disposed = false;
private _languages: string[] = [];
private _disposed: boolean = false;
constructor(
private readonly _proxy: MainThreadNotebookShape,
private readonly _documentsAndEditors: ExtHostDocumentsAndEditors,
private readonly _mainThreadBulkEdits: MainThreadBulkEditsShape,
private readonly _proxy: MainThreadNotebookDocumentsShape,
private readonly _textDocumentsAndEditors: ExtHostDocumentsAndEditors,
private readonly _textDocuments: ExtHostDocuments,
private readonly _emitter: INotebookEventEmitter,
private readonly _viewType: string,
private readonly _contentOptions: vscode.NotebookDocumentContentOptions,
metadata: Required<vscode.NotebookDocumentMetadata>,
public readonly uri: URI,
private readonly _storagePath: URI | undefined
) {
super();
const observableMetadata = getObservable(metadata);
this._metadata = observableMetadata.proxy;
this._metadataChangeListener = this._register(observableMetadata.onDidChange(() => {
this._tryUpdateMetadata();
}));
}
private _metadata: extHostTypes.NotebookDocumentMetadata,
readonly uri: URI,
) { }
dispose() {
this._disposed = true;
super.dispose();
dispose(this._cellDisposableMapping.values());
}
private _updateMetadata(newMetadata: Required<vscode.NotebookDocumentMetadata>) {
this._metadataChangeListener.dispose();
newMetadata = {
...notebookDocumentMetadataDefaults,
...newMetadata
};
if (this._metadataChangeListener) {
this._metadataChangeListener.dispose();
}
const observableMetadata = getObservable(newMetadata);
this._metadata = observableMetadata.proxy;
this._metadataChangeListener = this._register(observableMetadata.onDidChange(() => {
this._tryUpdateMetadata();
}));
this._tryUpdateMetadata();
}
private _tryUpdateMetadata() {
const edit: IWorkspaceCellEditDto = {
_type: WorkspaceEditType.Cell,
metadata: undefined,
edit: { editType: CellEditType.DocumentMetadata, metadata: this._metadata },
resource: this.uri,
notebookVersionId: this.notebookDocument.version,
};
return this._mainThreadBulkEdits.$tryApplyWorkspaceEdit({ edits: [edit] });
}
get notebookDocument(): vscode.NotebookDocument {
get apiNotebook(): vscode.NotebookDocument {
if (!this._notebook) {
const that = this;
this._notebook = Object.freeze({
this._notebook = {
get uri() { return that.uri; },
get version() { return that._versionId; },
get fileName() { return that.uri.fsPath; },
get viewType() { return that._viewType; },
get isDirty() { return that._isDirty; },
get isUntitled() { return that.uri.scheme === Schemas.untitled; },
get cells(): ReadonlyArray<vscode.NotebookCell> { return that._cells.map(cell => cell.cell); },
get languages() { return that._languages; },
set languages(value: string[]) { that._trySetLanguages(value); },
get isClosed() { return that._disposed; },
get metadata() { return that._metadata; },
set metadata(value: Required<vscode.NotebookDocumentMetadata>) { that._updateMetadata(value); },
get contentOptions() { return that._contentOptions; }
});
get cellCount() { return that._cells.length; },
cellAt(index) {
index = that._validateIndex(index);
return that._cells[index].apiCell;
},
getCells(range) {
const cells = range ? that._getCells(range) : that._cells;
return cells.map(cell => cell.apiCell);
},
save() {
return that._save();
}
};
}
return this._notebook;
}
private _trySetLanguages(newLanguages: string[]) {
this._languages = newLanguages;
this._proxy.$updateNotebookLanguages(this._viewType, this.uri, this._languages);
}
getNewBackupUri(): URI {
if (!this._storagePath) {
throw new Error('Backup requires a valid storage path');
}
const fileName = hashPath(this.uri) + (this._backupCounter++);
return joinPath(this._storagePath, fileName);
}
updateBackup(backup: vscode.NotebookDocumentBackup): void {
this._backup?.delete();
this._backup = backup;
@@ -332,42 +189,68 @@ export class ExtHostNotebookDocument extends Disposable {
}
acceptDocumentPropertiesChanged(data: INotebookDocumentPropertiesChangeData) {
const newMetadata = {
...notebookDocumentMetadataDefaults,
...data.metadata
};
if (this._metadataChangeListener) {
this._metadataChangeListener.dispose();
if (data.metadata) {
this._metadata = this._metadata.with(data.metadata);
}
const observableMetadata = getObservable(newMetadata);
this._metadata = observableMetadata.proxy;
this._metadataChangeListener = this._register(observableMetadata.onDidChange(() => {
this._tryUpdateMetadata();
}));
this._emitter.emitDocumentMetadataChange({ document: this.notebookDocument });
}
acceptModelChanged(event: NotebookCellsChangedEventDto, isDirty: boolean): void {
this._versionId = event.versionId;
this._isDirty = isDirty;
event.rawEvents.forEach(e => {
if (e.kind === NotebookCellsChangeType.Initialize) {
this._spliceNotebookCells(e.changes, true);
} if (e.kind === NotebookCellsChangeType.ModelChange) {
this._spliceNotebookCells(e.changes, false);
} else if (e.kind === NotebookCellsChangeType.Move) {
this._moveCell(e.index, e.newIdx);
} else if (e.kind === NotebookCellsChangeType.Output) {
this._setCellOutputs(e.index, e.outputs);
} else if (e.kind === NotebookCellsChangeType.ChangeLanguage) {
this._changeCellLanguage(e.index, e.language);
} else if (e.kind === NotebookCellsChangeType.ChangeCellMetadata) {
this._changeCellMetadata(e.index, e.metadata);
for (const rawEvent of event.rawEvents) {
if (rawEvent.kind === NotebookCellsChangeType.Initialize) {
this._spliceNotebookCells(rawEvent.changes, true);
} if (rawEvent.kind === NotebookCellsChangeType.ModelChange) {
this._spliceNotebookCells(rawEvent.changes, false);
} else if (rawEvent.kind === NotebookCellsChangeType.Move) {
this._moveCell(rawEvent.index, rawEvent.newIdx);
} else if (rawEvent.kind === NotebookCellsChangeType.Output) {
this._setCellOutputs(rawEvent.index, rawEvent.outputs);
} else if (rawEvent.kind === NotebookCellsChangeType.OutputItem) {
this._setCellOutputItems(rawEvent.index, rawEvent.outputId, rawEvent.append, rawEvent.outputItems);
} else if (rawEvent.kind === NotebookCellsChangeType.ChangeLanguage) {
this._changeCellLanguage(rawEvent.index, rawEvent.language);
} else if (rawEvent.kind === NotebookCellsChangeType.ChangeCellMetadata) {
this._changeCellMetadata(rawEvent.index, rawEvent.metadata);
}
});
}
}
private _validateIndex(index: number): number {
if (index < 0) {
return 0;
} else if (index >= this._cells.length) {
return this._cells.length - 1;
} else {
return index;
}
}
private _validateRange(range: vscode.NotebookRange): vscode.NotebookRange {
if (range.start < 0) {
range = range.with({ start: 0 });
}
if (range.end > this._cells.length) {
range = range.with({ end: this._cells.length });
}
return range;
}
private _getCells(range: vscode.NotebookRange): ExtHostCell[] {
range = this._validateRange(range);
const result: ExtHostCell[] = [];
for (let i = range.start; i < range.end; i++) {
result.push(this._cells[i]);
}
return result;
}
private async _save(): Promise<boolean> {
if (this._disposed) {
return Promise.reject(new Error('Notebook has been closed'));
}
return this._proxy.$trySaveDocument(this.uri);
}
private _spliceNotebookCells(splices: NotebookCellsSplice2[], initialization: boolean): void {
@@ -383,107 +266,88 @@ export class ExtHostNotebookDocument extends Disposable {
const cellDtos = splice[2];
const newCells = cellDtos.map(cell => {
const extCell = new ExtHostCell(this._mainThreadBulkEdits, this, this._documentsAndEditors, cell);
const extCell = new ExtHostCell(this, this._textDocumentsAndEditors, cell);
if (!initialization) {
addedCellDocuments.push(ExtHostCell.asModelAddData(this.notebookDocument, cell));
addedCellDocuments.push(ExtHostCell.asModelAddData(this.apiNotebook, cell));
}
if (!this._cellDisposableMapping.has(extCell.handle)) {
const store = new DisposableStore();
store.add(extCell);
this._cellDisposableMapping.set(extCell.handle, store);
}
const store = this._cellDisposableMapping.get(extCell.handle)!;
store.add(extCell.onDidChangeOutputs((diffs) => {
this.eventuallyUpdateCellOutputs(extCell, diffs);
}));
return extCell;
});
for (let j = splice[0]; j < splice[0] + splice[1]; j++) {
this._cellDisposableMapping.get(this._cells[j].handle)?.dispose();
this._cellDisposableMapping.delete(this._cells[j].handle);
}
const changeEvent = new RawContentChangeEvent(splice[0], splice[1], [], newCells);
const deletedItems = this._cells.splice(splice[0], splice[1], ...newCells);
for (let cell of deletedItems) {
removedCellDocuments.push(cell.uri);
changeEvent.deletedItems.push(cell.apiCell);
}
contentChangeEvents.push(new RawContentChangeEvent(splice[0], splice[1], deletedItems, newCells));
contentChangeEvents.push(changeEvent);
});
this._documentsAndEditors.acceptDocumentsAndEditorsDelta({
this._textDocumentsAndEditors.acceptDocumentsAndEditorsDelta({
addedDocuments: addedCellDocuments,
removedDocuments: removedCellDocuments
});
if (!initialization) {
this._emitter.emitModelChange({
document: this.notebookDocument,
changes: contentChangeEvents.map(RawContentChangeEvent.asApiEvent)
});
this._emitter.emitModelChange(deepFreeze({
document: this.apiNotebook,
changes: RawContentChangeEvent.asApiEvents(contentChangeEvents)
}));
}
}
private _moveCell(index: number, newIdx: number): void {
const cells = this._cells.splice(index, 1);
this._cells.splice(newIdx, 0, ...cells);
const changes: vscode.NotebookCellsChangeData[] = [{
start: index,
deletedCount: 1,
deletedItems: cells.map(data => data.cell),
items: []
}, {
start: newIdx,
deletedCount: 0,
deletedItems: [],
items: cells.map(data => data.cell)
}];
this._emitter.emitModelChange({
document: this.notebookDocument,
changes
});
const changes = [
new RawContentChangeEvent(index, 1, cells.map(c => c.apiCell), []),
new RawContentChangeEvent(newIdx, 0, [], cells)
];
this._emitter.emitModelChange(deepFreeze({
document: this.apiNotebook,
changes: RawContentChangeEvent.asApiEvents(changes)
}));
}
private _setCellOutputs(index: number, outputs: IProcessedOutput[]): void {
private _setCellOutputs(index: number, outputs: IOutputDto[]): void {
const cell = this._cells[index];
cell.setOutputs(outputs);
this._emitter.emitCellOutputsChange({ document: this.notebookDocument, cells: [cell.cell] });
this._emitter.emitCellOutputsChange(deepFreeze({ document: this.apiNotebook, cells: [cell.apiCell] }));
}
private _changeCellLanguage(index: number, language: string): void {
private _setCellOutputItems(index: number, outputId: string, append: boolean, outputItems: IOutputItemDto[]): void {
const cell = this._cells[index];
const event: vscode.NotebookCellLanguageChangeEvent = { document: this.notebookDocument, cell: cell.cell, language };
this._emitter.emitCellLanguageChange(event);
cell.setOutputItems(outputId, append, outputItems);
this._emitter.emitCellOutputsChange(deepFreeze({ document: this.apiNotebook, cells: [cell.apiCell] }));
}
private _changeCellMetadata(index: number, newMetadata: NotebookCellMetadata | undefined): void {
private _changeCellLanguage(index: number, newModeId: string): void {
const cell = this._cells[index];
cell.setMetadata(newMetadata || {});
const event: vscode.NotebookCellMetadataChangeEvent = { document: this.notebookDocument, cell: cell.cell };
this._emitter.emitCellMetadataChange(event);
if (cell.apiCell.document.languageId !== newModeId) {
this._textDocuments.$acceptModelModeChanged(cell.uri, newModeId);
}
}
async eventuallyUpdateCellOutputs(cell: ExtHostCell, diffs: ISplice<IProcessedOutput>[]) {
const outputDtos: NotebookCellOutputsSplice[] = diffs.map(diff => {
const outputs = diff.toInsert;
return [diff.start, diff.deleteCount, outputs];
});
private _changeCellMetadata(index: number, newMetadata: NotebookCellMetadata): void {
const cell = this._cells[index];
if (!outputDtos.length) {
return;
const originalInternalMetadata = cell.internalMetadata;
const originalExtMetadata = cell.apiCell.metadata;
cell.setMetadata(newMetadata);
const newExtMetadata = cell.apiCell.metadata;
if (!equals(originalExtMetadata, newExtMetadata)) {
this._emitter.emitCellMetadataChange(deepFreeze({ document: this.apiNotebook, cell: cell.apiCell }));
}
await this._proxy.$spliceNotebookCellOutputs(this._viewType, this.uri, cell.handle, outputDtos);
this._emitter.emitCellOutputsChange({
document: this.notebookDocument,
cells: [cell.cell]
});
if (originalInternalMetadata.runState !== newMetadata.runState) {
const executionState = newMetadata.runState ?? extHostTypes.NotebookCellExecutionState.Idle;
this._emitter.emitCellExecutionStateChange(deepFreeze({ document: this.apiNotebook, cell: cell.apiCell, executionState }));
}
}
getCellFromIndex(index: number): ExtHostCell | undefined {
return this._cells[index];
}
getCell(cellHandle: number): ExtHostCell | undefined {

View File

@@ -3,15 +3,18 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { readonly } from 'vs/base/common/errors';
import { Emitter, Event } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { MainThreadNotebookShape } from 'vs/workbench/api/common/extHost.protocol';
import { MainThreadNotebookEditorsShape } from 'vs/workbench/api/common/extHost.protocol';
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
import { addIdToOutput, CellEditType, ICellEditOperation, ICellReplaceEdit, INotebookEditData, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import * as extHostConverter from 'vs/workbench/api/common/extHostTypeConverters';
import { CellEditType, ICellEditOperation, ICellReplaceEdit } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import * as vscode from 'vscode';
import { ExtHostNotebookDocument } from './extHostNotebookDocument';
interface INotebookEditData {
documentVersionId: number;
cellEdits: ICellEditOperation[];
}
class NotebookEditorCellEditBuilder implements vscode.NotebookEditorEdit {
private readonly _documentVersionId: number;
@@ -41,7 +44,7 @@ class NotebookEditorCellEditBuilder implements vscode.NotebookEditorEdit {
this._throwIfFinalized();
this._collectedEdits.push({
editType: CellEditType.DocumentMetadata,
metadata: { ...notebookDocumentMetadataDefaults, ...value }
metadata: value
});
}
@@ -54,21 +57,6 @@ class NotebookEditorCellEditBuilder implements vscode.NotebookEditorEdit {
});
}
replaceCellOutput(index: number, outputs: (vscode.NotebookCellOutput | vscode.CellOutput)[]): void {
this._throwIfFinalized();
this._collectedEdits.push({
editType: CellEditType.Output,
index,
outputs: outputs.map(output => {
if (extHostTypes.NotebookCellOutput.isNotebookCellOutput(output)) {
return addIdToOutput(output.toJSON());
} else {
return addIdToOutput(output);
}
})
});
}
replaceCells(from: number, to: number, cells: vscode.NotebookCellData[]): void {
this._throwIfFinalized();
if (from === to && cells.length === 0) {
@@ -78,112 +66,89 @@ class NotebookEditorCellEditBuilder implements vscode.NotebookEditorEdit {
editType: CellEditType.Replace,
index: from,
count: to - from,
cells: cells.map(data => {
return {
...data,
outputs: data.outputs.map(output => addIdToOutput(output)),
};
})
cells: cells.map(extHostConverter.NotebookCellData.from)
});
}
}
export class ExtHostNotebookEditor extends Disposable implements vscode.NotebookEditor {
export class ExtHostNotebookEditor {
//TODO@rebornix noop setter?
selection?: vscode.NotebookCell;
private _visibleRanges: vscode.NotebookCellRange[] = [];
private _selections: vscode.NotebookRange[] = [];
private _visibleRanges: vscode.NotebookRange[] = [];
private _viewColumn?: vscode.ViewColumn;
private _active: boolean = false;
private _visible: boolean = false;
private _kernel?: vscode.NotebookKernel;
private readonly _hasDecorationsForKey = new Set<string>();
private _onDidDispose = new Emitter<void>();
private _onDidReceiveMessage = new Emitter<any>();
readonly onDidDispose: Event<void> = this._onDidDispose.event;
readonly onDidReceiveMessage: vscode.Event<any> = this._onDidReceiveMessage.event;
private _hasDecorationsForKey: { [key: string]: boolean; } = Object.create(null);
private _editor?: vscode.NotebookEditor;
constructor(
readonly id: string,
private readonly _viewType: string,
private readonly _proxy: MainThreadNotebookShape,
private readonly _webComm: vscode.NotebookCommunication,
private readonly _proxy: MainThreadNotebookEditorsShape,
readonly notebookData: ExtHostNotebookDocument,
visibleRanges: vscode.NotebookRange[],
selections: vscode.NotebookRange[],
viewColumn: vscode.ViewColumn | undefined
) {
super();
this._register(this._webComm.onDidReceiveMessage(e => {
this._onDidReceiveMessage.fire(e);
}));
this._selections = selections;
this._visibleRanges = visibleRanges;
this._viewColumn = viewColumn;
}
get viewColumn(): vscode.ViewColumn | undefined {
return this._viewColumn;
}
set viewColumn(_value) {
throw readonly('viewColumn');
}
get kernel() {
return this._kernel;
}
set kernel(_kernel: vscode.NotebookKernel | undefined) {
throw readonly('kernel');
}
_acceptKernel(kernel?: vscode.NotebookKernel) {
this._kernel = kernel;
get apiEditor(): vscode.NotebookEditor {
if (!this._editor) {
const that = this;
this._editor = {
get document() {
return that.notebookData.apiNotebook;
},
get selections() {
return that._selections;
},
get visibleRanges() {
return that._visibleRanges;
},
revealRange(range, revealType) {
that._proxy.$tryRevealRange(
that.id,
extHostConverter.NotebookRange.from(range),
revealType ?? extHostTypes.NotebookEditorRevealType.Default
);
},
get viewColumn() {
return that._viewColumn;
},
edit(callback) {
const edit = new NotebookEditorCellEditBuilder(this.document.version);
callback(edit);
return that._applyEdit(edit.finalize());
},
setDecorations(decorationType, range) {
return that.setDecorations(decorationType, range);
}
};
}
return this._editor;
}
get visible(): boolean {
return this._visible;
}
set visible(_state: boolean) {
throw readonly('visible');
}
_acceptVisibility(value: boolean) {
this._visible = value;
}
get visibleRanges() {
return this._visibleRanges;
}
set visibleRanges(_range: vscode.NotebookCellRange[]) {
throw readonly('visibleRanges');
}
_acceptVisibleRanges(value: vscode.NotebookCellRange[]): void {
_acceptVisibleRanges(value: vscode.NotebookRange[]): void {
this._visibleRanges = value;
}
get active(): boolean {
return this._active;
_acceptSelections(selections: vscode.NotebookRange[]): void {
this._selections = selections;
}
set active(_state: boolean) {
throw readonly('active');
}
_acceptActive(value: boolean) {
this._active = value;
}
get document(): vscode.NotebookDocument {
return this.notebookData.notebookDocument;
}
edit(callback: (editBuilder: NotebookEditorCellEditBuilder) => void): Thenable<boolean> {
const edit = new NotebookEditorCellEditBuilder(this.document.version);
callback(edit);
return this._applyEdit(edit.finalize());
_acceptViewColumn(value: vscode.ViewColumn | undefined) {
this._viewColumn = value;
}
private _applyEdit(editData: INotebookEditData): Promise<boolean> {
@@ -206,9 +171,9 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook
const prevIndex = compressedEditsIndex;
const prev = compressedEdits[prevIndex];
if (prev.editType === CellEditType.Replace && editData.cellEdits[i].editType === CellEditType.Replace) {
const edit = editData.cellEdits[i];
if ((edit.editType !== CellEditType.DocumentMetadata) && prev.index === edit.index) {
const edit = editData.cellEdits[i];
if (prev.editType === CellEditType.Replace && edit.editType === CellEditType.Replace) {
if (prev.index === edit.index) {
prev.cells.push(...(editData.cellEdits[i] as ICellReplaceEdit).cells);
prev.count += (editData.cellEdits[i] as ICellReplaceEdit).count;
continue;
@@ -219,42 +184,24 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook
compressedEditsIndex++;
}
return this._proxy.$tryApplyEdits(this._viewType, this.document.uri, editData.documentVersionId, compressedEdits);
return this._proxy.$tryApplyEdits(this.id, editData.documentVersionId, compressedEdits);
}
setDecorations(decorationType: vscode.NotebookEditorDecorationType, range: vscode.NotebookCellRange): void {
const willBeEmpty = (range.start === range.end);
if (willBeEmpty && !this._hasDecorationsForKey[decorationType.key]) {
setDecorations(decorationType: vscode.NotebookEditorDecorationType, range: vscode.NotebookRange): void {
if (range.isEmpty && !this._hasDecorationsForKey.has(decorationType.key)) {
// avoid no-op call to the renderer
return;
}
if (willBeEmpty) {
delete this._hasDecorationsForKey[decorationType.key];
if (range.isEmpty) {
this._hasDecorationsForKey.delete(decorationType.key);
} else {
this._hasDecorationsForKey[decorationType.key] = true;
this._hasDecorationsForKey.add(decorationType.key);
}
return this._proxy.$trySetDecorations(
this.id,
range,
extHostConverter.NotebookRange.from(range),
decorationType.key
);
}
revealRange(range: vscode.NotebookCellRange, revealType?: extHostTypes.NotebookEditorRevealType) {
this._proxy.$tryRevealRange(this.id, range, revealType || extHostTypes.NotebookEditorRevealType.Default);
}
async postMessage(message: any): Promise<boolean> {
return this._webComm.postMessage(message);
}
asWebviewUri(localResource: vscode.Uri): vscode.Uri {
return this._webComm.asWebviewUri(localResource);
}
dispose() {
this._onDidDispose.fire();
super.dispose();
}
}

View File

@@ -0,0 +1,259 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Emitter } from 'vs/base/common/event';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { ExtHostNotebookKernelsShape, IMainContext, INotebookKernelDto2, MainContext, MainThreadNotebookKernelsShape } from 'vs/workbench/api/common/extHost.protocol';
import * as vscode from 'vscode';
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { URI, UriComponents } from 'vs/base/common/uri';
import * as extHostTypeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
import { asWebviewUri } from 'vs/workbench/api/common/shared/webview';
interface IKernelData {
extensionId: ExtensionIdentifier,
controller: vscode.NotebookController;
onDidChangeSelection: Emitter<{ selected: boolean; notebook: vscode.NotebookDocument; }>;
onDidReceiveMessage: Emitter<{ editor: vscode.NotebookEditor, message: any }>;
}
export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape {
private readonly _proxy: MainThreadNotebookKernelsShape;
private readonly _kernelData = new Map<number, IKernelData>();
private _handlePool: number = 0;
constructor(
mainContext: IMainContext,
private readonly _initData: IExtHostInitDataService,
private readonly _extHostNotebook: ExtHostNotebookController
) {
this._proxy = mainContext.getProxy(MainContext.MainThreadNotebookKernels);
}
createNotebookController(extension: IExtensionDescription, id: string, viewType: string, label: string, handler?: vscode.NotebookExecuteHandler, preloads?: vscode.NotebookKernelPreload[]): vscode.NotebookController {
for (let data of this._kernelData.values()) {
if (data.controller.id === id && ExtensionIdentifier.equals(extension.identifier, data.extensionId)) {
throw new Error(`notebook controller with id '${id}' ALREADY exist`);
}
}
const handle = this._handlePool++;
const that = this;
const _defaultExecutHandler = () => console.warn(`NO execute handler from notebook controller '${data.id}' of extension: '${extension.identifier}'`);
let isDisposed = false;
const commandDisposables = new DisposableStore();
const onDidChangeSelection = new Emitter<{ selected: boolean, notebook: vscode.NotebookDocument }>();
const onDidReceiveMessage = new Emitter<{ editor: vscode.NotebookEditor, message: any }>();
const data: INotebookKernelDto2 = {
id: `${extension.identifier.value}/${id}`,
viewType,
extensionId: extension.identifier,
extensionLocation: extension.extensionLocation,
label: label || extension.identifier.value,
preloads: preloads ? preloads.map(extHostTypeConverters.NotebookKernelPreload.from) : []
};
//
let _executeHandler: vscode.NotebookExecuteHandler = handler ?? _defaultExecutHandler;
let _interruptHandler: vscode.NotebookInterruptHandler | undefined;
// todo@jrieken the selector needs to be massaged
this._proxy.$addKernel(handle, data).catch(err => {
// this can happen when a kernel with that ID is already registered
console.log(err);
isDisposed = true;
});
// update: all setters write directly into the dto object
// and trigger an update. the actual update will only happen
// once per event loop execution
let tokenPool = 0;
const _update = () => {
if (isDisposed) {
return;
}
const myToken = ++tokenPool;
Promise.resolve().then(() => {
if (myToken === tokenPool) {
this._proxy.$updateKernel(handle, data);
}
});
};
const controller: vscode.NotebookController = {
get id() { return id; },
get viewType() { return data.viewType; },
onDidChangeNotebookAssociation: onDidChangeSelection.event,
get label() {
return data.label;
},
set label(value) {
data.label = value ?? extension.displayName ?? extension.name;
_update();
},
get detail() {
return data.detail ?? '';
},
set detail(value) {
data.detail = value;
_update();
},
get description() {
return data.description ?? '';
},
set description(value) {
data.description = value;
_update();
},
get supportedLanguages() {
return data.supportedLanguages;
},
set supportedLanguages(value) {
data.supportedLanguages = value;
_update();
},
get hasExecutionOrder() {
return data.hasExecutionOrder ?? false;
},
set hasExecutionOrder(value) {
data.hasExecutionOrder = value;
_update();
},
get preloads() {
return data.preloads ? data.preloads.map(extHostTypeConverters.NotebookKernelPreload.to) : [];
},
get executeHandler() {
return _executeHandler;
},
set executeHandler(value) {
_executeHandler = value ?? _defaultExecutHandler;
},
get interruptHandler() {
return _interruptHandler;
},
set interruptHandler(value) {
_interruptHandler = value;
data.supportsInterrupt = Boolean(value);
_update();
},
createNotebookCellExecutionTask(cell) {
if (isDisposed) {
throw new Error('notebook controller is DISPOSED');
}
//todo@jrieken
return that._extHostNotebook.createNotebookCellExecution(cell.notebook.uri, cell.index, data.id)!;
},
dispose: () => {
if (!isDisposed) {
isDisposed = true;
this._kernelData.delete(handle);
commandDisposables.dispose();
onDidChangeSelection.dispose();
onDidReceiveMessage.dispose();
this._proxy.$removeKernel(handle);
}
},
// --- ipc
onDidReceiveMessage: onDidReceiveMessage.event,
postMessage(message, editor) {
return that._proxy.$postMessage(handle, editor && that._extHostNotebook.getIdByEditor(editor), message);
},
asWebviewUri(uri: URI) {
return asWebviewUri(that._initData.environment, String(handle), uri);
},
// --- priority
updateNotebookAffinity(notebook, priority) {
that._proxy.$updateNotebookPriority(handle, notebook.uri, priority);
}
};
this._kernelData.set(handle, { extensionId: extension.identifier, controller, onDidChangeSelection, onDidReceiveMessage });
return controller;
}
$acceptSelection(handle: number, uri: UriComponents, value: boolean): void {
const obj = this._kernelData.get(handle);
if (obj) {
obj.onDidChangeSelection.fire({
selected: value,
notebook: this._extHostNotebook.lookupNotebookDocument(URI.revive(uri))!.apiNotebook
});
}
}
async $executeCells(handle: number, uri: UriComponents, handles: number[]): Promise<void> {
const obj = this._kernelData.get(handle);
if (!obj) {
// extension can dispose kernels in the meantime
return;
}
const document = this._extHostNotebook.lookupNotebookDocument(URI.revive(uri));
if (!document) {
throw new Error('MISSING notebook');
}
const cells: vscode.NotebookCell[] = [];
for (let cellHandle of handles) {
const cell = document.getCell(cellHandle);
if (cell) {
cells.push(cell.apiCell);
}
}
try {
await obj.controller.executeHandler.call(obj.controller, cells, document.apiNotebook, obj.controller);
} catch (err) {
//
console.error(err);
}
}
async $cancelCells(handle: number, uri: UriComponents, handles: number[]): Promise<void> {
const obj = this._kernelData.get(handle);
if (!obj) {
// extension can dispose kernels in the meantime
return;
}
const document = this._extHostNotebook.lookupNotebookDocument(URI.revive(uri));
if (!document) {
throw new Error('MISSING notebook');
}
if (obj.controller.interruptHandler) {
await obj.controller.interruptHandler.call(obj.controller, document.apiNotebook);
}
// we do both? interrupt and cancellation or should we be selective?
for (let cellHandle of handles) {
const cell = document.getCell(cellHandle);
if (cell) {
this._extHostNotebook.cancelOneNotebookCellExecution(cell);
}
}
}
$acceptRendererMessage(handle: number, editorId: string, message: any): void {
const obj = this._kernelData.get(handle);
if (!obj) {
// extension can dispose kernels in the meantime
return;
}
const editor = this._extHostNotebook.getEditorById(editorId);
if (!editor) {
throw new Error(`send message for UNKNOWN editor: ${editorId}`);
}
obj.onDidReceiveMessage.fire(Object.freeze({ editor: editor.apiEditor, message }));
}
}

View File

@@ -73,7 +73,7 @@ export abstract class AbstractExtHostOutputChannel extends Disposable implements
}
}
dispose(): void {
override dispose(): void {
super.dispose();
if (!this._disposed) {
@@ -90,7 +90,7 @@ export class ExtHostPushOutputChannel extends AbstractExtHostOutputChannel {
super(name, false, undefined, proxy);
}
append(value: string): void {
override append(value: string): void {
super.append(value);
this._id.then(id => this._proxy.$append(id, value));
this._onDidAppend.fire();
@@ -103,7 +103,7 @@ class ExtHostLogFileOutputChannel extends AbstractExtHostOutputChannel {
super(name, true, file, proxy);
}
append(value: string): void {
override append(value: string): void {
throw new Error('Not supported');
}
}

View File

@@ -25,7 +25,7 @@ export class ExtHostProgress implements ExtHostProgressShape {
withProgress<R>(extension: IExtensionDescription, options: ProgressOptions, task: (progress: Progress<IProgressStep>, token: CancellationToken) => Thenable<R>): Thenable<R> {
const handle = this._handles++;
const { title, location, cancellable } = options;
const source = localize('extensionSource', "{0} (Extension)", extension.displayName || extension.name);
const source = { label: localize('extensionSource', "{0} (Extension)", extension.displayName || extension.name), id: extension.identifier.value };
this._proxy.$startProgress(handle, { location: ProgressLocation.from(location), title, source, cancellable }, extension);
return this._withProgress(handle, task, !!cancellable);

File diff suppressed because it is too large Load Diff

View File

@@ -259,6 +259,22 @@ export class ExtHostSCMInputBox implements vscode.SourceControlInputBox {
// noop
}
focus(): void {
checkProposedApiEnabled(this._extension);
if (!this._visible) {
this.visible = true;
}
this._proxy.$setInputBoxFocus(this._sourceControlHandle);
}
showValidationMessage(message: string, type: vscode.SourceControlInputBoxValidationType) {
checkProposedApiEnabled(this._extension);
this._proxy.$showValidationMessage(this._sourceControlHandle, message, type as any);
}
$onInputBoxValueChange(value: string): void {
this.updateValue(value);
}

View File

@@ -0,0 +1,31 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { Event, Emitter } from 'vs/base/common/event';
import { ExtHostTelemetryShape } from 'vs/workbench/api/common/extHost.protocol';
export class ExtHostTelemetry implements ExtHostTelemetryShape {
private readonly _onDidChangeTelemetryEnabled = new Emitter<boolean>();
readonly onDidChangeTelemetryEnabled: Event<boolean> = this._onDidChangeTelemetryEnabled.event;
private _enabled: boolean = false;
getTelemetryEnabled(): boolean {
return this._enabled;
}
$initializeTelemetryEnabled(enabled: boolean): void {
this._enabled = enabled;
}
$onDidChangeTelemetryEnabled(enabled: boolean): void {
this._enabled = enabled;
this._onDidChangeTelemetryEnabled.fire(enabled);
}
}
export const IExtHostTelemetry = createDecorator<IExtHostTelemetry>('IExtHostTelemetry');
export interface IExtHostTelemetry extends ExtHostTelemetry, ExtHostTelemetryShape { }

View File

@@ -5,22 +5,23 @@
import type * as vscode from 'vscode';
import { Event, Emitter } from 'vs/base/common/event';
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IShellLaunchConfigDto, IShellDefinitionDto, IShellAndArgsDto, ITerminalDimensionsDto, ITerminalLinkDto, TerminalIdentifier } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IShellAndArgsDto, ITerminalDimensionsDto, ITerminalLinkDto, TerminalIdentifier } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { URI, UriComponents } from 'vs/base/common/uri';
import { ITerminalChildProcess, ITerminalLaunchError, ITerminalDimensionsOverride } from 'vs/workbench/contrib/terminal/common/terminal';
import { URI } from 'vs/base/common/uri';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { TerminalDataBufferer } from 'vs/workbench/contrib/terminal/common/terminalDataBuffering';
import { IDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle';
import { Disposable as VSCodeDisposable, EnvironmentVariableMutatorType } from './extHostTypes';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { localize } from 'vs/nls';
import { NotSupportedError } from 'vs/base/common/errors';
import { serializeEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableShared';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { generateUuid } from 'vs/base/common/uuid';
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { IShellLaunchConfigDto, ITerminalChildProcess, ITerminalDimensionsOverride, ITerminalEnvironment, ITerminalLaunchError, TerminalShellType } from 'vs/platform/terminal/common/terminal';
import { TerminalDataBufferer } from 'vs/platform/terminal/common/terminalDataBuffering';
import { ITerminalProfile } from 'vs/workbench/contrib/terminal/common/terminal';
export interface IExtHostTerminalService extends ExtHostTerminalServiceShape, IDisposable {
@@ -116,23 +117,26 @@ export class ExtHostTerminal {
shellPath?: string,
shellArgs?: string[] | string,
cwd?: string | URI,
env?: { [key: string]: string | null },
env?: ITerminalEnvironment,
icon?: string,
initialText?: string,
waitOnExit?: boolean,
strictEnv?: boolean,
hideFromUser?: boolean,
isFeatureTerminal?: boolean
isFeatureTerminal?: boolean,
isExtensionOwnedTerminal?: boolean
): Promise<void> {
if (typeof this._id !== 'string') {
throw new Error('Terminal has already been created');
}
await this._proxy.$createTerminal(this._id, { name: this._name, shellPath, shellArgs, cwd, env, waitOnExit, strictEnv, hideFromUser, isFeatureTerminal });
await this._proxy.$createTerminal(this._id, { name: this._name, shellPath, shellArgs, cwd, env, icon, initialText, waitOnExit, strictEnv, hideFromUser, isFeatureTerminal, isExtensionOwnedTerminal });
}
public async createExtensionTerminal(): Promise<number> {
if (typeof this._id !== 'string') {
throw new Error('Terminal has already been created');
}
await this._proxy.$createTerminal(this._id, { name: this._name, isExtensionTerminal: true });
await this._proxy.$createTerminal(this._id, { name: this._name, isExtensionCustomPtyTerminal: true });
// At this point, the id has been set via `$acceptTerminalOpened`
if (typeof this._id === 'string') {
throw new Error('Terminal creation failed');
@@ -184,6 +188,9 @@ export class ExtHostTerminal {
}
export class ExtHostPseudoterminal implements ITerminalChildProcess {
readonly id = 0;
readonly shouldPersist = false;
private readonly _onProcessData = new Emitter<string>();
public readonly onProcessData: Event<string> = this._onProcessData.event;
private readonly _onProcessExit = new Emitter<number | undefined>();
@@ -194,6 +201,9 @@ export class ExtHostPseudoterminal implements ITerminalChildProcess {
public readonly onProcessTitleChanged: Event<string> = this._onProcessTitleChanged.event;
private readonly _onProcessOverrideDimensions = new Emitter<ITerminalDimensionsOverride | undefined>();
public get onProcessOverrideDimensions(): Event<ITerminalDimensionsOverride | undefined> { return this._onProcessOverrideDimensions.event; }
private readonly _onProcessShellTypeChanged = new Emitter<TerminalShellType>();
public readonly onProcessShellTypeChanged = this._onProcessShellTypeChanged.event;
constructor(private readonly _pty: vscode.Pseudoterminal) { }
@@ -217,6 +227,10 @@ export class ExtHostPseudoterminal implements ITerminalChildProcess {
}
}
async processBinary(data: string): Promise<void> {
// No-op, processBinary is not supported in extextion owned terminals.
}
acknowledgeDataEvent(charCount: number): void {
// No-op, flow control is not supported in extension owned terminals. If this is ever
// implemented it will need new pause and resume VS Code APIs.
@@ -320,10 +334,8 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
public abstract createTerminalFromOptions(options: vscode.TerminalOptions): vscode.Terminal;
public abstract getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string;
public abstract getDefaultShellArgs(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string[] | string;
public abstract $spawnExtHostProcess(id: number, shellLaunchConfigDto: IShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise<ITerminalLaunchError | undefined>;
public abstract $getAvailableShells(): Promise<IShellDefinitionDto[]>;
public abstract $getAvailableProfiles(configuredProfilesOnly: boolean): Promise<ITerminalProfile[]>;
public abstract $getDefaultShellAndArgs(useAutomationShell: boolean): Promise<IShellAndArgsDto>;
public abstract $acceptWorkspacePermissionsChanged(isAllowed: boolean): void;
public createExtensionTerminal(options: vscode.ExtensionTerminalOptions): vscode.Terminal {
const terminal = new ExtHostTerminal(this._proxy, generateUuid(), options, options.name);
@@ -764,27 +776,18 @@ export class WorkerExtHostTerminalService extends BaseExtHostTerminalService {
}
public getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string {
// Return the empty string to avoid throwing
return '';
throw new NotSupportedError();
}
public getDefaultShellArgs(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string[] | string {
throw new NotSupportedError();
}
public $spawnExtHostProcess(id: number, shellLaunchConfigDto: IShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise<ITerminalLaunchError | undefined> {
throw new NotSupportedError();
}
public $getAvailableShells(): Promise<IShellDefinitionDto[]> {
public $getAvailableProfiles(configuredProfilesOnly: boolean): Promise<ITerminalProfile[]> {
throw new NotSupportedError();
}
public async $getDefaultShellAndArgs(useAutomationShell: boolean): Promise<IShellAndArgsDto> {
throw new NotSupportedError();
}
public $acceptWorkspacePermissionsChanged(isAllowed: boolean): void {
// No-op for web worker ext host as workspace permissions aren't used
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,44 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Emitter } from 'vs/base/common/event';
import { TestItemImpl } from 'vs/workbench/api/common/extHostTypes';
import * as vscode from 'vscode';
export const enum ExtHostTestItemEventType {
NewChild,
Disposed,
Invalidated,
SetProp,
}
export type ExtHostTestItemEvent =
| [evt: ExtHostTestItemEventType.NewChild, item: TestItemImpl]
| [evt: ExtHostTestItemEventType.Disposed]
| [evt: ExtHostTestItemEventType.Invalidated]
| [evt: ExtHostTestItemEventType.SetProp, key: keyof vscode.TestItem<never>, value: any];
export interface IExtHostTestItemApi {
children: Map<string, TestItemImpl>;
parent?: TestItemImpl;
bus: Emitter<ExtHostTestItemEvent>;
}
const eventPrivateApis = new WeakMap<TestItemImpl, IExtHostTestItemApi>();
/**
* Gets the private API for a test item implementation. This implementation
* is a managed object, but we keep a weakmap to avoid exposing any of the
* internals to extensions.
*/
export const getPrivateApiFor = (impl: TestItemImpl) => {
let api = eventPrivateApis.get(impl);
if (!api) {
api = { children: new Map(), bus: new Emitter() };
eventPrivateApis.set(impl, api);
}
return api;
};

View File

@@ -86,7 +86,7 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
if (!options || !options.treeDataProvider) {
throw new Error('Options with treeDataProvider is mandatory');
}
const registerPromise = this._proxy.$registerTreeViewDataProvider(viewId, { showCollapseAll: !!options.showCollapseAll, canSelectMany: !!options.canSelectMany });
const treeView = this.createExtHostTreeView(viewId, options, extension);
return {
get onDidCollapseElement() { return treeView.onDidCollapseElement; },
@@ -112,7 +112,9 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
reveal: (element: T, options?: IRevealOptions): Promise<void> => {
return treeView.reveal(element, options);
},
dispose: () => {
dispose: async () => {
// Wait for the registration promise to finish before doing the dispose.
await registerPromise;
this.treeViews.delete(viewId);
treeView.dispose();
}
@@ -765,7 +767,7 @@ export class ExtHostTreeView<T> extends Disposable {
this.nodes.clear();
}
dispose() {
override dispose() {
this._refreshCancellationSource.dispose();
this.clearAll();

View File

@@ -6,7 +6,7 @@
import { ExtHostTunnelServiceShape } from 'vs/workbench/api/common/extHost.protocol';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import * as vscode from 'vscode';
import { RemoteTunnel, TunnelCreationOptions, TunnelOptions } from 'vs/platform/remote/common/tunnel';
import { ProvidedPortAttributes, RemoteTunnel, TunnelCreationOptions, TunnelOptions } from 'vs/platform/remote/common/tunnel';
import { IDisposable } from 'vs/base/common/lifecycle';
import { Emitter } from 'vs/base/common/event';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
@@ -46,6 +46,7 @@ export interface IExtHostTunnelService extends ExtHostTunnelServiceShape {
getTunnels(): Promise<vscode.TunnelDescription[]>;
onDidChangeTunnels: vscode.Event<void>;
setTunnelExtensionFunctions(provider: vscode.RemoteAuthorityResolver | undefined): Promise<IDisposable>;
registerPortsAttributesProvider(portSelector: { pid?: number, portRange?: [number, number], commandMatcher?: RegExp }, provider: vscode.PortAttributesProvider): IDisposable;
}
export const IExtHostTunnelService = createDecorator<IExtHostTunnelService>('IExtHostTunnelService');
@@ -71,6 +72,14 @@ export class ExtHostTunnelService implements IExtHostTunnelService {
async setTunnelExtensionFunctions(provider: vscode.RemoteAuthorityResolver | undefined): Promise<IDisposable> {
return { dispose: () => { } };
}
registerPortsAttributesProvider(portSelector: { pid?: number, portRange?: [number, number] }, provider: vscode.PortAttributesProvider) {
return { dispose: () => { } };
}
async $providePortAttributes(handles: number[], ports: number[], pid: number | undefined, commandline: string | undefined, cancellationToken: vscode.CancellationToken): Promise<ProvidedPortAttributes[]> {
return [];
}
async $forwardPort(tunnelOptions: TunnelOptions, tunnelCreationOptions: TunnelCreationOptions): Promise<TunnelDto | undefined> { return undefined; }
async $closeTunnel(remote: { host: string, port: number }): Promise<void> { }
async $onDidTunnelsChange(): Promise<void> { }

View File

@@ -3,36 +3,37 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as modes from 'vs/editor/common/modes';
import * as types from './extHostTypes';
import * as search from 'vs/workbench/contrib/search/common/search';
import { ITextEditorOptions } from 'vs/platform/editor/common/editor';
import { IDecorationOptions, IThemeDecorationRenderOptions, IDecorationRenderOptions, IContentDecorationRenderOptions } from 'vs/editor/common/editorCommon';
import { EndOfLineSequence, TrackedRangeStickiness } from 'vs/editor/common/model';
import type * as vscode from 'vscode';
import { URI, UriComponents } from 'vs/base/common/uri';
import { ProgressLocation as MainProgressLocation } from 'vs/platform/progress/common/progress';
import { EditorGroupColumn, SaveReason } from 'vs/workbench/common/editor';
import { IPosition } from 'vs/editor/common/core/position';
import * as editorRange from 'vs/editor/common/core/range';
import { ISelection } from 'vs/editor/common/core/selection';
import { coalesce, isNonEmptyArray } from 'vs/base/common/arrays';
import * as htmlContent from 'vs/base/common/htmlContent';
import * as languageSelector from 'vs/editor/common/modes/languageSelector';
import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol';
import { MarkerSeverity, IRelatedInformation, IMarkerData, MarkerTag } from 'vs/platform/markers/common/markers';
import { ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { isString, isNumber } from 'vs/base/common/types';
import { DisposableStore } from 'vs/base/common/lifecycle';
import * as marked from 'vs/base/common/marked/marked';
import { parse } from 'vs/base/common/marshalling';
import { cloneAndChange } from 'vs/base/common/objects';
import { LogLevel as _MainLogLevel } from 'vs/platform/log/common/log';
import { coalesce, isNonEmptyArray } from 'vs/base/common/arrays';
import { isDefined, isNumber, isString } from 'vs/base/common/types';
import { URI, UriComponents } from 'vs/base/common/uri';
import { RenderLineNumbersType } from 'vs/editor/common/config/editorOptions';
import { IPosition } from 'vs/editor/common/core/position';
import * as editorRange from 'vs/editor/common/core/range';
import { ISelection } from 'vs/editor/common/core/selection';
import { IContentDecorationRenderOptions, IDecorationOptions, IDecorationRenderOptions, IThemeDecorationRenderOptions } from 'vs/editor/common/editorCommon';
import { EndOfLineSequence, TrackedRangeStickiness } from 'vs/editor/common/model';
import * as modes from 'vs/editor/common/modes';
import * as languageSelector from 'vs/editor/common/modes/languageSelector';
import { EditorOverride, ITextEditorOptions } from 'vs/platform/editor/common/editor';
import { IMarkerData, IRelatedInformation, MarkerSeverity, MarkerTag } from 'vs/platform/markers/common/markers';
import { ProgressLocation as MainProgressLocation } from 'vs/platform/progress/common/progress';
import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol';
import { CommandsConverter } from 'vs/workbench/api/common/extHostCommands';
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
import { CellOutputKind, IDisplayOutput, INotebookDecorationRenderOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { ITestItem, ITestState } from 'vs/workbench/contrib/testing/common/testCollection';
import { EditorGroupColumn, SaveReason } from 'vs/workbench/common/editor';
import * as notebooks from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange';
import * as search from 'vs/workbench/contrib/search/common/search';
import { ISerializedTestResults, ITestItem, ITestMessage, SerializedTestResultItem } from 'vs/workbench/contrib/testing/common/testCollection';
import { ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import type * as vscode from 'vscode';
import * as types from './extHostTypes';
export interface PositionLike {
line: number;
@@ -509,7 +510,7 @@ export namespace TextEdit {
}
export namespace WorkspaceEdit {
export function from(value: vscode.WorkspaceEdit, documents?: ExtHostDocumentsAndEditors, notebooks?: ExtHostNotebookController): extHostProtocol.IWorkspaceEditDto {
export function from(value: vscode.WorkspaceEdit, documents?: ExtHostDocumentsAndEditors, extHostNotebooks?: ExtHostNotebookController): extHostProtocol.IWorkspaceEditDto {
const result: extHostProtocol.IWorkspaceEditDto = {
edits: []
};
@@ -544,7 +545,60 @@ export namespace WorkspaceEdit {
resource: entry.uri,
edit: entry.edit,
notebookMetadata: entry.notebookMetadata,
notebookVersionId: notebooks?.lookupNotebookDocument(entry.uri)?.notebookDocument.version
notebookVersionId: extHostNotebooks?.lookupNotebookDocument(entry.uri)?.apiNotebook.version
});
} else if (entry._type === types.FileEditType.CellOutput) {
if (entry.newOutputs) {
result.edits.push({
_type: extHostProtocol.WorkspaceEditType.Cell,
metadata: entry.metadata,
resource: entry.uri,
edit: {
editType: notebooks.CellEditType.Output,
index: entry.index,
append: entry.append,
outputs: entry.newOutputs.map(NotebookCellOutput.from)
}
});
}
// todo@joh merge metadata and output edit?
if (entry.newMetadata) {
result.edits.push({
_type: extHostProtocol.WorkspaceEditType.Cell,
metadata: entry.metadata,
resource: entry.uri,
edit: {
editType: notebooks.CellEditType.PartialMetadata,
index: entry.index,
metadata: entry.newMetadata
}
});
}
} else if (entry._type === types.FileEditType.CellReplace) {
result.edits.push({
_type: extHostProtocol.WorkspaceEditType.Cell,
metadata: entry.metadata,
resource: entry.uri,
notebookVersionId: extHostNotebooks?.lookupNotebookDocument(entry.uri)?.apiNotebook.version,
edit: {
editType: notebooks.CellEditType.Replace,
index: entry.index,
count: entry.count,
cells: entry.cells.map(NotebookCellData.from)
}
});
} else if (entry._type === types.FileEditType.CellOutputItem) {
result.edits.push({
_type: extHostProtocol.WorkspaceEditType.Cell,
metadata: entry.metadata,
resource: entry.uri,
edit: {
editType: notebooks.CellEditType.OutputItems,
outputId: entry.outputId,
items: entry.newOutputItems?.map(NotebookCellOutputItem.from) || [],
append: entry.append
}
});
}
}
@@ -736,8 +790,8 @@ export namespace location {
};
}
export function to(value: modes.Location): types.Location {
return new types.Location(value.uri, Range.to(value.range));
export function to(value: extHostProtocol.ILocationDto): types.Location {
return new types.Location(URI.revive(value.uri), Range.to(value.range));
}
}
@@ -756,9 +810,9 @@ export namespace DefinitionLink {
: undefined,
};
}
export function to(value: modes.LocationLink): vscode.LocationLink {
export function to(value: extHostProtocol.IDefinitionLinkDto): vscode.LocationLink {
return {
targetUri: value.uri,
targetUri: URI.revive(value.uri),
targetRange: Range.to(value.range),
targetSelectionRange: value.targetSelectionRange
? Range.to(value.targetSelectionRange)
@@ -796,6 +850,67 @@ export namespace EvaluatableExpression {
}
}
export namespace InlineValue {
export function from(inlineValue: vscode.InlineValue): modes.InlineValue {
if (inlineValue instanceof types.InlineValueText) {
return <modes.InlineValueText>{
type: 'text',
range: Range.from(inlineValue.range),
text: inlineValue.text
};
} else if (inlineValue instanceof types.InlineValueVariableLookup) {
return <modes.InlineValueVariableLookup>{
type: 'variable',
range: Range.from(inlineValue.range),
variableName: inlineValue.variableName,
caseSensitiveLookup: inlineValue.caseSensitiveLookup
};
} else if (inlineValue instanceof types.InlineValueEvaluatableExpression) {
return <modes.InlineValueExpression>{
type: 'expression',
range: Range.from(inlineValue.range),
expression: inlineValue.expression
};
} else {
throw new Error(`Unknown 'InlineValue' type`);
}
}
export function to(inlineValue: modes.InlineValue): vscode.InlineValue {
switch (inlineValue.type) {
case 'text':
return <vscode.InlineValueText>{
range: Range.to(inlineValue.range),
text: inlineValue.text
};
case 'variable':
return <vscode.InlineValueVariableLookup>{
range: Range.to(inlineValue.range),
variableName: inlineValue.variableName,
caseSensitiveLookup: inlineValue.caseSensitiveLookup
};
case 'expression':
return <vscode.InlineValueEvaluatableExpression>{
range: Range.to(inlineValue.range),
expression: inlineValue.expression
};
}
}
}
export namespace InlineValueContext {
export function from(inlineValueContext: vscode.InlineValueContext): extHostProtocol.IInlineValueContextDto {
return <extHostProtocol.IInlineValueContextDto>{
frameId: inlineValueContext.frameId,
stoppedLocation: Range.from(inlineValueContext.stoppedLocation)
};
}
export function to(inlineValueContext: extHostProtocol.IInlineValueContextDto): types.InlineValueContext {
return new types.InlineValueContext(inlineValueContext.frameId, Range.to(inlineValueContext.stoppedLocation));
}
}
export namespace DocumentHighlight {
export function from(documentHighlight: vscode.DocumentHighlight): modes.DocumentHighlight {
return {
@@ -1021,6 +1136,7 @@ export namespace InlineHint {
return {
text: hint.text,
range: Range.from(hint.range),
kind: InlineHintKind.from(hint.kind ?? types.InlineHintKind.Other),
description: hint.description && MarkdownString.fromStrict(hint.description),
whitespaceBefore: hint.whitespaceBefore,
whitespaceAfter: hint.whitespaceAfter
@@ -1028,13 +1144,24 @@ export namespace InlineHint {
}
export function to(hint: modes.InlineHint): vscode.InlineHint {
return new types.InlineHint(
const res = new types.InlineHint(
hint.text,
Range.to(hint.range),
htmlContent.isMarkdownString(hint.description) ? MarkdownString.to(hint.description) : hint.description,
hint.whitespaceBefore,
hint.whitespaceAfter
InlineHintKind.to(hint.kind)
);
res.whitespaceAfter = hint.whitespaceAfter;
res.whitespaceBefore = hint.whitespaceBefore;
res.description = htmlContent.isMarkdownString(hint.description) ? MarkdownString.to(hint.description) : hint.description;
return res;
}
}
export namespace InlineHintKind {
export function from(kind: vscode.InlineHintKind): modes.InlineHintKind {
return kind;
}
export function to(kind: modes.InlineHintKind): vscode.InlineHintKind {
return kind;
}
}
@@ -1218,7 +1345,7 @@ export namespace TextEditorOpenOptions {
inactive: options.background,
preserveFocus: options.preserveFocus,
selection: typeof options.selection === 'object' ? Range.from(options.selection) : undefined,
override: typeof options.override === 'boolean' ? false : undefined
override: typeof options.override === 'boolean' ? EditorOverride.DISABLED : undefined
};
}
@@ -1268,32 +1395,154 @@ export namespace LanguageSelector {
} else if (typeof selector === 'string') {
return selector;
} else {
const filter = selector as vscode.DocumentFilter; // TODO: microsoft/TypeScript#42768
return <languageSelector.LanguageFilter>{
language: selector.language,
scheme: selector.scheme,
pattern: typeof selector.pattern === 'undefined' ? undefined : GlobPattern.from(selector.pattern),
exclusive: selector.exclusive
language: filter.language,
scheme: filter.scheme,
pattern: typeof filter.pattern === 'undefined' ? undefined : GlobPattern.from(filter.pattern),
exclusive: filter.exclusive
};
}
}
}
export namespace NotebookCellOutput {
export function from(output: types.NotebookCellOutput): IDisplayOutput {
return output.toJSON();
export namespace NotebookRange {
export function from(range: vscode.NotebookRange): ICellRange {
return { start: range.start, end: range.end };
}
export function to(range: ICellRange): types.NotebookRange {
return new types.NotebookRange(range.start, range.end);
}
}
export namespace NotebookCellMetadata {
export function to(data: notebooks.NotebookCellMetadata): types.NotebookCellMetadata {
return new types.NotebookCellMetadata().with({
...data,
...{
executionOrder: null,
lastRunSuccess: null,
runState: null,
runStartTime: null,
runStartTimeAdjustment: null,
runEndTime: null
}
});
}
}
export namespace NotebookDocumentMetadata {
export function from(data: types.NotebookDocumentMetadata): notebooks.NotebookDocumentMetadata {
return data;
}
export function to(data: notebooks.NotebookDocumentMetadata): types.NotebookDocumentMetadata {
return new types.NotebookDocumentMetadata().with(data);
}
}
export namespace NotebookCellPreviousExecutionResult {
export function to(data: notebooks.NotebookCellMetadata): vscode.NotebookCellExecutionSummary {
return {
startTime: data.runStartTime,
endTime: data.runEndTime,
executionOrder: data.executionOrder,
success: data.lastRunSuccess
};
}
export function from(data: vscode.NotebookCellExecutionSummary): Partial<notebooks.NotebookCellMetadata> {
return {
lastRunSuccess: data.success,
runStartTime: data.startTime,
runEndTime: data.endTime,
executionOrder: data.executionOrder
};
}
}
export namespace NotebookCellKind {
export function from(data: vscode.NotebookCellKind): notebooks.CellKind {
switch (data) {
case types.NotebookCellKind.Markdown:
return notebooks.CellKind.Markdown;
case types.NotebookCellKind.Code:
default:
return notebooks.CellKind.Code;
}
}
export function to(data: notebooks.CellKind): vscode.NotebookCellKind {
switch (data) {
case notebooks.CellKind.Markdown:
return types.NotebookCellKind.Markdown;
case notebooks.CellKind.Code:
default:
return types.NotebookCellKind.Code;
}
}
}
export namespace NotebookCellData {
export function from(data: vscode.NotebookCellData): notebooks.ICellDto2 {
return {
cellKind: NotebookCellKind.from(data.kind),
language: data.language,
source: data.source,
metadata: {
...data.metadata,
...NotebookCellPreviousExecutionResult.from(data.latestExecutionSummary ?? {})
},
outputs: data.outputs ? data.outputs.map(NotebookCellOutput.from) : []
};
}
export function to(data: notebooks.ICellDto2): vscode.NotebookCellData {
return new types.NotebookCellData(
NotebookCellKind.to(data.cellKind),
data.source,
data.language,
data.outputs ? data.outputs.map(NotebookCellOutput.to) : undefined,
data.metadata ? NotebookCellMetadata.to(data.metadata) : undefined,
);
}
}
export namespace NotebookCellOutputItem {
export function from(output: types.NotebookCellOutputItem): IDisplayOutput {
export function from(item: types.NotebookCellOutputItem): notebooks.IOutputItemDto {
return {
outputKind: CellOutputKind.Rich,
data: { [output.mime]: output.value },
metadata: output.metadata && { custom: output.metadata }
mime: item.mime,
value: item.value,
metadata: item.metadata
};
}
export function to(item: notebooks.IOutputItemDto): types.NotebookCellOutputItem {
return new types.NotebookCellOutputItem(item.mime, item.value, item.metadata);
}
}
export namespace NotebookCellOutput {
export function from(output: types.NotebookCellOutput): notebooks.IOutputDto {
return {
outputId: output.id,
outputs: output.outputs.map(NotebookCellOutputItem.from),
metadata: output.metadata
};
}
export function to(output: notebooks.IOutputDto): vscode.NotebookCellOutput {
const items = output.outputs.map(NotebookCellOutputItem.to);
return new types.NotebookCellOutput(items, output.outputId, output.metadata);
}
}
export namespace NotebookExclusiveDocumentPattern {
export function from(pattern: { include: vscode.GlobPattern | undefined, exclude: vscode.GlobPattern | undefined }): { include: string | types.RelativePattern | undefined, exclude: string | types.RelativePattern | undefined };
export function from(pattern: vscode.GlobPattern): string | types.RelativePattern;
@@ -1368,7 +1617,7 @@ export namespace NotebookExclusiveDocumentPattern {
}
export namespace NotebookDecorationRenderOptions {
export function from(options: vscode.NotebookDecorationRenderOptions): INotebookDecorationRenderOptions {
export function from(options: vscode.NotebookDecorationRenderOptions): notebooks.INotebookDecorationRenderOptions {
return {
backgroundColor: <string | types.ThemeColor>options.backgroundColor,
borderColor: <string | types.ThemeColor>options.borderColor,
@@ -1377,65 +1626,170 @@ export namespace NotebookDecorationRenderOptions {
}
}
export namespace TestState {
export function from(item: vscode.TestState): ITestState {
export namespace NotebookStatusBarItem {
export function from(item: vscode.NotebookCellStatusBarItem, commandsConverter: CommandsConverter, disposables: DisposableStore): notebooks.INotebookCellStatusBarItem {
const command = typeof item.command === 'string' ? { title: '', command: item.command } : item.command;
return {
runState: item.runState,
duration: item.duration,
messages: item.messages.map(message => ({
message: MarkdownString.fromStrict(message.message) || '',
severity: message.severity,
expectedOutput: message.expectedOutput,
actualOutput: message.actualOutput,
location: message.location ? location.from(message.location) : undefined,
})),
alignment: item.alignment === types.NotebookCellStatusBarAlignment.Left ? notebooks.CellStatusbarAlignment.Left : notebooks.CellStatusbarAlignment.Right,
command: commandsConverter.toInternal(command, disposables), // TODO@roblou
text: item.text,
tooltip: item.tooltip,
accessibilityInformation: item.accessibilityInformation,
priority: item.priority
};
}
export function to(item: ITestState): vscode.TestState {
return new types.TestState(
item.runState,
item.messages.map(message => ({
message: typeof message.message === 'string' ? message.message : MarkdownString.to(message.message),
severity: message.severity,
expectedOutput: message.expectedOutput,
actualOutput: message.actualOutput,
location: message.location && location.to({
range: message.location.range,
uri: URI.revive(message.location.uri)
}),
})),
item.duration,
);
}
}
export namespace TestItem {
export function from(item: vscode.TestItem, parentExtId?: string): ITestItem {
export namespace NotebookDocumentContentOptions {
export function from(options: vscode.NotebookDocumentContentOptions | undefined): notebooks.TransientOptions {
return {
extId: item.id ?? (parentExtId ? `${parentExtId}\0${item.label}` : item.label),
label: item.label,
location: item.location ? location.from(item.location) : undefined,
debuggable: item.debuggable ?? false,
description: item.description,
runnable: item.runnable ?? true,
state: TestState.from(item.state),
transientOutputs: options?.transientOutputs ?? false,
transientCellMetadata: {
...options?.transientCellMetadata,
executionOrder: true,
runState: true,
runStartTime: true,
runStartTimeAdjustment: true,
runEndTime: true,
lastRunSuccess: true
},
transientDocumentMetadata: options?.transientDocumentMetadata ?? {}
};
}
}
export namespace NotebookKernelPreload {
export function from(preload: vscode.NotebookKernelPreload): { uri: UriComponents; provides: string[] } {
return {
uri: preload.uri,
provides: typeof preload.provides === 'string'
? [preload.provides]
: preload.provides ?? []
};
}
export function to(preload: { uri: UriComponents; provides: string[] }): vscode.NotebookKernelPreload {
return {
uri: URI.revive(preload.uri),
provides: preload.provides
};
}
}
export namespace TestMessage {
export function from(message: vscode.TestMessage): ITestMessage {
return {
message: MarkdownString.fromStrict(message.message) || '',
severity: message.severity,
expectedOutput: message.expectedOutput,
actualOutput: message.actualOutput,
location: message.location ? location.from(message.location) as any : undefined,
};
}
export function toShallow(item: ITestItem): Omit<vscode.RequiredTestItem, 'children'> {
export function to(item: ITestMessage): vscode.TestMessage {
const message = new types.TestMessage(typeof item.message === 'string' ? item.message : MarkdownString.to(item.message));
message.severity = item.severity;
message.actualOutput = item.actualOutput;
message.expectedOutput = item.expectedOutput;
return message;
}
}
export namespace TestItem {
export type Raw<T = unknown> = vscode.TestItem<T>;
export function from(item: vscode.TestItem<unknown>): ITestItem {
return {
extId: item.id,
label: item.label,
uri: item.uri,
range: Range.from(item.range) || null,
debuggable: item.debuggable ?? false,
description: item.description || null,
runnable: item.runnable ?? true,
error: item.error ? (MarkdownString.fromStrict(item.error) || null) : null,
};
}
export function fromResultSnapshot(item: vscode.TestResultSnapshot): ITestItem {
return {
extId: item.id,
label: item.label,
uri: item.uri,
range: Range.from(item.range) || null,
debuggable: false,
description: item.description || null,
error: null,
runnable: true,
};
}
export function toPlain(item: ITestItem): Omit<vscode.TestItem<never>, 'children' | 'invalidate' | 'discoverChildren'> {
return {
id: item.extId,
label: item.label,
location: item.location && location.to({
range: item.location.range,
uri: URI.revive(item.location.uri)
}),
uri: URI.revive(item.uri),
range: Range.to(item.range || undefined),
addChild: () => undefined,
dispose: () => undefined,
status: types.TestItemStatus.Pending,
data: undefined as never,
debuggable: item.debuggable,
description: item.description,
description: item.description || undefined,
runnable: item.runnable,
state: TestState.to(item.state),
};
}
export function to(item: ITestItem): types.TestItemImpl {
const testItem = new types.TestItemImpl(item.extId, item.label, URI.revive(item.uri), undefined);
testItem.range = Range.to(item.range || undefined);
testItem.debuggable = item.debuggable;
testItem.description = item.description || undefined;
testItem.runnable = item.runnable;
return testItem;
}
}
export namespace TestResults {
const convertTestResultItem = (item: SerializedTestResultItem, byInternalId: Map<string, SerializedTestResultItem>): vscode.TestResultSnapshot => ({
...TestItem.toPlain(item.item),
taskStates: item.tasks.map(t => ({
state: t.state,
duration: t.duration,
messages: t.messages.map(TestMessage.to),
})),
children: item.children
.map(c => byInternalId.get(c))
.filter(isDefined)
.map(c => convertTestResultItem(c, byInternalId)),
});
export function to(serialized: ISerializedTestResults): vscode.TestRunResult {
const roots: SerializedTestResultItem[] = [];
const byInternalId = new Map<string, SerializedTestResultItem>();
for (const item of serialized.items) {
byInternalId.set(item.item.extId, item);
if (item.direct) {
roots.push(item);
}
}
return {
completedAt: serialized.completedAt,
results: roots.map(r => convertTestResultItem(r, byInternalId)),
};
}
}
export namespace CodeActionTriggerKind {
export function to(value: modes.CodeActionTriggerType): types.CodeActionTriggerKind {
switch (value) {
case modes.CodeActionTriggerType.Invoke:
return types.CodeActionTriggerKind.Invoke;
case modes.CodeActionTriggerType.Auto:
return types.CodeActionTriggerKind.Automatic;
}
}
}

View File

@@ -7,13 +7,15 @@ import { coalesceInPlace, equals } from 'vs/base/common/arrays';
import { illegalArgument } from 'vs/base/common/errors';
import { IRelativePattern } from 'vs/base/common/glob';
import { isMarkdownString, MarkdownString as BaseMarkdownString } from 'vs/base/common/htmlContent';
import { ResourceMap } from 'vs/base/common/map';
import { ReadonlyMapView, ResourceMap } from 'vs/base/common/map';
import { isFalsyOrWhitespace } from 'vs/base/common/strings';
import { isStringArray } from 'vs/base/common/types';
import { URI } from 'vs/base/common/uri';
import { generateUuid } from 'vs/base/common/uuid';
import { FileSystemProviderErrorCode, markAsFileSystemProviderError } from 'vs/platform/files/common/files';
import { RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { addIdToOutput, CellEditType, ICellEditOperation, ICellOutputEdit, ITransformedDisplayOutputDto, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { getPrivateApiFor, ExtHostTestItemEventType, IExtHostTestItemApi } from 'vs/workbench/api/common/extHostTestingPrivateApi';
import { CellEditType, ICellEditOperation } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import type * as vscode from 'vscode';
function es5ClassCompat(target: Function): any {
@@ -419,7 +421,7 @@ export class Selection extends Range {
return this._anchor === this._end;
}
toJSON() {
override toJSON() {
return {
start: this.start,
end: this.end,
@@ -585,7 +587,10 @@ export interface IFileOperationOptions {
export const enum FileEditType {
File = 1,
Text = 2,
Cell = 3
Cell = 3,
CellOutput = 4,
CellReplace = 5,
CellOutputItem = 6
}
export interface IFileOperation {
@@ -611,13 +616,45 @@ export interface IFileCellEdit {
metadata?: vscode.WorkspaceEditEntryMetadata;
}
export interface ICellEdit {
_type: FileEditType.CellReplace;
metadata?: vscode.WorkspaceEditEntryMetadata;
uri: URI;
index: number;
count: number;
cells: vscode.NotebookCellData[];
}
export interface ICellOutputEdit {
_type: FileEditType.CellOutput;
uri: URI;
index: number;
append: boolean;
newOutputs?: NotebookCellOutput[];
newMetadata?: vscode.NotebookCellMetadata;
metadata?: vscode.WorkspaceEditEntryMetadata;
}
export interface ICellOutputItemsEdit {
_type: FileEditType.CellOutputItem;
uri: URI;
index: number;
outputId: string;
append: boolean;
newOutputItems?: NotebookCellOutputItem[];
metadata?: vscode.WorkspaceEditEntryMetadata;
}
type WorkspaceEditEntry = IFileOperation | IFileTextEdit | IFileCellEdit | ICellEdit | ICellOutputEdit | ICellOutputItemsEdit;
@es5ClassCompat
export class WorkspaceEdit implements vscode.WorkspaceEdit {
private readonly _edits = new Array<IFileOperation | IFileTextEdit | IFileCellEdit>();
private readonly _edits: WorkspaceEditEntry[] = [];
_allEntries(): ReadonlyArray<IFileTextEdit | IFileOperation | IFileCellEdit> {
_allEntries(): ReadonlyArray<WorkspaceEditEntry> {
return this._edits;
}
@@ -638,41 +675,40 @@ export class WorkspaceEdit implements vscode.WorkspaceEdit {
// --- notebook
replaceNotebookMetadata(uri: URI, value: vscode.NotebookDocumentMetadata, metadata?: vscode.WorkspaceEditEntryMetadata): void {
this._edits.push({ _type: FileEditType.Cell, metadata, uri, edit: { editType: CellEditType.DocumentMetadata, metadata: { ...notebookDocumentMetadataDefaults, ...value } }, notebookMetadata: value });
this._edits.push({ _type: FileEditType.Cell, metadata, uri, edit: { editType: CellEditType.DocumentMetadata, metadata: value }, notebookMetadata: value });
}
replaceNotebookCells(uri: URI, start: number, end: number, cells: vscode.NotebookCellData[], metadata?: vscode.WorkspaceEditEntryMetadata): void {
if (start !== end || cells.length > 0) {
this._edits.push({ _type: FileEditType.Cell, metadata, uri, edit: { editType: CellEditType.Replace, index: start, count: end - start, cells: cells.map(cell => ({ ...cell, outputs: cell.outputs.map(output => addIdToOutput(output)) })) } });
replaceNotebookCells(uri: URI, range: vscode.NotebookRange, cells: vscode.NotebookCellData[], metadata?: vscode.WorkspaceEditEntryMetadata): void;
replaceNotebookCells(uri: URI, start: number, end: number, cells: vscode.NotebookCellData[], metadata?: vscode.WorkspaceEditEntryMetadata): void;
replaceNotebookCells(uri: URI, startOrRange: number | vscode.NotebookRange, endOrCells: number | vscode.NotebookCellData[], cellsOrMetadata?: vscode.NotebookCellData[] | vscode.WorkspaceEditEntryMetadata, metadata?: vscode.WorkspaceEditEntryMetadata): void {
let start: number | undefined;
let end: number | undefined;
let cellData: vscode.NotebookCellData[] = [];
let workspaceEditMetadata: vscode.WorkspaceEditEntryMetadata | undefined;
if (NotebookRange.isNotebookRange(startOrRange) && NotebookCellData.isNotebookCellDataArray(endOrCells) && !NotebookCellData.isNotebookCellDataArray(cellsOrMetadata)) {
start = startOrRange.start;
end = startOrRange.end;
cellData = endOrCells;
workspaceEditMetadata = cellsOrMetadata;
} else if (typeof startOrRange === 'number' && typeof endOrCells === 'number' && NotebookCellData.isNotebookCellDataArray(cellsOrMetadata)) {
start = startOrRange;
end = endOrCells;
cellData = cellsOrMetadata;
workspaceEditMetadata = metadata;
}
if (start === undefined || end === undefined) {
throw new Error('Invalid arguments');
}
if (start !== end || cellData.length > 0) {
this._edits.push({ _type: FileEditType.CellReplace, uri, index: start, count: end - start, cells: cellData, metadata: workspaceEditMetadata });
}
}
replaceNotebookCellOutput(uri: URI, index: number, outputs: (vscode.NotebookCellOutput | vscode.CellOutput)[], metadata?: vscode.WorkspaceEditEntryMetadata): void {
this._editNotebookCellOutput(uri, index, false, outputs, metadata);
}
appendNotebookCellOutput(uri: URI, index: number, outputs: (vscode.NotebookCellOutput | vscode.CellOutput)[], metadata?: vscode.WorkspaceEditEntryMetadata): void {
this._editNotebookCellOutput(uri, index, true, outputs, metadata);
}
private _editNotebookCellOutput(uri: URI, index: number, append: boolean, outputs: (vscode.NotebookCellOutput | vscode.CellOutput)[], metadata: vscode.WorkspaceEditEntryMetadata | undefined): void {
const edit: ICellOutputEdit = {
editType: CellEditType.Output,
index,
append,
outputs: outputs.map(output => {
if (NotebookCellOutput.isNotebookCellOutput(output)) {
return output.toJSON();
} else {
return addIdToOutput(output);
}
})
};
this._edits.push({ _type: FileEditType.Cell, metadata, uri, edit });
}
replaceNotebookCellMetadata(uri: URI, index: number, cellMetadata: vscode.NotebookCellMetadata, metadata?: vscode.WorkspaceEditEntryMetadata): void {
this._edits.push({ _type: FileEditType.Cell, metadata, uri, edit: { editType: CellEditType.Metadata, index, metadata: cellMetadata } });
this._edits.push({ _type: FileEditType.Cell, metadata, uri, edit: { editType: CellEditType.PartialMetadata, index, metadata: cellMetadata } });
}
// --- text
@@ -1143,9 +1179,9 @@ export class DocumentSymbol {
}
export enum CodeActionTrigger {
Automatic = 1,
Manual = 2,
export enum CodeActionTriggerKind {
Invoke = 1,
Automatic = 2,
}
@es5ClassCompat
@@ -1383,20 +1419,26 @@ export enum SignatureHelpTriggerKind {
ContentChange = 3,
}
export enum InlineHintKind {
Other = 0,
Type = 1,
Parameter = 2,
}
@es5ClassCompat
export class InlineHint {
text: string;
range: Range;
kind?: vscode.InlineHintKind;
description?: string | vscode.MarkdownString;
whitespaceBefore?: boolean;
whitespaceAfter?: boolean;
constructor(text: string, range: Range, description?: string | vscode.MarkdownString, whitespaceBefore?: boolean, whitespaceAfter?: boolean) {
constructor(text: string, range: Range, kind?: vscode.InlineHintKind) {
this.text = text;
this.range = range;
this.description = description;
this.whitespaceBefore = whitespaceBefore;
this.whitespaceAfter = whitespaceAfter;
this.kind = kind;
}
}
@@ -2397,6 +2439,53 @@ export class EvaluatableExpression implements vscode.EvaluatableExpression {
}
}
@es5ClassCompat
export class InlineValueText implements vscode.InlineValueText {
readonly range: Range;
readonly text: string;
constructor(range: Range, text: string) {
this.range = range;
this.text = text;
}
}
@es5ClassCompat
export class InlineValueVariableLookup implements vscode.InlineValueVariableLookup {
readonly range: Range;
readonly variableName?: string;
readonly caseSensitiveLookup: boolean;
constructor(range: Range, variableName?: string, caseSensitiveLookup: boolean = true) {
this.range = range;
this.variableName = variableName;
this.caseSensitiveLookup = caseSensitiveLookup;
}
}
@es5ClassCompat
export class InlineValueEvaluatableExpression implements vscode.InlineValueEvaluatableExpression {
readonly range: Range;
readonly expression?: string;
constructor(range: Range, expression?: string) {
this.range = range;
this.expression = expression;
}
}
@es5ClassCompat
export class InlineValueContext implements vscode.InlineValueContext {
readonly frameId: number;
readonly stoppedLocation: vscode.Range;
constructor(frameId: number, range: vscode.Range) {
this.frameId = frameId;
this.stoppedLocation = range;
}
}
//#region file api
export enum FileChangeType {
@@ -2807,6 +2896,201 @@ export enum ColorThemeKind {
//#region Notebook
export class NotebookRange {
static isNotebookRange(thing: any): thing is vscode.NotebookRange {
if (thing instanceof NotebookRange) {
return true;
}
if (!thing) {
return false;
}
return typeof (<NotebookRange>thing).start === 'number'
&& typeof (<NotebookRange>thing).end === 'number';
}
private _start: number;
private _end: number;
get start() {
return this._start;
}
get end() {
return this._end;
}
get isEmpty(): boolean {
return this._start === this._end;
}
constructor(start: number, end: number) {
if (start < 0) {
throw illegalArgument('start must be positive');
}
if (end < 0) {
throw illegalArgument('end must be positive');
}
if (start <= end) {
this._start = start;
this._end = end;
} else {
this._start = end;
this._end = start;
}
}
with(change: { start?: number, end?: number }): NotebookRange {
let start = this._start;
let end = this._end;
if (change.start !== undefined) {
start = change.start;
}
if (change.end !== undefined) {
end = change.end;
}
if (start === this._start && end === this._end) {
return this;
}
return new NotebookRange(start, end);
}
}
export class NotebookCellMetadata {
readonly inputCollapsed?: boolean;
readonly outputCollapsed?: boolean;
readonly [key: string]: any;
constructor(inputCollapsed?: boolean, outputCollapsed?: boolean);
constructor(data: Record<string, any>);
constructor(inputCollapsedOrData: (boolean | undefined) | Record<string, any>, outputCollapsed?: boolean) {
if (typeof inputCollapsedOrData === 'object') {
Object.assign(this, inputCollapsedOrData);
} else {
this.inputCollapsed = inputCollapsedOrData;
this.outputCollapsed = outputCollapsed;
}
}
with(change: {
inputCollapsed?: boolean | null,
outputCollapsed?: boolean | null,
[key: string]: any
}): NotebookCellMetadata {
let { inputCollapsed, outputCollapsed, ...remaining } = change;
if (inputCollapsed === undefined) {
inputCollapsed = this.inputCollapsed;
} else if (inputCollapsed === null) {
inputCollapsed = undefined;
}
if (outputCollapsed === undefined) {
outputCollapsed = this.outputCollapsed;
} else if (outputCollapsed === null) {
outputCollapsed = undefined;
}
if (inputCollapsed === this.inputCollapsed &&
outputCollapsed === this.outputCollapsed &&
Object.keys(remaining).length === 0
) {
return this;
}
return new NotebookCellMetadata(
{
inputCollapsed,
outputCollapsed,
...remaining
}
);
}
}
export class NotebookDocumentMetadata {
readonly trusted: boolean;
readonly [key: string]: any;
constructor(trusted?: boolean);
constructor(data: Record<string, any>);
constructor(trustedOrData: boolean | Record<string, any> = true) {
if (typeof trustedOrData === 'object') {
Object.assign(this, trustedOrData);
this.trusted = trustedOrData.trusted ?? true;
} else {
this.trusted = trustedOrData;
}
}
with(change: {
trusted?: boolean | null,
[key: string]: any
}): NotebookDocumentMetadata {
let { trusted, ...remaining } = change;
if (trusted === undefined) {
trusted = this.trusted;
} else if (trusted === null) {
trusted = undefined;
}
if (trusted === this.trusted &&
Object.keys(remaining).length === 0
) {
return this;
}
return new NotebookDocumentMetadata(
{
trusted,
...remaining
}
);
}
}
export class NotebookCellData {
static isNotebookCellDataArray(value: unknown): value is vscode.NotebookCellData[] {
return Array.isArray(value) && (<unknown[]>value).every(elem => NotebookCellData.isNotebookCellData(elem));
}
static isNotebookCellData(value: unknown): value is vscode.NotebookCellData {
// return value instanceof NotebookCellData;
return true;
}
kind: NotebookCellKind;
source: string;
language: string;
outputs?: NotebookCellOutput[];
metadata?: NotebookCellMetadata;
latestExecutionSummary?: vscode.NotebookCellExecutionSummary;
constructor(kind: NotebookCellKind, source: string, language: string, outputs?: NotebookCellOutput[], metadata?: NotebookCellMetadata, latestExecutionSummary?: vscode.NotebookCellExecutionSummary) {
this.kind = kind;
this.source = source;
this.language = language;
this.outputs = outputs ?? [];
this.metadata = metadata;
this.latestExecutionSummary = latestExecutionSummary;
}
}
export class NotebookData {
cells: NotebookCellData[];
metadata: NotebookDocumentMetadata;
constructor(cells: NotebookCellData[], metadata?: NotebookDocumentMetadata) {
this.cells = cells;
this.metadata = metadata ?? new NotebookDocumentMetadata();
}
}
export class NotebookCellOutputItem {
static isNotebookCellOutputItem(obj: unknown): obj is vscode.NotebookCellOutputItem {
@@ -2814,64 +3098,47 @@ export class NotebookCellOutputItem {
}
constructor(
readonly mime: string,
readonly value: unknown, // JSON'able
readonly metadata?: Record<string, string | number | boolean>
) { }
public mime: string,
public value: unknown, // JSON'able
public metadata?: Record<string, any>
) {
if (isFalsyOrWhitespace(this.mime)) {
throw new Error('INVALID mime type, must not be empty or falsy');
}
}
}
export class NotebookCellOutput {
static isNotebookCellOutput(obj: unknown): obj is vscode.NotebookCellOutput {
return obj instanceof NotebookCellOutput;
}
id: string;
outputs: NotebookCellOutputItem[];
metadata?: Record<string, any>;
readonly id: string = generateUuid();
constructor(readonly outputs: NotebookCellOutputItem[]) { }
toJSON(): ITransformedDisplayOutputDto {
let data: { [key: string]: unknown; } = {};
let custom: { [key: string]: unknown; } = {};
let hasMetadata = false;
for (let item of this.outputs) {
data[item.mime] = item.value;
if (item.metadata) {
custom[item.mime] = item.metadata;
hasMetadata = true;
}
constructor(
outputs: NotebookCellOutputItem[],
idOrMetadata?: string | Record<string, any>,
metadata?: Record<string, any>
) {
this.outputs = outputs;
if (typeof idOrMetadata === 'string') {
this.id = idOrMetadata;
this.metadata = metadata;
} else {
this.id = generateUuid();
this.metadata = idOrMetadata ?? metadata;
}
return {
outputId: this.id,
outputKind: CellOutputKind.Rich,
data,
metadata: hasMetadata ? { custom } : undefined
};
}
}
export enum CellKind {
export enum NotebookCellKind {
Markdown = 1,
Code = 2
}
export enum CellOutputKind {
Text = 1,
Error = 2,
Rich = 3
}
export enum NotebookCellRunState {
Running = 1,
Idle = 2,
Success = 3,
Error = 4
}
export enum NotebookRunState {
Running = 1,
Idle = 2
export enum NotebookCellExecutionState {
Idle = 1,
Pending = 2,
Executing = 3,
}
export enum NotebookCellStatusBarAlignment {
@@ -2886,6 +3153,21 @@ export enum NotebookEditorRevealType {
AtTop = 3
}
export class NotebookCellStatusBarItem {
constructor(
public text: string,
public alignment: NotebookCellStatusBarAlignment,
public command?: string | vscode.Command,
public tooltip?: string,
public priority?: number,
public accessibilityInformation?: vscode.AccessibilityInformation) { }
}
export enum NotebookControllerAffinity {
Default = 1,
Preferred = 2
}
//#endregion
@@ -2947,7 +3229,7 @@ export class LinkedEditingRanges {
}
//#region Testing
export enum TestRunState {
export enum TestResultState {
Unset = 0,
Queued = 1,
Running = 2,
@@ -2964,34 +3246,131 @@ export enum TestMessageSeverity {
Hint = 3
}
@es5ClassCompat
export class TestState {
#runState: TestRunState;
#duration?: number;
#messages: ReadonlyArray<Readonly<vscode.TestMessage>>;
export enum TestItemStatus {
Pending = 0,
Resolved = 1,
}
public get runState() {
return this.#runState;
const testItemPropAccessor = <K extends keyof vscode.TestItem<never>>(
api: IExtHostTestItemApi,
key: K,
defaultValue: vscode.TestItem<never>[K],
equals: (a: vscode.TestItem<never>[K], b: vscode.TestItem<never>[K]) => boolean
) => {
let value = defaultValue;
return {
enumerable: true,
configurable: false,
get() {
return value;
},
set(newValue: vscode.TestItem<never>[K]) {
if (!equals(value, newValue)) {
value = newValue;
api.bus.fire([ExtHostTestItemEventType.SetProp, key, newValue]);
}
},
};
};
const strictEqualComparator = <T>(a: T, b: T) => a === b;
const rangeComparator = (a: vscode.Range | undefined, b: vscode.Range | undefined) => {
if (a === b) { return true; }
if (!a || !b) { return false; }
return a.isEqual(b);
};
export class TestItemImpl implements vscode.TestItem<unknown> {
public readonly id!: string;
public readonly uri!: vscode.Uri;
public readonly children!: ReadonlyMap<string, TestItemImpl>;
public readonly parent!: TestItemImpl | undefined;
public range!: vscode.Range | undefined;
public description!: string | undefined;
public runnable!: boolean;
public debuggable!: boolean;
public error!: string | vscode.MarkdownString;
public status!: vscode.TestItemStatus;
/** Extension-owned resolve handler */
public resolveHandler?: (token: vscode.CancellationToken) => void;
constructor(id: string, public label: string, uri: vscode.Uri, public data: unknown) {
const api = getPrivateApiFor(this);
Object.defineProperties(this, {
id: {
value: id,
enumerable: true,
writable: false,
},
uri: {
value: uri,
enumerable: true,
writable: false,
},
parent: {
enumerable: false,
get: () => api.parent,
},
children: {
value: new ReadonlyMapView(api.children),
enumerable: true,
writable: false,
},
range: testItemPropAccessor(api, 'range', undefined, rangeComparator),
description: testItemPropAccessor(api, 'description', undefined, strictEqualComparator),
runnable: testItemPropAccessor(api, 'runnable', true, strictEqualComparator),
debuggable: testItemPropAccessor(api, 'debuggable', true, strictEqualComparator),
status: testItemPropAccessor(api, 'status', TestItemStatus.Resolved, strictEqualComparator),
error: testItemPropAccessor(api, 'error', undefined, strictEqualComparator),
});
}
public get duration() {
return this.#duration;
public invalidate() {
getPrivateApiFor(this).bus.fire([ExtHostTestItemEventType.Invalidated]);
}
public get messages() {
return this.#messages;
public dispose() {
const api = getPrivateApiFor(this);
if (api.parent) {
getPrivateApiFor(api.parent).children.delete(this.id);
}
api.bus.fire([ExtHostTestItemEventType.Disposed]);
}
constructor(runState: TestRunState, messages: vscode.TestMessage[] = [], duration?: number) {
this.#runState = runState;
this.#messages = Object.freeze(messages.map(m => Object.freeze(m)));
this.#duration = duration;
public addChild(child: vscode.TestItem<unknown>) {
if (!(child instanceof TestItemImpl)) {
throw new Error('Test child must be created through vscode.test.createTestItem()');
}
const api = getPrivateApiFor(this);
if (api.children.has(child.id)) {
throw new Error(`Attempted to insert a duplicate test item ID ${child.id}`);
}
api.children.set(child.id, child);
api.bus.fire([ExtHostTestItemEventType.NewChild, child]);
}
}
export type RequiredTestItem = vscode.RequiredTestItem;
export type TestItem = vscode.TestItem;
export class TestMessage implements vscode.TestMessage {
public severity = TestMessageSeverity.Error;
public expectedOutput?: string;
public actualOutput?: string;
public static diff(message: string | vscode.MarkdownString, expected: string, actual: string) {
const msg = new TestMessage(message);
msg.expectedOutput = expected;
msg.actualOutput = actual;
return msg;
}
constructor(public message: string | vscode.MarkdownString) { }
}
//#endregion
@@ -3001,3 +3380,17 @@ export enum ExternalUriOpenerPriority {
Default = 2,
Preferred = 3,
}
export enum WorkspaceTrustState {
Untrusted = 0,
Trusted = 1,
Unspecified = 2
}
export enum PortAutoForwardAction {
Notify = 1,
OpenBrowser = 2,
OpenPreview = 3,
Silent = 4,
Ignore = 5
}

View File

@@ -3,12 +3,14 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { VSBuffer } from 'vs/base/common/buffer';
import { Emitter, Event } from 'vs/base/common/event';
import { URI } from 'vs/base/common/uri';
import * as modes from 'vs/editor/common/modes';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { normalizeVersion, parseVersion } from 'vs/platform/extensions/common/extensionValidator';
import { ILogService } from 'vs/platform/log/common/log';
import { IExtHostApiDeprecationService } from 'vs/workbench/api/common/extHostApiDeprecationService';
import { deserializeWebviewMessage } from 'vs/workbench/api/common/extHostWebviewMessaging';
import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
import { asWebviewUri, WebviewInitData } from 'vs/workbench/api/common/shared/webview';
import type * as vscode from 'vscode';
@@ -29,6 +31,8 @@ export class ExtHostWebview implements vscode.Webview {
#isDisposed: boolean = false;
#hasCalledAsWebviewUri = false;
#serializeBuffersForPostMessage = false;
constructor(
handle: extHostProtocol.WebviewHandle,
proxy: extHostProtocol.MainThreadWebviewsShape,
@@ -44,6 +48,7 @@ export class ExtHostWebview implements vscode.Webview {
this.#initData = initData;
this.#workspace = workspace;
this.#extension = extension;
this.#serializeBuffersForPostMessage = shouldSerializeBuffersForPostMessage(extension);
this.#deprecationService = deprecationService;
}
@@ -97,7 +102,7 @@ export class ExtHostWebview implements vscode.Webview {
public set options(newOptions: vscode.WebviewOptions) {
this.assertNotDisposed();
this.#proxy.$setOptions(this.#handle, convertWebviewOptions(this.#extension, this.#workspace, newOptions));
this.#proxy.$setOptions(this.#handle, serializeWebviewOptions(this.#extension, this.#workspace, newOptions));
this.#options = newOptions;
}
@@ -105,7 +110,8 @@ export class ExtHostWebview implements vscode.Webview {
if (this.#isDisposed) {
return false;
}
return this.#proxy.$postMessage(this.#handle, message);
const serialized = serializeMessage(message, { serializeBuffersForPostMessage: this.#serializeBuffersForPostMessage });
return this.#proxy.$postMessage(this.#handle, serialized.message, ...serialized.buffers);
}
private assertNotDisposed() {
@@ -115,6 +121,49 @@ export class ExtHostWebview implements vscode.Webview {
}
}
export function shouldSerializeBuffersForPostMessage(extension: IExtensionDescription): boolean {
if (!extension.enableProposedApi) {
return false;
}
try {
const version = normalizeVersion(parseVersion(extension.engines.vscode));
return !!version && version.majorBase >= 1 && version.minorBase >= 56;
} catch {
return false;
}
}
export function serializeMessage(message: any, options: { serializeBuffersForPostMessage?: boolean }): { message: string, buffers: VSBuffer[] } {
if (options.serializeBuffersForPostMessage) {
// Extract all ArrayBuffers from the message and replace them with references.
const vsBuffers: Array<{ original: ArrayBuffer, vsBuffer: VSBuffer }> = [];
const replacer = (_key: string, value: any) => {
if (value && value instanceof ArrayBuffer) {
let index = vsBuffers.findIndex(x => x.original === value);
if (index === -1) {
const bytes = new Uint8Array(value);
const vsBuffer = VSBuffer.wrap(bytes);
index = vsBuffers.length;
vsBuffers.push({ original: value, vsBuffer });
}
return <extHostProtocol.WebviewMessageArrayBufferReference>{
$$vscode_array_buffer_reference$$: true,
index,
};
}
return value;
};
const serializedMessage = JSON.stringify(message, replacer);
return { message: serializedMessage, buffers: vsBuffers.map(x => x.vsBuffer) };
} else {
return { message: JSON.stringify(message), buffers: [] };
}
}
export class ExtHostWebviews implements extHostProtocol.ExtHostWebviewsShape {
private readonly _webviewProxy: extHostProtocol.MainThreadWebviewsShape;
@@ -133,10 +182,12 @@ export class ExtHostWebviews implements extHostProtocol.ExtHostWebviewsShape {
public $onMessage(
handle: extHostProtocol.WebviewHandle,
message: any
jsonMessage: string,
...buffers: VSBuffer[]
): void {
const webview = this.getWebview(handle);
if (webview) {
const { message } = deserializeWebviewMessage(jsonMessage, buffers);
webview._onMessageEmitter.fire(message);
}
}
@@ -148,7 +199,7 @@ export class ExtHostWebviews implements extHostProtocol.ExtHostWebviewsShape {
this._logService.warn(`${extensionId} created a webview without a content security policy: https://aka.ms/vscode-webview-missing-csp`);
}
public createNewWebview(handle: string, options: modes.IWebviewOptions & modes.IWebviewPanelOptions, extension: IExtensionDescription): ExtHostWebview {
public createNewWebview(handle: string, options: extHostProtocol.IWebviewOptions, extension: IExtensionDescription): ExtHostWebview {
const webview = new ExtHostWebview(handle, this._webviewProxy, reviveOptions(options), this.initData, this.workspace, extension, this._deprecationService);
this._webviews.set(handle, webview);
@@ -170,22 +221,24 @@ export function toExtensionData(extension: IExtensionDescription): extHostProtoc
return { id: extension.identifier, location: extension.extensionLocation };
}
export function convertWebviewOptions(
export function serializeWebviewOptions(
extension: IExtensionDescription,
workspace: IExtHostWorkspace | undefined,
options: vscode.WebviewPanelOptions & vscode.WebviewOptions,
): modes.IWebviewOptions {
options: vscode.WebviewOptions,
): extHostProtocol.IWebviewOptions {
return {
...options,
enableCommandUris: options.enableCommandUris,
enableScripts: options.enableScripts,
portMapping: options.portMapping,
localResourceRoots: options.localResourceRoots || getDefaultLocalResourceRoots(extension, workspace)
};
}
function reviveOptions(
options: modes.IWebviewOptions & modes.IWebviewPanelOptions
): vscode.WebviewOptions {
export function reviveOptions(options: extHostProtocol.IWebviewOptions): vscode.WebviewOptions {
return {
...options,
enableCommandUris: options.enableCommandUris,
enableScripts: options.enableScripts,
portMapping: options.portMapping,
localResourceRoots: options.localResourceRoots?.map(components => URI.from(components)),
};
}

View File

@@ -0,0 +1,122 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { VSBuffer } from 'vs/base/common/buffer';
import * as extHostProtocol from './extHost.protocol';
class ArrayBufferSet {
public readonly buffers: ArrayBuffer[] = [];
public add(buffer: ArrayBuffer): number {
let index = this.buffers.indexOf(buffer);
if (index < 0) {
index = this.buffers.length;
this.buffers.push(buffer);
}
return index;
}
}
export function serializeWebviewMessage(
message: any,
transfer?: readonly ArrayBuffer[]
): { message: string, buffers: VSBuffer[] } {
if (transfer) {
// Extract all ArrayBuffers from the message and replace them with references.
const arrayBuffers = new ArrayBufferSet();
const replacer = (_key: string, value: any) => {
if (value instanceof ArrayBuffer) {
const index = arrayBuffers.add(value);
return <extHostProtocol.WebviewMessageArrayBufferReference>{
$$vscode_array_buffer_reference$$: true,
index,
};
} else if (ArrayBuffer.isView(value)) {
const type = getTypedArrayType(value);
if (type) {
const index = arrayBuffers.add(value.buffer);
return <extHostProtocol.WebviewMessageArrayBufferReference>{
$$vscode_array_buffer_reference$$: true,
index,
view: {
type: type,
byteLength: value.byteLength,
byteOffset: value.byteOffset,
}
};
}
}
return value;
};
const serializedMessage = JSON.stringify(message, replacer);
const buffers = arrayBuffers.buffers.map(arrayBuffer => {
const bytes = new Uint8Array(arrayBuffer);
return VSBuffer.wrap(bytes);
});
return { message: serializedMessage, buffers };
} else {
return { message: JSON.stringify(message), buffers: [] };
}
}
function getTypedArrayType(value: ArrayBufferView): extHostProtocol.WebviewMessageArrayBufferViewType | undefined {
switch (value.constructor.name) {
case 'Int8Array': return extHostProtocol.WebviewMessageArrayBufferViewType.Int8Array;
case 'Uint8Array': return extHostProtocol.WebviewMessageArrayBufferViewType.Uint8Array;
case 'Uint8ClampedArray': return extHostProtocol.WebviewMessageArrayBufferViewType.Uint8ClampedArray;
case 'Int16Array': return extHostProtocol.WebviewMessageArrayBufferViewType.Int16Array;
case 'Uint16Array': return extHostProtocol.WebviewMessageArrayBufferViewType.Uint16Array;
case 'Int32Array': return extHostProtocol.WebviewMessageArrayBufferViewType.Int32Array;
case 'Uint32Array': return extHostProtocol.WebviewMessageArrayBufferViewType.Uint32Array;
case 'Float32Array': return extHostProtocol.WebviewMessageArrayBufferViewType.Float32Array;
case 'Float64Array': return extHostProtocol.WebviewMessageArrayBufferViewType.Float64Array;
case 'BigInt64Array': return extHostProtocol.WebviewMessageArrayBufferViewType.BigInt64Array;
case 'BigUint64Array': return extHostProtocol.WebviewMessageArrayBufferViewType.BigUint64Array;
}
return undefined;
}
export function deserializeWebviewMessage(jsonMessage: string, buffers: VSBuffer[]): { message: any, arrayBuffers: ArrayBuffer[] } {
const arrayBuffers: ArrayBuffer[] = buffers.map(buffer => {
const arrayBuffer = new ArrayBuffer(buffer.byteLength);
const uint8Array = new Uint8Array(arrayBuffer);
uint8Array.set(buffer.buffer);
return arrayBuffer;
});
const reviver = !buffers.length ? undefined : (_key: string, value: any) => {
if (typeof value === 'object' && (value as extHostProtocol.WebviewMessageArrayBufferReference).$$vscode_array_buffer_reference$$) {
const ref = value as extHostProtocol.WebviewMessageArrayBufferReference;
const { index } = ref;
const arrayBuffer = arrayBuffers[index];
if (ref.view) {
switch (ref.view.type) {
case extHostProtocol.WebviewMessageArrayBufferViewType.Int8Array: return new Int8Array(arrayBuffer, ref.view.byteOffset, ref.view.byteLength / Int8Array.BYTES_PER_ELEMENT);
case extHostProtocol.WebviewMessageArrayBufferViewType.Uint8Array: return new Uint8Array(arrayBuffer, ref.view.byteOffset, ref.view.byteLength / Uint8Array.BYTES_PER_ELEMENT);
case extHostProtocol.WebviewMessageArrayBufferViewType.Uint8ClampedArray: return new Uint8ClampedArray(arrayBuffer, ref.view.byteOffset, ref.view.byteLength / Uint8ClampedArray.BYTES_PER_ELEMENT);
case extHostProtocol.WebviewMessageArrayBufferViewType.Int16Array: return new Int16Array(arrayBuffer, ref.view.byteOffset, ref.view.byteLength / Int16Array.BYTES_PER_ELEMENT);
case extHostProtocol.WebviewMessageArrayBufferViewType.Uint16Array: return new Uint16Array(arrayBuffer, ref.view.byteOffset, ref.view.byteLength / Uint16Array.BYTES_PER_ELEMENT);
case extHostProtocol.WebviewMessageArrayBufferViewType.Int32Array: return new Int32Array(arrayBuffer, ref.view.byteOffset, ref.view.byteLength / Int32Array.BYTES_PER_ELEMENT);
case extHostProtocol.WebviewMessageArrayBufferViewType.Uint32Array: return new Uint32Array(arrayBuffer, ref.view.byteOffset, ref.view.byteLength / Uint32Array.BYTES_PER_ELEMENT);
case extHostProtocol.WebviewMessageArrayBufferViewType.Float32Array: return new Float32Array(arrayBuffer, ref.view.byteOffset, ref.view.byteLength / Float32Array.BYTES_PER_ELEMENT);
case extHostProtocol.WebviewMessageArrayBufferViewType.Float64Array: return new Float64Array(arrayBuffer, ref.view.byteOffset, ref.view.byteLength / Float64Array.BYTES_PER_ELEMENT);
case extHostProtocol.WebviewMessageArrayBufferViewType.BigInt64Array: return new BigInt64Array(arrayBuffer, ref.view.byteOffset, ref.view.byteLength / BigInt64Array.BYTES_PER_ELEMENT);
case extHostProtocol.WebviewMessageArrayBufferViewType.BigUint64Array: return new BigUint64Array(arrayBuffer, ref.view.byteOffset, ref.view.byteLength / BigUint64Array.BYTES_PER_ELEMENT);
default: throw new Error('Unknown array buffer view type');
}
}
return arrayBuffer;
}
return value;
};
const message = JSON.parse(jsonMessage, reviver);
return { message, arrayBuffers };
}

View File

@@ -7,10 +7,9 @@ import { Emitter } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { generateUuid } from 'vs/base/common/uuid';
import * as modes from 'vs/editor/common/modes';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import { convertWebviewOptions, ExtHostWebview, ExtHostWebviews, toExtensionData } from 'vs/workbench/api/common/extHostWebview';
import { serializeWebviewOptions, ExtHostWebview, ExtHostWebviews, toExtensionData, shouldSerializeBuffersForPostMessage } from 'vs/workbench/api/common/extHostWebview';
import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
import { EditorGroupColumn } from 'vs/workbench/common/editor';
import type * as vscode from 'vscode';
@@ -48,20 +47,20 @@ class ExtHostWebviewPanel extends Disposable implements vscode.WebviewPanel {
viewType: string,
title: string,
viewColumn: vscode.ViewColumn | undefined,
editorOptions: vscode.WebviewPanelOptions,
panelOptions: vscode.WebviewPanelOptions,
webview: ExtHostWebview
) {
super();
this.#handle = handle;
this.#proxy = proxy;
this.#viewType = viewType;
this.#options = editorOptions;
this.#options = panelOptions;
this.#viewColumn = viewColumn;
this.#title = title;
this.#webview = webview;
}
public dispose() {
public override dispose() {
if (this.#isDisposed) {
return;
}
@@ -200,8 +199,14 @@ export class ExtHostWebviewPanels implements extHostProtocol.ExtHostWebviewPanel
preserveFocus: typeof showOptions === 'object' && !!showOptions.preserveFocus
};
const serializeBuffersForPostMessage = shouldSerializeBuffersForPostMessage(extension);
const handle = ExtHostWebviewPanels.newHandle();
this._proxy.$createWebviewPanel(toExtensionData(extension), handle, viewType, title, webviewShowOptions, convertWebviewOptions(extension, this.workspace, options));
this._proxy.$createWebviewPanel(toExtensionData(extension), handle, viewType, {
title,
panelOptions: serializeWebviewPanelOptions(options),
webviewOptions: serializeWebviewOptions(extension, this.workspace, options),
serializeBuffersForPostMessage,
}, webviewShowOptions);
const webview = this.webviews.createNewWebview(handle, options, extension);
const panel = this.createNewWebviewPanel(handle, viewType, title, viewColumn, options, webview);
@@ -260,7 +265,9 @@ export class ExtHostWebviewPanels implements extHostProtocol.ExtHostWebviewPanel
}
this._serializers.set(viewType, { serializer, extension });
this._proxy.$registerSerializer(viewType);
this._proxy.$registerSerializer(viewType, {
serializeBuffersForPostMessage: shouldSerializeBuffersForPostMessage(extension)
});
return new extHostTypes.Disposable(() => {
this._serializers.delete(viewType);
@@ -271,10 +278,13 @@ export class ExtHostWebviewPanels implements extHostProtocol.ExtHostWebviewPanel
async $deserializeWebviewPanel(
webviewHandle: extHostProtocol.WebviewHandle,
viewType: string,
title: string,
state: any,
position: EditorGroupColumn,
options: modes.IWebviewOptions & modes.IWebviewPanelOptions
initData: {
title: string;
state: any;
webviewOptions: extHostProtocol.IWebviewOptions;
panelOptions: extHostProtocol.IWebviewPanelOptions;
},
position: EditorGroupColumn
): Promise<void> {
const entry = this._serializers.get(viewType);
if (!entry) {
@@ -282,12 +292,12 @@ export class ExtHostWebviewPanels implements extHostProtocol.ExtHostWebviewPanel
}
const { serializer, extension } = entry;
const webview = this.webviews.createNewWebview(webviewHandle, options, extension);
const revivedPanel = this.createNewWebviewPanel(webviewHandle, viewType, title, position, options, webview);
await serializer.deserializeWebviewPanel(revivedPanel, state);
const webview = this.webviews.createNewWebview(webviewHandle, initData.webviewOptions, extension);
const revivedPanel = this.createNewWebviewPanel(webviewHandle, viewType, initData.title, position, initData.panelOptions, webview);
await serializer.deserializeWebviewPanel(revivedPanel, initData.state);
}
public createNewWebviewPanel(webviewHandle: string, viewType: string, title: string, position: vscode.ViewColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions, webview: ExtHostWebview) {
public createNewWebviewPanel(webviewHandle: string, viewType: string, title: string, position: vscode.ViewColumn, options: extHostProtocol.IWebviewPanelOptions, webview: ExtHostWebview) {
const panel = new ExtHostWebviewPanel(webviewHandle, this._proxy, viewType, title, position, options, webview);
this._webviewPanels.set(webviewHandle, panel);
return panel;
@@ -297,3 +307,10 @@ export class ExtHostWebviewPanels implements extHostProtocol.ExtHostWebviewPanel
return this._webviewPanels.get(handle);
}
}
function serializeWebviewPanelOptions(options: vscode.WebviewPanelOptions): extHostProtocol.IWebviewPanelOptions {
return {
enableFindWidget: options.enableFindWidget,
retainContextWhenHidden: options.retainContextWhenHidden,
};
}

View File

@@ -43,7 +43,7 @@ class ExtHostWebviewView extends Disposable implements vscode.WebviewView {
this.#isVisible = isVisible;
}
public dispose() {
public override dispose() {
if (this.#isDisposed) {
return;
}
@@ -146,7 +146,10 @@ export class ExtHostWebviewViews implements extHostProtocol.ExtHostWebviewViewsS
}
this._viewProviders.set(viewType, { provider, extension });
this._proxy.$registerWebviewViewProvider(toExtensionData(extension), viewType, webviewOptions);
this._proxy.$registerWebviewViewProvider(toExtensionData(extension), viewType, {
retainContextWhenHidden: webviewOptions?.retainContextWhenHidden,
serializeBuffersForPostMessage: false,
});
return new extHostTypes.Disposable(() => {
this._viewProviders.delete(viewType);

View File

@@ -168,6 +168,9 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac
private readonly _onDidChangeWorkspace = new Emitter<vscode.WorkspaceFoldersChangeEvent>();
readonly onDidChangeWorkspace: Event<vscode.WorkspaceFoldersChangeEvent> = this._onDidChangeWorkspace.event;
private readonly _onDidGrantWorkspaceTrust = new Emitter<void>();
readonly onDidGrantWorkspaceTrust: Event<void> = this._onDidGrantWorkspaceTrust.event;
private readonly _logService: ILogService;
private readonly _requestIdProvider: Counter;
private readonly _barrier: Barrier;
@@ -181,6 +184,8 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac
private readonly _activeSearchCallbacks: ((match: IRawFileMatch2) => any)[] = [];
private _trusted: boolean = false;
constructor(
@IExtHostRpcService extHostRpc: IExtHostRpcService,
@IExtHostInitDataService initData: IExtHostInitDataService,
@@ -198,7 +203,8 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac
this._confirmedWorkspace = data ? new ExtHostWorkspaceImpl(data.id, data.name, [], data.configuration ? URI.revive(data.configuration) : null, !!data.isUntitled, uri => ignorePathCasing(uri, extHostFileSystemInfo)) : undefined;
}
$initializeWorkspace(data: IWorkspaceData | null): void {
$initializeWorkspace(data: IWorkspaceData | null, trusted: boolean): void {
this._trusted = trusted;
this.$acceptWorkspaceData(data);
this._barrier.open();
}
@@ -549,6 +555,24 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac
resolveProxy(url: string): Promise<string | undefined> {
return this._proxy.$resolveProxy(url);
}
// --- trust ---
get trusted(): boolean {
return this._trusted;
}
requestWorkspaceTrust(options?: vscode.WorkspaceTrustRequestOptions): Promise<boolean | undefined> {
const promise = this._proxy.$requestWorkspaceTrust(options);
return options?.modal ? promise : Promise.resolve(this._trusted);
}
$onDidGrantWorkspaceTrust(): void {
if (!this._trusted) {
this._trusted = true;
this._onDidGrantWorkspaceTrust.fire();
}
}
}
export const IExtHostWorkspace = createDecorator<IExtHostWorkspace>('IExtHostWorkspace');

View File

@@ -43,11 +43,21 @@ const apiMenus: IAPIMenu[] = [
id: MenuId.EditorTitle,
description: localize('menus.editorTitle', "The editor title menu")
},
{
key: 'editor/title/run',
id: MenuId.EditorTitleRun,
description: localize('menus.editorTitleRun', "Run submenu inside the editor title menu")
},
{
key: 'editor/context',
id: MenuId.EditorContext,
description: localize('menus.editorContext', "The editor context menu")
},
{
key: 'editor/context/copy',
id: MenuId.EditorContextCopy,
description: localize('menus.editorContextCopyAs', "'Copy as' submenu in the editor context menu")
},
{
key: 'explorer/context',
id: MenuId.ExplorerContext,
@@ -86,6 +96,11 @@ const apiMenus: IAPIMenu[] = [
proposed: true,
supportsSubmenus: false
},
{
key: 'menuBar/edit/copy',
id: MenuId.MenubarCopy,
description: localize('menus.opy', "'Copy as' submenu in the top level Edit menu")
},
{
key: 'scm/title',
id: MenuId.SCMTitle,
@@ -99,17 +114,17 @@ const apiMenus: IAPIMenu[] = [
{
key: 'scm/resourceState/context',
id: MenuId.SCMResourceContext,
description: localize('menus.resourceGroupContext', "The Source Control resource group context menu")
description: localize('menus.resourceStateContext', "The Source Control resource state context menu")
},
{
key: 'scm/resourceFolder/context',
id: MenuId.SCMResourceFolderContext,
description: localize('menus.resourceStateContext', "The Source Control resource state context menu")
description: localize('menus.resourceFolderContext', "The Source Control resource folder context menu")
},
{
key: 'scm/resourceGroup/context',
id: MenuId.SCMResourceGroupContext,
description: localize('menus.resourceFolderContext', "The Source Control resource folder context menu")
description: localize('menus.resourceGroupContext', "The Source Control resource group context menu")
},
{
key: 'scm/change/title',
@@ -123,6 +138,12 @@ const apiMenus: IAPIMenu[] = [
proposed: true,
supportsSubmenus: false
},
{
key: 'statusBar/remoteIndicator',
id: MenuId.StatusBarRemoteIndicatorMenu,
description: localize('menus.statusBarRemoteIndicator', "The remote indicator menu in the status bar"),
supportsSubmenus: false
},
{
key: 'view/title',
id: MenuId.ViewTitle,
@@ -155,12 +176,26 @@ const apiMenus: IAPIMenu[] = [
description: localize('comment.actions', "The contributed comment context menu, rendered as buttons below the comment editor"),
supportsSubmenus: false
},
/* {{SQL CARBON EDIT}} We use our own Notebook contributions
{
key: 'notebook/toolbar',
id: MenuId.NotebookToolbar,
description: localize('notebook.toolbar', "The contributed notebook toolbar menu"),
proposed: true
},
*/
{
key: 'notebook/cell/title',
id: MenuId.NotebookCellTitle,
description: localize('notebook.cell.title', "The contributed notebook cell title menu"),
proposed: true
},
{
key: 'testing/item/context',
id: MenuId.TestItem,
description: localize('testing.item.title', "The contributed test item menu"),
proposed: true
},
{
key: 'extension/context',
id: MenuId.ExtensionContext,
@@ -176,6 +211,21 @@ const apiMenus: IAPIMenu[] = [
id: MenuId.TimelineItemContext,
description: localize('view.timelineContext', "The Timeline view item context menu")
},
{
key: 'ports/item/context',
id: MenuId.TunnelContext,
description: localize('view.tunnelContext', "The Ports view item context menu")
},
{
key: 'ports/item/origin/inline',
id: MenuId.TunnelOriginInline,
description: localize('view.tunnelOriginInline', "The Ports view item origin inline menu")
},
{
key: 'ports/item/port/inline',
id: MenuId.TunnelPortInline,
description: localize('view.tunnelPortInline', "The Ports view item port inline menu")
},
// {{SQL CARBON EDIT}} start menu entries
{
key: 'dashboard/toolbar',
@@ -221,7 +271,7 @@ const apiMenus: IAPIMenu[] = [
key: 'dataGrid/item/context',
id: MenuId.DataGridItemContext,
description: localize('dataGrid.context', "The data grid item context menu")
},
}
// {{SQL CARBON EDIT}} end menu entries
];
@@ -384,7 +434,7 @@ namespace schema {
type: 'string'
},
icon: {
description: localize('vscode.extension.contributes.submenu.icon', '(Optional) Icon which is used to represent the submenu in the UI. Either a file path, an object with file paths for dark and light themes, or a theme icon references, like `\\$(zap)`'),
description: localize({ key: 'vscode.extension.contributes.submenu.icon', comment: ['do not translate or change `\\$(zap)`, \\ in front of $ is important.'] }, '(Optional) Icon which is used to represent the submenu in the UI. Either a file path, an object with file paths for dark and light themes, or a theme icon references, like `\\$(zap)`'),
anyOf: [{
type: 'string'
},
@@ -512,7 +562,7 @@ namespace schema {
type: 'string'
},
icon: {
description: localize('vscode.extension.contributes.commandType.icon', '(Optional) Icon which is used to represent the command in the UI. Either a file path, an object with file paths for dark and light themes, or a theme icon references, like `\\$(zap)`'),
description: localize({ key: 'vscode.extension.contributes.commandType.icon', comment: ['do not translate or change `\\$(zap)`, \\ in front of $ is important.'] }, '(Optional) Icon which is used to represent the command in the UI. Either a file path, an object with file paths for dark and light themes, or a theme icon references, like `\\$(zap)`'),
anyOf: [{
type: 'string'
},
@@ -565,7 +615,7 @@ commandsExtensionPoint.setHandler(extensions => {
let absoluteIcon: { dark: URI; light?: URI; } | ThemeIcon | undefined;
if (icon) {
if (typeof icon === 'string') {
absoluteIcon = ThemeIcon.fromString(icon) || { dark: resources.joinPath(extension.description.extensionLocation, icon) };
absoluteIcon = ThemeIcon.fromString(icon) ?? { dark: resources.joinPath(extension.description.extensionLocation, icon), light: resources.joinPath(extension.description.extensionLocation, icon) };
} else {
absoluteIcon = {