Merge from vscode e3c4990c67c40213af168300d1cfeb71d680f877 (#16569)

This commit is contained in:
Cory Rivera
2021-08-25 16:28:29 -07:00
committed by GitHub
parent ab1112bfb3
commit cb7b7da0a4
1752 changed files with 59525 additions and 33878 deletions

View File

@@ -1,6 +1,6 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { CommandsRegistry } from 'vs/platform/commands/common/commands';

View File

@@ -65,6 +65,7 @@ import './mainThreadComments';
import './mainThreadNotebook';
import './mainThreadNotebookKernels';
import './mainThreadNotebookDocumentsAndEditors';
import './mainThreadNotebookRenderers';
import './mainThreadTask';
import './mainThreadLabelService';
import './mainThreadTunnelService';

View File

@@ -34,12 +34,14 @@ export class MainThreadAuthenticationProvider extends Disposable {
const allowedExtensions = readAllowedExtensions(this.storageService, this.id, accountName);
if (!allowedExtensions.length) {
this.dialogService.show(Severity.Info, nls.localize('noTrustedExtensions', "This account has not been used by any extensions."), []);
this.dialogService.show(Severity.Info, nls.localize('noTrustedExtensions', "This account has not been used by any extensions."));
return;
}
const quickPick = this.quickInputService.createQuickPick<{ label: string, description: string, extension: AllowedExtension }>();
quickPick.canSelectMany = true;
quickPick.customButton = true;
quickPick.customLabel = nls.localize('manageTrustedExtensions.cancel', 'Cancel');
const usages = readAccountUsages(this.storageService, this.id, accountName);
const items = allowedExtensions.map(extension => {
const usage = usages.find(usage => extension.id === usage.extensionId);
@@ -68,6 +70,10 @@ export class MainThreadAuthenticationProvider extends Disposable {
quickPick.dispose();
});
quickPick.onDidCustom(() => {
quickPick.hide();
});
quickPick.show();
}

View File

@@ -54,7 +54,7 @@ CommandsRegistry.registerCommand('_remoteCLI.manageExtensions', async function (
const extensionManagementServerService = accessor.get(IExtensionManagementServerService);
const remoteExtensionManagementService = extensionManagementServerService.remoteExtensionManagementServer?.extensionManagementService;
if (!remoteExtensionManagementService) {
return undefined;
return undefined; // {{SQL CARBON EDIT}} Strict nulls
}
const cliService = instantiationService.createChild(new ServiceCollection([IExtensionManagementService, remoteExtensionManagementService])).createInstance(RemoteExtensionCLIManagementService);

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { multibyteAwareBtoa } from 'vs/base/browser/dom';
import { CancelablePromise, createCancelablePromise, timeout } from 'vs/base/common/async';
import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async';
import { VSBuffer } from 'vs/base/common/buffer';
import { CancellationToken } from 'vs/base/common/cancellation';
import { isPromiseCanceledError, onUnexpectedError } from 'vs/base/common/errors';
@@ -16,7 +16,7 @@ import { isEqual, isEqualOrParent, toLocalResource } from 'vs/base/common/resour
import { URI, UriComponents } from 'vs/base/common/uri';
import { localize } from 'vs/nls';
import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
import { FileChangesEvent, FileChangeType, FileSystemProviderCapabilities, IFileService } from 'vs/platform/files/common/files';
import { FileOperation, IFileService } from 'vs/platform/files/common/files';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ILabelService } from 'vs/platform/label/common/label';
import { IUndoRedoService, UndoRedoElementType } from 'vs/platform/undoRedo/common/undoRedo';
@@ -35,9 +35,10 @@ import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editor
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IPathService } from 'vs/workbench/services/path/common/pathService';
import { IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
import { IWorkingCopyFileService, WorkingCopyFileEvent } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService';
import { IWorkingCopy, IWorkingCopyBackup, NO_TYPE_ID, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopy';
import { ResourceWorkingCopy } from 'vs/workbench/services/workingCopy/common/resourceWorkingCopy';
const enum CustomEditorModelType {
Custom,
@@ -50,6 +51,8 @@ export class MainThreadCustomEditors extends Disposable implements extHostProtoc
private readonly _editorProviders = new Map<string, IDisposable>();
private readonly _editorRenameBackups = new Map<string, CustomDocumentBackupData>();
constructor(
context: extHostProtocol.IExtHostContext,
private readonly mainThreadWebview: MainThreadWebviews,
@@ -60,7 +63,7 @@ export class MainThreadCustomEditors extends Disposable implements extHostProtoc
@ICustomEditorService private readonly _customEditorService: ICustomEditorService,
@IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService,
@IWebviewWorkbenchService private readonly _webviewWorkbenchService: IWebviewWorkbenchService,
@IInstantiationService private readonly _instantiationService: IInstantiationService
@IInstantiationService private readonly _instantiationService: IInstantiationService,
) {
super();
@@ -89,6 +92,9 @@ export class MainThreadCustomEditors extends Disposable implements extHostProtoc
},
resolveWebview: () => { throw new Error('not implemented'); }
}));
// Working copy operations
this._register(workingCopyFileService.onWillRunWorkingCopyFileOperation(async e => this.onWillRunWorkingCopyFileOperation(e)));
}
override dispose() {
@@ -137,9 +143,18 @@ export class MainThreadCustomEditors extends Disposable implements extHostProtoc
webviewInput.webview.options = options;
webviewInput.webview.extension = extension;
// If there's an old resource this was a move and we must resolve the backup at the same time as the webview
// This is because the backup must be ready upon model creation, and the input resolve method comes after
let backupId = webviewInput.backupId;
if (webviewInput.oldResource && !webviewInput.backupId) {
const backup = this._editorRenameBackups.get(webviewInput.oldResource.toString());
backupId = backup?.backupId;
this._editorRenameBackups.delete(webviewInput.oldResource.toString());
}
let modelRef: IReference<ICustomEditorModel>;
try {
modelRef = await this.getOrCreateCustomEditorModel(modelType, resource, viewType, { backupId: webviewInput.backupId }, cancellation);
modelRef = await this.getOrCreateCustomEditorModel(modelType, resource, viewType, { backupId }, cancellation);
} catch (error) {
onUnexpectedError(error);
webviewInput.webview.html = this.mainThreadWebview.getWebviewResolvedFailedContent(viewType);
@@ -252,6 +267,31 @@ export class MainThreadCustomEditors extends Disposable implements extHostProtoc
}
return model;
}
//#region Working Copy
private async onWillRunWorkingCopyFileOperation(e: WorkingCopyFileEvent) {
if (e.operation !== FileOperation.MOVE) {
return;
}
e.waitUntil((async () => {
const models = [];
for (const file of e.files) {
if (file.source) {
models.push(...(await this._customEditorService.models.getAllModels(file.source)));
}
}
for (const model of models) {
if (model instanceof MainThreadCustomEditorModel && model.isDirty()) {
const workingCopy = await model.backup(CancellationToken.None);
if (workingCopy.meta) {
// This cast is safe because we do an instanceof check above and a custom document backup data is always returned
this._editorRenameBackups.set(model.editorResource.toString(), workingCopy.meta as CustomDocumentBackupData);
}
}
}
})());
}
//#endregion
}
namespace HotExitState {
@@ -276,9 +316,7 @@ namespace HotExitState {
}
class MainThreadCustomEditorModel extends Disposable implements ICustomEditorModel, IWorkingCopy {
#isDisposed = false;
class MainThreadCustomEditorModel extends ResourceWorkingCopy implements ICustomEditorModel {
private _fromBackup: boolean = false;
private _hotExitState: HotExitState.State = HotExitState.Allowed;
@@ -288,13 +326,9 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
private _savePoint: number = -1;
private readonly _edits: Array<number> = [];
private _isDirtyFromContentChange = false;
private _inOrphaned = false;
private _ongoingSave?: CancelablePromise<void>;
private readonly _onDidChangeOrphaned = this._register(new Emitter<void>());
public readonly onDidChangeOrphaned = this._onDidChangeOrphaned.event;
// TODO@mjbvz consider to enable a `typeId` that is specific for custom
// editors. Using a distinct `typeId` allows the working copy to have
// any resource (including file based resources) even if other working
@@ -322,7 +356,7 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
untitledDocumentData = editors[0].untitledDocumentData;
}
const { editable } = await proxy.$createCustomDocument(resource, viewType, options.backupId, untitledDocumentData, cancellation);
return instantiationService.createInstance(MainThreadCustomEditorModel, proxy, viewType, resource, !!options.backupId, editable, getEditors);
return instantiationService.createInstance(MainThreadCustomEditorModel, proxy, viewType, resource, !!options.backupId, editable, !!untitledDocumentData, getEditors);
}
constructor(
@@ -331,16 +365,17 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
private readonly _editorResource: URI,
fromBackup: boolean,
private readonly _editable: boolean,
startDirty: boolean,
private readonly _getEditors: () => CustomEditorInput[],
@IFileDialogService private readonly _fileDialogService: IFileDialogService,
@IFileService private readonly _fileService: IFileService,
@IFileService fileService: IFileService,
@ILabelService private readonly _labelService: ILabelService,
@IUndoRedoService private readonly _undoService: IUndoRedoService,
@IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService,
@IWorkingCopyService workingCopyService: IWorkingCopyService,
@IPathService private readonly _pathService: IPathService
@IPathService private readonly _pathService: IPathService,
) {
super();
super(MainThreadCustomEditorModel.toWorkingCopyResource(_viewType, _editorResource), fileService);
this._fromBackup = fromBackup;
@@ -348,7 +383,10 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
this._register(workingCopyService.registerWorkingCopy(this));
}
this._register(_fileService.onDidFilesChange(e => this.onDidFilesChange(e)));
// Normally means we're re-opening an untitled file
if (startDirty) {
this._isDirtyFromContentChange = true;
}
}
get editorResource() {
@@ -356,8 +394,6 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
}
override dispose() {
this.#isDisposed = true;
if (this._editable) {
this._undoService.removeElements(this._editorResource);
}
@@ -369,11 +405,7 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
//#region IWorkingCopy
public get resource() {
// Make sure each custom editor has a unique resource for backup and edits
return MainThreadCustomEditorModel.toWorkingCopyResource(this._viewType, this._editorResource);
}
// Make sure each custom editor has a unique resource for backup and edits
private static toWorkingCopyResource(viewType: string, resource: URI) {
const authority = viewType.replace(/[^a-z0-9\-_]/gi, '-');
const path = `/${multibyteAwareBtoa(resource.with({ query: null, fragment: null }).toString(true))}`;
@@ -403,10 +435,6 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
return this._fromBackup;
}
public isOrphaned(): boolean {
return this._inOrphaned;
}
private isUntitled() {
return this._editorResource.scheme === Schemas.untitled;
}
@@ -417,66 +445,12 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
private readonly _onDidChangeContent: Emitter<void> = this._register(new Emitter<void>());
readonly onDidChangeContent: Event<void> = this._onDidChangeContent.event;
readonly onDidChangeReadonly = Event.None;
//#endregion
private async onDidFilesChange(e: FileChangesEvent): Promise<void> {
let fileEventImpactsModel = false;
let newInOrphanModeGuess: boolean | undefined;
// If we are currently orphaned, we check if the model file was added back
if (this._inOrphaned) {
const modelFileAdded = e.contains(this.editorResource, FileChangeType.ADDED);
if (modelFileAdded) {
newInOrphanModeGuess = false;
fileEventImpactsModel = true;
}
}
// Otherwise we check if the model file was deleted
else {
const modelFileDeleted = e.contains(this.editorResource, FileChangeType.DELETED);
if (modelFileDeleted) {
newInOrphanModeGuess = true;
fileEventImpactsModel = true;
}
}
if (fileEventImpactsModel && this._inOrphaned !== newInOrphanModeGuess) {
let newInOrphanModeValidated: boolean = false;
if (newInOrphanModeGuess) {
// We have received reports of users seeing delete events even though the file still
// exists (network shares issue: https://github.com/microsoft/vscode/issues/13665).
// Since we do not want to mark the model as orphaned, we have to check if the
// file is really gone and not just a faulty file event.
await timeout(100);
if (this.#isDisposed) {
newInOrphanModeValidated = true;
} else {
const exists = await this._fileService.exists(this.editorResource);
newInOrphanModeValidated = !exists;
}
}
if (this._inOrphaned !== newInOrphanModeValidated && !this.#isDisposed) {
this.setOrphaned(newInOrphanModeValidated);
}
}
}
private setOrphaned(orphaned: boolean): void {
if (this._inOrphaned !== orphaned) {
this._inOrphaned = orphaned;
this._onDidChangeOrphaned.fire();
}
}
public isEditable(): boolean {
return this._editable;
}
public isOnReadonlyFileSystem(): boolean {
return this._fileService.hasCapability(this.editorResource, FileSystemProviderCapabilities.Readonly);
public isReadonly(): boolean {
return !this._editable;
}
public get viewType() {
@@ -569,7 +543,7 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
}
}
public async revert(_options?: IRevertOptions) {
public async revert(options?: IRevertOptions) {
if (!this._editable) {
return;
}
@@ -578,7 +552,10 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
return;
}
this._proxy.$revert(this._editorResource, this.viewType, CancellationToken.None);
if (!options?.soft) {
this._proxy.$revert(this._editorResource, this.viewType, CancellationToken.None);
}
this.change(() => {
this._isDirtyFromContentChange = false;
this._fromBackup = false;
@@ -650,7 +627,7 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
return true;
} else {
// Since the editor is readonly, just copy the file over
await this._fileService.copy(resource, targetResource, false /* overwrite */);
await this.fileService.copy(resource, targetResource, false /* overwrite */);
return true;
}
}
@@ -698,6 +675,7 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
pendingState.operation.cancel();
});
let errorMessage = '';
try {
const backupId = await pendingState.operation;
// Make sure state has not changed in the meantime
@@ -716,12 +694,15 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
if (this._hotExitState === pendingState) {
this._hotExitState = HotExitState.NotAllowed;
}
if (e.message) {
errorMessage = e.message;
}
}
if (this._hotExitState === HotExitState.Allowed) {
return backupData;
}
throw new Error('Cannot back up in this state');
throw new Error(`Cannot back up in this state: ${errorMessage}`);
}
}

View File

@@ -329,7 +329,8 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
type: session.configuration.type,
name: session.name,
folderUri: session.root ? session.root.uri : undefined,
configuration: session.configuration
configuration: session.configuration,
parent: session.parentSession?.getId(),
};
}
}

View File

@@ -20,6 +20,7 @@ import { IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/commo
import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity';
import { Emitter } from 'vs/base/common/event';
import { IPathService } from 'vs/workbench/services/path/common/pathService';
import { ResourceMap } from 'vs/base/common/map';
export class BoundModelReferenceCollection {
@@ -105,52 +106,39 @@ export class MainThreadDocuments extends Disposable implements MainThreadDocumen
private _onIsCaughtUpWithContentChanges = this._register(new Emitter<URI>());
public readonly onIsCaughtUpWithContentChanges = this._onIsCaughtUpWithContentChanges.event;
private readonly _modelService: IModelService;
private readonly _textModelResolverService: ITextModelService;
private readonly _textFileService: ITextFileService;
private readonly _fileService: IFileService;
private readonly _environmentService: IWorkbenchEnvironmentService;
private readonly _uriIdentityService: IUriIdentityService;
private _modelTrackers: { [modelUrl: string]: ModelTracker; };
private readonly _proxy: ExtHostDocumentsShape;
private readonly _modelIsSynced = new Set<string>();
private readonly _modelTrackers = new ResourceMap<ModelTracker>();
private readonly _modelIsSynced = new ResourceMap<void>();
private readonly _modelReferenceCollection: BoundModelReferenceCollection;
constructor(
documentsAndEditors: MainThreadDocumentsAndEditors,
extHostContext: IExtHostContext,
@IModelService modelService: IModelService,
@ITextFileService textFileService: ITextFileService,
@IFileService fileService: IFileService,
@ITextModelService textModelResolverService: ITextModelService,
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
@IUriIdentityService uriIdentityService: IUriIdentityService,
@IModelService private readonly _modelService: IModelService,
@ITextFileService private readonly _textFileService: ITextFileService,
@IFileService private readonly _fileService: IFileService,
@ITextModelService private readonly _textModelResolverService: ITextModelService,
@IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService,
@IUriIdentityService private readonly _uriIdentityService: IUriIdentityService,
@IWorkingCopyFileService workingCopyFileService: IWorkingCopyFileService,
@IPathService private readonly _pathService: IPathService
) {
super();
this._modelService = modelService;
this._textModelResolverService = textModelResolverService;
this._textFileService = textFileService;
this._fileService = fileService;
this._environmentService = environmentService;
this._uriIdentityService = uriIdentityService;
this._modelReferenceCollection = this._register(new BoundModelReferenceCollection(uriIdentityService.extUri));
this._modelReferenceCollection = this._register(new BoundModelReferenceCollection(_uriIdentityService.extUri));
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostDocuments);
this._register(documentsAndEditors.onDocumentAdd(models => models.forEach(this._onModelAdded, this)));
this._register(documentsAndEditors.onDocumentRemove(urls => urls.forEach(this._onModelRemoved, this)));
this._register(modelService.onModelModeChanged(this._onModelModeChanged, this));
this._register(_modelService.onModelModeChanged(this._onModelModeChanged, this));
this._register(textFileService.files.onDidSave(e => {
this._register(_textFileService.files.onDidSave(e => {
if (this._shouldHandleFileEvent(e.model.resource)) {
this._proxy.$acceptModelSaved(e.model.resource);
}
}));
this._register(textFileService.files.onDidChangeDirty(m => {
this._register(_textFileService.files.onDidChangeDirty(m => {
if (this._shouldHandleFileEvent(m.resource)) {
this._proxy.$acceptDirtyStateChanged(m.resource, m.isDirty());
}
@@ -167,22 +155,18 @@ export class MainThreadDocuments extends Disposable implements MainThreadDocumen
}
}
}));
this._modelTrackers = Object.create(null);
}
public override dispose(): void {
Object.keys(this._modelTrackers).forEach((modelUrl) => {
this._modelTrackers[modelUrl].dispose();
});
this._modelTrackers = Object.create(null);
dispose(this._modelTrackers.values());
this._modelTrackers.clear();
super.dispose();
}
public isCaughtUpWithContentChanges(resource: URI): boolean {
const modelUrl = resource.toString();
if (this._modelTrackers[modelUrl]) {
return this._modelTrackers[modelUrl].isCaughtUpWithContentChanges();
const tracker = this._modelTrackers.get(resource);
if (tracker) {
return tracker.isCaughtUpWithContentChanges();
}
return true;
}
@@ -198,28 +182,25 @@ export class MainThreadDocuments extends Disposable implements MainThreadDocumen
// don't synchronize too large models
return;
}
const modelUrl = model.uri;
this._modelIsSynced.add(modelUrl.toString());
this._modelTrackers[modelUrl.toString()] = new ModelTracker(model, this._onIsCaughtUpWithContentChanges, this._proxy, this._textFileService);
this._modelIsSynced.set(model.uri, undefined);
this._modelTrackers.set(model.uri, new ModelTracker(model, this._onIsCaughtUpWithContentChanges, this._proxy, this._textFileService));
}
private _onModelModeChanged(event: { model: ITextModel; oldModeId: string; }): void {
let { model } = event;
const modelUrl = model.uri;
if (!this._modelIsSynced.has(modelUrl.toString())) {
if (!this._modelIsSynced.has(model.uri)) {
return;
}
this._proxy.$acceptModelModeChanged(model.uri, model.getLanguageIdentifier().language);
}
private _onModelRemoved(modelUrl: URI): void {
const strModelUrl = modelUrl.toString();
if (!this._modelIsSynced.has(strModelUrl)) {
if (!this._modelIsSynced.has(modelUrl)) {
return;
}
this._modelIsSynced.delete(strModelUrl);
this._modelTrackers[strModelUrl].dispose();
delete this._modelTrackers[strModelUrl];
this._modelIsSynced.delete(modelUrl);
this._modelTrackers.get(modelUrl)!.dispose();
this._modelTrackers.delete(modelUrl);
}
// --- from extension host process
@@ -252,7 +233,7 @@ export class MainThreadDocuments extends Disposable implements MainThreadDocumen
return Promise.reject(new Error(`cannot open ${canonicalUri.toString()}`));
} else if (!extUri.isEqual(documentUri, canonicalUri)) {
return Promise.reject(new Error(`cannot open ${canonicalUri.toString()}. Detail: Actual document opened as ${documentUri.toString()}`));
} else if (!this._modelIsSynced.has(canonicalUri.toString())) {
} else if (!this._modelIsSynced.has(canonicalUri)) {
return Promise.reject(new Error(`cannot open ${canonicalUri.toString()}. Detail: Files above 50MB cannot be synchronized with extensions.`));
} else {
return canonicalUri;
@@ -291,7 +272,7 @@ export class MainThreadDocuments extends Disposable implements MainThreadDocumen
}).then(model => {
const resource = model.resource;
if (!this._modelIsSynced.has(resource.toString())) {
if (!this._modelIsSynced.has(resource)) {
throw new Error(`expected URI ${resource.toString()} to have come to LIFE`);
}

View File

@@ -20,7 +20,7 @@ import { MainThreadTextEditor } from 'vs/workbench/api/browser/mainThreadEditor'
import { MainThreadTextEditors } from 'vs/workbench/api/browser/mainThreadEditors';
import { ExtHostContext, ExtHostDocumentsAndEditorsShape, IDocumentsAndEditorsDelta, IExtHostContext, IModelAddedData, ITextEditorAddData, MainContext } from 'vs/workbench/api/common/extHost.protocol';
import { BaseTextEditor } from 'vs/workbench/browser/parts/editor/textEditor';
import { IEditorPane } from 'vs/workbench/common/editor';
import { editorGroupToViewColumn, EditorGroupColumn, IEditorPane } from 'vs/workbench/common/editor';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
@@ -30,7 +30,6 @@ import { IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/commo
import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { IPathService } from 'vs/workbench/services/path/common/pathService';
import { editorGroupToViewColumn, EditorViewColumn } from 'vs/workbench/api/common/shared/editor';
import { diffSets, diffMaps } from 'vs/base/common/collections';
@@ -410,7 +409,7 @@ export class MainThreadDocumentsAndEditors {
};
}
private _findEditorPosition(editor: MainThreadTextEditor): EditorViewColumn | undefined {
private _findEditorPosition(editor: MainThreadTextEditor): EditorGroupColumn | undefined {
for (const editorPane of this._editorService.visibleEditorPanes) {
if (editor.matches(editorPane)) {
return editorGroupToViewColumn(this._editorGroupService, editorPane.group);

View File

@@ -23,4 +23,4 @@ export class MainThreadDownloadService extends Disposable implements MainThreadD
return this.downloadService.download(URI.revive(uri), URI.revive(to));
}
}
}

View File

@@ -414,7 +414,7 @@ export class MainThreadTextEditor {
if (!this._codeEditor) {
return;
}
this._codeEditor.setDecorations(key, ranges);
this._codeEditor.setDecorations('exthost-api', key, ranges);
}
public setDecorationsFast(key: string, _ranges: number[]): void {

View File

@@ -7,8 +7,9 @@ import { DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle'
import { URI } from 'vs/base/common/uri';
import { ExtHostContext, IExtHostEditorTabsShape, IExtHostContext, MainContext, IEditorTabDto } from 'vs/workbench/api/common/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { Verbosity } from 'vs/workbench/common/editor';
import { EditorResourceAccessor, Verbosity } from 'vs/workbench/common/editor';
import { GroupChangeKind, IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
export interface ITabInfo {
name: string;
@@ -27,11 +28,12 @@ export class MainThreadEditorTabs {
constructor(
extHostContext: IExtHostContext,
@IEditorGroupsService private readonly _editorGroupsService: IEditorGroupsService,
@IEditorService editorService: IEditorService
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostEditorTabs);
this._editorGroupsService.groups.forEach(this._subscribeToGroup, this);
this._editorGroupsService.whenReady.then(() => this._editorGroupsService.groups.forEach(this._subscribeToGroup, this));
this._dispoables.add(_editorGroupsService.onDidAddGroup(this._subscribeToGroup, this));
this._dispoables.add(_editorGroupsService.onDidRemoveGroup(e => {
const subscription = this._groups.get(e);
@@ -41,6 +43,7 @@ export class MainThreadEditorTabs {
this._pushEditorTabs();
}
}));
this._dispoables.add(editorService.onDidActiveEditorChange(this._pushEditorTabs, this));
this._pushEditorTabs();
}
@@ -69,7 +72,8 @@ export class MainThreadEditorTabs {
tabs.push({
group: group.id,
name: editor.getTitle(Verbosity.SHORT) ?? '',
resource: editor.resource
resource: EditorResourceAccessor.getOriginalUri(editor) ?? editor.resource,
isActive: (this._editorGroupsService.activeGroup === group) && group.isActive(editor)
});
}
}

View File

@@ -26,6 +26,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment'
import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService';
import { revive } from 'vs/base/common/marshalling';
import { ResourceNotebookCellEdit } from 'vs/workbench/contrib/bulkEdit/browser/bulkCellEdits';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
export function reviveWorkspaceEditDto2(data: IWorkspaceEditDto | undefined): ResourceEdit[] {
if (!data?.edits) {
@@ -249,10 +250,10 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
return Promise.resolve(editor.insertSnippet(template, ranges, opts));
}
$registerTextEditorDecorationType(key: string, options: IDecorationRenderOptions): void {
$registerTextEditorDecorationType(extensionId: ExtensionIdentifier, key: string, options: IDecorationRenderOptions): void {
key = `${this._instanceId}-${key}`;
this._registeredDecorationTypes[key] = true;
this._codeEditorService.registerDecorationType(key, options);
this._codeEditorService.registerDecorationType(`exthost-api-${extensionId}`, key, options);
}
$removeTextEditorDecorationType(key: string): void {

View File

@@ -21,6 +21,7 @@ import { ILocalExtension } from 'vs/platform/extensionManagement/common/extensio
import { ExtensionActivationReason } from 'vs/workbench/api/common/extHostExtensionActivator';
import { ITimerService } from 'vs/workbench/services/timer/browser/timerService';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { ICommandService } from 'vs/platform/commands/common/commands';
@extHostNamedCustomer(MainContext.MainThreadExtensionService)
export class MainThreadExtensionService implements MainThreadExtensionServiceShape {
@@ -35,6 +36,7 @@ export class MainThreadExtensionService implements MainThreadExtensionServiceSha
@IHostService private readonly _hostService: IHostService,
@IWorkbenchExtensionEnablementService private readonly _extensionEnablementService: IWorkbenchExtensionEnablementService,
@ITimerService private readonly _timerService: ITimerService,
@ICommandService private readonly _commandService: ICommandService,
@IWorkbenchEnvironmentService protected readonly _environmentService: IWorkbenchEnvironmentService,
) {
this._extensionHostKind = extHostContext.extensionHostKind;
@@ -105,15 +107,36 @@ export class MainThreadExtensionService implements MainThreadExtensionServiceSha
});
} else {
const enablementState = this._extensionEnablementService.getEnablementState(missingInstalledDependency);
this._notificationService.notify({
severity: Severity.Error,
message: localize('disabledDep', "Cannot activate the '{0}' extension because it depends on the '{1}' extension, which is disabled. Would you like to enable the extension and reload the window?", extName, missingInstalledDependency.manifest.displayName || missingInstalledDependency.manifest.name),
actions: {
primary: [new Action('enable', localize('enable dep', "Enable and Reload"), '', true,
() => this._extensionEnablementService.setEnablement([missingInstalledDependency], enablementState === EnablementState.DisabledGlobally ? EnablementState.EnabledGlobally : EnablementState.EnabledWorkspace)
.then(() => this._hostService.reload(), e => this._notificationService.error(e)))]
}
});
if (enablementState === EnablementState.DisabledByVirtualWorkspace) {
this._notificationService.notify({
severity: Severity.Error,
message: localize('notSupportedInWorkspace', "Cannot activate the '{0}' extension because it depends on the '{1}' extension which is not supported in the current workspace", extName, missingInstalledDependency.manifest.displayName || missingInstalledDependency.manifest.name),
});
} else if (enablementState === EnablementState.DisabledByTrustRequirement) {
this._notificationService.notify({
severity: Severity.Error,
message: localize('restrictedMode', "Cannot activate the '{0}' extension because it depends on the '{1}' extension which is not supported in Restricted Mode", extName, missingInstalledDependency.manifest.displayName || missingInstalledDependency.manifest.name),
actions: {
primary: [new Action('manageWorkspaceTrust', localize('manageWorkspaceTrust', "Manage Workspace Trust"), '', true,
() => this._commandService.executeCommand('workbench.trust.manage'))]
}
});
} else if (this._extensionEnablementService.canChangeEnablement(missingInstalledDependency)) {
this._notificationService.notify({
severity: Severity.Error,
message: localize('disabledDep', "Cannot activate the '{0}' extension because it depends on the '{1}' extension which is disabled. Would you like to enable the extension and reload the window?", extName, missingInstalledDependency.manifest.displayName || missingInstalledDependency.manifest.name),
actions: {
primary: [new Action('enable', localize('enable dep', "Enable and Reload"), '', true,
() => this._extensionEnablementService.setEnablement([missingInstalledDependency], enablementState === EnablementState.DisabledGlobally ? EnablementState.EnabledGlobally : EnablementState.EnabledWorkspace)
.then(() => this._hostService.reload(), e => this._notificationService.error(e)))]
}
});
} else {
this._notificationService.notify({
severity: Severity.Error,
message: localize('disabledDepNoAction', "Cannot activate the '{0}' extension because it depends on the '{1}' extension which is disabled.", extName, missingInstalledDependency.manifest.displayName || missingInstalledDependency.manifest.name),
});
}
}
}

View File

@@ -6,7 +6,7 @@
import { Emitter, Event } from 'vs/base/common/event';
import { IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { URI, UriComponents } from 'vs/base/common/uri';
import { FileWriteOptions, FileSystemProviderCapabilities, IFileChange, IFileService, IStat, IWatchOptions, FileType, FileOverwriteOptions, FileDeleteOptions, FileOpenOptions, IFileStat, FileOperationError, FileOperationResult, FileSystemProviderErrorCode, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileSystemProviderWithFileReadWriteCapability, IFileSystemProviderWithFileFolderCopyCapability } from 'vs/platform/files/common/files';
import { FileWriteOptions, FileSystemProviderCapabilities, IFileChange, IFileService, IStat, IWatchOptions, FileType, FileOverwriteOptions, FileDeleteOptions, FileOpenOptions, IFileStat, FileOperationError, FileOperationResult, FileSystemProviderErrorCode, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileSystemProviderWithFileReadWriteCapability, IFileSystemProviderWithFileFolderCopyCapability, FilePermission } from 'vs/platform/files/common/files';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { ExtHostContext, ExtHostFileSystemShape, IExtHostContext, IFileChangeDto, MainContext, MainThreadFileSystemShape } from '../common/extHost.protocol';
import { VSBuffer } from 'vs/base/common/buffer';
@@ -65,6 +65,7 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape {
ctime: stat.ctime,
mtime: stat.mtime,
size: stat.size,
permissions: MainThreadFileSystem._asFilePermission(stat),
type: MainThreadFileSystem._asFileType(stat)
};
}).catch(MainThreadFileSystem._handleError);
@@ -95,6 +96,13 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape {
return res;
}
private static _asFilePermission(stat: IFileStat): FilePermission | undefined {
if (stat.readonly) {
return FilePermission.Readonly;
}
return undefined;
}
$readFile(uri: UriComponents): Promise<VSBuffer> {
return this._fileService.readFile(URI.revive(uri)).then(file => file.value).catch(MainThreadFileSystem._handleError);
}

View File

@@ -33,4 +33,4 @@ export class MainThreadLabelService implements MainThreadLabelServiceShape {
dispose(): void {
// noop
}
}
}

View File

@@ -11,7 +11,7 @@ import * as search from 'vs/workbench/contrib/search/common/search';
import { CancellationToken } from 'vs/base/common/cancellation';
import { Position as EditorPosition } from 'vs/editor/common/core/position';
import { Range as EditorRange, IRange } from 'vs/editor/common/core/range';
import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ILanguageConfigurationDto, IRegExpDto, IIndentationRuleDto, IOnEnterRuleDto, ILocationDto, IWorkspaceSymbolDto, reviveWorkspaceEditDto, IDocumentFilterDto, IDefinitionLinkDto, ISignatureHelpProviderMetadataDto, ILinkDto, ICallHierarchyItemDto, ISuggestDataDto, ICodeActionDto, ISuggestDataDtoField, ISuggestResultDtoField, ICodeActionProviderMetadataDto, ILanguageWordDefinitionDto } from '../common/extHost.protocol';
import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ILanguageConfigurationDto, IRegExpDto, IIndentationRuleDto, IOnEnterRuleDto, ILocationDto, IWorkspaceSymbolDto, reviveWorkspaceEditDto, IDocumentFilterDto, IDefinitionLinkDto, ISignatureHelpProviderMetadataDto, ILinkDto, ICallHierarchyItemDto, ISuggestDataDto, ICodeActionDto, ISuggestDataDtoField, ISuggestResultDtoField, ICodeActionProviderMetadataDto, ILanguageWordDefinitionDto, IdentifiableInlineCompletions, IdentifiableInlineCompletion } from '../common/extHost.protocol';
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
import { LanguageConfiguration, IndentationRule, OnEnterRule } from 'vs/editor/common/modes/languageConfiguration';
import { IModeService } from 'vs/editor/common/services/modeService';
@@ -471,7 +471,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
provideCompletionItems: async (model: ITextModel, position: EditorPosition, context: modes.CompletionContext, token: CancellationToken): Promise<modes.CompletionList | undefined> => {
const result = await this._proxy.$provideCompletionItems(handle, model.uri, position, context, token);
if (!result) {
return <any>result;
return <any>result; // {{SQL CARBON EDIT}}
}
return {
suggestions: result[ISuggestResultDtoField.completions].map(d => MainThreadLanguageFeatures._inflateSuggestDto(result[ISuggestResultDtoField.defaultRanges], d)),
@@ -500,6 +500,21 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
this._registrations.set(handle, modes.CompletionProviderRegistry.register(selector, provider));
}
$registerInlineCompletionsSupport(handle: number, selector: IDocumentFilterDto[]): void {
const provider: modes.InlineCompletionsProvider<IdentifiableInlineCompletions> = {
provideInlineCompletions: async (model: ITextModel, position: EditorPosition, context: modes.InlineCompletionContext, token: CancellationToken): Promise<IdentifiableInlineCompletions | undefined> => {
return this._proxy.$provideInlineCompletions(handle, model.uri, position, context, token);
},
handleItemDidShow: async (completions: IdentifiableInlineCompletions, item: IdentifiableInlineCompletion): Promise<void> => {
return this._proxy.$handleInlineCompletionDidShow(handle, completions.pid, item.idx);
},
freeInlineCompletions: (completions: IdentifiableInlineCompletions): void => {
this._proxy.$freeInlineCompletionsList(handle, completions.pid);
}
};
this._registrations.set(handle, modes.InlineCompletionsProviderRegistry.register(selector, provider));
}
// --- parameter hints
$registerSignatureHelpProvider(handle: number, selector: IDocumentFilterDto[], metadata: ISignatureHelpProviderMetadataDto): void {
@@ -525,10 +540,10 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
// --- inline hints
$registerInlineHintsProvider(handle: number, selector: IDocumentFilterDto[], eventHandle: number | undefined): void {
const provider = <modes.InlineHintsProvider>{
provideInlineHints: async (model: ITextModel, range: EditorRange, token: CancellationToken): Promise<modes.InlineHint[] | undefined> => {
const result = await this._proxy.$provideInlineHints(handle, model.uri, range, token);
$registerInlayHintsProvider(handle: number, selector: IDocumentFilterDto[], eventHandle: number | undefined): void {
const provider = <modes.InlayHintsProvider>{
provideInlayHints: async (model: ITextModel, range: EditorRange, token: CancellationToken): Promise<modes.InlayHint[] | undefined> => {
const result = await this._proxy.$provideInlayHints(handle, model.uri, range, token);
return result?.hints;
}
};
@@ -536,13 +551,13 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
if (typeof eventHandle === 'number') {
const emitter = new Emitter<void>();
this._registrations.set(eventHandle, emitter);
provider.onDidChangeInlineHints = emitter.event;
provider.onDidChangeInlayHints = emitter.event;
}
this._registrations.set(handle, modes.InlineHintsProviderRegistry.register(selector, provider));
this._registrations.set(handle, modes.InlayHintsProviderRegistry.register(selector, provider));
}
$emitInlineHintsEvent(eventHandle: number, event?: any): void {
$emitInlayHintsEvent(eventHandle: number, event?: any): void {
const obj = this._registrations.get(eventHandle);
if (obj instanceof Emitter) {
obj.fire(event);

View File

@@ -6,13 +6,11 @@
import { VSBuffer } from 'vs/base/common/buffer';
import { CancellationToken } from 'vs/base/common/cancellation';
import { Emitter } from 'vs/base/common/event';
import { IRelativePattern } from 'vs/base/common/glob';
import { DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService';
import { NotebookSelector } from 'vs/workbench/contrib/notebook/common/notebookSelector';
import { INotebookCellStatusBarItemProvider, INotebookExclusiveDocumentFilter, NotebookDataDto, TransientCellMetadata, TransientDocumentMetadata, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookCellStatusBarItemProvider, INotebookContributionData, NotebookDataDto, TransientCellMetadata, TransientDocumentMetadata, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookContentProvider, INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { ExtHostContext, ExtHostNotebookShape, IExtHostContext, MainContext, MainThreadNotebookShape, NotebookExtensionDescription } from '../common/extHost.protocol';
@@ -43,13 +41,8 @@ export class MainThreadNotebooks implements MainThreadNotebookShape {
dispose(this._notebookSerializer.values());
}
async $registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, options: {
transientOutputs: boolean;
transientCellMetadata: TransientCellMetadata;
transientDocumentMetadata: TransientDocumentMetadata;
viewOptions?: { displayName: string; filenamePattern: (string | IRelativePattern | INotebookExclusiveDocumentFilter)[]; exclusive: boolean; };
}): Promise<void> {
let contentOptions = { transientOutputs: options.transientOutputs, transientCellMetadata: options.transientCellMetadata, transientDocumentMetadata: options.transientDocumentMetadata };
async $registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, options: TransientOptions, data: INotebookContributionData | undefined): Promise<void> {
let contentOptions = { ...options };
const controller: INotebookContentProvider = {
get options() {
@@ -60,7 +53,6 @@ export class MainThreadNotebooks implements MainThreadNotebookShape {
contentOptions.transientDocumentMetadata = newOptions.transientDocumentMetadata;
contentOptions.transientOutputs = newOptions.transientOutputs;
},
viewOptions: options.viewOptions,
open: async (uri: URI, backupId: string | undefined, untitledDocumentData: VSBuffer | undefined, token: CancellationToken) => {
const data = await this._proxy.$openNotebook(viewType, uri, backupId, untitledDocumentData, token);
return {
@@ -79,7 +71,11 @@ export class MainThreadNotebooks implements MainThreadNotebookShape {
}
};
const disposable = this._notebookService.registerNotebookController(viewType, extension, controller);
const disposable = new DisposableStore();
disposable.add(this._notebookService.registerNotebookController(viewType, extension, controller));
if (data) {
disposable.add(this._notebookService.registerContributedNotebookType(viewType, data));
}
this._notebookProviders.set(viewType, { controller, disposable });
}
@@ -104,7 +100,7 @@ export class MainThreadNotebooks implements MainThreadNotebookShape {
}
}
$registerNotebookSerializer(handle: number, extension: NotebookExtensionDescription, viewType: string, options: TransientOptions): void {
$registerNotebookSerializer(handle: number, extension: NotebookExtensionDescription, viewType: string, options: TransientOptions, data: INotebookContributionData | undefined): void {
const registration = this._notebookService.registerNotebookSerializer(viewType, extension, {
options,
dataToNotebook: (data: VSBuffer): Promise<NotebookDataDto> => {
@@ -114,7 +110,12 @@ export class MainThreadNotebooks implements MainThreadNotebookShape {
return this._proxy.$notebookToData(handle, data, CancellationToken.None);
}
});
this._notebookSerializer.set(handle, registration);
const disposables = new DisposableStore();
disposables.add(registration);
if (data) {
disposables.add(this._notebookService.registerContributedNotebookType(viewType, data));
}
this._notebookSerializer.set(handle, disposables);
}
$unregisterNotebookSerializer(handle: number): void {
@@ -129,7 +130,7 @@ export class MainThreadNotebooks implements MainThreadNotebookShape {
}
}
async $registerNotebookCellStatusBarItemProvider(handle: number, eventHandle: number | undefined, selector: NotebookSelector): Promise<void> {
async $registerNotebookCellStatusBarItemProvider(handle: number, eventHandle: number | undefined, viewType: string): Promise<void> {
const that = this;
const provider: INotebookCellStatusBarItemProvider = {
async provideCellStatusBarItems(uri: URI, index: number, token: CancellationToken) {
@@ -143,7 +144,7 @@ export class MainThreadNotebooks implements MainThreadNotebookShape {
}
};
},
selector: selector
viewType
};
if (typeof eventHandle === 'number') {

View File

@@ -1,6 +1,6 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { DisposableStore, dispose } from 'vs/base/common/lifecycle';
@@ -9,19 +9,21 @@ import { URI, UriComponents } from 'vs/base/common/uri';
import { BoundModelReferenceCollection } from 'vs/workbench/api/browser/mainThreadDocuments';
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
import { IImmediateCellEditOperation, IMainCellDto, NotebookCellsChangeType } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { IImmediateCellEditOperation, IMainCellDto, NotebookCellsChangeType, NotebookDataDto } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookEditorModelResolverService } from 'vs/workbench/contrib/notebook/common/notebookEditorModelResolverService';
import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity';
import { ExtHostContext, ExtHostNotebookShape, IExtHostContext, MainThreadNotebookDocumentsShape } from '../common/extHost.protocol';
import { ExtHostContext, ExtHostNotebookDocumentsShape, IExtHostContext, MainThreadNotebookDocumentsShape } from '../common/extHost.protocol';
import { MainThreadNotebooksAndEditors } from 'vs/workbench/api/browser/mainThreadNotebookDocumentsAndEditors';
import { onUnexpectedError } from 'vs/base/common/errors';
import { Schemas } from 'vs/base/common/network';
import { NotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookProvider';
export class MainThreadNotebookDocuments implements MainThreadNotebookDocumentsShape {
private readonly _disposables = new DisposableStore();
private readonly _proxy: ExtHostNotebookShape;
private readonly _proxy: ExtHostNotebookDocumentsShape;
private readonly _documentEventListenersMapping = new ResourceMap<DisposableStore>();
private readonly _modelReferenceCollection: BoundModelReferenceCollection;
@@ -32,7 +34,7 @@ export class MainThreadNotebookDocuments implements MainThreadNotebookDocumentsS
@INotebookEditorModelResolverService private readonly _notebookEditorModelResolverService: INotebookEditorModelResolverService,
@IUriIdentityService private readonly _uriIdentityService: IUriIdentityService
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostNotebook);
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostNotebookDocuments);
this._modelReferenceCollection = new BoundModelReferenceCollection(this._uriIdentityService.extUri);
notebooksAndEditors.onDidAddNotebooks(this._handleNotebooksAdded, this, this._disposables);
@@ -47,7 +49,6 @@ export class MainThreadNotebookDocuments implements MainThreadNotebookDocumentsS
this._disposables.dispose();
this._modelReferenceCollection.dispose();
dispose(this._documentEventListenersMapping.values());
}
private _handleNotebooksAdded(notebooks: readonly NotebookTextModel[]): void {
@@ -114,18 +115,59 @@ export class MainThreadNotebookDocuments implements MainThreadNotebookDocumentsS
language: cell.language,
cellKind: cell.cellKind,
outputs: cell.outputs,
metadata: cell.metadata
metadata: cell.metadata,
internalMetadata: cell.internalMetadata,
};
}
async $tryOpenDocument(uriComponents: UriComponents): Promise<URI> {
async $tryCreateNotebook(options: { viewType: string, content?: NotebookDataDto }): Promise<UriComponents> {
const info = this._notebookService.getContributedNotebookType(options.viewType);
if (!info) {
throw new Error('UNKNOWN view type: ' + options.viewType);
}
// find a free URI for the untitled case
const suffix = NotebookProviderInfo.possibleFileEnding(info.selectors) ?? '';
let uri: URI;
for (let counter = 1; ; counter++) {
let candidate = URI.from({ scheme: Schemas.untitled, path: `Untitled-${counter}${suffix}`, query: options.viewType });
if (!this._notebookService.getNotebookTextModel(candidate)) {
uri = candidate;
break;
}
}
const ref = await this._notebookEditorModelResolverService.resolve(uri, options.viewType);
// untitled notebooks are disposed when they get saved. we should not hold a reference
// to such a disposed notebook and therefore dispose the reference as well
ref.object.notebook.onWillDispose(() => {
ref.dispose();
});
// untitled notebooks are dirty by default
this._proxy.$acceptDirtyStateChanged(uri, true);
// apply content changes... slightly HACKY -> this triggers a change event
if (options.content) {
ref.object.notebook.reset(
options.content.cells,
options.content.metadata,
ref.object.notebook.transientOptions
);
}
return uri;
}
async $tryOpenNotebook(uriComponents: UriComponents): Promise<URI> {
const uri = URI.revive(uriComponents);
const ref = await this._notebookEditorModelResolverService.resolve(uri, undefined);
this._modelReferenceCollection.add(uri, ref);
return uri;
}
async $trySaveDocument(uriComponents: UriComponents) {
async $trySaveNotebook(uriComponents: UriComponents) {
const uri = URI.revive(uriComponents);
const ref = await this._notebookEditorModelResolverService.resolve(uri);

View File

@@ -1,6 +1,6 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { diffMaps, diffSets } from 'vs/base/common/collections';
@@ -30,7 +30,7 @@ interface INotebookAndEditorDelta {
}
class NotebookAndEditorState {
static compute(before: NotebookAndEditorState | undefined, after: NotebookAndEditorState): INotebookAndEditorDelta {
static delta(before: NotebookAndEditorState | undefined, after: NotebookAndEditorState): INotebookAndEditorDelta {
if (!before) {
return {
addedDocuments: [...after.documents],
@@ -107,7 +107,7 @@ export class MainThreadNotebooksAndEditors {
extHostContext.set(MainContext.MainThreadNotebookDocuments, this._mainThreadNotebooks);
extHostContext.set(MainContext.MainThreadNotebookEditors, this._mainThreadEditors);
this._notebookService.onDidCreateNotebookDocument(() => this._updateState(), this, this._disposables);
this._notebookService.onWillAddNotebookDocument(() => this._updateState(), this, this._disposables);
this._notebookService.onDidRemoveNotebookDocument(() => this._updateState(), this, this._disposables);
this._editorService.onDidActiveEditorChange(() => this._updateState(), this, this._disposables);
this._editorService.onDidVisibleEditorsChange(() => this._updateState(), this, this._disposables);
@@ -170,7 +170,7 @@ export class MainThreadNotebooksAndEditors {
}
const newState = new NotebookAndEditorState(new Set(this._notebookService.listNotebookDocuments()), editors, activeEditor, visibleEditorsMap);
this._onDelta(NotebookAndEditorState.compute(this._currentState, newState));
this._onDelta(NotebookAndEditorState.delta(this._currentState, newState));
this._currentState = newState;
}
@@ -234,7 +234,8 @@ export class MainThreadNotebooksAndEditors {
language: cell.language,
cellKind: cell.cellKind,
outputs: cell.outputs,
metadata: cell.metadata
metadata: cell.metadata,
internalMetadata: cell.internalMetadata,
}))
};
}

View File

@@ -1,12 +1,12 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { DisposableStore, dispose } from 'vs/base/common/lifecycle';
import { getNotebookEditorFromEditorPane, INotebookEditor, NotebookEditorOptions } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { getNotebookEditorFromEditorPane, INotebookEditor, INotebookEditorOptions } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { INotebookEditorService } from 'vs/workbench/contrib/notebook/browser/notebookEditorService';
import { ExtHostContext, ExtHostNotebookShape, IExtHostContext, INotebookDocumentShowOptions, INotebookEditorViewColumnInfo, MainThreadNotebookEditorsShape, NotebookEditorRevealType } from '../common/extHost.protocol';
import { ExtHostContext, ExtHostNotebookEditorsShape, IExtHostContext, INotebookDocumentShowOptions, INotebookEditorViewColumnInfo, MainThreadNotebookEditorsShape, NotebookEditorRevealType } from '../common/extHost.protocol';
import { MainThreadNotebooksAndEditors } from 'vs/workbench/api/browser/mainThreadNotebookDocumentsAndEditors';
import { ICellEditOperation, INotebookDecorationRenderOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange';
@@ -36,7 +36,7 @@ export class MainThreadNotebookEditors implements MainThreadNotebookEditorsShape
private readonly _disposables = new DisposableStore();
private readonly _proxy: ExtHostNotebookShape;
private readonly _proxy: ExtHostNotebookEditorsShape;
private readonly _mainThreadEditors = new Map<string, MainThreadNotebook>();
private _currentViewColumnInfo?: INotebookEditorViewColumnInfo;
@@ -50,7 +50,7 @@ export class MainThreadNotebookEditors implements MainThreadNotebookEditorsShape
@INotebookEditorService private readonly _notebookEditorService: INotebookEditorService,
@IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostNotebook);
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostNotebookEditors);
notebooksAndEditors.onDidAddEditors(this._handleEditorsAdded, this, this._disposables);
notebooksAndEditors.onDidRemoveEditors(this._handleEditorsRemoved, this, this._disposables);
@@ -121,10 +121,8 @@ export class MainThreadNotebookEditors implements MainThreadNotebookEditorsShape
return editor.textModel.applyEdits(cellEdits, true, undefined, () => undefined, undefined);
}
async $tryShowNotebookDocument(resource: UriComponents, viewType: string, options: INotebookDocumentShowOptions): Promise<string> {
const editorOptions = new NotebookEditorOptions({
const editorOptions: INotebookEditorOptions = {
cellSelections: options.selections,
preserveFocus: options.preserveFocus,
pinned: options.pinned,
@@ -132,8 +130,8 @@ export class MainThreadNotebookEditors implements MainThreadNotebookEditorsShape
// preserve pre 1.38 behaviour to not make group active when preserveFocus: true
// but make sure to restore the editor to fix https://github.com/microsoft/vscode/issues/79633
activation: options.preserveFocus ? EditorActivation.RESTORE : undefined,
override: EditorOverride.DISABLED,
});
override: EditorOverride.DISABLED
};
const input = NotebookEditorInput.create(this._instantiationService, URI.revive(resource), viewType);
const editorPane = await this._editorService.openEditor(input, editorOptions, options.position);
@@ -188,4 +186,12 @@ export class MainThreadNotebookEditors implements MainThreadNotebookEditorsShape
notebookEditor.setEditorDecorations(key, range);
}
}
$trySetSelections(id: string, ranges: ICellRange[]): void {
const editor = this._notebookEditorService.getNotebookEditor(id);
if (editor) {
// @rebornix how to set an editor selection?
// editor.setSelections(ranges)
}
}
}

View File

@@ -1,6 +1,6 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { flatten, isNonEmptyArray } from 'vs/base/common/arrays';
@@ -44,7 +44,7 @@ abstract class MainThreadKernel implements INotebookKernel {
constructor(data: INotebookKernelDto2, private _modeService: IModeService) {
this.id = data.id;
this.viewType = data.viewType;
this.viewType = data.notebookType;
this.extension = data.extensionId;
this.implementsInterrupt = data.supportsInterrupt ?? false;
@@ -52,7 +52,7 @@ abstract class MainThreadKernel implements INotebookKernel {
this.description = data.description;
this.detail = data.detail;
this.supportedLanguages = isNonEmptyArray(data.supportedLanguages) ? data.supportedLanguages : _modeService.getRegisteredModes();
this.implementsExecutionOrder = data.hasExecutionOrder ?? false;
this.implementsExecutionOrder = data.supportsExecutionOrder ?? false;
this.localResourceRoot = URI.revive(data.extensionLocation);
this.preloads = data.preloads?.map(u => ({ uri: URI.revive(u.uri), provides: u.provides })) ?? [];
}
@@ -77,8 +77,8 @@ abstract class MainThreadKernel implements INotebookKernel {
this.supportedLanguages = isNonEmptyArray(data.supportedLanguages) ? data.supportedLanguages : this._modeService.getRegisteredModes();
event.supportedLanguages = true;
}
if (data.hasExecutionOrder !== undefined) {
this.implementsExecutionOrder = data.hasExecutionOrder;
if (data.supportsExecutionOrder !== undefined) {
this.implementsExecutionOrder = data.supportsExecutionOrder;
event.hasExecutionOrder = true;
}
this._onDidChange.fire(event);
@@ -122,9 +122,6 @@ export class MainThreadNotebookKernels implements MainThreadNotebookKernelsShape
private _onEditorAdd(editor: INotebookEditor) {
const ipcListener = editor.onDidReceiveMessage(e => {
if (e.forRenderer) {
return;
}
if (!editor.hasModel()) {
return;
}
@@ -134,7 +131,7 @@ export class MainThreadNotebookKernels implements MainThreadNotebookKernelsShape
}
for (let [handle, candidate] of this._kernels) {
if (candidate[0] === selected) {
this._proxy.$acceptRendererMessage(handle, editor.getId(), e.message);
this._proxy.$acceptKernelMessageFromRenderer(handle, editor.getId(), e.message);
break;
}
}
@@ -164,11 +161,11 @@ export class MainThreadNotebookKernels implements MainThreadNotebookKernelsShape
}
if (editorId === undefined) {
// all editors
editor.postMessage(undefined, message);
editor.postMessage(message);
didSend = true;
} else if (editor.getId() === editorId) {
// selected editors
editor.postMessage(undefined, message);
editor.postMessage(message);
didSend = true;
break;
}
@@ -188,16 +185,16 @@ export class MainThreadNotebookKernels implements MainThreadNotebookKernelsShape
await that._proxy.$cancelCells(handle, uri, handles);
}
}(data, this._modeService);
const registration = this._notebookKernelService.registerKernel(kernel);
const listener = this._notebookKernelService.onDidChangeNotebookKernelBinding(e => {
if (e.oldKernel === kernel.id) {
this._proxy.$acceptSelection(handle, e.notebook, false);
this._proxy.$acceptNotebookAssociation(handle, e.notebook, false);
} else if (e.newKernel === kernel.id) {
this._proxy.$acceptSelection(handle, e.notebook, true);
this._proxy.$acceptNotebookAssociation(handle, e.notebook, true);
}
});
const registration = this._notebookKernelService.registerKernel(kernel);
this._kernels.set(handle, [kernel, combinedDisposable(listener, registration)]);
}

View File

@@ -0,0 +1,29 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Disposable } from 'vs/base/common/lifecycle';
import { ExtHostContext, ExtHostNotebookRenderersShape, IExtHostContext, MainContext, MainThreadNotebookRenderersShape } from 'vs/workbench/api/common/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { INotebookRendererMessagingService } from 'vs/workbench/contrib/notebook/common/notebookRendererMessagingService';
@extHostNamedCustomer(MainContext.MainThreadNotebookRenderers)
export class MainThreadNotebookRenderers extends Disposable implements MainThreadNotebookRenderersShape {
private readonly proxy: ExtHostNotebookRenderersShape;
constructor(
extHostContext: IExtHostContext,
@INotebookRendererMessagingService private readonly messaging: INotebookRendererMessagingService,
) {
super();
this.proxy = extHostContext.getProxy(ExtHostContext.ExtHostNotebookRenderers);
this._register(messaging.onShouldPostMessage(e => {
this.proxy.$postRendererMessage(e.editorId, e.rendererId, e.message);
}));
}
$postMessage(editorId: string, rendererId: string, message: unknown): void {
this.messaging.fireDidReceiveMessage(editorId, rendererId, message);
}
}

View File

@@ -27,7 +27,7 @@ export class MainThreadStatusBar implements MainThreadStatusBarShape {
this.entries.clear();
}
$setEntry(id: number, statusId: string, statusName: string, text: string, tooltip: string | undefined, command: Command | undefined, color: string | ThemeColor | undefined, backgroundColor: string | ThemeColor | undefined, alignment: MainThreadStatusBarAlignment, priority: number | undefined, accessibilityInformation: IAccessibilityInformation): void {
$setEntry(entryId: number, id: string, name: string, text: string, tooltip: string | undefined, command: Command | undefined, color: string | ThemeColor | undefined, backgroundColor: string | ThemeColor | undefined, alignment: MainThreadStatusBarAlignment, priority: number | undefined, accessibilityInformation: IAccessibilityInformation): void {
// if there are icons in the text use the tooltip for the aria label
let ariaLabel: string;
let role: string | undefined = undefined;
@@ -37,23 +37,23 @@ export class MainThreadStatusBar implements MainThreadStatusBarShape {
} else {
ariaLabel = getCodiconAriaLabel(text);
}
const entry: IStatusbarEntry = { text, tooltip, command, color, backgroundColor, ariaLabel, role };
const entry: IStatusbarEntry = { name, text, tooltip, command, color, backgroundColor, ariaLabel, role };
if (typeof priority === 'undefined') {
priority = 0;
}
// Reset existing entry if alignment or priority changed
let existingEntry = this.entries.get(id);
let existingEntry = this.entries.get(entryId);
if (existingEntry && (existingEntry.alignment !== alignment || existingEntry.priority !== priority)) {
dispose(existingEntry.accessor);
this.entries.delete(id);
this.entries.delete(entryId);
existingEntry = undefined;
}
// Create new entry if not existing
if (!existingEntry) {
this.entries.set(id, { accessor: this.statusbarService.addEntry(entry, statusId, statusName, alignment, priority), alignment, priority });
this.entries.set(entryId, { accessor: this.statusbarService.addEntry(entry, id, alignment, priority), alignment, priority });
}
// Otherwise update

View File

@@ -702,9 +702,6 @@ export class MainThreadTask implements MainThreadTaskShape {
});
});
},
getDefaultShellAndArgs: (): Promise<{ shell: string, args: string[] | string | undefined }> => {
return Promise.resolve(this._proxy.$getDefaultShellAndArgs());
},
findExecutable: (command: string, cwd?: string, paths?: string[]): Promise<string | undefined> => {
return this._proxy.$findExecutable(command, cwd, paths);
}

View File

@@ -3,22 +3,23 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
import { StopWatch } from 'vs/base/common/stopwatch';
import { DisposableStore, Disposable, IDisposable } from 'vs/base/common/lifecycle';
import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceShape, MainContext, IExtHostContext, TerminalLaunchConfig, ITerminalDimensionsDto, TerminalIdentifier } from 'vs/workbench/api/common/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { URI } from 'vs/base/common/uri';
import { StopWatch } from 'vs/base/common/stopwatch';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ILogService } from 'vs/platform/log/common/log';
import { IShellLaunchConfig, IShellLaunchConfigDto, ITerminalDimensions } from 'vs/platform/terminal/common/terminal';
import { IShellLaunchConfig, IShellLaunchConfigDto, ITerminalDimensions, TitleEventSource } from 'vs/platform/terminal/common/terminal';
import { TerminalDataBufferer } from 'vs/platform/terminal/common/terminalDataBuffering';
import { ExtHostContext, ExtHostTerminalServiceShape, IExtHostContext, ITerminalDimensionsDto, MainContext, MainThreadTerminalServiceShape, TerminalIdentifier, TerminalLaunchConfig } from 'vs/workbench/api/common/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { ITerminalExternalLinkProvider, ITerminalInstance, ITerminalInstanceService, ITerminalLink, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { TerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy';
import { IEnvironmentVariableService, ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { deserializeEnvironmentVariableCollection, serializeEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableShared';
import { IAvailableProfilesRequest as IAvailableProfilesRequest, IDefaultShellAndArgsRequest, IStartExtensionTerminalRequest, ITerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/common/terminal';
import { ExtensionHostKind } from 'vs/workbench/services/extensions/common/extensions';
import { IStartExtensionTerminalRequest, ITerminalProcessExtHostProxy, ITerminalProfileResolverService } from 'vs/workbench/contrib/terminal/common/terminal';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { withNullAsUndefined } from 'vs/base/common/types';
import { OperatingSystem, OS } from 'vs/base/common/platform';
@extHostNamedCustomer(MainContext.MainThreadTerminalService)
export class MainThreadTerminalService implements MainThreadTerminalServiceShape {
@@ -30,11 +31,10 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
* This comes in play only when dealing with terminals created on the extension host side
*/
private _extHostTerminalIds = new Map<string, number>();
private _remoteAuthority: string | null;
private readonly _toDispose = new DisposableStore();
private readonly _terminalProcessProxies = new Map<number, ITerminalProcessExtHostProxy>();
private readonly _profileProviders = new Map<string, IDisposable>();
private _dataEventTracker: TerminalDataEventTracker | undefined;
private _extHostKind: ExtensionHostKind;
/**
* A single shared terminal link provider for the exthost. When an ext registers a link
* provider, this is registered with the terminal on the renderer side and all links are
@@ -43,17 +43,19 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
*/
private _linkProvider: IDisposable | undefined;
private _os: OperatingSystem = OS;
constructor(
extHostContext: IExtHostContext,
private readonly _extHostContext: IExtHostContext,
@ITerminalService private readonly _terminalService: ITerminalService,
@ITerminalInstanceService readonly terminalInstanceService: ITerminalInstanceService,
@IRemoteAgentService private readonly _remoteAgentService: IRemoteAgentService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@IEnvironmentVariableService private readonly _environmentVariableService: IEnvironmentVariableService,
@ILogService private readonly _logService: ILogService,
@ITerminalProfileResolverService private readonly _terminalProfileResolverService: ITerminalProfileResolverService,
@IRemoteAgentService remoteAgentService: IRemoteAgentService
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTerminalService);
this._remoteAuthority = extHostContext.remoteAuthority;
this._proxy = _extHostContext.getProxy(ExtHostContext.ExtHostTerminalService);
// ITerminalService listeners
this._toDispose.add(_terminalService.onInstanceCreated((instance) => {
@@ -61,8 +63,6 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
this._onInstanceDimensionsChanged(instance);
}));
this._extHostKind = extHostContext.extensionHostKind;
this._toDispose.add(_terminalService.onInstanceDisposed(instance => this._onTerminalDisposed(instance)));
this._toDispose.add(_terminalService.onInstanceProcessIdReady(instance => this._onTerminalProcessIdReady(instance)));
this._toDispose.add(_terminalService.onInstanceDimensionsChanged(instance => this._onInstanceDimensionsChanged(instance)));
@@ -70,12 +70,6 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
this._toDispose.add(_terminalService.onInstanceRequestStartExtensionTerminal(e => this._onRequestStartExtensionTerminal(e)));
this._toDispose.add(_terminalService.onActiveInstanceChanged(instance => this._onActiveTerminalChanged(instance ? instance.instanceId : null)));
this._toDispose.add(_terminalService.onInstanceTitleChanged(instance => instance && this._onTitleChanged(instance.instanceId, instance.title)));
this._toDispose.add(_terminalService.onRequestAvailableProfiles(e => this._onRequestAvailableProfiles(e)));
// ITerminalInstanceService listeners
if (terminalInstanceService.onRequestDefaultShellAndArgs) {
this._toDispose.add(terminalInstanceService.onRequestDefaultShellAndArgs(e => this._onRequestDefaultShellAndArgs(e)));
}
// Set initial ext host state
this._terminalService.terminalInstances.forEach(t => {
@@ -94,7 +88,11 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
this._proxy.$initEnvironmentVariableCollections(serializedCollections);
}
this._terminalService.extHostReady(extHostContext.remoteAuthority!); // TODO@Tyriar: remove null assertion
remoteAgentService.getEnvironment().then(async env => {
this._os = env?.os || OS;
this._updateDefaultProfile();
});
this._terminalService.onDidChangeAvailableProfiles(() => this._updateDefaultProfile());
}
public dispose(): void {
@@ -102,6 +100,13 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
this._linkProvider?.dispose();
}
private async _updateDefaultProfile() {
const remoteAuthority = withNullAsUndefined(this._extHostContext.remoteAuthority);
const defaultProfile = this._terminalProfileResolverService.getDefaultProfile({ remoteAuthority, os: this._os });
const defaultAutomationProfile = this._terminalProfileResolverService.getDefaultProfile({ remoteAuthority, os: this._os, allowAutomationShell: true });
this._proxy.$acceptDefaultProfile(...await Promise.all([defaultProfile, defaultAutomationProfile]));
}
private _getTerminalId(id: TerminalIdentifier): number | undefined {
if (typeof id === 'number') {
return id;
@@ -135,9 +140,19 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
: undefined,
extHostTerminalId: extHostTerminalId,
isFeatureTerminal: launchConfig.isFeatureTerminal,
isExtensionOwnedTerminal: launchConfig.isExtensionOwnedTerminal
isExtensionOwnedTerminal: launchConfig.isExtensionOwnedTerminal,
useShellEnvironment: launchConfig.useShellEnvironment
};
const terminal = this._terminalService.createTerminal(shellLaunchConfig);
let terminal: ITerminalInstance | undefined;
if (launchConfig.isSplitTerminal) {
const activeInstance = this._terminalService.getActiveInstance();
if (activeInstance) {
terminal = withNullAsUndefined(this._terminalService.splitInstance(activeInstance, shellLaunchConfig));
}
}
if (!terminal) {
terminal = this._terminalService.createTerminal(shellLaunchConfig);
}
this._extHostTerminalIds.set(extHostTerminalId, terminal.instanceId);
}
@@ -196,6 +211,18 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
this._terminalService.registerProcessSupport(isSupported);
}
public $registerProfileProvider(id: string): void {
// Proxy profile provider requests through the extension host
this._profileProviders.set(id, this._terminalService.registerTerminalProfileProvider(id, {
createContributedTerminalProfile: async (isSplitTerminal) => this._proxy.$createContributedProfileTerminal(id, isSplitTerminal)
}));
}
public $unregisterProfileProvider(id: string): void {
this._profileProviders.get(id)?.dispose();
this._profileProviders.delete(id);
}
private _onActiveTerminalChanged(terminalId: number | null): void {
this._proxy.$acceptActiveTerminalChanged(terminalId);
}
@@ -265,7 +292,15 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
}
public $sendProcessTitle(terminalId: number, title: string): void {
this._terminalProcessProxies.get(terminalId)?.emitTitle(title);
// Since title events can only come from vscode.Pseudoterminals right now, these are routed
// directly to the instance as API source events such that they will replace the initial
// `name` property provided for the Pseudoterminal. If we support showing both Api and
// Process titles at the same time we may want to pass this through as a Process source
// event.
const instance = this._terminalService.getInstanceFromId(terminalId);
if (instance) {
instance.setTitle(title, TitleEventSource.Api);
}
}
public $sendProcessData(terminalId: number, data: string): void {
@@ -308,28 +343,6 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
this._getTerminalProcess(terminalId)?.emitLatency(sum / COUNT);
}
private _isPrimaryExtHost(): boolean {
// The "primary" ext host is the remote ext host if there is one, otherwise the local
const conn = this._remoteAgentService.getConnection();
if (conn) {
return this._remoteAuthority === conn.remoteAuthority;
}
return this._extHostKind !== ExtensionHostKind.LocalWebWorker;
}
private async _onRequestAvailableProfiles(req: IAvailableProfilesRequest): Promise<void> {
if (this._isPrimaryExtHost()) {
req.callback(await this._proxy.$getAvailableProfiles(req.configuredProfilesOnly));
}
}
private async _onRequestDefaultShellAndArgs(req: IDefaultShellAndArgsRequest): Promise<void> {
if (this._isPrimaryExtHost()) {
const res = await this._proxy.$getDefaultShellAndArgs(req.useAutomationShell);
req.callback(res.shell, res.args);
}
}
private _getTerminalProcess(terminalId: number): ITerminalProcessExtHostProxy | undefined {
const terminal = this._terminalProcessProxies.get(terminalId);
if (!terminal) {

View File

@@ -60,7 +60,7 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
});
}
$reveal(treeViewId: string, itemInfo: { item: ITreeItem, parentChain: ITreeItem[]; } | undefined, options: IRevealOptions): Promise<void> {
$reveal(treeViewId: string, itemInfo: { item: ITreeItem, parentChain: ITreeItem[] } | undefined, options: IRevealOptions): Promise<void> {
this.logService.trace('MainThreadTreeViews#$reveal', treeViewId, itemInfo?.item, itemInfo?.parentChain, options);
return this.viewsService.openView(treeViewId, options.focus)
@@ -73,7 +73,7 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie
});
}
$refresh(treeViewId: string, itemsToRefreshByHandle: { [treeItemHandle: string]: ITreeItem; }): Promise<void> {
$refresh(treeViewId: string, itemsToRefreshByHandle: { [treeItemHandle: string]: ITreeItem }): Promise<void> {
this.logService.trace('MainThreadTreeViews#$refresh', treeViewId, itemsToRefreshByHandle);
const viewer = this.getTreeView(treeViewId);

View File

@@ -41,7 +41,8 @@ export class MainThreadTunnelService extends Disposable implements MainThreadTun
}
private processFindingEnabled(): boolean {
return (!!this.configurationService.getValue(PORT_AUTO_FORWARD_SETTING)) && (this.configurationService.getValue(PORT_AUTO_SOURCE_SETTING) === PORT_AUTO_SOURCE_SETTING_PROCESS);
return (!!this.configurationService.getValue(PORT_AUTO_FORWARD_SETTING) || this.tunnelService.hasTunnelProvider)
&& (this.configurationService.getValue(PORT_AUTO_SOURCE_SETTING) === PORT_AUTO_SOURCE_SETTING_PROCESS);
}
async $setRemoteTunnelService(processId: number): Promise<void> {

View File

@@ -14,8 +14,7 @@ import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { IProductService } from 'vs/platform/product/common/productService';
import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol';
import { serializeMessage } from 'vs/workbench/api/common/extHostWebview';
import { deserializeWebviewMessage } from 'vs/workbench/api/common/extHostWebviewMessaging';
import { serializeWebviewMessage, deserializeWebviewMessage } from 'vs/workbench/api/common/extHostWebviewMessaging';
import { Webview, WebviewContentOptions, WebviewExtensionDescription, WebviewOverlay } from 'vs/workbench/contrib/webview/browser/webview';
export class MainThreadWebviews extends Disposable implements extHostProtocol.MainThreadWebviewsShape {
@@ -74,7 +73,7 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
disposables.add(webview.onDidClickLink((uri) => this.onDidClickLink(handle, uri)));
disposables.add(webview.onMessage((message) => {
const serialized = serializeMessage(message.message, options);
const serialized = serializeWebviewMessage(message.message, options);
this._proxy.$onMessage(handle, serialized.message, ...serialized.buffers);
}));

View File

@@ -60,8 +60,7 @@ export class MainThreadWindow implements MainThreadWindowShape {
}
async $asExternalUri(uriComponents: UriComponents, options: IOpenUriOptions): Promise<UriComponents> {
const uri = URI.revive(uriComponents);
const result = await this.openerService.resolveExternalUri(uri, options);
const result = await this.openerService.resolveExternalUri(URI.revive(uriComponents), options);
return result.resolved;
}
}

View File

@@ -7,8 +7,6 @@ import { URI } from 'vs/base/common/uri';
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import { CommandsRegistry, ICommandService, ICommandHandler } from 'vs/platform/commands/common/commands';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows';
import { IWorkspacesService, IRecent } from 'vs/platform/workspaces/common/workspaces';
import { ILogService } from 'vs/platform/log/common/log';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IViewDescriptorService, IViewsService, ViewVisibilityState } from 'vs/workbench/common/views';
@@ -30,100 +28,6 @@ function adjustHandler(handler: (executor: ICommandsExecutor, ...args: any[]) =>
};
}
interface INewWindowAPICommandOptions {
reuseWindow?: boolean;
/**
* 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 {
public static readonly ID = 'vscode.newWindow';
public static execute(executor: ICommandsExecutor, options?: INewWindowAPICommandOptions): Promise<any> {
const commandOptions: IOpenEmptyWindowOptions = {
forceReuseWindow: options && options.reuseWindow,
remoteAuthority: options && options.remoteAuthority
};
return executor.executeCommand('_files.newWindow', commandOptions);
}
}
CommandsRegistry.registerCommand({
id: NewWindowAPICommand.ID,
handler: adjustHandler(NewWindowAPICommand.execute),
description: {
description: 'Opens an new window',
args: [
]
}
});
CommandsRegistry.registerCommand('_workbench.removeFromRecentlyOpened', function (accessor: ServicesAccessor, uri: URI) {
const workspacesService = accessor.get(IWorkspacesService);
return workspacesService.removeRecentlyOpened([uri]);
});
export class RemoveFromRecentlyOpenedAPICommand {
public static readonly ID = 'vscode.removeFromRecentlyOpened';
public static execute(executor: ICommandsExecutor, path: string | URI): Promise<any> {
if (typeof path === 'string') {
path = path.match(/^[^:/?#]+:\/\//) ? URI.parse(path) : URI.file(path);
} else {
path = URI.revive(path); // called from extension host
}
return executor.executeCommand('_workbench.removeFromRecentlyOpened', path);
}
}
CommandsRegistry.registerCommand(RemoveFromRecentlyOpenedAPICommand.ID, adjustHandler(RemoveFromRecentlyOpenedAPICommand.execute));
export interface OpenIssueReporterArgs {
readonly extensionId: string;
readonly issueTitle?: string;
readonly issueBody?: string;
}
export class OpenIssueReporter {
public static readonly ID = 'vscode.openIssueReporter';
public static execute(executor: ICommandsExecutor, args: string | OpenIssueReporterArgs): Promise<void> {
const commandArgs = typeof args === 'string'
? { extensionId: args }
: args;
return executor.executeCommand('workbench.action.openIssueReporter', commandArgs);
}
}
interface RecentEntry {
uri: URI;
type: 'workspace' | 'folder' | 'file';
label?: string;
remoteAuthority?: string;
}
CommandsRegistry.registerCommand('_workbench.addToRecentlyOpened', async function (accessor: ServicesAccessor, recentEntry: RecentEntry) {
const workspacesService = accessor.get(IWorkspacesService);
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, remoteAuthority };
} else if (recentEntry.type === 'folder') {
recent = { folderUri: uri, label, remoteAuthority };
} else {
recent = { fileUri: uri, label, remoteAuthority };
}
return workspacesService.addRecentlyOpened([recent]);
});
CommandsRegistry.registerCommand('_workbench.getRecentlyOpened', async function (accessor: ServicesAccessor) {
const workspacesService = accessor.get(IWorkspacesService);
return workspacesService.getRecentlyOpened();
});
CommandsRegistry.registerCommand('_extensionTests.setLogLevel', function (accessor: ServicesAccessor, level: number) {
const logService = accessor.get(ILogService);
const environmentService = accessor.get(IEnvironmentService);

View File

@@ -3,7 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
import * as errors from 'vs/base/common/errors';
import { Emitter, Event } from 'vs/base/common/event';
@@ -29,7 +28,7 @@ import { IExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocu
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';
import { ExtHostLanguageFeatures, InlineCompletionController } from 'vs/workbench/api/common/extHostLanguageFeatures';
import { ExtHostLanguages } from 'vs/workbench/api/common/extHostLanguages';
import { ExtHostMessageService } from 'vs/workbench/api/common/extHostMessageService';
import { IExtHostOutputService } from 'vs/workbench/api/common/extHostOutput';
@@ -59,7 +58,7 @@ import { getRemoteName } from 'vs/platform/remote/common/remoteHosts';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IExtHostDecorations } from 'vs/workbench/api/common/extHostDecorations';
import { IExtHostTask } from 'vs/workbench/api/common/extHostTask';
// import { IExtHostDebugService } from 'vs/workbench/api/common/extHostDebugService';
// import { IExtHostDebugService } from 'vs/workbench/api/common/extHostDebugService'; {{SQL CARBON EDIT}}
import { IExtHostSearch } from 'vs/workbench/api/common/extHostSearch';
import { ILogService } from 'vs/platform/log/common/log';
import { IURITransformerService } from 'vs/workbench/api/common/extHostUriTransformerService';
@@ -82,11 +81,15 @@ import { IExtHostFileSystemInfo } from 'vs/workbench/api/common/extHostFileSyste
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 { IExtHostEditorTabs } 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';
import { ExtHostNotebookRenderers } from 'vs/workbench/api/common/extHostNotebookRenderers';
import { Schemas } from 'vs/base/common/network';
import { matchesScheme } from 'vs/platform/opener/common/opener';
import { ExtHostNotebookEditors } from 'vs/workbench/api/common/extHostNotebookEditors';
import { ExtHostNotebookDocuments } from 'vs/workbench/api/common/extHostNotebookDocuments';
export interface IExtensionApiFactory {
(extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode;
@@ -114,6 +117,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
const extHostApiDeprecation = accessor.get(IExtHostApiDeprecationService);
const extHostWindow = accessor.get(IExtHostWindow);
const extHostSecretState = accessor.get(IExtHostSecretState);
const extHostEditorTabs = accessor.get(IExtHostEditorTabs);
// register addressable instances
rpcProtocol.set(ExtHostContext.ExtHostFileSystemInfo, extHostFileSystemInfo);
@@ -126,6 +130,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
rpcProtocol.set(ExtHostContext.ExtHostWindow, extHostWindow);
rpcProtocol.set(ExtHostContext.ExtHostSecretState, extHostSecretState);
rpcProtocol.set(ExtHostContext.ExtHostTelemetry, extHostTelemetry);
rpcProtocol.set(ExtHostContext.ExtHostEditorTabs, extHostEditorTabs);
// automatically create and register addressable instances
const extHostDecorations = rpcProtocol.set(ExtHostContext.ExtHostDecorations, accessor.get(IExtHostDecorations));
@@ -138,16 +143,18 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
const extHostOutputService = rpcProtocol.set(ExtHostContext.ExtHostOutputService, accessor.get(IExtHostOutputService));
// manually create and register addressable instances
const extHostEditorTabs = rpcProtocol.set(ExtHostContext.ExtHostEditorTabs, new ExtHostEditorTabs());
const extHostUrls = rpcProtocol.set(ExtHostContext.ExtHostUrls, new ExtHostUrls(rpcProtocol));
const extHostDocuments = rpcProtocol.set(ExtHostContext.ExtHostDocuments, new ExtHostDocuments(rpcProtocol, extHostDocumentsAndEditors));
const extHostDocumentContentProviders = rpcProtocol.set(ExtHostContext.ExtHostDocumentContentProviders, new ExtHostDocumentContentProvider(rpcProtocol, extHostDocumentsAndEditors, extHostLogService));
const extHostDocumentSaveParticipant = rpcProtocol.set(ExtHostContext.ExtHostDocumentSaveParticipant, new ExtHostDocumentSaveParticipant(extHostLogService, extHostDocuments, rpcProtocol.getProxy(MainContext.MainThreadBulkEdits)));
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 extHostNotebook = rpcProtocol.set(ExtHostContext.ExtHostNotebook, new ExtHostNotebookController(rpcProtocol, extHostCommands, extHostDocumentsAndEditors, extHostDocuments, extensionStoragePaths));
const extHostNotebookDocuments = rpcProtocol.set(ExtHostContext.ExtHostNotebookDocuments, new ExtHostNotebookDocuments(extHostLogService, extHostNotebook));
const extHostNotebookEditors = rpcProtocol.set(ExtHostContext.ExtHostNotebookEditors, new ExtHostNotebookEditors(extHostLogService, rpcProtocol, extHostNotebook));
const extHostNotebookKernels = rpcProtocol.set(ExtHostContext.ExtHostNotebookKernels, new ExtHostNotebookKernels(rpcProtocol, initData, extHostNotebook, extHostLogService));
const extHostNotebookRenderers = rpcProtocol.set(ExtHostContext.ExtHostNotebookRenderers, new ExtHostNotebookRenderers(rpcProtocol, 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));
const extHostEditorInsets = rpcProtocol.set(ExtHostContext.ExtHostEditorInsets, new ExtHostEditorInsets(rpcProtocol.getProxy(MainContext.MainThreadEditorInsets), extHostEditors, initData));
const extHostDiagnostics = rpcProtocol.set(ExtHostContext.ExtHostDiagnostics, new ExtHostDiagnostics(rpcProtocol, extHostLogService));
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));
@@ -160,7 +167,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
const extHostTheming = rpcProtocol.set(ExtHostContext.ExtHostTheming, new ExtHostTheming(rpcProtocol));
const extHostAuthentication = rpcProtocol.set(ExtHostContext.ExtHostAuthentication, new ExtHostAuthentication(rpcProtocol));
const extHostTimeline = rpcProtocol.set(ExtHostContext.ExtHostTimeline, new ExtHostTimeline(rpcProtocol, extHostCommands));
const extHostWebviews = rpcProtocol.set(ExtHostContext.ExtHostWebviews, new ExtHostWebviews(rpcProtocol, initData.environment, extHostWorkspace, extHostLogService, extHostApiDeprecation));
const extHostWebviews = rpcProtocol.set(ExtHostContext.ExtHostWebviews, new ExtHostWebviews(rpcProtocol, { remote: initData.remote }, extHostWorkspace, extHostLogService, extHostApiDeprecation));
const extHostWebviewPanels = rpcProtocol.set(ExtHostContext.ExtHostWebviewPanels, new ExtHostWebviewPanels(rpcProtocol, extHostWebviews, extHostWorkspace));
const extHostCustomEditors = rpcProtocol.set(ExtHostContext.ExtHostCustomEditors, new ExtHostCustomEditors(rpcProtocol, extHostDocuments, extensionStoragePaths, extHostWebviews, extHostWebviewPanels));
const extHostWebviewViews = rpcProtocol.set(ExtHostContext.ExtHostWebviewViews, new ExtHostWebviewViews(rpcProtocol, extHostWebviews));
@@ -219,7 +226,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
})();
const authentication: typeof vscode.authentication = {
getSession(providerId: string, scopes: string[], options?: vscode.AuthenticationGetSessionOptions) {
getSession(providerId: string, scopes: readonly string[], options?: vscode.AuthenticationGetSessionOptions) {
return extHostAuthentication.getSession(extension, providerId, scopes, options as any);
},
get onDidChangeSessions(): Event<vscode.AuthenticationSessionsChangeEvent> {
@@ -298,7 +305,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
get uriScheme() { return initData.environment.appUriScheme; },
get clipboard(): vscode.Clipboard { return extHostClipboard.value; },
get shell() {
return extHostTerminalService.getDefaultShell(false, configProvider);
return extHostTerminalService.getDefaultShell(false);
},
get isTelemetryEnabled() {
return extHostTelemetry.getTelemetryEnabled();
@@ -316,12 +323,26 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
allowContributedOpeners: options?.allowContributedOpeners,
});
},
asExternalUri(uri: URI) {
async asExternalUri(uri: URI) {
if (uri.scheme === initData.environment.appUriScheme) {
return extHostUrls.createAppUri(uri);
}
return extHostWindow.asExternalUri(uri, { allowTunneling: !!initData.remote.authority });
const isHttp = matchesScheme(uri, Schemas.http) || matchesScheme(uri, Schemas.https);
if (!isHttp) {
checkProposedApiEnabled(extension); // https://github.com/microsoft/vscode/issues/124263
}
try {
return await extHostWindow.asExternalUri(uri, { allowTunneling: !!initData.remote.authority });
} catch (err) {
if (isHttp) {
return uri;
}
throw err;
}
},
get remoteName() {
return getRemoteName(initData.remote.authority);
@@ -482,6 +503,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
registerCompletionItemProvider(selector: vscode.DocumentSelector, provider: vscode.CompletionItemProvider, ...triggerCharacters: string[]): vscode.Disposable {
return extHostLanguageFeatures.registerCompletionItemProvider(extension, checkSelector(selector), provider, triggerCharacters);
},
registerInlineCompletionItemProvider(selector: vscode.DocumentSelector, provider: vscode.InlineCompletionItemProvider): vscode.Disposable {
checkProposedApiEnabled(extension);
return extHostLanguageFeatures.registerInlineCompletionsProvider(extension, checkSelector(selector), provider);
},
registerDocumentLinkProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentLinkProvider): vscode.Disposable {
return extHostLanguageFeatures.registerDocumentLinkProvider(extension, checkSelector(selector), provider);
},
@@ -504,9 +529,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
checkProposedApiEnabled(extension);
return extHostLanguages.tokenAtPosition(doc, pos);
},
registerInlineHintsProvider(selector: vscode.DocumentSelector, provider: vscode.InlineHintsProvider): vscode.Disposable {
registerInlayHintsProvider(selector: vscode.DocumentSelector, provider: vscode.InlayHintsProvider): vscode.Disposable {
checkProposedApiEnabled(extension);
return extHostLanguageFeatures.registerInlineHintsProvider(extension, selector, provider);
return extHostLanguageFeatures.registerInlayHintsProvider(extension, selector, provider);
}
};
@@ -532,7 +557,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
return extHostEditors.showTextDocument(document, columnOrOptions, preserveFocus);
},
createTextEditorDecorationType(options: vscode.DecorationRenderOptions): vscode.TextEditorDecorationType {
return extHostEditors.createTextEditorDecorationType(options);
return extHostEditors.createTextEditorDecorationType(extension, options);
},
onDidChangeActiveTextEditor(listener, thisArg?, disposables?) {
return extHostEditors.onDidChangeActiveTextEditor(listener, thisArg, disposables);
@@ -599,26 +624,21 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
showSaveDialog(options) {
return extHostDialogs.showSaveDialog(options);
},
createStatusBarItem(alignmentOrOptions?: vscode.StatusBarAlignment | vscode.StatusBarItemOptions, priority?: number): vscode.StatusBarItem {
let id: string;
let name: string;
createStatusBarItem(alignmentOrId?: vscode.StatusBarAlignment | string, priorityOrAlignment?: number | vscode.StatusBarAlignment, priorityArg?: number): vscode.StatusBarItem {
let id: string | undefined;
let alignment: number | undefined;
let accessibilityInformation: vscode.AccessibilityInformation | undefined = undefined;
let priority: number | undefined;
if (alignmentOrOptions && typeof alignmentOrOptions !== 'number') {
id = alignmentOrOptions.id;
name = alignmentOrOptions.name;
alignment = alignmentOrOptions.alignment;
priority = alignmentOrOptions.priority;
accessibilityInformation = alignmentOrOptions.accessibilityInformation;
if (typeof alignmentOrId === 'string') {
id = alignmentOrId;
alignment = priorityOrAlignment;
priority = priorityArg;
} else {
id = extension.identifier.value;
name = nls.localize('extensionLabel', "{0} (Extension)", extension.displayName || extension.name);
alignment = alignmentOrOptions as number; // {{SQL CARBON EDIT}} strict-null-check
priority = priority;
alignment = alignmentOrId as number; // {{SQL CARBON EDIT}} strict-null-check
priority = priorityOrAlignment;
}
return extHostStatusBar.createStatusBarEntry(id, name, alignment, priority, accessibilityInformation);
return extHostStatusBar.createStatusBarEntry(extension, id, alignment, priority);
},
setStatusBarMessage(text: string, timeoutOrThenable?: number | Thenable<any>): vscode.Disposable {
return extHostStatusBar.setStatusBarMessage(text, timeoutOrThenable);
@@ -647,18 +667,18 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
if ('pty' in nameOrOptions) {
return extHostTerminalService.createExtensionTerminal(nameOrOptions);
}
if (nameOrOptions.message) {
checkProposedApiEnabled(extension);
}
if (nameOrOptions.icon) {
if (nameOrOptions.iconPath) {
checkProposedApiEnabled(extension);
}
return extHostTerminalService.createTerminalFromOptions(nameOrOptions);
}
return extHostTerminalService.createTerminal(nameOrOptions, shellPath, shellArgs);
},
registerTerminalLinkProvider(handler: vscode.TerminalLinkProvider): vscode.Disposable {
return extHostTerminalService.registerLinkProvider(handler);
registerTerminalLinkProvider(provider: vscode.TerminalLinkProvider): vscode.Disposable {
return extHostTerminalService.registerLinkProvider(provider);
},
registerTerminalProfileProvider(id: string, provider: vscode.TerminalProfileProvider): vscode.Disposable {
return extHostTerminalService.registerProfileProvider(id, provider);
},
registerTreeDataProvider(viewId: string, treeDataProvider: vscode.TreeDataProvider<any>): vscode.Disposable {
return extHostTreeViews.registerTreeDataProvider(viewId, treeDataProvider, extension);
@@ -715,11 +735,11 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
},
onDidChangeNotebookEditorSelection(listener, thisArgs?, disposables?) {
checkProposedApiEnabled(extension);
return extHostNotebook.onDidChangeNotebookEditorSelection(listener, thisArgs, disposables);
return extHostNotebookEditors.onDidChangeNotebookEditorSelection(listener, thisArgs, disposables);
},
onDidChangeNotebookEditorVisibleRanges(listener, thisArgs?, disposables?) {
checkProposedApiEnabled(extension);
return extHostNotebook.onDidChangeNotebookEditorVisibleRanges(listener, thisArgs, disposables);
return extHostNotebookEditors.onDidChangeNotebookEditorVisibleRanges(listener, thisArgs, disposables);
},
showNotebookDocument(uriOrDocument, options?) {
checkProposedApiEnabled(extension);
@@ -736,6 +756,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
get onDidChangeOpenEditors() {
checkProposedApiEnabled(extension);
return extHostEditorTabs.onDidChangeTabs;
},
getInlineCompletionItemController<T extends vscode.InlineCompletionItem>(provider: vscode.InlineCompletionItemProvider<T>): vscode.InlineCompletionController<T> {
checkProposedApiEnabled(extension);
return InlineCompletionController.get(provider);
}
};
@@ -847,6 +871,34 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
onWillSaveTextDocument: (listener, thisArgs?, disposables?) => {
return extHostDocumentSaveParticipant.getOnWillSaveTextDocumentEvent(extension)(listener, thisArgs, disposables);
},
get notebookDocuments(): vscode.NotebookDocument[] {
return extHostNotebook.notebookDocuments.map(d => d.apiNotebook);
},
async openNotebookDocument(uriOrType?: URI | string, content?: vscode.NotebookData) {
let uri: URI;
if (URI.isUri(uriOrType)) {
uri = uriOrType;
await extHostNotebook.openNotebookDocument(uriOrType);
} else if (typeof uriOrType === 'string') {
uri = URI.revive(await extHostNotebook.createNotebookDocument({ viewType: uriOrType, content }));
} else {
throw new Error('Invalid arguments');
}
return extHostNotebook.getNotebookDocument(uri).apiNotebook;
},
get onDidOpenNotebookDocument(): Event<vscode.NotebookDocument> {
return extHostNotebook.onDidOpenNotebookDocument;
},
get onDidCloseNotebookDocument(): Event<vscode.NotebookDocument> {
return extHostNotebook.onDidCloseNotebookDocument;
},
registerNotebookSerializer(viewType: string, serializer: vscode.NotebookSerializer, options?: vscode.NotebookDocumentContentOptions, registration?: vscode.NotebookRegistrationData) {
return extHostNotebook.registerNotebookSerializer(extension, viewType, serializer, options, extension.enableProposedApi ? registration : undefined);
},
registerNotebookContentProvider: (viewType: string, provider: vscode.NotebookContentProvider, options?: vscode.NotebookDocumentContentOptions, registration?: vscode.NotebookRegistrationData) => {
checkProposedApiEnabled(extension);
return extHostNotebook.registerNotebookContentProvider(extension, viewType, provider, options, extension.enableProposedApi ? registration : undefined);
},
onDidChangeConfiguration: (listener: (_: any) => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) => {
return configProvider.onDidChangeConfiguration(listener, thisArgs, disposables);
},
@@ -864,7 +916,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
return extHostTask.registerTaskProvider(extension, type, provider);
},
registerFileSystemProvider(scheme, provider, options) {
return extHostFileSystem.registerFileSystemProvider(extension.identifier, scheme, provider, options);
return extHostFileSystem.registerFileSystemProvider(extension.identifier, scheme, provider, options, extension.enableProposedApi);
},
get fs() {
return extHostConsumerFileSystem.value;
@@ -1014,12 +1066,12 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
extHostLogService.warn('Debug API is disabled in Azure Data Studio');
return undefined!;
},
addBreakpoints(breakpoints: vscode.Breakpoint[]) {
extHostLogService.warn('Debug API is disabled in Azure Data Studio');
addBreakpoints(breakpoints: readonly vscode.Breakpoint[]) {
extHostLogService.warn('Debug API is disabled in Azure Data Studio'); // {{SQL CARBON EDIT}}
return undefined!;
},
removeBreakpoints(breakpoints: vscode.Breakpoint[]) {
extHostLogService.warn('Debug API is disabled in Azure Data Studio');
removeBreakpoints(breakpoints: readonly vscode.Breakpoint[]) {
extHostLogService.warn('Debug API is disabled in Azure Data Studio'); // {{SQL CARBON EDIT}}
return undefined!;
},
asDebugSourceUri(source: vscode.DebugProtocolSource, session?: vscode.DebugSession): vscode.Uri {
@@ -1056,52 +1108,34 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
};
// namespace: notebook
const notebook: typeof vscode.notebook = {
openNotebookDocument: (uriComponents) => {
checkProposedApiEnabled(extension);
return extHostNotebook.openNotebookDocument(uriComponents);
const notebooks: typeof vscode.notebooks = {
createNotebookController(id: string, notebookType: string, label: string, handler?, rendererScripts?: vscode.NotebookRendererScript[]) {
return extHostNotebookKernels.createNotebookController(extension, id, notebookType, label, handler, extension.enableProposedApi ? rendererScripts : undefined);
},
get onDidOpenNotebookDocument(): Event<vscode.NotebookDocument> {
checkProposedApiEnabled(extension);
return extHostNotebook.onDidOpenNotebookDocument;
},
get onDidCloseNotebookDocument(): Event<vscode.NotebookDocument> {
checkProposedApiEnabled(extension);
return extHostNotebook.onDidCloseNotebookDocument;
registerNotebookCellStatusBarItemProvider: (notebookType: string, provider: vscode.NotebookCellStatusBarItemProvider) => {
return extHostNotebook.registerNotebookCellStatusBarItemProvider(extension, notebookType, provider);
},
get onDidSaveNotebookDocument(): Event<vscode.NotebookDocument> {
checkProposedApiEnabled(extension);
return extHostNotebook.onDidSaveNotebookDocument;
},
get notebookDocuments(): vscode.NotebookDocument[] {
checkProposedApiEnabled(extension);
return extHostNotebook.notebookDocuments.map(d => d.apiNotebook);
},
registerNotebookSerializer(viewType, serializer, options) {
checkProposedApiEnabled(extension);
return extHostNotebook.registerNotebookSerializer(extension, viewType, serializer, options);
},
registerNotebookContentProvider: (viewType, provider, options) => {
checkProposedApiEnabled(extension);
return extHostNotebook.registerNotebookContentProvider(extension, viewType, provider, options);
},
registerNotebookCellStatusBarItemProvider: (selector: vscode.NotebookSelector, provider: vscode.NotebookCellStatusBarItemProvider) => {
checkProposedApiEnabled(extension);
return extHostNotebook.registerNotebookCellStatusBarItemProvider(extension, selector, provider);
return extHostNotebookDocuments.onDidSaveNotebookDocument;
},
createNotebookEditorDecorationType(options: vscode.NotebookDecorationRenderOptions): vscode.NotebookEditorDecorationType {
checkProposedApiEnabled(extension);
return extHostNotebook.createNotebookEditorDecorationType(options);
return extHostNotebookEditors.createNotebookEditorDecorationType(options);
},
createRendererMessaging(rendererId) {
checkProposedApiEnabled(extension);
return extHostNotebookRenderers.createRendererMessaging(rendererId);
},
onDidChangeNotebookDocumentMetadata(listener, thisArgs?, disposables?) {
checkProposedApiEnabled(extension);
return extHostNotebook.onDidChangeNotebookDocumentMetadata(listener, thisArgs, disposables);
return extHostNotebookDocuments.onDidChangeNotebookDocumentMetadata(listener, thisArgs, disposables);
},
onDidChangeNotebookCells(listener, thisArgs?, disposables?) {
checkProposedApiEnabled(extension);
return extHostNotebook.onDidChangeNotebookCells(listener, thisArgs, disposables);
},
onDidChangeCellExecutionState(listener, thisArgs?, disposables?) {
onDidChangeNotebookCellExecutionState(listener, thisArgs?, disposables?) {
checkProposedApiEnabled(extension);
return extHostNotebook.onDidChangeNotebookCellExecutionState(listener, thisArgs, disposables);
},
@@ -1117,14 +1151,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
checkProposedApiEnabled(extension);
return new ExtHostNotebookConcatDocument(extHostNotebook, extHostDocuments, notebook, selector);
},
createNotebookCellExecutionTask(uri: vscode.Uri, index: number, kernelId: string): vscode.NotebookCellExecutionTask | undefined {
checkProposedApiEnabled(extension);
return extHostNotebook.createNotebookCellExecution(uri, index, kernelId);
},
createNotebookController(id, viewType, label, executeHandler, preloads) {
checkProposedApiEnabled(extension);
return extHostNotebookKernels.createNotebookController(extension, id, viewType, label, executeHandler, preloads);
}
};
return <typeof vscode>{
@@ -1138,7 +1164,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
env,
extensions,
languages,
notebook,
notebooks,
scm,
tasks,
test,
@@ -1191,6 +1217,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
InlineValueText: extHostTypes.InlineValueText,
InlineValueVariableLookup: extHostTypes.InlineValueVariableLookup,
InlineValueEvaluatableExpression: extHostTypes.InlineValueEvaluatableExpression,
InlineCompletionTriggerKind: extHostTypes.InlineCompletionTriggerKind,
EventEmitter: Emitter,
ExtensionKind: extHostTypes.ExtensionKind,
ExtensionMode: extHostTypes.ExtensionMode,
@@ -1199,9 +1226,12 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
FileDecoration: extHostTypes.FileDecoration,
FileSystemError: extHostTypes.FileSystemError,
FileType: files.FileType,
FilePermission: files.FilePermission,
FoldingRange: extHostTypes.FoldingRange,
FoldingRangeKind: extHostTypes.FoldingRangeKind,
FunctionBreakpoint: extHostTypes.FunctionBreakpoint,
InlineCompletionItem: extHostTypes.InlineSuggestion,
InlineCompletionList: extHostTypes.InlineSuggestions,
Hover: extHostTypes.Hover,
IndentAction: languageConfiguration.IndentAction,
Location: extHostTypes.Location,
@@ -1254,10 +1284,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
ViewColumn: extHostTypes.ViewColumn,
WorkspaceEdit: extHostTypes.WorkspaceEdit,
// proposed api types
InlineHint: extHostTypes.InlineHint,
InlineHintKind: extHostTypes.InlineHintKind,
InlayHint: extHostTypes.InlayHint,
InlayHintKind: extHostTypes.InlayHintKind,
RemoteAuthorityResolverError: extHostTypes.RemoteAuthorityResolverError,
RemoteTrustOption: RemoteTrustOption,
ResolvedAuthority: extHostTypes.ResolvedAuthority,
SourceControlInputBoxValidationType: extHostTypes.SourceControlInputBoxValidationType,
ExtensionRuntime: extHostTypes.ExtensionRuntime,
@@ -1265,16 +1294,16 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
NotebookRange: extHostTypes.NotebookRange,
NotebookCellKind: extHostTypes.NotebookCellKind,
NotebookCellExecutionState: extHostTypes.NotebookCellExecutionState,
NotebookDocumentMetadata: extHostTypes.NotebookDocumentMetadata,
NotebookCellMetadata: extHostTypes.NotebookCellMetadata,
NotebookCellData: extHostTypes.NotebookCellData,
NotebookData: extHostTypes.NotebookData,
NotebookRendererScript: extHostTypes.NotebookRendererScript,
NotebookCellStatusBarAlignment: extHostTypes.NotebookCellStatusBarAlignment,
NotebookEditorRevealType: extHostTypes.NotebookEditorRevealType,
NotebookCellOutput: extHostTypes.NotebookCellOutput,
NotebookCellOutputItem: extHostTypes.NotebookCellOutputItem,
NotebookCellStatusBarItem: extHostTypes.NotebookCellStatusBarItem,
NotebookControllerAffinity: extHostTypes.NotebookControllerAffinity,
PortAttributes: extHostTypes.PortAttributes,
LinkedEditingRanges: extHostTypes.LinkedEditingRanges,
TestItemStatus: extHostTypes.TestItemStatus,
TestResultState: extHostTypes.TestResultState,

View File

@@ -12,7 +12,7 @@ import { IExtHostCommands, ExtHostCommands } from 'vs/workbench/api/common/extHo
import { IExtHostDocumentsAndEditors, ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { IExtHostTerminalService, WorkerExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService';
import { IExtHostTask, WorkerExtHostTask } from 'vs/workbench/api/common/extHostTask';
// import { IExtHostDebugService, WorkerExtHostDebugService } from 'vs/workbench/api/common/extHostDebugService';
// import { IExtHostDebugService, WorkerExtHostDebugService } from 'vs/workbench/api/common/extHostDebugService'; {{SQL CARBON EDIT}}
import { IExtHostSearch, ExtHostSearch } from 'vs/workbench/api/common/extHostSearch';
import { IExtensionStoragePaths, ExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
import { IExtHostStorage, ExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
@@ -23,13 +23,14 @@ import { IExtHostConsumerFileSystem, ExtHostConsumerFileSystem } from 'vs/workbe
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';
import { ExtHostEditorTabs, IExtHostEditorTabs } from 'vs/workbench/api/common/extHostEditorTabs';
registerSingleton(IExtensionStoragePaths, ExtensionStoragePaths);
registerSingleton(IExtHostApiDeprecationService, ExtHostApiDeprecationService);
registerSingleton(IExtHostCommands, ExtHostCommands);
registerSingleton(IExtHostConfiguration, ExtHostConfiguration);
registerSingleton(IExtHostConsumerFileSystem, ExtHostConsumerFileSystem);
// registerSingleton(IExtHostDebugService, WorkerExtHostDebugService);
// registerSingleton(IExtHostDebugService, WorkerExtHostDebugService); {{SQL CARBON EDIT}}
registerSingleton(IExtHostDecorations, ExtHostDecorations);
registerSingleton(IExtHostDocumentsAndEditors, ExtHostDocumentsAndEditors);
registerSingleton(IExtHostFileSystemInfo, ExtHostFileSystemInfo);
@@ -43,3 +44,4 @@ registerSingleton(IExtHostWindow, ExtHostWindow);
registerSingleton(IExtHostWorkspace, ExtHostWorkspace);
registerSingleton(IExtHostSecretState, ExtHostSecretState);
registerSingleton(IExtHostTelemetry, ExtHostTelemetry);
registerSingleton(IExtHostEditorTabs, ExtHostEditorTabs);

View File

@@ -3,7 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as performance from 'vs/base/common/performance';
import { VSBuffer } from 'vs/base/common/buffer';
import { CancellationToken } from 'vs/base/common/cancellation';
import { IRemoteConsoleLog } from 'vs/base/common/console';
@@ -11,7 +10,10 @@ import { SerializedError } from 'vs/base/common/errors';
import { IRelativePattern } from 'vs/base/common/glob';
import { IMarkdownString } from 'vs/base/common/htmlContent';
import { IDisposable } from 'vs/base/common/lifecycle';
import { revive } from 'vs/base/common/marshalling';
import * as performance from 'vs/base/common/performance';
import Severity from 'vs/base/common/severity';
import { Dto } from 'vs/base/common/types';
import { URI, UriComponents } from 'vs/base/common/uri';
import { RenderLineNumbersType, TextEditorCursorStyle } from 'vs/editor/common/config/editorOptions';
import { IPosition } from 'vs/editor/common/core/position';
@@ -22,8 +24,9 @@ import { EndOfLineSequence, ISingleEditOperation } from 'vs/editor/common/model'
import { IModelChangedEvent } from 'vs/editor/common/model/mirrorTextModel';
import * as modes from 'vs/editor/common/modes';
import { CharacterPair, CommentRule, EnterAction } from 'vs/editor/common/modes/languageConfiguration';
import { IAccessibilityInformation } from 'vs/platform/accessibility/common/accessibility';
import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
import { ConfigurationTarget, IConfigurationData, IConfigurationChange, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration';
import { ConfigurationTarget, IConfigurationChange, IConfigurationData, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration';
import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import * as files from 'vs/platform/files/common/files';
@@ -32,40 +35,35 @@ import { LogLevel } from 'vs/platform/log/common/log';
import { IMarkerData } from 'vs/platform/markers/common/markers';
import { IProgressOptions, IProgressStep } from 'vs/platform/progress/common/progress';
import * as quickInput from 'vs/platform/quickinput/common/quickInput';
import { RemoteAuthorityResolverErrorCode, ResolverResult, TunnelDescription, IRemoteConnectionData } from 'vs/platform/remote/common/remoteAuthorityResolver';
import * as statusbar from 'vs/workbench/services/statusbar/common/statusbar';
import { IRemoteConnectionData, RemoteAuthorityResolverErrorCode, ResolverResult, TunnelDescription } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { ProvidedPortAttributes, TunnelCreationOptions, TunnelOptions, TunnelProviderFeatures } from 'vs/platform/remote/common/tunnel';
import { ClassifiedEvent, GDPRClassification, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings';
import { ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
import { ThemeColor } from 'vs/platform/theme/common/themeService';
import { TreeDataTransferDTO } from 'vs/workbench/api/common/shared/treeDataTransfer';
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 { 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 { IShellLaunchConfig, IShellLaunchConfigDto, ITerminalDimensions, ITerminalEnvironment, ITerminalLaunchError, ITerminalProfile } from 'vs/platform/terminal/common/terminal';
import { ThemeColor, ThemeIcon } from 'vs/platform/theme/common/themeService';
import { IExtensionIdWithVersion } from 'vs/platform/userDataSync/common/extensionsStorageSync';
import { WorkspaceTrustRequestOptions } from 'vs/platform/workspace/common/workspaceTrust';
import { ExtensionActivationReason } from 'vs/workbench/api/common/extHostExtensionActivator';
import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService';
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 { 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 { 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, 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 * as tasks from 'vs/workbench/api/common/shared/tasks';
import { EditorGroupColumn, SaveReason } from 'vs/workbench/common/editor';
import { IRevealOptions, ITreeItem } from 'vs/workbench/common/views';
import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
import { IAdapterDescriptor, IConfig, IDebugSessionReplMode } from 'vs/workbench/contrib/debug/common/debug';
import { CellKind, ICellEditOperation, IImmediateCellEditOperation, IMainCellDto, INotebookCellStatusBarItem, INotebookContributionData, INotebookDecorationRenderOptions, IOutputDto, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookDataDto, NotebookDocumentMetadata, TransientCellMetadata, TransientDocumentMetadata, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange';
import { InputValidationType } from 'vs/workbench/contrib/scm/common/scm';
import { ITextQueryBuilderOptions } from 'vs/workbench/contrib/search/common/queryBuilder';
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { ExtensionRunTestsRequest, InternalTestItem, ISerializedTestResults, ITestItem, ITestMessage, ITestRunTask, RunTestForProviderRequest, RunTestsRequest, TestIdWithSrc, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection';
import { InternalTimelineOptions, Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor } from 'vs/workbench/contrib/timeline/common/timeline';
import { ActivationKind, ExtensionHostKind, MissingExtensionDependency } from 'vs/workbench/services/extensions/common/extensions';
import { createExtHostContextProxyIdentifier as createExtId, createMainContextProxyIdentifier as createMainId, IRPCProtocol } from 'vs/workbench/services/extensions/common/proxyIdentifier';
import { CandidatePort } from 'vs/workbench/services/remote/common/remoteExplorerService';
import * as search from 'vs/workbench/services/search/common/search';
import * as statusbar from 'vs/workbench/services/statusbar/common/statusbar';
// {{SQL CARBON EDIT}}
import { ITreeItem as sqlITreeItem } from 'sql/workbench/common/views';
@@ -80,8 +78,6 @@ export interface IEnvironment {
extensionTestsLocationURI?: URI;
globalStorageHome: URI;
workspaceStorageHome: URI;
webviewResourceRoot: string;
webviewCspSource: string;
useHostProxy?: boolean;
}
@@ -176,7 +172,7 @@ export interface MainThreadAuthenticationShape extends IDisposable {
$unregisterAuthenticationProvider(id: string): void;
$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>;
$getSession(providerId: string, scopes: readonly string[], extensionId: string, extensionName: string, options: { createIfNone?: boolean, clearSessionPreference?: boolean }): Promise<modes.AuthenticationSession | undefined>;
$removeSession(providerId: string, sessionId: string): Promise<void>;
}
@@ -279,7 +275,7 @@ export interface MainThreadBulkEditsShape extends IDisposable {
export interface MainThreadTextEditorsShape extends IDisposable {
$tryShowTextDocument(resource: UriComponents, options: ITextDocumentShowOptions): Promise<string | undefined>;
$registerTextEditorDecorationType(key: string, options: editorCommon.IDecorationRenderOptions): void;
$registerTextEditorDecorationType(extensionId: ExtensionIdentifier, key: string, options: editorCommon.IDecorationRenderOptions): void;
$removeTextEditorDecorationType(key: string): void;
$tryShowEditor(id: string, position: EditorGroupColumn): Promise<void>;
$tryHideEditor(id: string): Promise<void>;
@@ -376,6 +372,14 @@ export interface ISignatureHelpProviderMetadataDto {
readonly retriggerCharacters: readonly string[];
}
export interface IdentifiableInlineCompletions extends modes.InlineCompletions<IdentifiableInlineCompletion> {
pid: number;
}
export interface IdentifiableInlineCompletion extends modes.InlineCompletion {
idx: number;
}
export interface MainThreadLanguageFeaturesShape extends IDisposable {
$unregister(handle: number): void;
$registerDocumentSymbolProvider(handle: number, selector: IDocumentFilterDto[], label: string): void;
@@ -402,9 +406,10 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable {
$emitDocumentSemanticTokensEvent(eventHandle: number): void;
$registerDocumentRangeSemanticTokensProvider(handle: number, selector: IDocumentFilterDto[], legend: modes.SemanticTokensLegend): void;
$registerSuggestSupport(handle: number, selector: IDocumentFilterDto[], triggerCharacters: string[], supportsResolveDetails: boolean, displayName: string): void;
$registerInlineCompletionsSupport(handle: number, selector: IDocumentFilterDto[]): void;
$registerSignatureHelpProvider(handle: number, selector: IDocumentFilterDto[], metadata: ISignatureHelpProviderMetadataDto): void;
$registerInlineHintsProvider(handle: number, selector: IDocumentFilterDto[], eventHandle: number | undefined): void;
$emitInlineHintsEvent(eventHandle: number, event?: any): void;
$registerInlayHintsProvider(handle: number, selector: IDocumentFilterDto[], eventHandle: number | undefined): void;
$emitInlayHintsEvent(eventHandle: number, event?: any): void;
$registerDocumentLinkProvider(handle: number, selector: IDocumentFilterDto[], supportsResolve: boolean): void;
$registerDocumentColorProvider(handle: number, selector: IDocumentFilterDto[]): void;
$registerFoldingRangeProvider(handle: number, selector: IDocumentFilterDto[], eventHandle: number | undefined): void;
@@ -463,7 +468,7 @@ export interface TerminalLaunchConfig {
shellArgs?: string[] | string;
cwd?: string | UriComponents;
env?: ITerminalEnvironment;
icon?: string;
icon?: URI | { light: URI; dark: URI } | ThemeIcon;
initialText?: string;
waitOnExit?: boolean;
strictEnv?: boolean;
@@ -471,6 +476,8 @@ export interface TerminalLaunchConfig {
isExtensionCustomPtyTerminal?: boolean;
isFeatureTerminal?: boolean;
isExtensionOwnedTerminal?: boolean;
useShellEnvironment?: boolean;
isSplitTerminal?: boolean;
}
export interface MainThreadTerminalServiceShape extends IDisposable {
@@ -484,6 +491,8 @@ export interface MainThreadTerminalServiceShape extends IDisposable {
$startLinkProvider(): void;
$stopLinkProvider(): void;
$registerProcessSupport(isSupported: boolean): void;
$registerProfileProvider(id: string): void;
$unregisterProfileProvider(id: string): void;
$setEnvironmentVariableCollection(extensionIdentifier: string, persistent: boolean, collection: ISerializableEnvironmentVariableCollection | undefined): void;
// Process
@@ -628,7 +637,8 @@ export interface MainThreadEditorTabsShape extends IDisposable {
export interface IEditorTabDto {
group: number;
name: string;
resource: UriComponents
resource: UriComponents;
isActive: boolean;
}
export interface IExtHostEditorTabsShape {
@@ -652,7 +662,6 @@ export interface WebviewExtensionDescription {
export interface NotebookExtensionDescription {
readonly id: ExtensionIdentifier;
readonly location: UriComponents;
readonly description?: string;
}
export enum WebviewEditorCapabilities {
@@ -713,7 +722,7 @@ export interface WebviewMessageArrayBufferReference {
export interface MainThreadWebviewsShape extends IDisposable {
$setHtml(handle: WebviewHandle, value: string): void;
$setOptions(handle: WebviewHandle, options: IWebviewOptions): void;
$postMessage(handle: WebviewHandle, value: any, ...buffers: VSBuffer[]): Promise<boolean>
$postMessage(handle: WebviewHandle, value: string, ...buffers: VSBuffer[]): Promise<boolean>
}
export interface MainThreadWebviewPanelsShape extends IDisposable {
@@ -823,11 +832,6 @@ export interface ExtHostWebviewViewsShape {
$disposeWebviewView(webviewHandle: WebviewHandle): void;
}
export enum CellKind {
Markdown = 1,
Code = 2
}
export enum CellOutputKind {
Text = 1,
Error = 2,
@@ -878,19 +882,14 @@ export interface INotebookCellStatusBarListDto {
}
export interface MainThreadNotebookShape extends IDisposable {
$registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, options: {
transientOutputs: boolean;
transientCellMetadata: TransientCellMetadata;
transientDocumentMetadata: TransientDocumentMetadata;
viewOptions?: { displayName: string; filenamePattern: (string | IRelativePattern | INotebookExclusiveDocumentFilter)[]; exclusive: boolean; };
}): Promise<void>;
$registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, options: TransientOptions, registration: INotebookContributionData | undefined): Promise<void>;
$updateNotebookProviderOptions(viewType: string, options?: { transientOutputs: boolean; transientCellMetadata: TransientCellMetadata; transientDocumentMetadata: TransientDocumentMetadata; }): Promise<void>;
$unregisterNotebookProvider(viewType: string): Promise<void>;
$registerNotebookSerializer(handle: number, extension: NotebookExtensionDescription, viewType: string, options: TransientOptions): void;
$registerNotebookSerializer(handle: number, extension: NotebookExtensionDescription, viewType: string, options: TransientOptions, registration: INotebookContributionData | undefined): void;
$unregisterNotebookSerializer(handle: number): void;
$registerNotebookCellStatusBarItemProvider(handle: number, eventHandle: number | undefined, selector: NotebookSelector): Promise<void>;
$registerNotebookCellStatusBarItemProvider(handle: number, eventHandle: number | undefined, viewType: string): Promise<void>;
$unregisterNotebookCellStatusBarItemProvider(handle: number, eventHandle: number | undefined): Promise<void>;
$emitCellStatusBarEvent(eventHandle: number): void;
}
@@ -900,19 +899,21 @@ export interface MainThreadNotebookEditorsShape extends IDisposable {
$tryRevealRange(id: string, range: ICellRange, revealType: NotebookEditorRevealType): Promise<void>;
$registerNotebookEditorDecorationType(key: string, options: INotebookDecorationRenderOptions): void;
$removeNotebookEditorDecorationType(key: string): void;
$trySetSelections(id: string, range: ICellRange[]): 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>;
$tryCreateNotebook(options: { viewType: string, content?: NotebookDataDto }): Promise<UriComponents>;
$tryOpenNotebook(uriComponents: UriComponents): Promise<UriComponents>;
$trySaveNotebook(uri: UriComponents): Promise<boolean>;
$applyEdits(resource: UriComponents, edits: IImmediateCellEditOperation[], computeUndoRedo?: boolean): Promise<void>;
}
export interface INotebookKernelDto2 {
id: string;
viewType: string;
notebookType: string;
extensionId: ExtensionIdentifier;
extensionLocation: UriComponents;
label: string;
@@ -920,7 +921,7 @@ export interface INotebookKernelDto2 {
description?: string;
supportedLanguages?: string[];
supportsInterrupt?: boolean;
hasExecutionOrder?: boolean;
supportsExecutionOrder?: boolean;
preloads?: { uri: UriComponents; provides: string[] }[];
}
@@ -932,6 +933,10 @@ export interface MainThreadNotebookKernelsShape extends IDisposable {
$updateNotebookPriority(handle: number, uri: UriComponents, value: number | undefined): void;
}
export interface MainThreadNotebookRenderersShape extends IDisposable {
$postMessage(editorId: string, rendererId: string, message: unknown): void;
}
export interface MainThreadUrlsShape extends IDisposable {
$registerUriHandler(handle: number, extensionId: ExtensionIdentifier): Promise<void>;
$unregisterUriHandler(handle: number): Promise<void>;
@@ -1312,6 +1317,7 @@ export type IResolveAuthorityResult = IResolveAuthorityErrorResult | IResolveAut
export interface ExtHostExtensionServiceShape {
$resolveAuthority(remoteAuthority: string, resolveAttempt: number): Promise<IResolveAuthorityResult>;
$getCanonicalURI(remoteAuthority: string, uri: UriComponents): Promise<UriComponents>;
$startExtensionHost(enabledExtensionIds: ExtensionIdentifier[]): Promise<void>;
$extensionTestsExecute(): Promise<number>;
$extensionTestsExit(code: number): Promise<void>;
@@ -1450,17 +1456,16 @@ export interface ISignatureHelpContextDto {
readonly activeSignatureHelp?: ISignatureHelpDto;
}
export interface IInlineHintDto {
export interface IInlayHintDto {
text: string;
range: IRange;
kind: modes.InlineHintKind;
position: IPosition;
kind: modes.InlayHintKind;
whitespaceBefore?: boolean;
whitespaceAfter?: boolean;
hoverMessage?: string;
}
export interface IInlineHintsDto {
hints: IInlineHintDto[]
export interface IInlayHintsDto {
hints: IInlayHintDto[]
}
export interface ILocationDto {
@@ -1653,9 +1658,12 @@ export interface ExtHostLanguageFeaturesShape {
$provideCompletionItems(handle: number, resource: UriComponents, position: IPosition, context: modes.CompletionContext, token: CancellationToken): Promise<ISuggestResultDto | undefined>;
$resolveCompletionItem(handle: number, id: ChainedCacheId, token: CancellationToken): Promise<ISuggestDataDto | undefined>;
$releaseCompletionItems(handle: number, id: number): void;
$provideInlineCompletions(handle: number, resource: UriComponents, position: IPosition, context: modes.InlineCompletionContext, token: CancellationToken): Promise<IdentifiableInlineCompletions | undefined>;
$handleInlineCompletionDidShow(handle: number, pid: number, idx: number): void;
$freeInlineCompletionsList(handle: number, pid: number): void;
$provideSignatureHelp(handle: number, resource: UriComponents, position: IPosition, context: modes.SignatureHelpContext, token: CancellationToken): Promise<ISignatureHelpDto | undefined>;
$releaseSignatureHelp(handle: number, id: number): void;
$provideInlineHints(handle: number, resource: UriComponents, range: IRange, token: CancellationToken): Promise<IInlineHintsDto | undefined>
$provideInlayHints(handle: number, resource: UriComponents, range: IRange, token: CancellationToken): Promise<IInlayHintsDto | undefined>
$provideDocumentLinks(handle: number, resource: UriComponents, token: CancellationToken): Promise<ILinksListDto | undefined>;
$resolveDocumentLink(handle: number, id: ChainedCacheId, token: CancellationToken): Promise<ILinkDto | undefined>;
$releaseDocumentLinks(handle: number, id: number): void;
@@ -1686,11 +1694,6 @@ export interface ExtHostTelemetryShape {
$onDidChangeTelemetryEnabled(enabled: boolean): void;
}
export interface IShellAndArgsDto {
shell: string;
args: string[] | string | undefined;
}
export interface ITerminalLinkDto {
/** The ID of the link to enable activation and disposal. */
id: number;
@@ -1724,11 +1727,11 @@ export interface ExtHostTerminalServiceShape {
$acceptProcessRequestInitialCwd(id: number): void;
$acceptProcessRequestCwd(id: number): void;
$acceptProcessRequestLatency(id: number): number;
$getAvailableProfiles(configuredProfilesOnly: boolean): Promise<ITerminalProfile[]>;
$getDefaultShellAndArgs(useAutomationShell: boolean): Promise<IShellAndArgsDto>;
$provideLinks(id: number, line: string): Promise<ITerminalLinkDto[]>;
$activateLink(id: number, linkId: number): void;
$initEnvironmentVariableCollections(collections: [string, ISerializableEnvironmentVariableCollection][]): void;
$acceptDefaultProfile(profile: ITerminalProfile, automationProfile: ITerminalProfile): void;
$createContributedProfileTerminal(id: string, isSplitTerminal: boolean): Promise<void>;
}
export interface ExtHostSCMShape {
@@ -1747,7 +1750,6 @@ export interface ExtHostTaskShape {
$onDidEndTaskProcess(value: tasks.TaskProcessEndedDTO): void;
$OnDidEndTask(execution: tasks.TaskExecutionDTO): void;
$resolveVariables(workspaceFolder: UriComponents, toResolve: { process?: { name: string; cwd?: string; }, variables: string[]; }): Promise<{ process?: string; variables: { [key: string]: string; }; }>;
$getDefaultShellAndArgs(): Thenable<{ shell: string, args: string[] | string | undefined; }>;
$jsonTasksSupported(): Thenable<boolean>;
$findExecutable(command: string, cwd?: string, paths?: string[]): Promise<string | undefined>;
}
@@ -1806,6 +1808,7 @@ export interface IDebugSessionFullDto {
id: DebugSessionUUID;
type: string;
name: string;
parent: DebugSessionUUID | undefined;
folderUri: UriComponents | undefined;
configuration: IConfig;
}
@@ -1913,22 +1916,7 @@ export interface INotebookDocumentsAndEditorsDelta {
visibleEditors?: string[];
}
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 {
export interface ExtHostNotebookShape extends ExtHostNotebookDocumentsAndEditorsShape {
$provideNotebookCellStatusBarItems(handle: number, uri: UriComponents, index: number, token: CancellationToken): Promise<INotebookCellStatusBarListDto | undefined>;
$releaseNotebookCellStatusBarItems(id: number): void;
@@ -1941,6 +1929,10 @@ export interface ExtHostNotebookShape extends ExtHostNotebookDocumentsAndEditors
$notebookToData(handle: number, data: NotebookDataDto, token: CancellationToken): Promise<VSBuffer>;
}
export interface ExtHostNotebookRenderersShape {
$postRendererMessage(editorId: string, rendererId: string, message: unknown): void;
}
export interface ExtHostNotebookDocumentsAndEditorsShape {
$acceptDocumentAndEditorsDelta(delta: INotebookDocumentsAndEditorsDelta): void;
}
@@ -1960,10 +1952,10 @@ export interface ExtHostNotebookEditorsShape {
}
export interface ExtHostNotebookKernelsShape {
$acceptSelection(handle: number, uri: UriComponents, value: boolean): void;
$acceptNotebookAssociation(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;
$acceptKernelMessageFromRenderer(handle: number, editorId: string, message: any): void;
}
export interface ExtHostStorageShape {
@@ -2094,6 +2086,7 @@ export const MainContext = {
MainThreadNotebookDocuments: createMainId<MainThreadNotebookDocumentsShape>('MainThreadNotebookDocumentsShape'),
MainThreadNotebookEditors: createMainId<MainThreadNotebookEditorsShape>('MainThreadNotebookEditorsShape'),
MainThreadNotebookKernels: createMainId<MainThreadNotebookKernelsShape>('MainThreadNotebookKernels'),
MainThreadNotebookRenderers: createMainId<MainThreadNotebookRenderersShape>('MainThreadNotebookRenderers'),
MainThreadTheming: createMainId<MainThreadThemingShape>('MainThreadTheming'),
MainThreadTunnelService: createMainId<MainThreadTunnelServiceShape>('MainThreadTunnelService'),
MainThreadTimeline: createMainId<MainThreadTimelineShape>('MainThreadTimeline'),
@@ -2140,7 +2133,10 @@ export const ExtHostContext = {
ExtHostOutputService: createMainId<ExtHostOutputServiceShape>('ExtHostOutputService'),
ExtHosLabelService: createMainId<ExtHostLabelServiceShape>('ExtHostLabelService'),
ExtHostNotebook: createMainId<ExtHostNotebookShape>('ExtHostNotebook'),
ExtHostNotebookDocuments: createMainId<ExtHostNotebookDocumentsShape>('ExtHostNotebookDocuments'),
ExtHostNotebookEditors: createMainId<ExtHostNotebookEditorsShape>('ExtHostNotebookEditors'),
ExtHostNotebookKernels: createMainId<ExtHostNotebookKernelsShape>('ExtHostNotebookKernels'),
ExtHostNotebookRenderers: createMainId<ExtHostNotebookRenderersShape>('ExtHostNotebookRenderers'),
ExtHostTheming: createMainId<ExtHostThemingShape>('ExtHostTheming'),
ExtHostTunnelService: createMainId<ExtHostTunnelServiceShape>('ExtHostTunnelService'),
ExtHostAuthentication: createMainId<ExtHostAuthenticationShape>('ExtHostAuthentication'),

View File

@@ -4,17 +4,14 @@
*--------------------------------------------------------------------------------------------*/
import { URI } from 'vs/base/common/uri';
import { DisposableStore } from 'vs/base/common/lifecycle';
import type * as vscode from 'vscode';
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import * as types from 'vs/workbench/api/common/extHostTypes';
import { IRawColorInfo, IWorkspaceEditDto, ICallHierarchyItemDto, IIncomingCallDto, IOutgoingCallDto } from 'vs/workbench/api/common/extHost.protocol';
import * as modes from 'vs/editor/common/modes';
import * as search from 'vs/workbench/contrib/search/common/search';
import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
import { ApiCommand, ApiCommandArgument, ApiCommandResult, ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
import { CustomCodeAction } from 'vs/workbench/api/common/extHostLanguageFeatures';
import { ICommandsExecutor, RemoveFromRecentlyOpenedAPICommand, OpenIssueReporter, OpenIssueReporterArgs } from './apiCommands';
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
import { IRange } from 'vs/editor/common/core/range';
import { IPosition } from 'vs/editor/common/core/position';
@@ -326,10 +323,10 @@ const newCommands: ApiCommand[] = [
),
// --- inline hints
new ApiCommand(
'vscode.executeInlineHintProvider', '_executeInlineHintProvider', 'Execute inline hints provider',
'vscode.executeInlayHintProvider', '_executeInlayHintProvider', 'Execute inlay hints provider',
[ApiCommandArgument.Uri, ApiCommandArgument.Range],
new ApiCommandResult<modes.InlineHint[], vscode.InlineHint[]>('A promise that resolves to an array of InlineHint objects', result => {
return result.map(typeConverters.InlineHint.to);
new ApiCommandResult<modes.InlayHint[], vscode.InlayHint[]>('A promise that resolves to an array of Inlay objects', result => {
return result.map(typeConverters.InlayHint.to);
})
),
// --- notebooks
@@ -420,63 +417,8 @@ export class ExtHostApiCommands {
static register(commands: ExtHostCommands) {
newCommands.forEach(commands.registerApiCommand, commands);
return new ExtHostApiCommands(commands).registerCommands();
}
private _commands: ExtHostCommands;
private readonly _disposables = new DisposableStore();
private constructor(commands: ExtHostCommands) {
this._commands = commands;
}
registerCommands() {
// -----------------------------------------------------------------
// The following commands are registered on both sides separately.
//
// We are trying to maintain backwards compatibility for cases where
// API commands are encoded as markdown links, for example.
// -----------------------------------------------------------------
type ICommandHandler = (...args: any[]) => any;
const adjustHandler = (handler: (executor: ICommandsExecutor, ...args: any[]) => any): ICommandHandler => {
return (...args: any[]) => {
return handler(this._commands, ...args);
};
};
this._register(RemoveFromRecentlyOpenedAPICommand.ID, adjustHandler(RemoveFromRecentlyOpenedAPICommand.execute), {
description: 'Removes an entry with the given path from the recently opened list.',
args: [
{ name: 'path', description: 'Path to remove from recently opened.', constraint: (value: any) => typeof value === 'string' }
]
});
this._register(OpenIssueReporter.ID, adjustHandler(OpenIssueReporter.execute), {
description: 'Opens the issue reporter with the provided extension id as the selected source',
args: [
{ name: 'extensionId', description: 'extensionId to report an issue on', constraint: (value: unknown) => typeof value === 'string' || (typeof value === 'object' && typeof (value as OpenIssueReporterArgs).extensionId === 'string') }
]
});
}
// --- command impl
/**
* @deprecated use the ApiCommand instead
*/
private _register(id: string, handler: (...args: any[]) => any, description?: ICommandHandlerDescription): void {
const disposable = this._commands.registerCommand(false, id, handler, this, description);
this._disposables.add(disposable);
}
}
function tryMapWith<T, R>(f: (x: T) => R) {

View File

@@ -48,11 +48,11 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
return Object.freeze(this._providers.slice());
}
async getSession(requestingExtension: IExtensionDescription, providerId: string, scopes: string[], options: vscode.AuthenticationGetSessionOptions & { createIfNone: true }): Promise<vscode.AuthenticationSession>;
async getSession(requestingExtension: IExtensionDescription, providerId: string, scopes: string[], options: vscode.AuthenticationGetSessionOptions = {}): Promise<vscode.AuthenticationSession | undefined> {
async getSession(requestingExtension: IExtensionDescription, providerId: string, scopes: readonly string[], options: vscode.AuthenticationGetSessionOptions & { createIfNone: true }): Promise<vscode.AuthenticationSession>;
async getSession(requestingExtension: IExtensionDescription, providerId: string, scopes: readonly string[], options: vscode.AuthenticationGetSessionOptions = {}): Promise<vscode.AuthenticationSession | undefined> {
const extensionId = ExtensionIdentifier.toKey(requestingExtension.identifier);
const inFlightRequests = this._inFlightRequests.get(extensionId) || [];
const sortedScopes = scopes.sort().join(' ');
const sortedScopes = [...scopes].sort().join(' ');
let inFlightRequest: GetSessionsRequest | undefined = inFlightRequests.find(request => request.scopes === sortedScopes);
if (inFlightRequest) {
@@ -81,7 +81,7 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
}
}
private async _getSession(requestingExtension: IExtensionDescription, extensionId: string, providerId: string, scopes: string[], options: vscode.AuthenticationGetSessionOptions = {}): Promise<vscode.AuthenticationSession | undefined> {
private async _getSession(requestingExtension: IExtensionDescription, extensionId: string, providerId: string, scopes: readonly string[], options: vscode.AuthenticationGetSessionOptions = {}): Promise<vscode.AuthenticationSession | undefined> {
await this._proxy.$ensureProvider(providerId);
const extensionName = requestingExtension.displayName || requestingExtension.name;
return this._proxy.$getSession(providerId, scopes, extensionId, extensionName, options);

View File

@@ -8,10 +8,9 @@ import { DisposableStore } from 'vs/base/common/lifecycle';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { ExtHostTextEditor } from 'vs/workbench/api/common/extHostTextEditor';
import { ExtHostEditors } from 'vs/workbench/api/common/extHostTextEditors';
import { asWebviewUri, webviewGenericCspSource, WebviewInitData } from 'vs/workbench/api/common/shared/webview';
import type * as vscode from 'vscode';
import { ExtHostEditorInsetsShape, MainThreadEditorInsetsShape } from './extHost.protocol';
import { asWebviewUri, WebviewInitData } from 'vs/workbench/api/common/shared/webview';
import { generateUuid } from 'vs/base/common/uuid';
export class ExtHostEditorInsets implements ExtHostEditorInsetsShape {
@@ -61,16 +60,15 @@ export class ExtHostEditorInsets implements ExtHostEditorInsetsShape {
const webview = new class implements vscode.Webview {
private readonly _uuid = generateUuid();
private _html: string = '';
private _options: vscode.WebviewOptions = Object.create(null);
asWebviewUri(resource: vscode.Uri): vscode.Uri {
return asWebviewUri(that._initData, this._uuid, resource);
return asWebviewUri(resource, that._initData.remote);
}
get cspSource(): string {
return that._initData.webviewCspSource;
return webviewGenericCspSource;
}
set options(value: vscode.WebviewOptions) {

View File

@@ -170,12 +170,12 @@ export class ExtHostCommands implements ExtHostCommandsShape {
const toArgs = cloneAndChange(args, function (value) {
if (value instanceof extHostTypes.Position) {
return extHostTypeConverter.Position.from(value);
}
if (value instanceof extHostTypes.Range) {
} else if (value instanceof extHostTypes.Range) {
return extHostTypeConverter.Range.from(value);
}
if (value instanceof extHostTypes.Location) {
} else if (value instanceof extHostTypes.Location) {
return extHostTypeConverter.location.from(value);
} else if (extHostTypes.NotebookRange.isNotebookRange(value)) {
return extHostTypeConverter.NotebookRange.from(value);
}
if (!Array.isArray(value)) {
return value;

View File

@@ -31,6 +31,7 @@ import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { withNullAsUndefined } from 'vs/base/common/types';
import * as process from 'vs/base/common/process';
import { IExtHostEditorTabs } from 'vs/workbench/api/common/extHostEditorTabs';
export const IExtHostDebugService = createDecorator<IExtHostDebugService>('IExtHostDebugService');
@@ -47,8 +48,8 @@ export interface IExtHostDebugService extends ExtHostDebugServiceShape {
onDidChangeBreakpoints: Event<vscode.BreakpointsChangeEvent>;
breakpoints: vscode.Breakpoint[];
addBreakpoints(breakpoints0: vscode.Breakpoint[]): Promise<void>;
removeBreakpoints(breakpoints0: vscode.Breakpoint[]): Promise<void>;
addBreakpoints(breakpoints0: readonly vscode.Breakpoint[]): Promise<void>;
removeBreakpoints(breakpoints0: readonly vscode.Breakpoint[]): Promise<void>;
startDebugging(folder: vscode.WorkspaceFolder | undefined, nameOrConfig: string | vscode.DebugConfiguration, options: vscode.DebugSessionOptions): Promise<boolean>;
stopDebugging(session?: vscode.DebugSession): Promise<void>;
registerDebugConfigurationProvider(type: string, provider: vscode.DebugConfigurationProvider, trigger: vscode.DebugConfigurationProviderTriggerKind): vscode.Disposable;
@@ -109,6 +110,7 @@ export abstract class ExtHostDebugServiceBase implements IExtHostDebugService, E
@IExtHostExtensionService private _extensionService: IExtHostExtensionService,
@IExtHostDocumentsAndEditors private _editorsService: IExtHostDocumentsAndEditors,
@IExtHostConfiguration protected _configurationService: IExtHostConfiguration,
@IExtHostEditorTabs protected _editorTabs: IExtHostEditorTabs
) {
this._configProviderHandleCounter = 0;
this._configProviders = [];
@@ -843,7 +845,8 @@ export abstract class ExtHostDebugServiceBase implements IExtHostDebugService, E
let ds = this._debugSessions.get(dto.id);
if (!ds) {
const folder = await this.getFolder(dto.folderUri);
ds = new ExtHostDebugSession(this._debugServiceProxy, dto.id, dto.type, dto.name, folder, dto.configuration);
const parent = dto.parent ? this._debugSessions.get(dto.parent) : undefined;
ds = new ExtHostDebugSession(this._debugServiceProxy, dto.id, dto.type, dto.name, folder, dto.configuration, parent);
this._debugSessions.set(ds.id, ds);
this._debugServiceProxy.$sessionCached(ds.id);
}
@@ -870,7 +873,8 @@ export class ExtHostDebugSession implements vscode.DebugSession {
private _type: string,
private _name: string,
private _workspaceFolder: vscode.WorkspaceFolder | undefined,
private _configuration: vscode.DebugConfiguration) {
private _configuration: vscode.DebugConfiguration,
private _parentSession: vscode.DebugSession | undefined) {
}
public get id(): string {
@@ -884,12 +888,15 @@ export class ExtHostDebugSession implements vscode.DebugSession {
public get name(): string {
return this._name;
}
public set name(name: string) {
this._name = name;
this._debugServiceProxy.$setDebugSessionName(this._id, name);
}
public get parentSession(): vscode.DebugSession | undefined {
return this._parentSession;
}
_acceptNameChanged(name: string) {
this._name = name;
}
@@ -930,7 +937,21 @@ export class ExtHostDebugConsole {
export class ExtHostVariableResolverService extends AbstractVariableResolverService {
constructor(folders: vscode.WorkspaceFolder[], editorService: ExtHostDocumentsAndEditors | undefined, configurationService: ExtHostConfigProvider, workspaceService?: IExtHostWorkspace) {
constructor(folders: vscode.WorkspaceFolder[], editorService: ExtHostDocumentsAndEditors | undefined, configurationService: ExtHostConfigProvider, editorTabs: IExtHostEditorTabs, workspaceService?: IExtHostWorkspace) {
function getActiveUri(): URI | undefined {
if (editorService) {
const activeEditor = editorService.activeEditor();
if (activeEditor) {
return activeEditor.document.uri;
}
const tabs = editorTabs.tabs.filter(tab => tab.isActive);
if (tabs.length > 0) {
return tabs[0].resource;
}
}
return undefined;
}
super({
getFolderUri: (folderName: string): URI | undefined => {
const found = folders.filter(f => f.name === folderName);
@@ -952,19 +973,17 @@ export class ExtHostVariableResolverService extends AbstractVariableResolverServ
return process.env['VSCODE_EXEC_PATH'];
},
getFilePath: (): string | undefined => {
if (editorService) {
const activeEditor = editorService.activeEditor();
if (activeEditor) {
return path.normalize(activeEditor.document.uri.fsPath);
}
const activeUri = getActiveUri();
if (activeUri) {
return path.normalize(activeUri.fsPath);
}
return undefined;
},
getWorkspaceFolderPathForFile: (): string | undefined => {
if (editorService && workspaceService) {
const activeEditor = editorService.activeEditor();
if (activeEditor) {
const ws = workspaceService.getWorkspaceFolder(activeEditor.document.uri);
if (workspaceService) {
const activeUri = getActiveUri();
if (activeUri) {
const ws = workspaceService.getWorkspaceFolder(activeUri);
if (ws) {
return path.normalize(ws.uri.fsPath);
}
@@ -1076,12 +1095,13 @@ export class WorkerExtHostDebugService extends ExtHostDebugServiceBase {
@IExtHostWorkspace workspaceService: IExtHostWorkspace,
@IExtHostExtensionService extensionService: IExtHostExtensionService,
@IExtHostDocumentsAndEditors editorsService: IExtHostDocumentsAndEditors,
@IExtHostConfiguration configurationService: IExtHostConfiguration
@IExtHostConfiguration configurationService: IExtHostConfiguration,
@IExtHostEditorTabs editorTabs: IExtHostEditorTabs
) {
super(extHostRpcService, workspaceService, extensionService, editorsService, configurationService);
super(extHostRpcService, workspaceService, extensionService, editorsService, configurationService, editorTabs);
}
protected createVariableResolver(folders: vscode.WorkspaceFolder[], editorService: ExtHostDocumentsAndEditors, configurationService: ExtHostConfigProvider): AbstractVariableResolverService {
return new ExtHostVariableResolverService(folders, editorService, configurationService);
return new ExtHostVariableResolverService(folders, editorService, configurationService, this._editorTabs);
}
}

View File

@@ -217,7 +217,7 @@ export class ExtHostDiagnostics implements ExtHostDiagnosticsShape {
private readonly _collections = new Map<string, DiagnosticCollection>();
private readonly _onDidChangeDiagnostics = new Emitter<vscode.Uri[]>();
static _debouncer(last: (vscode.Uri | string)[] | undefined, current: (vscode.Uri | string)[]): (vscode.Uri | string)[] {
static _debouncer(last: vscode.Uri[] | undefined, current: vscode.Uri[]): vscode.Uri[] {
if (!last) {
return current;
} else {
@@ -225,24 +225,12 @@ export class ExtHostDiagnostics implements ExtHostDiagnosticsShape {
}
}
static _mapper(last: (vscode.Uri | string)[]): { uris: vscode.Uri[] } {
const uris: vscode.Uri[] = [];
const map = new Set<string>();
static _mapper(last: vscode.Uri[]): { uris: readonly vscode.Uri[] } {
const map = new ResourceMap<vscode.Uri>();
for (const uri of last) {
if (typeof uri === 'string') {
if (!map.has(uri)) {
map.add(uri);
uris.push(URI.parse(uri));
}
} else {
if (!map.has(uri.toString())) {
map.add(uri.toString());
uris.push(uri);
}
}
map.set(uri, uri);
}
Object.freeze(uris);
return { uris };
return { uris: Object.freeze(Array.from(map.values())) };
}
readonly onDidChangeDiagnostics: Event<vscode.DiagnosticChangeEvent> = Event.map(Event.debounce(this._onDidChangeDiagnostics.event, ExtHostDiagnostics._debouncer, 50), ExtHostDiagnostics._mapper);

View File

@@ -7,15 +7,25 @@ import type * as vscode from 'vscode';
import { IEditorTabDto, IExtHostEditorTabsShape } from 'vs/workbench/api/common/extHost.protocol';
import { URI } from 'vs/base/common/uri';
import { Emitter, Event } from 'vs/base/common/event';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
export interface IEditorTab {
name: string;
group: number;
resource: vscode.Uri
isActive: boolean
}
export class ExtHostEditorTabs implements IExtHostEditorTabsShape {
export interface IExtHostEditorTabs extends IExtHostEditorTabsShape {
readonly _serviceBrand: undefined;
tabs: readonly IEditorTab[];
onDidChangeTabs: Event<void>;
}
export const IExtHostEditorTabs = createDecorator<IExtHostEditorTabs>('IExtHostEditorTabs');
export class ExtHostEditorTabs implements IExtHostEditorTabs {
readonly _serviceBrand: undefined;
private readonly _onDidChangeTabs = new Emitter<void>();
readonly onDidChangeTabs: Event<void> = this._onDidChangeTabs.event;
@@ -31,7 +41,8 @@ export class ExtHostEditorTabs implements IExtHostEditorTabsShape {
return {
name: dto.name,
group: dto.group,
resource: URI.revive(dto.resource)
resource: URI.revive(dto.resource),
isActive: dto.isActive
};
});
this._onDidChangeTabs.fire();

View File

@@ -7,10 +7,10 @@ import * as nls from 'vs/nls';
import * as path from 'vs/base/common/path';
import * as performance from 'vs/base/common/performance';
import { originalFSPath, joinPath } from 'vs/base/common/resources';
import { Barrier, timeout } from 'vs/base/common/async';
import { asPromise, Barrier, timeout } from 'vs/base/common/async';
import { dispose, toDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle';
import { TernarySearchTree } from 'vs/base/common/map';
import { URI } from 'vs/base/common/uri';
import { URI, UriComponents } from 'vs/base/common/uri';
import { ILogService } from 'vs/platform/log/common/log';
import { ExtHostExtensionServiceShape, IInitData, MainContext, MainThreadExtensionServiceShape, MainThreadTelemetryShape, MainThreadWorkspaceShape, IResolveAuthorityResult } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostConfiguration, IExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
@@ -292,19 +292,19 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
try {
if (typeof extension.module.deactivate === 'function') {
result = Promise.resolve(extension.module.deactivate()).then(undefined, (err) => {
// TODO: Do something with err if this is not the shutdown case
this._logService.error(err);
return Promise.resolve(undefined);
});
}
} catch (err) {
// TODO: Do something with err if this is not the shutdown case
this._logService.error(err);
}
// clean up subscriptions
try {
dispose(extension.subscriptions);
} catch (err) {
// TODO: Do something with err if this is not the shutdown case
this._logService.error(err);
}
return result;
@@ -631,7 +631,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
// -- called by main thread
public async $resolveAuthority(remoteAuthority: string, resolveAttempt: number): Promise<IResolveAuthorityResult> {
private async _activateAndGetResolver(remoteAuthority: string): Promise<{ authorityPrefix: string; resolver: vscode.RemoteAuthorityResolver | undefined; }> {
const authorityPlusIndex = remoteAuthority.indexOf('+');
if (authorityPlusIndex === -1) {
throw new Error(`Not an authority that can be resolved!`);
@@ -641,7 +641,12 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
await this._almostReadyToRunExtensions.wait();
await this._activateByEvent(`onResolveRemoteAuthority:${authorityPrefix}`, false);
const resolver = this._resolvers[authorityPrefix];
return { authorityPrefix, resolver: this._resolvers[authorityPrefix] };
}
public async $resolveAuthority(remoteAuthority: string, resolveAttempt: number): Promise<IResolveAuthorityResult> {
const { authorityPrefix, resolver } = await this._activateAndGetResolver(remoteAuthority);
if (!resolver) {
return {
type: 'error',
@@ -668,7 +673,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
};
const options: ResolvedOptions = {
extensionHostEnv: result.extensionHostEnv,
trust: result.trust
isTrusted: result.isTrusted
};
return {
@@ -695,6 +700,28 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
}
}
public async $getCanonicalURI(remoteAuthority: string, uriComponents: UriComponents): Promise<UriComponents> {
const { authorityPrefix, resolver } = await this._activateAndGetResolver(remoteAuthority);
if (!resolver) {
throw new Error(`Cannot get canonical URI because no remote extension is installed to resolve ${authorityPrefix}`);
}
const uri = URI.revive(uriComponents);
if (typeof resolver.getCanonicalURI === 'undefined') {
// resolver cannot compute canonical URI
return uri;
}
const result = await asPromise(() => resolver.getCanonicalURI!(uri));
if (!result) {
return uri;
}
return result;
}
public $startExtensionHost(enabledExtensionIds: ExtensionIdentifier[]): Promise<void> {
this._registry.keepOnly(enabledExtensionIds);
return this._startExtensionHost();

View File

@@ -115,6 +115,7 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
private readonly _fsProvider = new Map<number, vscode.FileSystemProvider>();
private readonly _registeredSchemes = new Set<string>();
private readonly _watches = new Map<number, IDisposable>();
private readonly _enableProposedApi = new Map<number, boolean>();
private _linkProviderRegistration?: IDisposable;
private _handlePool: number = 0;
@@ -133,7 +134,7 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
}
}
registerFileSystemProvider(extension: ExtensionIdentifier, scheme: string, provider: vscode.FileSystemProvider, options: { isCaseSensitive?: boolean, isReadonly?: boolean } = {}) {
registerFileSystemProvider(extension: ExtensionIdentifier, scheme: string, provider: vscode.FileSystemProvider, options: { isCaseSensitive?: boolean, isReadonly?: boolean } = {}, enableProposedApi?: boolean) {
if (this._registeredSchemes.has(scheme)) {
throw new Error(`a provider for the scheme '${scheme}' is already registered`);
@@ -146,6 +147,7 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
this._linkProvider.add(scheme);
this._registeredSchemes.add(scheme);
this._fsProvider.set(handle, provider);
this._enableProposedApi.set(handle, enableProposedApi ?? false);
let capabilities = files.FileSystemProviderCapabilities.FileReadWrite;
if (options.isCaseSensitive) {
@@ -200,17 +202,22 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
this._linkProvider.delete(scheme);
this._registeredSchemes.delete(scheme);
this._fsProvider.delete(handle);
this._enableProposedApi.delete(handle);
this._proxy.$unregisterProvider(handle);
});
}
private static _asIStat(stat: vscode.FileStat): files.IStat {
const { type, ctime, mtime, size } = stat;
return { type, ctime, mtime, size };
private static _asIStat(stat: vscode.FileStat, enableProposedApi: boolean): files.IStat {
const { type, ctime, mtime, size, permissions } = stat;
if (enableProposedApi) {
return { type, ctime, mtime, size, permissions };
} else {
return { type, ctime, mtime, size };
}
}
$stat(handle: number, resource: UriComponents): Promise<files.IStat> {
return Promise.resolve(this._getFsProvider(handle).stat(URI.revive(resource))).then(ExtHostFileSystem._asIStat);
return Promise.resolve(this._getFsProvider(handle).stat(URI.revive(resource))).then(stat => ExtHostFileSystem._asIStat(stat, this._enableProposedApi.get(handle) ?? false));
}
$readdir(handle: number, resource: UriComponents): Promise<[string, files.FileType][]> {

View File

@@ -24,4 +24,4 @@ export class ExtHostLabelService implements ExtHostLabelServiceShape {
this._proxy.$unregisterResourceLabelFormatter(handle);
});
}
}
}

View File

@@ -19,7 +19,7 @@ import { regExpLeadsToEndlessLoop, regExpFlags } from 'vs/base/common/strings';
import { IPosition } from 'vs/editor/common/core/position';
import { IRange, Range as EditorRange } from 'vs/editor/common/core/range';
import { isFalsyOrEmpty, isNonEmptyArray, coalesce, asArray } from 'vs/base/common/arrays';
import { isObject } from 'vs/base/common/types';
import { isArray, isObject } from 'vs/base/common/types';
import { ISelection, Selection } from 'vs/editor/common/core/selection';
import { ILogService } from 'vs/platform/log/common/log';
import { CancellationToken } from 'vs/base/common/cancellation';
@@ -33,6 +33,7 @@ import { IExtHostApiDeprecationService } from 'vs/workbench/api/common/extHostAp
import { Cache } from './cache';
import { StopWatch } from 'vs/base/common/stopwatch';
import { CancellationError } from 'vs/base/common/errors';
import { Emitter } from 'vs/base/common/event';
// --- adapter
@@ -1038,6 +1039,99 @@ class SuggestAdapter {
}
}
class InlineCompletionAdapter {
private readonly _cache = new Cache<vscode.InlineCompletionItem>('InlineCompletionItem');
private readonly _disposables = new Map<number, DisposableStore>();
constructor(
private readonly _documents: ExtHostDocuments,
private readonly _provider: vscode.InlineCompletionItemProvider,
private readonly _commands: CommandsConverter,
) { }
public async provideInlineCompletions(resource: URI, position: IPosition, context: vscode.InlineCompletionContext, token: CancellationToken): Promise<extHostProtocol.IdentifiableInlineCompletions | undefined> {
const doc = this._documents.getDocument(resource);
const pos = typeConvert.Position.to(position);
const result = await asPromise(() => this._provider.provideInlineCompletionItems(doc, pos, context, token));
if (!result) {
// undefined and null are valid results
return undefined;
}
if (token.isCancellationRequested) {
// cancelled -> return without further ado, esp no caching
// of results as they will leak
return undefined;
}
const normalizedResult: vscode.InlineCompletionList = isArray(result) ? { items: result } : result;
const pid = this._cache.add(normalizedResult.items);
let disposableStore: DisposableStore | undefined = undefined;
return {
pid,
items: normalizedResult.items.map<extHostProtocol.IdentifiableInlineCompletion>((item, idx) => {
let command: modes.Command | undefined = undefined;
if (item.command) {
if (!disposableStore) {
disposableStore = new DisposableStore();
this._disposables.set(pid, disposableStore);
}
command = this._commands.toInternal(item.command, disposableStore);
}
return ({
text: item.text,
range: item.range ? typeConvert.Range.from(item.range) : undefined,
command,
idx: idx,
});
}),
};
}
public disposeCompletions(pid: number) {
this._cache.delete(pid);
const d = this._disposables.get(pid);
if (d) {
d.clear();
}
this._disposables.delete(pid);
}
public handleDidShowCompletionItem(pid: number, idx: number): void {
const completionItem = this._cache.get(pid, idx);
if (completionItem) {
InlineCompletionController.get(this._provider).fireOnDidShowCompletionItem({
completionItem
});
}
}
}
export class InlineCompletionController<T extends vscode.InlineCompletionItem> implements vscode.InlineCompletionController<T> {
private static readonly map = new WeakMap<vscode.InlineCompletionItemProvider<any>, InlineCompletionController<any>>();
public static get<T extends vscode.InlineCompletionItem>(provider: vscode.InlineCompletionItemProvider<T>): InlineCompletionController<T> {
let existing = InlineCompletionController.map.get(provider);
if (!existing) {
existing = new InlineCompletionController();
InlineCompletionController.map.set(provider, existing);
}
return existing;
}
private readonly _onDidShowCompletionItemEmitter = new Emitter<vscode.InlineCompletionItemDidShowEvent<T>>();
public readonly onDidShowCompletionItem: vscode.Event<vscode.InlineCompletionItemDidShowEvent<T>> = this._onDidShowCompletionItemEmitter.event;
public fireOnDidShowCompletionItem(event: vscode.InlineCompletionItemDidShowEvent<T>): void {
this._onDidShowCompletionItemEmitter.fire(event);
}
}
class SignatureHelpAdapter {
private readonly _cache = new Cache<vscode.SignatureHelp>('SignatureHelp');
@@ -1082,16 +1176,16 @@ class SignatureHelpAdapter {
}
}
class InlineHintsAdapter {
class InlayHintsAdapter {
constructor(
private readonly _documents: ExtHostDocuments,
private readonly _provider: vscode.InlineHintsProvider,
private readonly _provider: vscode.InlayHintsProvider,
) { }
provideInlineHints(resource: URI, range: IRange, token: CancellationToken): Promise<extHostProtocol.IInlineHintsDto | undefined> {
provideInlayHints(resource: URI, range: IRange, token: CancellationToken): Promise<extHostProtocol.IInlayHintsDto | undefined> {
const doc = this._documents.getDocument(resource);
return asPromise(() => this._provider.provideInlineHints(doc, typeConvert.Range.to(range), token)).then(value => {
return value ? { hints: value.map(typeConvert.InlineHint.from) } : undefined;
return asPromise(() => this._provider.provideInlayHints(doc, typeConvert.Range.to(range), token)).then(value => {
return value ? { hints: value.map(typeConvert.InlayHint.from) } : undefined;
});
}
}
@@ -1105,50 +1199,62 @@ class LinkProviderAdapter {
private readonly _provider: vscode.DocumentLinkProvider
) { }
provideLinks(resource: URI, token: CancellationToken): Promise<extHostProtocol.ILinksListDto | undefined> {
async provideLinks(resource: URI, token: CancellationToken): Promise<extHostProtocol.ILinksListDto | undefined> {
const doc = this._documents.getDocument(resource);
return asPromise(() => this._provider.provideDocumentLinks(doc, token)).then(links => {
if (!Array.isArray(links) || links.length === 0) {
// bad result
return undefined;
}
const links = await asPromise(() => this._provider.provideDocumentLinks(doc, token));
if (!Array.isArray(links) || links.length === 0) {
// bad result
return undefined;
}
if (token.isCancellationRequested) {
// cancelled -> return without further ado, esp no caching
// of results as they will leak
return undefined;
}
if (typeof this._provider.resolveDocumentLink !== 'function') {
// no resolve -> no caching
return { links: links.filter(LinkProviderAdapter._validateLink).map(typeConvert.DocumentLink.from) };
if (token.isCancellationRequested) {
// cancelled -> return without further ado, esp no caching
// of results as they will leak
return undefined;
}
} else {
// cache links for future resolving
const pid = this._cache.add(links);
const result: extHostProtocol.ILinksListDto = { links: [], id: pid };
for (let i = 0; i < links.length; i++) {
if (typeof this._provider.resolveDocumentLink !== 'function') {
// no resolve -> no caching
return { links: links.map(typeConvert.DocumentLink.from) };
} else {
// cache links for future resolving
const pid = this._cache.add(links);
const result: extHostProtocol.ILinksListDto = { links: [], id: pid };
for (let i = 0; i < links.length; i++) {
const dto: extHostProtocol.ILinkDto = typeConvert.DocumentLink.from(links[i]);
dto.cacheId = [pid, i];
result.links.push(dto);
if (!LinkProviderAdapter._validateLink(links[i])) {
continue;
}
return result;
const dto: extHostProtocol.ILinkDto = typeConvert.DocumentLink.from(links[i]);
dto.cacheId = [pid, i];
result.links.push(dto);
}
});
return result;
}
}
resolveLink(id: extHostProtocol.ChainedCacheId, token: CancellationToken): Promise<extHostProtocol.ILinkDto | undefined> {
private static _validateLink(link: vscode.DocumentLink): boolean {
if (link.target && link.target.path.length > 50_000) {
console.warn('DROPPING link because it is too long');
return false;
}
return true;
}
async resolveLink(id: extHostProtocol.ChainedCacheId, token: CancellationToken): Promise<extHostProtocol.ILinkDto | undefined> {
if (typeof this._provider.resolveDocumentLink !== 'function') {
return Promise.resolve(undefined);
return undefined;
}
const item = this._cache.get(...id);
if (!item) {
return Promise.resolve(undefined);
return undefined;
}
return asPromise(() => this._provider.resolveDocumentLink!(item, token)).then(value => {
return value && typeConvert.DocumentLink.from(value) || undefined;
});
const link = await asPromise(() => this._provider.resolveDocumentLink!(item, token));
if (!link || !LinkProviderAdapter._validateLink(link)) {
return undefined;
}
return typeConvert.DocumentLink.from(link);
}
releaseLinks(id: number): any {
@@ -1355,7 +1461,7 @@ type Adapter = DocumentSymbolAdapter | CodeLensAdapter | DefinitionAdapter | Hov
| TypeDefinitionAdapter | ColorProviderAdapter | FoldingProviderAdapter | DeclarationAdapter
| SelectionRangeAdapter | CallHierarchyAdapter | DocumentSemanticTokensAdapter | DocumentRangeSemanticTokensAdapter
| EvaluatableExpressionAdapter | InlineValuesAdapter
| LinkedEditingRangeAdapter | InlineHintsAdapter;
| LinkedEditingRangeAdapter | InlayHintsAdapter | InlineCompletionAdapter;
class AdapterData {
constructor(
@@ -1809,6 +1915,28 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF
this._withAdapter(handle, SuggestAdapter, adapter => adapter.releaseCompletionItems(id), undefined);
}
// --- ghost test
registerInlineCompletionsProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.InlineCompletionItemProvider): vscode.Disposable {
const handle = this._addNewAdapter(new InlineCompletionAdapter(this._documents, provider, this._commands.converter), extension);
this._proxy.$registerInlineCompletionsSupport(handle, this._transformDocumentSelector(selector));
return this._createDisposable(handle);
}
$provideInlineCompletions(handle: number, resource: UriComponents, position: IPosition, context: modes.InlineCompletionContext, token: CancellationToken): Promise<extHostProtocol.IdentifiableInlineCompletions | undefined> {
return this._withAdapter(handle, InlineCompletionAdapter, adapter => adapter.provideInlineCompletions(URI.revive(resource), position, context, token), undefined);
}
$handleInlineCompletionDidShow(handle: number, pid: number, idx: number): void {
this._withAdapter(handle, InlineCompletionAdapter, async adapter => {
adapter.handleDidShowCompletionItem(pid, idx);
}, undefined);
}
$freeInlineCompletionsList(handle: number, pid: number): void {
this._withAdapter(handle, InlineCompletionAdapter, async adapter => { adapter.disposeCompletions(pid); }, undefined);
}
// --- parameter hints
registerSignatureHelpProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.SignatureHelpProvider, metadataOrTriggerChars: string[] | vscode.SignatureHelpProviderMetadata): vscode.Disposable {
@@ -1831,23 +1959,23 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF
// --- inline hints
registerInlineHintsProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.InlineHintsProvider): vscode.Disposable {
registerInlayHintsProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.InlayHintsProvider): vscode.Disposable {
const eventHandle = typeof provider.onDidChangeInlineHints === 'function' ? this._nextHandle() : undefined;
const handle = this._addNewAdapter(new InlineHintsAdapter(this._documents, provider), extension);
const eventHandle = typeof provider.onDidChangeInlayHints === 'function' ? this._nextHandle() : undefined;
const handle = this._addNewAdapter(new InlayHintsAdapter(this._documents, provider), extension);
this._proxy.$registerInlineHintsProvider(handle, this._transformDocumentSelector(selector), eventHandle);
this._proxy.$registerInlayHintsProvider(handle, this._transformDocumentSelector(selector), eventHandle);
let result = this._createDisposable(handle);
if (eventHandle !== undefined) {
const subscription = provider.onDidChangeInlineHints!(_ => this._proxy.$emitInlineHintsEvent(eventHandle));
const subscription = provider.onDidChangeInlayHints!(_ => this._proxy.$emitInlayHintsEvent(eventHandle));
result = Disposable.from(result, subscription);
}
return result;
}
$provideInlineHints(handle: number, resource: UriComponents, range: IRange, token: CancellationToken): Promise<extHostProtocol.IInlineHintsDto | undefined> {
return this._withAdapter(handle, InlineHintsAdapter, adapter => adapter.provideInlineHints(URI.revive(resource), range, token), undefined);
$provideInlayHints(handle: number, resource: UriComponents, range: IRange, token: CancellationToken): Promise<extHostProtocol.IInlayHintsDto | undefined> {
return this._withAdapter(handle, InlayHintsAdapter, adapter => adapter.provideInlayHints(URI.revive(resource), range, token), undefined);
}
// --- links

View File

@@ -56,6 +56,11 @@ export class ExtensionMemento implements vscode.Memento {
}, 0);
}
get keys(): readonly string[] {
// Filter out `undefined` values, as they can stick around in the `_value` until the `onDidChangeStorage` event runs
return Object.entries(this._value ?? {}).filter(([, value]) => value !== undefined).map(([key]) => key);
}
get whenReady(): Promise<ExtensionMemento> {
return this._init;
}

View File

@@ -3,54 +3,31 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { timeout } from 'vs/base/common/async';
import { VSBuffer } from 'vs/base/common/buffer';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { CancellationToken } from 'vs/base/common/cancellation';
import { Emitter, Event } from 'vs/base/common/event';
import { IRelativePattern } from 'vs/base/common/glob';
import { hash } from 'vs/base/common/hash';
import { IdGenerator } from 'vs/base/common/idGenerator';
import { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { ResourceMap } from 'vs/base/common/map';
import { isFalsyOrWhitespace } from 'vs/base/common/strings';
import { assertIsDefined } from 'vs/base/common/types';
import { URI, UriComponents } from 'vs/base/common/uri';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { ILogService } from 'vs/platform/log/common/log';
import { Cache } from 'vs/workbench/api/common/cache';
import { ExtHostNotebookShape, IMainContext, IModelAddedData, INotebookCellStatusBarListDto, INotebookDocumentPropertiesChangeData, INotebookDocumentsAndEditorsDelta, INotebookDocumentShowOptions, INotebookEditorAddData, INotebookEditorPropertiesChangeData, INotebookEditorViewColumnInfo, MainContext, MainThreadNotebookDocumentsShape, MainThreadNotebookEditorsShape, MainThreadNotebookShape } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostNotebookShape, IMainContext, IModelAddedData, INotebookCellStatusBarListDto, INotebookDocumentsAndEditorsDelta, INotebookDocumentShowOptions, INotebookEditorAddData, MainContext, MainThreadNotebookDocumentsShape, MainThreadNotebookEditorsShape, MainThreadNotebookShape } from 'vs/workbench/api/common/extHost.protocol';
import { CommandsConverter, ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
import { CellEditType, IImmediateCellEditOperation, INotebookExclusiveDocumentFilter, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookDataDto, NullablePartialNotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookExclusiveDocumentFilter, INotebookContributionData, NotebookCellsChangeType, NotebookDataDto } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import type * as vscode from 'vscode';
import { ExtHostCell, ExtHostNotebookDocument } from './extHostNotebookDocument';
import { ExtHostNotebookEditor } from './extHostNotebookEditor';
export class NotebookEditorDecorationType {
private static readonly _Keys = new IdGenerator('NotebookEditorDecorationType');
readonly value: vscode.NotebookEditorDecorationType;
constructor(proxy: MainThreadNotebookEditorsShape, options: vscode.NotebookDecorationRenderOptions) {
const key = NotebookEditorDecorationType._Keys.nextId();
proxy.$registerNotebookEditorDecorationType(key, typeConverters.NotebookDecorationRenderOptions.from(options));
this.value = {
key,
dispose() {
proxy.$removeNotebookEditorDecorationType(key);
}
};
}
}
type NotebookContentProviderData = {
readonly provider: vscode.NotebookContentProvider;
readonly extension: IExtensionDescription;
@@ -68,12 +45,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
private readonly _documents = new ResourceMap<ExtHostNotebookDocument>();
private readonly _editors = new Map<string, ExtHostNotebookEditor>();
private readonly _commandsConverter: CommandsConverter;
private readonly _onDidChangeNotebookEditorSelection = new Emitter<vscode.NotebookEditorSelectionChangeEvent>();
readonly onDidChangeNotebookEditorSelection = this._onDidChangeNotebookEditorSelection.event;
private readonly _onDidChangeNotebookEditorVisibleRanges = new Emitter<vscode.NotebookEditorVisibleRangesChangeEvent>();
readonly onDidChangeNotebookEditorVisibleRanges = this._onDidChangeNotebookEditorVisibleRanges.event;
private readonly _onDidChangeNotebookDocumentMetadata = new Emitter<vscode.NotebookDocumentMetadataChangeEvent>();
readonly onDidChangeNotebookDocumentMetadata = this._onDidChangeNotebookDocumentMetadata.event;
private readonly _onDidChangeNotebookCells = new Emitter<vscode.NotebookCellsChangeEvent>();
readonly onDidChangeNotebookCells = this._onDidChangeNotebookCells.event;
private readonly _onDidChangeCellOutputs = new Emitter<vscode.NotebookCellOutputsChangeEvent>();
@@ -98,13 +70,10 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
onDidOpenNotebookDocument: Event<vscode.NotebookDocument> = this._onDidOpenNotebookDocument.event;
private _onDidCloseNotebookDocument = new Emitter<vscode.NotebookDocument>();
onDidCloseNotebookDocument: Event<vscode.NotebookDocument> = this._onDidCloseNotebookDocument.event;
private _onDidSaveNotebookDocument = new Emitter<vscode.NotebookDocument>();
onDidSaveNotebookDocument: Event<vscode.NotebookDocument> = this._onDidSaveNotebookDocument.event;
private _onDidChangeVisibleNotebookEditors = new Emitter<vscode.NotebookEditor[]>();
onDidChangeVisibleNotebookEditors = this._onDidChangeVisibleNotebookEditors.event;
private _activeExecutions = new ResourceMap<NotebookCellExecutionTask>();
private _statusBarCache = new Cache<IDisposable>('NotebookCellStatusBarCache');
constructor(
@@ -112,7 +81,6 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
commands: ExtHostCommands,
private _textDocumentsAndEditors: ExtHostDocumentsAndEditors,
private _textDocuments: ExtHostDocuments,
private readonly logService: ILogService,
private readonly _extensionStoragePaths: IExtensionStoragePaths,
) {
this._notebookProxy = mainContext.getProxy(MainContext.MainThreadNotebook);
@@ -138,8 +106,12 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
});
}
getEditorById(editorId: string): ExtHostNotebookEditor | undefined {
return this._editors.get(editorId);
getEditorById(editorId: string): ExtHostNotebookEditor {
const editor = this._editors.get(editorId);
if (!editor) {
throw new Error(`unknown text editor: ${editorId}. known editors: ${[...this._editors.keys()]} `);
}
return editor;
}
getIdByEditor(editor: vscode.NotebookEditor): string | undefined {
@@ -155,13 +127,11 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
return [...this._documents.values()];
}
lookupNotebookDocument(uri: URI): ExtHostNotebookDocument | undefined {
return this._documents.get(uri);
}
private _getNotebookDocument(uri: URI): ExtHostNotebookDocument {
getNotebookDocument(uri: URI, relaxed: true): ExtHostNotebookDocument | undefined;
getNotebookDocument(uri: URI): ExtHostNotebookDocument;
getNotebookDocument(uri: URI, relaxed?: true): ExtHostNotebookDocument | undefined {
const result = this._documents.get(uri);
if (!result) {
if (!result && !relaxed) {
throw new Error(`NO notebook document for '${uri}'`);
}
return result;
@@ -179,13 +149,8 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
extension: IExtensionDescription,
viewType: string,
provider: vscode.NotebookContentProvider,
options?: vscode.NotebookDocumentContentOptions & {
viewOptions?: {
displayName: string;
filenamePattern: (vscode.GlobPattern | { include: vscode.GlobPattern; exclude: vscode.GlobPattern })[];
exclusive?: boolean;
};
}
options?: vscode.NotebookDocumentContentOptions,
registration?: vscode.NotebookRegistrationData
): vscode.Disposable {
if (isFalsyOrWhitespace(viewType)) {
throw new Error(`viewType cannot be empty or just whitespace`);
@@ -196,7 +161,6 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
this._notebookContentProviders.set(viewType, { extension, provider });
let listener: IDisposable | undefined;
if (provider.onDidChangeNotebookContentOptions) {
listener = provider.onDidChangeNotebookContentOptions(() => {
@@ -205,21 +169,12 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
});
}
const viewOptionsFilenamePattern = options?.viewOptions?.filenamePattern
.map(pattern => typeConverters.NotebookExclusiveDocumentPattern.from(pattern))
.filter(pattern => pattern !== undefined) as (string | IRelativePattern | INotebookExclusiveDocumentFilter)[];
if (options?.viewOptions?.filenamePattern && !viewOptionsFilenamePattern) {
console.warn(`Notebook content provider view options file name pattern is invalid ${options?.viewOptions?.filenamePattern}`);
}
const internalOptions = typeConverters.NotebookDocumentContentOptions.from(options);
this._notebookProxy.$registerNotebookProvider({ id: extension.identifier, location: extension.extensionLocation, description: extension.description }, viewType, {
transientOutputs: internalOptions.transientOutputs,
transientCellMetadata: internalOptions.transientCellMetadata,
transientDocumentMetadata: internalOptions.transientDocumentMetadata,
viewOptions: options?.viewOptions && viewOptionsFilenamePattern ? { displayName: options.viewOptions.displayName, filenamePattern: viewOptionsFilenamePattern, exclusive: options.viewOptions.exclusive || false } : undefined
});
this._notebookProxy.$registerNotebookProvider(
{ id: extension.identifier, location: extension.extensionLocation },
viewType,
typeConverters.NotebookDocumentContentOptions.from(options),
ExtHostNotebookController._convertNotebookRegistrationData(extension, registration)
);
return new extHostTypes.Disposable(() => {
listener?.dispose();
@@ -228,13 +183,33 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
});
}
registerNotebookCellStatusBarItemProvider(extension: IExtensionDescription, selector: vscode.NotebookSelector, provider: vscode.NotebookCellStatusBarItemProvider) {
private static _convertNotebookRegistrationData(extension: IExtensionDescription, registration: vscode.NotebookRegistrationData | undefined): INotebookContributionData | undefined {
if (!registration) {
return undefined; // {{SQL CARBON EDIT}} Strict nulls
}
const viewOptionsFilenamePattern = registration.filenamePattern
.map(pattern => typeConverters.NotebookExclusiveDocumentPattern.from(pattern))
.filter(pattern => pattern !== undefined) as (string | IRelativePattern | INotebookExclusiveDocumentFilter)[];
if (registration.filenamePattern && !viewOptionsFilenamePattern) {
console.warn(`Notebook content provider view options file name pattern is invalid ${registration.filenamePattern}`);
return undefined;
}
return {
extension: extension.identifier,
providerDisplayName: extension.displayName || extension.name,
displayName: registration.displayName,
filenamePattern: viewOptionsFilenamePattern,
exclusive: registration.exclusive || false
};
}
registerNotebookCellStatusBarItemProvider(extension: IExtensionDescription, notebookType: string, provider: vscode.NotebookCellStatusBarItemProvider) {
const handle = ExtHostNotebookController._notebookStatusBarItemProviderHandlePool++;
const eventHandle = typeof provider.onDidChangeCellStatusBarItems === 'function' ? ExtHostNotebookController._notebookStatusBarItemProviderHandlePool++ : undefined;
this._notebookStatusBarItemProviders.set(handle, provider);
this._notebookProxy.$registerNotebookCellStatusBarItemProvider(handle, eventHandle, selector);
this._notebookProxy.$registerNotebookCellStatusBarItemProvider(handle, eventHandle, notebookType);
let subscription: vscode.Disposable | undefined;
if (eventHandle !== undefined) {
@@ -250,8 +225,12 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
});
}
createNotebookEditorDecorationType(options: vscode.NotebookDecorationRenderOptions): vscode.NotebookEditorDecorationType {
return new NotebookEditorDecorationType(this._notebookEditorsProxy, options).value;
async createNotebookDocument(options: { viewType: string, content?: vscode.NotebookData }): Promise<URI> {
const canonicalUri = await this._notebookDocumentsProxy.$tryCreateNotebook({
viewType: options.viewType,
content: options.content && typeConverters.NotebookData.from(options.content)
});
return URI.revive(canonicalUri);
}
async openNotebookDocument(uri: URI): Promise<vscode.NotebookDocument> {
@@ -259,7 +238,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
if (cached) {
return cached.apiNotebook;
}
const canonicalUri = await this._notebookDocumentsProxy.$tryOpenDocument(uri);
const canonicalUri = await this._notebookDocumentsProxy.$tryOpenNotebook(uri);
const document = this._documents.get(URI.revive(canonicalUri));
return assertIsDefined(document?.apiNotebook);
}
@@ -285,7 +264,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
};
}
const editorId = await this._notebookEditorsProxy.$tryShowNotebookDocument(notebookOrUri.uri, notebookOrUri.viewType, resolvedOptions);
const editorId = await this._notebookEditorsProxy.$tryShowNotebookDocument(notebookOrUri.uri, notebookOrUri.notebookType, resolvedOptions);
const editor = editorId && this._editors.get(editorId)?.apiEditor;
if (editor) {
@@ -293,9 +272,9 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
}
if (editorId) {
throw new Error(`Could NOT open editor for "${notebookOrUri.toString()}" because another editor opened in the meantime.`);
throw new Error(`Could NOT open editor for "${notebookOrUri.uri.toString()}" because another editor opened in the meantime.`);
} else {
throw new Error(`Could NOT open editor for "${notebookOrUri.toString()}".`);
throw new Error(`Could NOT open editor for "${notebookOrUri.uri.toString()}".`);
}
}
@@ -319,7 +298,8 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
const disposables = new DisposableStore();
const cacheId = this._statusBarCache.add([disposables]);
const items = (result && result.map(item => typeConverters.NotebookStatusBarItem.from(item, this._commandsConverter, disposables))) ?? undefined;
const resultArr = Array.isArray(result) ? result : [result];
const items = resultArr.map(item => typeConverters.NotebookStatusBarItem.from(item, this._commandsConverter, disposables));
return {
cacheId,
items
@@ -335,18 +315,18 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
private _handlePool = 0;
private readonly _notebookSerializer = new Map<number, vscode.NotebookSerializer>();
registerNotebookSerializer(extension: IExtensionDescription, viewType: string, serializer: vscode.NotebookSerializer, options?: vscode.NotebookDocumentContentOptions): vscode.Disposable {
registerNotebookSerializer(extension: IExtensionDescription, viewType: string, serializer: vscode.NotebookSerializer, options?: vscode.NotebookDocumentContentOptions, registration?: vscode.NotebookRegistrationData): vscode.Disposable {
if (isFalsyOrWhitespace(viewType)) {
throw new Error(`viewType cannot be empty or just whitespace`);
}
const handle = this._handlePool++;
this._notebookSerializer.set(handle, serializer);
const internalOptions = typeConverters.NotebookDocumentContentOptions.from(options);
this._notebookProxy.$registerNotebookSerializer(
handle,
{ id: extension.identifier, location: extension.extensionLocation, description: extension.description },
{ id: extension.identifier, location: extension.extensionLocation },
viewType,
internalOptions
typeConverters.NotebookDocumentContentOptions.from(options),
ExtHostNotebookController._convertNotebookRegistrationData(extension, registration)
);
return toDisposable(() => {
this._notebookProxy.$unregisterNotebookSerializer(handle);
@@ -359,10 +339,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
throw new Error('NO serializer found');
}
const data = await serializer.deserializeNotebook(bytes.buffer, token);
return {
metadata: typeConverters.NotebookDocumentMetadata.from(data.metadata),
cells: data.cells.map(typeConverters.NotebookCellData.from),
};
return typeConverters.NotebookData.from(data);
}
async $notebookToData(handle: number, data: NotebookDataDto, token: CancellationToken): Promise<VSBuffer> {
@@ -370,38 +347,30 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
if (!serializer) {
throw new Error('NO serializer found');
}
const bytes = await serializer.serializeNotebook({
metadata: typeConverters.NotebookDocumentMetadata.to(data.metadata),
cells: data.cells.map(typeConverters.NotebookCellData.to)
}, token);
const bytes = await serializer.serializeNotebook(typeConverters.NotebookData.to(data), token);
return VSBuffer.wrap(bytes);
}
cancelOneNotebookCellExecution(cell: ExtHostCell): void {
const execution = this._activeExecutions.get(cell.uri);
execution?.cancel();
}
// --- open, save, saveAs, backup
async $openNotebook(viewType: string, uri: UriComponents, backupId: string | undefined, untitledDocumentData: VSBuffer | undefined, token: CancellationToken): Promise<NotebookDataDto> {
const { provider } = this._getProviderData(viewType);
const data = await provider.openNotebook(URI.revive(uri), { backupId, untitledDocumentData: untitledDocumentData?.buffer }, token);
return {
metadata: typeConverters.NotebookDocumentMetadata.from(data.metadata),
metadata: data.metadata ?? Object.create(null),
cells: data.cells.map(typeConverters.NotebookCellData.from),
};
}
async $saveNotebook(viewType: string, uri: UriComponents, token: CancellationToken): Promise<boolean> {
const document = this._getNotebookDocument(URI.revive(uri));
const document = this.getNotebookDocument(URI.revive(uri));
const { provider } = this._getProviderData(viewType);
await provider.saveNotebook(document.apiNotebook, token);
return true;
}
async $saveNotebookAs(viewType: string, uri: UriComponents, target: UriComponents, token: CancellationToken): Promise<boolean> {
const document = this._getNotebookDocument(URI.revive(uri));
const document = this.getNotebookDocument(URI.revive(uri));
const { provider } = this._getProviderData(viewType);
await provider.saveNotebookAs(URI.revive(target), document.apiNotebook, token);
return true;
@@ -410,7 +379,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
private _backupIdPool: number = 0;
async $backupNotebook(viewType: string, uri: UriComponents, cancellation: CancellationToken): Promise<string> {
const document = this._getNotebookDocument(URI.revive(uri));
const document = this.getNotebookDocument(URI.revive(uri));
const provider = this._getProviderData(viewType);
const storagePath = this._extensionStoragePaths.workspaceValue(provider.extension) ?? this._extensionStoragePaths.globalValue(provider.extension);
@@ -422,70 +391,6 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
return backup.id;
}
$acceptModelChanged(uri: UriComponents, event: NotebookCellsChangedEventDto, isDirty: boolean): void {
const document = this._getNotebookDocument(URI.revive(uri));
document.acceptModelChanged(event, isDirty);
}
$acceptDirtyStateChanged(uri: UriComponents, isDirty: boolean): void {
const document = this._getNotebookDocument(URI.revive(uri));
document.acceptModelChanged({ rawEvents: [], versionId: document.apiNotebook.version }, isDirty);
}
$acceptModelSaved(uri: UriComponents): void {
const document = this._getNotebookDocument(URI.revive(uri));
this._onDidSaveNotebookDocument.fire(document.apiNotebook);
}
$acceptEditorPropertiesChanged(id: string, data: INotebookEditorPropertiesChangeData): void {
this.logService.debug('ExtHostNotebook#$acceptEditorPropertiesChanged', id, data);
const editor = this._editors.get(id);
if (!editor) {
throw new Error(`unknown text editor: ${id}. known editors: ${[...this._editors.keys()]} `);
}
// ONE: make all state updates
if (data.visibleRanges) {
editor._acceptVisibleRanges(data.visibleRanges.ranges.map(typeConverters.NotebookRange.to));
}
if (data.selections) {
editor._acceptSelections(data.selections.selections.map(typeConverters.NotebookRange.to));
}
// TWO: send all events after states have been updated
if (data.visibleRanges) {
this._onDidChangeNotebookEditorVisibleRanges.fire({
notebookEditor: editor.apiEditor,
visibleRanges: editor.apiEditor.visibleRanges
});
}
if (data.selections) {
this._onDidChangeNotebookEditorSelection.fire(Object.freeze({
notebookEditor: editor.apiEditor,
selections: editor.apiEditor.selections
}));
}
}
$acceptEditorViewColumns(data: INotebookEditorViewColumnInfo): void {
for (const id in data) {
const editor = this._editors.get(id);
if (!editor) {
throw new Error(`unknown text editor: ${id}. known editors: ${[...this._editors.keys()]} `);
}
editor._acceptViewColumn(typeConverters.ViewColumn.to(data[id]));
}
}
$acceptDocumentPropertiesChanged(uri: UriComponents, data: INotebookDocumentPropertiesChangeData): void {
this.logService.debug('ExtHostNotebook#$acceptDocumentPropertiesChanged', uri.path, data);
const document = this._getNotebookDocument(URI.revive(uri));
document.acceptDocumentPropertiesChanged(data);
if (data.metadata) {
this._onDidChangeNotebookDocumentMetadata.fire({ document: document.apiNotebook });
}
}
private _createExtHostEditor(document: ExtHostNotebookDocument, editorId: string, data: INotebookEditorAddData) {
@@ -559,7 +464,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
}
},
viewType,
modelData.metadata ? typeConverters.NotebookDocumentMetadata.to(modelData.metadata) : new extHostTypes.NotebookDocumentMetadata(),
modelData.metadata ?? Object.create({}),
uri,
);
@@ -639,213 +544,4 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
this._onDidChangeActiveNotebookEditor.fire(this._activeNotebookEditor?.apiEditor);
}
}
createNotebookCellExecution(docUri: vscode.Uri, index: number, kernelId: string): vscode.NotebookCellExecutionTask | undefined {
const document = this.lookupNotebookDocument(docUri);
if (!document) {
throw new Error(`Invalid uri: ${docUri} `);
}
const cell = document.getCellFromIndex(index);
if (!cell) {
throw new Error(`Invalid cell index: ${docUri}, ${index} `);
}
// TODO@roblou also validate kernelId, once kernel has moved from editor to document
if (this._activeExecutions.has(cell.uri)) {
throw new Error(`duplicate execution for ${cell.uri}`);
}
const execution = new NotebookCellExecutionTask(docUri, document, cell, this._notebookDocumentsProxy);
this._activeExecutions.set(cell.uri, execution);
const listener = execution.onDidChangeState(() => {
if (execution.state === NotebookCellExecutionTaskState.Resolved) {
execution.dispose();
listener.dispose();
this._activeExecutions.delete(cell.uri);
}
});
return execution.asApiObject();
}
}
enum NotebookCellExecutionTaskState {
Init,
Started,
Resolved
}
class NotebookCellExecutionTask extends Disposable {
private _onDidChangeState = new Emitter<void>();
readonly onDidChangeState = this._onDidChangeState.event;
private _state = NotebookCellExecutionTaskState.Init;
get state(): NotebookCellExecutionTaskState { return this._state; }
private readonly _tokenSource = this._register(new CancellationTokenSource());
private readonly _collector: TimeoutBasedCollector<IImmediateCellEditOperation>;
private _executionOrder: number | undefined;
constructor(
private readonly _uri: vscode.Uri,
private readonly _document: ExtHostNotebookDocument,
private readonly _cell: ExtHostCell,
private readonly _proxy: MainThreadNotebookDocumentsShape) {
super();
this._collector = new TimeoutBasedCollector(10, edits => this.applyEdits(edits));
this._executionOrder = _cell.internalMetadata.executionOrder;
this.mixinMetadata({
runState: extHostTypes.NotebookCellExecutionState.Pending,
executionOrder: null
});
}
cancel(): void {
this._tokenSource.cancel();
}
private async applyEditSoon(edit: IImmediateCellEditOperation): Promise<void> {
await this._collector.addItem(edit);
}
private async applyEdits(edits: IImmediateCellEditOperation[]): Promise<void> {
return this._proxy.$applyEdits(this._uri, edits, false);
}
private verifyStateForOutput() {
if (this._state === NotebookCellExecutionTaskState.Init) {
throw new Error('Must call start before modifying cell output');
}
if (this._state === NotebookCellExecutionTaskState.Resolved) {
throw new Error('Cannot modify cell output after calling resolve');
}
}
private mixinMetadata(mixinMetadata: NullablePartialNotebookCellMetadata) {
const edit: IImmediateCellEditOperation = { editType: CellEditType.PartialMetadata, handle: this._cell.handle, metadata: mixinMetadata };
this.applyEdits([edit]);
}
private cellIndexToHandle(cellIndex: number | undefined): number | undefined {
const cell = typeof cellIndex === 'number' ? this._document.getCellFromIndex(cellIndex) : this._cell;
if (!cell) {
return undefined; // {{SQL CARBON EDIT}} Strict null
}
return cell.handle;
}
asApiObject(): vscode.NotebookCellExecutionTask {
const that = this;
return Object.freeze(<vscode.NotebookCellExecutionTask>{
get document() { return that._document.apiNotebook; },
get cell() { return that._cell.apiCell; },
get executionOrder() { return that._executionOrder; },
set executionOrder(v: number | undefined) {
that._executionOrder = v;
that.mixinMetadata({
executionOrder: v
});
},
start(context?: vscode.NotebookCellExecuteStartContext): void {
if (that._state === NotebookCellExecutionTaskState.Resolved || that._state === NotebookCellExecutionTaskState.Started) {
throw new Error('Cannot call start again');
}
that._state = NotebookCellExecutionTaskState.Started;
that._onDidChangeState.fire();
that.mixinMetadata({
runState: extHostTypes.NotebookCellExecutionState.Executing,
runStartTime: context?.startTime ?? null
});
},
end(result?: vscode.NotebookCellExecuteEndContext): void {
if (that._state === NotebookCellExecutionTaskState.Resolved) {
throw new Error('Cannot call resolve twice');
}
that._state = NotebookCellExecutionTaskState.Resolved;
that._onDidChangeState.fire();
that.mixinMetadata({
runState: extHostTypes.NotebookCellExecutionState.Idle,
lastRunSuccess: result?.success ?? null,
runEndTime: result?.endTime ?? null,
});
},
clearOutput(cellIndex?: number): Thenable<void> {
that.verifyStateForOutput();
return this.replaceOutput([], cellIndex);
},
async appendOutput(outputs: vscode.NotebookCellOutput | vscode.NotebookCellOutput[], cellIndex?: number): Promise<void> {
that.verifyStateForOutput();
const handle = that.cellIndexToHandle(cellIndex);
if (typeof handle !== 'number') {
return;
}
outputs = Array.isArray(outputs) ? outputs : [outputs];
return that.applyEditSoon({ editType: CellEditType.Output, handle, append: true, outputs: outputs.map(typeConverters.NotebookCellOutput.from) });
},
async replaceOutput(outputs: vscode.NotebookCellOutput | vscode.NotebookCellOutput[], cellIndex?: number): Promise<void> {
that.verifyStateForOutput();
const handle = that.cellIndexToHandle(cellIndex);
if (typeof handle !== 'number') {
return;
}
outputs = Array.isArray(outputs) ? outputs : [outputs];
return that.applyEditSoon({ editType: CellEditType.Output, handle, outputs: outputs.map(typeConverters.NotebookCellOutput.from) });
},
async appendOutputItems(items: vscode.NotebookCellOutputItem | vscode.NotebookCellOutputItem[], outputId: string): Promise<void> {
that.verifyStateForOutput();
items = Array.isArray(items) ? items : [items];
return that.applyEditSoon({ editType: CellEditType.OutputItems, append: true, items: items.map(typeConverters.NotebookCellOutputItem.from), outputId });
},
async replaceOutputItems(items: vscode.NotebookCellOutputItem | vscode.NotebookCellOutputItem[], outputId: string): Promise<void> {
that.verifyStateForOutput();
items = Array.isArray(items) ? items : [items];
return that.applyEditSoon({ editType: CellEditType.OutputItems, items: items.map(typeConverters.NotebookCellOutputItem.from), outputId });
},
token: that._tokenSource.token
});
}
}
class TimeoutBasedCollector<T> {
private batch: T[] = [];
private waitPromise: Promise<void> | undefined;
constructor(
private readonly delay: number,
private readonly callback: (items: T[]) => Promise<void>) { }
addItem(item: T): Promise<void> {
this.batch.push(item);
if (!this.waitPromise) {
this.waitPromise = timeout(this.delay).then(() => {
this.waitPromise = undefined;
const batch = this.batch;
this.batch = [];
return this.callback(batch);
});
}
return this.waitPromise;
}
}

View File

@@ -6,12 +6,12 @@
import { Schemas } from 'vs/base/common/network';
import { deepFreeze, equals } from 'vs/base/common/objects';
import { URI } from 'vs/base/common/uri';
import { CellKind, INotebookDocumentPropertiesChangeData, MainThreadNotebookDocumentsShape } from 'vs/workbench/api/common/extHost.protocol';
import { 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 * 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 { CellKind, IMainCellDto, IOutputDto, IOutputItemDto, NotebookCellInternalMetadata, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookCellsSplice2 } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import * as vscode from 'vscode';
class RawContentChangeEvent {
@@ -44,19 +44,19 @@ export class ExtHostCell {
};
}
private _outputs: extHostTypes.NotebookCellOutput[];
private _metadata: extHostTypes.NotebookCellMetadata;
private _outputs: vscode.NotebookCellOutput[];
private _metadata: NotebookCellMetadata;
private _previousResult: vscode.NotebookCellExecutionSummary | undefined;
private _internalMetadata: NotebookCellMetadata;
private _internalMetadata: NotebookCellInternalMetadata;
readonly handle: number;
readonly uri: URI;
readonly cellKind: CellKind;
private _cell: vscode.NotebookCell | undefined;
private _apiCell: vscode.NotebookCell | undefined;
constructor(
private readonly _notebook: ExtHostNotebookDocument,
readonly notebook: ExtHostNotebookDocument,
private readonly _extHostDocument: ExtHostDocumentsAndEditors,
private readonly _cellData: IMainCellDto,
) {
@@ -64,33 +64,33 @@ export class ExtHostCell {
this.uri = URI.revive(_cellData.uri);
this.cellKind = _cellData.cellKind;
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);
this._internalMetadata = _cellData.internalMetadata ?? {};
this._metadata = _cellData.metadata ?? {};
this._previousResult = extHostTypeConverters.NotebookCellExecutionSummary.to(_cellData.internalMetadata ?? {});
}
get internalMetadata(): NotebookCellMetadata {
get internalMetadata(): NotebookCellInternalMetadata {
return this._internalMetadata;
}
get apiCell(): vscode.NotebookCell {
if (!this._cell) {
if (!this._apiCell) {
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<vscode.NotebookCell>({
get index() { return that._notebook.getCellIndex(that); },
notebook: that._notebook.apiNotebook,
this._apiCell = Object.freeze<vscode.NotebookCell>({
get index() { return that.notebook.getCellIndex(that); },
notebook: that.notebook.apiNotebook,
kind: extHostTypeConverters.NotebookCellKind.to(this._cellData.cellKind),
document: data.document,
get outputs() { return that._outputs.slice(0); },
get metadata() { return that._metadata; },
get latestExecutionSummary() { return that._previousResult; }
get executionSummary() { return that._previousResult; }
});
}
return this._cell;
return this._apiCell;
}
setOutputs(newOutputs: IOutputDto[]): void {
@@ -102,16 +102,19 @@ export class ExtHostCell {
const output = this._outputs.find(op => op.id === outputId);
if (output) {
if (!append) {
output.outputs.length = 0;
output.items.length = 0;
}
output.outputs.push(...newItems);
output.items.push(...newItems);
}
}
setMetadata(newMetadata: NotebookCellMetadata): void {
this._internalMetadata = newMetadata;
this._metadata = extHostTypeConverters.NotebookCellMetadata.to(newMetadata);
this._previousResult = extHostTypeConverters.NotebookCellPreviousExecutionResult.to(newMetadata);
this._metadata = newMetadata;
}
setInternalMetadata(newInternalMetadata: NotebookCellInternalMetadata): void {
this._internalMetadata = newInternalMetadata;
this._previousResult = extHostTypeConverters.NotebookCellExecutionSummary.to(newInternalMetadata);
}
}
@@ -141,8 +144,8 @@ export class ExtHostNotebookDocument {
private readonly _textDocumentsAndEditors: ExtHostDocumentsAndEditors,
private readonly _textDocuments: ExtHostDocuments,
private readonly _emitter: INotebookEventEmitter,
private readonly _viewType: string,
private _metadata: extHostTypes.NotebookDocumentMetadata,
private readonly _notebookType: string,
private _metadata: Record<string, any>,
readonly uri: URI,
) { }
@@ -156,7 +159,7 @@ export class ExtHostNotebookDocument {
this._notebook = {
get uri() { return that.uri; },
get version() { return that._versionId; },
get viewType() { return that._viewType; },
get notebookType() { return that._notebookType; },
get isDirty() { return that._isDirty; },
get isUntitled() { return that.uri.scheme === Schemas.untitled; },
get isClosed() { return that._disposed; },
@@ -190,7 +193,7 @@ export class ExtHostNotebookDocument {
acceptDocumentPropertiesChanged(data: INotebookDocumentPropertiesChangeData) {
if (data.metadata) {
this._metadata = this._metadata.with(data.metadata);
this._metadata = { ...this._metadata, ...data.metadata };
}
}
@@ -213,11 +216,14 @@ export class ExtHostNotebookDocument {
this._changeCellLanguage(rawEvent.index, rawEvent.language);
} else if (rawEvent.kind === NotebookCellsChangeType.ChangeCellMetadata) {
this._changeCellMetadata(rawEvent.index, rawEvent.metadata);
} else if (rawEvent.kind === NotebookCellsChangeType.ChangeCellInternalMetadata) {
this._changeCellInternalMetadata(rawEvent.index, rawEvent.internalMetadata);
}
}
}
private _validateIndex(index: number): number {
index = index | 0;
if (index < 0) {
return 0;
} else if (index >= this._cells.length) {
@@ -228,13 +234,15 @@ export class ExtHostNotebookDocument {
}
private _validateRange(range: vscode.NotebookRange): vscode.NotebookRange {
if (range.start < 0) {
range = range.with({ start: 0 });
let start = range.start | 0;
let end = range.end | 0;
if (start < 0) {
start = 0;
}
if (range.end > this._cells.length) {
range = range.with({ end: this._cells.length });
if (end > this._cells.length) {
end = this._cells.length;
}
return range;
return range.with({ start, end });
}
private _getCells(range: vscode.NotebookRange): ExtHostCell[] {
@@ -250,7 +258,7 @@ export class ExtHostNotebookDocument {
if (this._disposed) {
return Promise.reject(new Error('Notebook has been closed'));
}
return this._proxy.$trySaveDocument(this.uri);
return this._proxy.$trySaveNotebook(this.uri);
}
private _spliceNotebookCells(splices: NotebookCellsSplice2[], initialization: boolean): void {
@@ -275,7 +283,7 @@ export class ExtHostNotebookDocument {
const changeEvent = new RawContentChangeEvent(splice[0], splice[1], [], newCells);
const deletedItems = this._cells.splice(splice[0], splice[1], ...newCells);
for (let cell of deletedItems) {
for (const cell of deletedItems) {
removedCellDocuments.push(cell.uri);
changeEvent.deletedItems.push(cell.apiCell);
}
@@ -331,7 +339,6 @@ export class ExtHostNotebookDocument {
private _changeCellMetadata(index: number, newMetadata: NotebookCellMetadata): void {
const cell = this._cells[index];
const originalInternalMetadata = cell.internalMetadata;
const originalExtMetadata = cell.apiCell.metadata;
cell.setMetadata(newMetadata);
const newExtMetadata = cell.apiCell.metadata;
@@ -339,13 +346,24 @@ export class ExtHostNotebookDocument {
if (!equals(originalExtMetadata, newExtMetadata)) {
this._emitter.emitCellMetadataChange(deepFreeze({ document: this.apiNotebook, cell: cell.apiCell }));
}
}
if (originalInternalMetadata.runState !== newMetadata.runState) {
const executionState = newMetadata.runState ?? extHostTypes.NotebookCellExecutionState.Idle;
this._emitter.emitCellExecutionStateChange(deepFreeze({ document: this.apiNotebook, cell: cell.apiCell, executionState }));
private _changeCellInternalMetadata(index: number, newInternalMetadata: NotebookCellInternalMetadata): void {
const cell = this._cells[index];
const originalInternalMetadata = cell.internalMetadata;
cell.setInternalMetadata(newInternalMetadata);
if (originalInternalMetadata.runState !== newInternalMetadata.runState) {
const executionState = newInternalMetadata.runState ?? extHostTypes.NotebookCellExecutionState.Idle;
this._emitter.emitCellExecutionStateChange(deepFreeze({ document: this.apiNotebook, cell: cell.apiCell, state: executionState }));
}
}
getCellFromApiCell(apiCell: vscode.NotebookCell): ExtHostCell | undefined {
return this._cells.find(cell => cell.apiCell === apiCell);
}
getCellFromIndex(index: number): ExtHostCell | undefined {
return this._cells[index];
}

View File

@@ -0,0 +1,50 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Emitter } from 'vs/base/common/event';
import { URI, UriComponents } from 'vs/base/common/uri';
import { ILogService } from 'vs/platform/log/common/log';
import { ExtHostNotebookDocumentsShape, INotebookDocumentPropertiesChangeData } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
import { NotebookCellsChangedEventDto } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import type * as vscode from 'vscode';
export class ExtHostNotebookDocuments implements ExtHostNotebookDocumentsShape {
private readonly _onDidChangeNotebookDocumentMetadata = new Emitter<vscode.NotebookDocumentMetadataChangeEvent>();
readonly onDidChangeNotebookDocumentMetadata = this._onDidChangeNotebookDocumentMetadata.event;
private _onDidSaveNotebookDocument = new Emitter<vscode.NotebookDocument>();
readonly onDidSaveNotebookDocument = this._onDidSaveNotebookDocument.event;
constructor(
@ILogService private readonly _logService: ILogService,
private readonly _notebooksAndEditors: ExtHostNotebookController,
) { }
$acceptModelChanged(uri: UriComponents, event: NotebookCellsChangedEventDto, isDirty: boolean): void {
const document = this._notebooksAndEditors.getNotebookDocument(URI.revive(uri));
document.acceptModelChanged(event, isDirty);
}
$acceptDirtyStateChanged(uri: UriComponents, isDirty: boolean): void {
const document = this._notebooksAndEditors.getNotebookDocument(URI.revive(uri));
document.acceptModelChanged({ rawEvents: [], versionId: document.apiNotebook.version }, isDirty);
}
$acceptModelSaved(uri: UriComponents): void {
const document = this._notebooksAndEditors.getNotebookDocument(URI.revive(uri));
this._onDidSaveNotebookDocument.fire(document.apiNotebook);
}
$acceptDocumentPropertiesChanged(uri: UriComponents, data: INotebookDocumentPropertiesChangeData): void {
this._logService.debug('ExtHostNotebook#$acceptDocumentPropertiesChanged', uri.path, data);
const document = this._notebooksAndEditors.getNotebookDocument(URI.revive(uri));
document.acceptDocumentPropertiesChanged(data);
if (data.metadata) {
this._onDidChangeNotebookDocumentMetadata.fire({ document: document.apiNotebook });
}
}
}

View File

@@ -9,6 +9,7 @@ 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';
import { illegalArgument } from 'vs/base/common/errors';
interface INotebookEditData {
documentVersionId: number;
@@ -40,7 +41,7 @@ class NotebookEditorCellEditBuilder implements vscode.NotebookEditorEdit {
}
}
replaceMetadata(value: vscode.NotebookDocumentMetadata): void {
replaceMetadata(value: { [key: string]: any }): void {
this._throwIfFinalized();
this._collectedEdits.push({
editType: CellEditType.DocumentMetadata,
@@ -48,7 +49,7 @@ class NotebookEditorCellEditBuilder implements vscode.NotebookEditorEdit {
});
}
replaceCellMetadata(index: number, metadata: vscode.NotebookCellMetadata): void {
replaceCellMetadata(index: number, metadata: Record<string, any>): void {
this._throwIfFinalized();
this._collectedEdits.push({
editType: CellEditType.Metadata,
@@ -73,6 +74,8 @@ class NotebookEditorCellEditBuilder implements vscode.NotebookEditorEdit {
export class ExtHostNotebookEditor {
public static readonly apiEditorsToExtHost = new WeakMap<vscode.NotebookEditor, ExtHostNotebookEditor>();
private _selections: vscode.NotebookRange[] = [];
private _visibleRanges: vscode.NotebookRange[] = [];
private _viewColumn?: vscode.ViewColumn;
@@ -105,6 +108,13 @@ export class ExtHostNotebookEditor {
get selections() {
return that._selections;
},
set selections(value: vscode.NotebookRange[]) {
if (!Array.isArray(value) || !value.every(extHostTypes.NotebookRange.isNotebookRange)) {
throw illegalArgument('selections');
}
that._selections = value;
that._trySetSelections(value);
},
get visibleRanges() {
return that._visibleRanges;
},
@@ -127,6 +137,8 @@ export class ExtHostNotebookEditor {
return that.setDecorations(decorationType, range);
}
};
ExtHostNotebookEditor.apiEditorsToExtHost.set(this._editor, this);
}
return this._editor;
}
@@ -147,6 +159,10 @@ export class ExtHostNotebookEditor {
this._selections = selections;
}
private _trySetSelections(value: vscode.NotebookRange[]): void {
this._proxy.$trySetSelections(this.id, value.map(extHostConverter.NotebookRange.from));
}
_acceptViewColumn(value: vscode.ViewColumn | undefined) {
this._viewColumn = value;
}

View File

@@ -0,0 +1,88 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Emitter } from 'vs/base/common/event';
import { IdGenerator } from 'vs/base/common/idGenerator';
import { ILogService } from 'vs/platform/log/common/log';
import { ExtHostNotebookEditorsShape, INotebookEditorPropertiesChangeData, INotebookEditorViewColumnInfo, MainContext, MainThreadNotebookEditorsShape } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import type * as vscode from 'vscode';
class NotebookEditorDecorationType {
private static readonly _Keys = new IdGenerator('NotebookEditorDecorationType');
readonly value: vscode.NotebookEditorDecorationType;
constructor(proxy: MainThreadNotebookEditorsShape, options: vscode.NotebookDecorationRenderOptions) {
const key = NotebookEditorDecorationType._Keys.nextId();
proxy.$registerNotebookEditorDecorationType(key, typeConverters.NotebookDecorationRenderOptions.from(options));
this.value = {
key,
dispose() {
proxy.$removeNotebookEditorDecorationType(key);
}
};
}
}
export class ExtHostNotebookEditors implements ExtHostNotebookEditorsShape {
private readonly _onDidChangeNotebookEditorSelection = new Emitter<vscode.NotebookEditorSelectionChangeEvent>();
private readonly _onDidChangeNotebookEditorVisibleRanges = new Emitter<vscode.NotebookEditorVisibleRangesChangeEvent>();
readonly onDidChangeNotebookEditorSelection = this._onDidChangeNotebookEditorSelection.event;
readonly onDidChangeNotebookEditorVisibleRanges = this._onDidChangeNotebookEditorVisibleRanges.event;
constructor(
@ILogService private readonly _logService: ILogService,
@IExtHostRpcService private readonly _extHostRpc: IExtHostRpcService,
private readonly _notebooksAndEditors: ExtHostNotebookController,
) {
}
createNotebookEditorDecorationType(options: vscode.NotebookDecorationRenderOptions): vscode.NotebookEditorDecorationType {
return new NotebookEditorDecorationType(this._extHostRpc.getProxy(MainContext.MainThreadNotebookEditors), options).value;
}
$acceptEditorPropertiesChanged(id: string, data: INotebookEditorPropertiesChangeData): void {
this._logService.debug('ExtHostNotebook#$acceptEditorPropertiesChanged', id, data);
const editor = this._notebooksAndEditors.getEditorById(id);
// ONE: make all state updates
if (data.visibleRanges) {
editor._acceptVisibleRanges(data.visibleRanges.ranges.map(typeConverters.NotebookRange.to));
}
if (data.selections) {
editor._acceptSelections(data.selections.selections.map(typeConverters.NotebookRange.to));
}
// TWO: send all events after states have been updated
if (data.visibleRanges) {
this._onDidChangeNotebookEditorVisibleRanges.fire({
notebookEditor: editor.apiEditor,
visibleRanges: editor.apiEditor.visibleRanges
});
}
if (data.selections) {
this._onDidChangeNotebookEditorSelection.fire(Object.freeze({
notebookEditor: editor.apiEditor,
selections: editor.apiEditor.selections
}));
}
}
$acceptEditorViewColumns(data: INotebookEditorViewColumnInfo): void {
for (const id in data) {
const editor = this._notebooksAndEditors.getEditorById(id);
editor._acceptViewColumn(typeConverters.ViewColumn.to(data[id]));
}
}
}

View File

@@ -1,11 +1,11 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* Licensed under the Source EULA. 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 { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { ExtHostNotebookKernelsShape, IMainContext, INotebookKernelDto2, MainContext, MainThreadNotebookDocumentsShape, 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';
@@ -13,30 +13,42 @@ 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';
import { ResourceMap } from 'vs/base/common/map';
import { timeout } from 'vs/base/common/async';
import { ExtHostCell, ExtHostNotebookDocument } from 'vs/workbench/api/common/extHostNotebookDocument';
import { CellEditType, IImmediateCellEditOperation, IOutputDto, NotebookCellExecutionState, NullablePartialNotebookCellInternalMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { asArray } from 'vs/base/common/arrays';
import { ILogService } from 'vs/platform/log/common/log';
import { NotebookCellOutput } from 'vs/workbench/api/common/extHostTypes';
import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
interface IKernelData {
extensionId: ExtensionIdentifier,
controller: vscode.NotebookController;
onDidChangeSelection: Emitter<{ selected: boolean; notebook: vscode.NotebookDocument; }>;
onDidReceiveMessage: Emitter<{ editor: vscode.NotebookEditor, message: any }>;
onDidReceiveMessage: Emitter<{ editor: vscode.NotebookEditor, message: any; }>;
associatedNotebooks: ResourceMap<boolean>;
}
export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape {
private readonly _proxy: MainThreadNotebookKernelsShape;
private readonly _activeExecutions = new ResourceMap<NotebookCellExecutionTask>();
private readonly _kernelData = new Map<number, IKernelData>();
private _handlePool: number = 0;
constructor(
mainContext: IMainContext,
private readonly _mainContext: IMainContext,
private readonly _initData: IExtHostInitDataService,
private readonly _extHostNotebook: ExtHostNotebookController
private readonly _extHostNotebook: ExtHostNotebookController,
@ILogService private readonly _logService: ILogService,
) {
this._proxy = mainContext.getProxy(MainContext.MainThreadNotebookKernels);
this._proxy = _mainContext.getProxy(MainContext.MainThreadNotebookKernels);
}
createNotebookController(extension: IExtensionDescription, id: string, viewType: string, label: string, handler?: vscode.NotebookExecuteHandler, preloads?: vscode.NotebookKernelPreload[]): vscode.NotebookController {
createNotebookController(extension: IExtensionDescription, id: string, viewType: string, label: string, handler?: (cells: vscode.NotebookCell[], notebook: vscode.NotebookDocument, controller: vscode.NotebookController) => void | Thenable<void>, preloads?: vscode.NotebookRendererScript[]): vscode.NotebookController {
for (let data of this._kernelData.values()) {
if (data.controller.id === id && ExtensionIdentifier.equals(extension.identifier, data.extensionId)) {
@@ -44,31 +56,33 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape {
}
}
const handle = this._handlePool++;
const that = this;
this._logService.trace(`NotebookController[${handle}], CREATED by ${extension.identifier.value}, ${id}`);
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 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,
notebookType: viewType,
extensionId: extension.identifier,
extensionLocation: extension.extensionLocation,
label: label || extension.identifier.value,
preloads: preloads ? preloads.map(extHostTypeConverters.NotebookKernelPreload.from) : []
preloads: preloads ? preloads.map(extHostTypeConverters.NotebookRendererScript.from) : []
};
//
let _executeHandler: vscode.NotebookExecuteHandler = handler ?? _defaultExecutHandler;
let _interruptHandler: vscode.NotebookInterruptHandler | undefined;
let _executeHandler = handler ?? _defaultExecutHandler;
let _interruptHandler: ((this: vscode.NotebookController, notebook: vscode.NotebookDocument) => void | Thenable<void>) | 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);
@@ -91,10 +105,13 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape {
});
};
// notebook documents that are associated to this controller
const associatedNotebooks = new ResourceMap<boolean>();
const controller: vscode.NotebookController = {
get id() { return id; },
get viewType() { return data.viewType; },
onDidChangeNotebookAssociation: onDidChangeSelection.event,
get notebookType() { return data.notebookType; },
onDidChangeSelectedNotebooks: onDidChangeSelection.event,
get label() {
return data.label;
},
@@ -123,15 +140,15 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape {
data.supportedLanguages = value;
_update();
},
get hasExecutionOrder() {
return data.hasExecutionOrder ?? false;
get supportsExecutionOrder() {
return data.supportsExecutionOrder ?? false;
},
set hasExecutionOrder(value) {
data.hasExecutionOrder = value;
set supportsExecutionOrder(value) {
data.supportsExecutionOrder = value;
_update();
},
get preloads() {
return data.preloads ? data.preloads.map(extHostTypeConverters.NotebookKernelPreload.to) : [];
get rendererScripts() {
return data.preloads ? data.preloads.map(extHostTypeConverters.NotebookRendererScript.to) : [];
},
get executeHandler() {
return _executeHandler;
@@ -147,15 +164,19 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape {
data.supportsInterrupt = Boolean(value);
_update();
},
createNotebookCellExecutionTask(cell) {
createNotebookCellExecution(cell) {
if (isDisposed) {
throw new Error('notebook controller is DISPOSED');
}
//todo@jrieken
return that._extHostNotebook.createNotebookCellExecution(cell.notebook.uri, cell.index, data.id)!;
if (!associatedNotebooks.has(cell.notebook.uri)) {
that._logService.trace(`NotebookController[${handle}] NOT associated to notebook, associated to THESE notebooks:`, Array.from(associatedNotebooks.keys()).map(u => u.toString()));
throw new Error(`notebook controller is NOT associated to notebook: ${cell.notebook.uri.toString()}`);
}
return that._createNotebookCellExecution(cell);
},
dispose: () => {
if (!isDisposed) {
this._logService.trace(`NotebookController[${handle}], DISPOSED`);
isDisposed = true;
this._kernelData.delete(handle);
commandDisposables.dispose();
@@ -164,30 +185,47 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape {
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);
}
},
// --- ipc
onDidReceiveMessage: onDidReceiveMessage.event,
postMessage(message, editor) {
checkProposedApiEnabled(extension);
return that._proxy.$postMessage(handle, editor && that._extHostNotebook.getIdByEditor(editor), message);
},
asWebviewUri(uri: URI) {
checkProposedApiEnabled(extension);
return asWebviewUri(uri, that._initData.remote);
},
};
this._kernelData.set(handle, { extensionId: extension.identifier, controller, onDidChangeSelection, onDidReceiveMessage });
this._kernelData.set(handle, {
extensionId: extension.identifier,
controller,
onDidReceiveMessage,
onDidChangeSelection,
associatedNotebooks
});
return controller;
}
$acceptSelection(handle: number, uri: UriComponents, value: boolean): void {
$acceptNotebookAssociation(handle: number, uri: UriComponents, value: boolean): void {
const obj = this._kernelData.get(handle);
if (obj) {
// update data structure
const notebook = this._extHostNotebook.getNotebookDocument(URI.revive(uri))!;
if (value) {
obj.associatedNotebooks.set(notebook.uri, true);
} else {
obj.associatedNotebooks.delete(notebook.uri);
}
this._logService.trace(`NotebookController[${handle}] ASSOCIATE notebook`, notebook.uri.toString(), value);
// send event
obj.onDidChangeSelection.fire({
selected: value,
notebook: this._extHostNotebook.lookupNotebookDocument(URI.revive(uri))!.apiNotebook
notebook: notebook.apiNotebook
});
}
}
@@ -198,11 +236,7 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape {
// extension can dispose kernels in the meantime
return;
}
const document = this._extHostNotebook.lookupNotebookDocument(URI.revive(uri));
if (!document) {
throw new Error('MISSING notebook');
}
const document = this._extHostNotebook.getNotebookDocument(URI.revive(uri));
const cells: vscode.NotebookCell[] = [];
for (let cellHandle of handles) {
const cell = document.getCell(cellHandle);
@@ -212,9 +246,11 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape {
}
try {
this._logService.trace(`NotebookController[${handle}] EXECUTE cells`, document.uri.toString(), cells.length);
await obj.controller.executeHandler.call(obj.controller, cells, document.apiNotebook, obj.controller);
} catch (err) {
//
this._logService.error(`NotebookController[${handle}] execute cells FAILED`, err);
console.error(err);
}
}
@@ -225,24 +261,24 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape {
// extension can dispose kernels in the meantime
return;
}
const document = this._extHostNotebook.lookupNotebookDocument(URI.revive(uri));
if (!document) {
throw new Error('MISSING notebook');
}
// cancel or interrupt depends on the controller. When an interrupt handler is used we
// don't trigger the cancelation token of executions.
const document = this._extHostNotebook.getNotebookDocument(URI.revive(uri));
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);
} else {
for (let cellHandle of handles) {
const cell = document.getCell(cellHandle);
if (cell) {
this._activeExecutions.get(cell.uri)?.cancel();
}
}
}
}
$acceptRendererMessage(handle: number, editorId: string, message: any): void {
$acceptKernelMessageFromRenderer(handle: number, editorId: string, message: any): void {
const obj = this._kernelData.get(handle);
if (!obj) {
// extension can dispose kernels in the meantime
@@ -250,10 +286,231 @@ export class ExtHostNotebookKernels implements ExtHostNotebookKernelsShape {
}
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 }));
}
// ---
_createNotebookCellExecution(cell: vscode.NotebookCell): vscode.NotebookCellExecution {
if (cell.index < 0) {
throw new Error('CANNOT execute cell that has been REMOVED from notebook');
}
const notebook = this._extHostNotebook.getNotebookDocument(cell.notebook.uri);
const cellObj = notebook.getCellFromApiCell(cell);
if (!cellObj) {
throw new Error('invalid cell');
}
if (this._activeExecutions.has(cellObj.uri)) {
throw new Error(`duplicate execution for ${cellObj.uri}`);
}
const execution = new NotebookCellExecutionTask(cellObj.notebook, cellObj, this._mainContext.getProxy(MainContext.MainThreadNotebookDocuments));
this._activeExecutions.set(cellObj.uri, execution);
const listener = execution.onDidChangeState(() => {
if (execution.state === NotebookCellExecutionTaskState.Resolved) {
execution.dispose();
listener.dispose();
this._activeExecutions.delete(cellObj.uri);
}
});
return execution.asApiObject();
}
}
enum NotebookCellExecutionTaskState {
Init,
Started,
Resolved
}
class NotebookCellExecutionTask extends Disposable {
private _onDidChangeState = new Emitter<void>();
readonly onDidChangeState = this._onDidChangeState.event;
private _state = NotebookCellExecutionTaskState.Init;
get state(): NotebookCellExecutionTaskState { return this._state; }
private readonly _tokenSource = this._register(new CancellationTokenSource());
private readonly _collector: TimeoutBasedCollector<IImmediateCellEditOperation>;
private _executionOrder: number | undefined;
constructor(
private readonly _document: ExtHostNotebookDocument,
private readonly _cell: ExtHostCell,
private readonly _proxy: MainThreadNotebookDocumentsShape
) {
super();
this._collector = new TimeoutBasedCollector(10, edits => this.applyEdits(edits));
this._executionOrder = _cell.internalMetadata.executionOrder;
this.mixinMetadata({
runState: NotebookCellExecutionState.Pending,
executionOrder: null
});
}
cancel(): void {
this._tokenSource.cancel();
}
private async applyEditSoon(edit: IImmediateCellEditOperation): Promise<void> {
await this._collector.addItem(edit);
}
private async applyEdits(edits: IImmediateCellEditOperation[]): Promise<void> {
return this._proxy.$applyEdits(this._document.uri, edits, false);
}
private verifyStateForOutput() {
if (this._state === NotebookCellExecutionTaskState.Init) {
throw new Error('Must call start before modifying cell output');
}
if (this._state === NotebookCellExecutionTaskState.Resolved) {
throw new Error('Cannot modify cell output after calling resolve');
}
}
private mixinMetadata(mixinMetadata: NullablePartialNotebookCellInternalMetadata) {
const edit: IImmediateCellEditOperation = { editType: CellEditType.PartialInternalMetadata, handle: this._cell.handle, internalMetadata: mixinMetadata };
this.applyEdits([edit]);
}
private cellIndexToHandle(cellOrCellIndex: vscode.NotebookCell | number | undefined): number {
let cell: ExtHostCell | undefined = this._cell;
if (typeof cellOrCellIndex === 'number') {
// todo@jrieken remove support for number shortly
cell = this._document.getCellFromIndex(cellOrCellIndex);
} else if (cellOrCellIndex) {
cell = this._document.getCellFromApiCell(cellOrCellIndex);
}
if (!cell) {
throw new Error('INVALID cell');
}
return cell.handle;
}
private validateAndConvertOutputs(items: vscode.NotebookCellOutput[]): IOutputDto[] {
return items.map(output => {
const newOutput = NotebookCellOutput.ensureUniqueMimeTypes(output.items, true);
if (newOutput === output.items) {
return extHostTypeConverters.NotebookCellOutput.from(output);
}
return extHostTypeConverters.NotebookCellOutput.from({
items: newOutput,
id: output.id,
metadata: output.metadata
});
});
}
private async updateOutputs(outputs: vscode.NotebookCellOutput | vscode.NotebookCellOutput[], cell: vscode.NotebookCell | number | undefined, append: boolean): Promise<void> {
const handle = this.cellIndexToHandle(cell);
const outputDtos = this.validateAndConvertOutputs(asArray(outputs));
return this.applyEditSoon({ editType: CellEditType.Output, handle, append, outputs: outputDtos });
}
private async updateOutputItems(items: vscode.NotebookCellOutputItem | vscode.NotebookCellOutputItem[], outputOrOutputId: vscode.NotebookCellOutput | string, append: boolean): Promise<void> {
if (NotebookCellOutput.isNotebookCellOutput(outputOrOutputId)) {
outputOrOutputId = outputOrOutputId.id;
}
items = NotebookCellOutput.ensureUniqueMimeTypes(asArray(items), true);
return this.applyEditSoon({ editType: CellEditType.OutputItems, items: items.map(extHostTypeConverters.NotebookCellOutputItem.from), outputId: outputOrOutputId, append });
}
asApiObject(): vscode.NotebookCellExecution {
const that = this;
const result: vscode.NotebookCellExecution = {
get token() { return that._tokenSource.token; },
get cell() { return that._cell.apiCell; },
get executionOrder() { return that._executionOrder; },
set executionOrder(v: number | undefined) {
that._executionOrder = v;
that.mixinMetadata({
executionOrder: v
});
},
start(startTime?: number): void {
if (that._state === NotebookCellExecutionTaskState.Resolved || that._state === NotebookCellExecutionTaskState.Started) {
throw new Error('Cannot call start again');
}
that._state = NotebookCellExecutionTaskState.Started;
that._onDidChangeState.fire();
that.mixinMetadata({
runState: NotebookCellExecutionState.Executing,
runStartTime: startTime ?? null
});
},
end(success: boolean | undefined, endTime?: number): void {
if (that._state === NotebookCellExecutionTaskState.Resolved) {
throw new Error('Cannot call resolve twice');
}
that._state = NotebookCellExecutionTaskState.Resolved;
that._onDidChangeState.fire();
that.mixinMetadata({
runState: null,
lastRunSuccess: success ?? null,
runEndTime: endTime ?? null,
});
},
clearOutput(cell?: vscode.NotebookCell | number): Thenable<void> {
that.verifyStateForOutput();
return that.updateOutputs([], cell, false);
},
appendOutput(outputs: vscode.NotebookCellOutput | vscode.NotebookCellOutput[], cell?: vscode.NotebookCell | number): Promise<void> {
that.verifyStateForOutput();
return that.updateOutputs(outputs, cell, true);
},
replaceOutput(outputs: vscode.NotebookCellOutput | vscode.NotebookCellOutput[], cell?: vscode.NotebookCell | number): Promise<void> {
that.verifyStateForOutput();
return that.updateOutputs(outputs, cell, false);
},
appendOutputItems(items: vscode.NotebookCellOutputItem | vscode.NotebookCellOutputItem[], output: vscode.NotebookCellOutput | string): Promise<void> {
that.verifyStateForOutput();
return that.updateOutputItems(items, output, true);
},
replaceOutputItems(items: vscode.NotebookCellOutputItem | vscode.NotebookCellOutputItem[], output: vscode.NotebookCellOutput | string): Promise<void> {
that.verifyStateForOutput();
return that.updateOutputItems(items, output, false);
}
};
return Object.freeze(result);
}
}
class TimeoutBasedCollector<T> {
private batch: T[] = [];
private waitPromise: Promise<void> | undefined;
constructor(
private readonly delay: number,
private readonly callback: (items: T[]) => Promise<void>) { }
addItem(item: T): Promise<void> {
this.batch.push(item);
if (!this.waitPromise) {
this.waitPromise = timeout(this.delay).then(() => {
this.waitPromise = undefined;
const batch = this.batch;
this.batch = [];
return this.callback(batch);
});
}
return this.waitPromise;
}
}

View File

@@ -0,0 +1,59 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Emitter } from 'vs/base/common/event';
import { ExtHostNotebookRenderersShape, IMainContext, MainContext, MainThreadNotebookRenderersShape } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
import { ExtHostNotebookEditor } from 'vs/workbench/api/common/extHostNotebookEditor';
import * as vscode from 'vscode';
export class ExtHostNotebookRenderers implements ExtHostNotebookRenderersShape {
private readonly _rendererMessageEmitters = new Map<string /* rendererId */, Emitter<vscode.NotebookRendererMessage<any>>>();
private readonly proxy: MainThreadNotebookRenderersShape;
constructor(mainContext: IMainContext, private readonly _extHostNotebook: ExtHostNotebookController) {
this.proxy = mainContext.getProxy(MainContext.MainThreadNotebookRenderers);
}
public $postRendererMessage(editorId: string, rendererId: string, message: unknown): void {
const editor = this._extHostNotebook.getEditorById(editorId);
this._rendererMessageEmitters.get(rendererId)?.fire({ editor: editor.apiEditor, message });
}
public createRendererMessaging<TSend, TRecv>(rendererId: string): vscode.NotebookRendererMessaging<TSend, TRecv> {
const messaging: vscode.NotebookRendererMessaging<TSend, TRecv> = {
onDidReceiveMessage: (...args) =>
this.getOrCreateEmitterFor(rendererId).event(...args),
postMessage: (editor, message) => {
const extHostEditor = ExtHostNotebookEditor.apiEditorsToExtHost.get(editor);
if (!extHostEditor) {
throw new Error(`The first argument to postMessage() must be a NotebookEditor`);
}
this.proxy.$postMessage(extHostEditor.id, rendererId, message);
},
};
return messaging;
}
private getOrCreateEmitterFor(rendererId: string) {
let emitter = this._rendererMessageEmitters.get(rendererId);
if (emitter) {
return emitter;
}
emitter = new Emitter({
onLastListenerRemove: () => {
emitter?.dispose();
this._rendererMessageEmitters.delete(rendererId);
}
});
this._rendererMessageEmitters.set(rendererId, emitter);
return emitter;
}
}

View File

@@ -10,8 +10,10 @@ import { MainContext, MainThreadStatusBarShape, IMainContext, ICommandDto } from
import { localize } from 'vs/nls';
import { CommandsConverter } from 'vs/workbench/api/common/extHostCommands';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
private static ID_GEN = 0;
private static ALLOWED_BACKGROUND_COLORS = new Map<string, ThemeColor>(
@@ -21,17 +23,20 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
#proxy: MainThreadStatusBarShape;
#commands: CommandsConverter;
private _id: number;
private _entryId: number;
private _extension?: IExtensionDescription;
private _id?: string;
private _alignment: number;
private _priority?: number;
private _disposed: boolean = false;
private _visible: boolean = false;
private _statusId: string;
private _statusName: string;
private _text: string = '';
private _tooltip?: string;
private _name?: string;
private _color?: string | ThemeColor;
private _backgroundColor?: ThemeColor;
private readonly _internalCommandRegistration = new DisposableStore();
@@ -43,20 +48,23 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
private _timeoutHandle: any;
private _accessibilityInformation?: vscode.AccessibilityInformation;
constructor(proxy: MainThreadStatusBarShape, commands: CommandsConverter, id: string, name: string, alignment: ExtHostStatusBarAlignment = ExtHostStatusBarAlignment.Left, priority?: number, accessibilityInformation?: vscode.AccessibilityInformation) {
constructor(proxy: MainThreadStatusBarShape, commands: CommandsConverter, extension: IExtensionDescription, id?: string, alignment?: ExtHostStatusBarAlignment, priority?: number);
constructor(proxy: MainThreadStatusBarShape, commands: CommandsConverter, extension: IExtensionDescription | undefined, id: string, alignment?: ExtHostStatusBarAlignment, priority?: number);
constructor(proxy: MainThreadStatusBarShape, commands: CommandsConverter, extension?: IExtensionDescription, id?: string, alignment: ExtHostStatusBarAlignment = ExtHostStatusBarAlignment.Left, priority?: number) {
this.#proxy = proxy;
this.#commands = commands;
this._id = ExtHostStatusBarEntry.ID_GEN++;
this._statusId = id;
this._statusName = name;
this._entryId = ExtHostStatusBarEntry.ID_GEN++;
this._extension = extension;
this._id = id;
this._alignment = alignment;
this._priority = priority;
this._accessibilityInformation = accessibilityInformation;
}
public get id(): number {
return this._id;
public get id(): string {
return this._id ?? this._extension!.identifier.value;
}
public get alignment(): vscode.StatusBarAlignment {
@@ -71,6 +79,10 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
return this._text;
}
public get name(): string | undefined {
return this._name;
}
public get tooltip(): string | undefined {
return this._tooltip;
}
@@ -96,6 +108,11 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
this.update();
}
public set name(name: string | undefined) {
this._name = name;
this.update();
}
public set tooltip(tooltip: string | undefined) {
this._tooltip = tooltip;
this.update();
@@ -150,7 +167,7 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
public hide(): void {
clearTimeout(this._timeoutHandle);
this._visible = false;
this.#proxy.$dispose(this.id);
this.#proxy.$dispose(this._entryId);
}
private update(): void {
@@ -164,6 +181,28 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
this._timeoutHandle = setTimeout(() => {
this._timeoutHandle = undefined;
// If the id is not set, derive it from the extension identifier,
// otherwise make sure to prefix it with the extension identifier
// to get a more unique value across extensions.
let id: string;
if (this._extension) {
if (this._id) {
id = `${this._extension.identifier.value}.${this._id}`;
} else {
id = this._extension.identifier.value;
}
} else {
id = this._id!;
}
// If the name is not set, derive it from the extension descriptor
let name: string;
if (this._name) {
name = this._name;
} else {
name = localize('extensionLabel', "{0} (Extension)", this._extension!.displayName || this._extension!.name);
}
// If a background color is set, the foreground is determined
let color = this._color;
if (this._backgroundColor) {
@@ -171,7 +210,7 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
}
// Set to status bar
this.#proxy.$setEntry(this.id, this._statusId, this._statusName, this._text, this._tooltip, this._command?.internal, color,
this.#proxy.$setEntry(this._entryId, id, name, this._text, this._tooltip, this._command?.internal, color,
this._backgroundColor, this._alignment === ExtHostStatusBarAlignment.Left ? MainThreadStatusBarAlignment.LEFT : MainThreadStatusBarAlignment.RIGHT,
this._priority, this._accessibilityInformation);
}, 0);
@@ -189,7 +228,8 @@ class StatusBarMessage {
private _messages: { message: string }[] = [];
constructor(statusBar: ExtHostStatusBar) {
this._item = statusBar.createStatusBarEntry('status.extensionMessage', localize('status.extensionMessage', "Extension Status"), ExtHostStatusBarAlignment.Left, Number.MIN_VALUE);
this._item = statusBar.createStatusBarEntry(undefined, 'status.extensionMessage', ExtHostStatusBarAlignment.Left, Number.MIN_VALUE);
this._item.name = localize('status.extensionMessage', "Extension Status");
}
dispose() {
@@ -233,12 +273,13 @@ export class ExtHostStatusBar {
this._statusMessage = new StatusBarMessage(this);
}
createStatusBarEntry(id: string, name: string, alignment?: ExtHostStatusBarAlignment, priority?: number, accessibilityInformation?: vscode.AccessibilityInformation): vscode.StatusBarItem {
return new ExtHostStatusBarEntry(this._proxy, this._commands, id, name, alignment, priority, accessibilityInformation);
createStatusBarEntry(extension: IExtensionDescription | undefined, id: string, alignment?: ExtHostStatusBarAlignment, priority?: number): vscode.StatusBarItem;
createStatusBarEntry(extension: IExtensionDescription, id?: string, alignment?: ExtHostStatusBarAlignment, priority?: number): vscode.StatusBarItem;
createStatusBarEntry(extension: IExtensionDescription, id: string, alignment?: ExtHostStatusBarAlignment, priority?: number): vscode.StatusBarItem {
return new ExtHostStatusBarEntry(this._proxy, this._commands, extension, id, alignment, priority);
}
setStatusBarMessage(text: string, timeoutOrThenable?: number | Thenable<any>): Disposable {
const d = this._statusMessage.setMessage(text);
let handle: any;

View File

@@ -605,8 +605,6 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape, IExtHostTask
public abstract $resolveVariables(uriComponents: UriComponents, toResolve: { process?: { name: string; cwd?: string; path?: string }, variables: string[] }): Promise<{ process?: string, variables: { [key: string]: string; } }>;
public abstract $getDefaultShellAndArgs(): Promise<{ shell: string, args: string[] | string | undefined }>;
private nextHandle(): number {
return this._handleCounter++;
}
@@ -775,10 +773,6 @@ export class WorkerExtHostTask extends ExtHostTaskBase {
return result;
}
public $getDefaultShellAndArgs(): Promise<{ shell: string, args: string[] | string | undefined }> {
throw new Error('Not implemented');
}
public async $jsonTasksSupported(): Promise<boolean> {
return false;
}

View File

@@ -1,6 +1,6 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';

View File

@@ -5,13 +5,12 @@
import type * as vscode from 'vscode';
import { Event, Emitter } from 'vs/base/common/event';
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IShellAndArgsDto, ITerminalDimensionsDto, ITerminalLinkDto, TerminalIdentifier } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, ITerminalDimensionsDto, ITerminalLinkDto, TerminalIdentifier } from 'vs/workbench/api/common/extHost.protocol';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { URI } from 'vs/base/common/uri';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { IDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle';
import { Disposable as VSCodeDisposable, EnvironmentVariableMutatorType } from './extHostTypes';
import { Disposable as VSCodeDisposable, EnvironmentVariableMutatorType, ThemeColor } from './extHostTypes';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { localize } from 'vs/nls';
import { NotSupportedError } from 'vs/base/common/errors';
@@ -19,9 +18,10 @@ import { serializeEnvironmentVariableCollection } from 'vs/workbench/contrib/ter
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 { IProcessReadyEvent, IShellLaunchConfigDto, ITerminalChildProcess, ITerminalDimensionsOverride, ITerminalLaunchError, ITerminalProfile, TerminalIcon, TerminalShellType } from 'vs/platform/terminal/common/terminal';
import { TerminalDataBufferer } from 'vs/platform/terminal/common/terminalDataBuffering';
import { ITerminalProfile } from 'vs/workbench/contrib/terminal/common/terminal';
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
import { withNullAsUndefined } from 'vs/base/common/types';
export interface IExtHostTerminalService extends ExtHostTerminalServiceShape, IDisposable {
@@ -37,15 +37,22 @@ export interface IExtHostTerminalService extends ExtHostTerminalServiceShape, ID
onDidWriteTerminalData: Event<vscode.TerminalDataWriteEvent>;
createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal;
createTerminalFromOptions(options: vscode.TerminalOptions, isFeatureTerminal?: boolean): vscode.Terminal;
createTerminalFromOptions(options: vscode.TerminalOptions, internalOptions?: ITerminalInternalOptions): vscode.Terminal;
createExtensionTerminal(options: vscode.ExtensionTerminalOptions): vscode.Terminal;
attachPtyToTerminal(id: number, pty: vscode.Pseudoterminal): void;
getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string;
getDefaultShellArgs(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string[] | string;
getDefaultShell(useAutomationShell: boolean): string;
getDefaultShellArgs(useAutomationShell: boolean): string[] | string;
registerLinkProvider(provider: vscode.TerminalLinkProvider): vscode.Disposable;
registerProfileProvider(id: string, provider: vscode.TerminalProfileProvider): vscode.Disposable;
getEnvironmentVariableCollection(extension: IExtensionDescription, persistent?: boolean): vscode.EnvironmentVariableCollection;
}
export interface ITerminalInternalOptions {
isFeatureTerminal?: boolean;
useShellEnvironment?: boolean;
isSplitTerminal?: boolean;
}
export const IExtHostTerminalService = createDecorator<IExtHostTerminalService>('IExtHostTerminalService');
export class ExtHostTerminal {
@@ -114,29 +121,39 @@ export class ExtHostTerminal {
}
public async create(
shellPath?: string,
shellArgs?: string[] | string,
cwd?: string | URI,
env?: ITerminalEnvironment,
icon?: string,
initialText?: string,
waitOnExit?: boolean,
strictEnv?: boolean,
hideFromUser?: boolean,
isFeatureTerminal?: boolean,
isExtensionOwnedTerminal?: boolean
options: vscode.TerminalOptions,
internalOptions?: ITerminalInternalOptions,
): 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, icon, initialText, waitOnExit, strictEnv, hideFromUser, isFeatureTerminal, isExtensionOwnedTerminal });
await this._proxy.$createTerminal(this._id, {
name: options.name,
shellPath: withNullAsUndefined(options.shellPath),
shellArgs: withNullAsUndefined(options.shellArgs),
cwd: withNullAsUndefined(options.cwd),
env: withNullAsUndefined(options.env),
icon: withNullAsUndefined(asTerminalIcon(options.iconPath)),
initialText: withNullAsUndefined(options.message),
strictEnv: withNullAsUndefined(options.strictEnv),
hideFromUser: withNullAsUndefined(options.hideFromUser),
isFeatureTerminal: withNullAsUndefined(internalOptions?.isFeatureTerminal),
isExtensionOwnedTerminal: true,
useShellEnvironment: withNullAsUndefined(internalOptions?.useShellEnvironment),
isSplitTerminal: withNullAsUndefined(internalOptions?.isSplitTerminal)
});
}
public async createExtensionTerminal(): Promise<number> {
public async createExtensionTerminal(isSplitTerminal?: boolean, iconPath?: URI | { light: URI; dark: URI } | ThemeIcon): Promise<number> {
if (typeof this._id !== 'string') {
throw new Error('Terminal has already been created');
}
await this._proxy.$createTerminal(this._id, { name: this._name, isExtensionCustomPtyTerminal: true });
await this._proxy.$createTerminal(this._id, {
name: this._name,
isExtensionCustomPtyTerminal: true,
icon: iconPath,
isSplitTerminal
});
// At this point, the id has been set via `$acceptTerminalOpened`
if (typeof this._id === 'string') {
throw new Error('Terminal creation failed');
@@ -195,8 +212,8 @@ export class ExtHostPseudoterminal implements ITerminalChildProcess {
public readonly onProcessData: Event<string> = this._onProcessData.event;
private readonly _onProcessExit = new Emitter<number | undefined>();
public readonly onProcessExit: Event<number | undefined> = this._onProcessExit.event;
private readonly _onProcessReady = new Emitter<{ pid: number, cwd: string }>();
public get onProcessReady(): Event<{ pid: number, cwd: string }> { return this._onProcessReady.event; }
private readonly _onProcessReady = new Emitter<IProcessReadyEvent>();
public get onProcessReady(): Event<IProcessReadyEvent> { return this._onProcessReady.event; }
private readonly _onProcessTitleChanged = new Emitter<string>();
public readonly onProcessTitleChanged: Event<string> = this._onProcessTitleChanged.event;
private readonly _onProcessOverrideDimensions = new Emitter<ITerminalDimensionsOverride | undefined>();
@@ -259,6 +276,9 @@ export class ExtHostPseudoterminal implements ITerminalChildProcess {
if (this._pty.onDidOverrideDimensions) {
this._pty.onDidOverrideDimensions(e => this._onProcessOverrideDimensions.fire(e ? { cols: e.columns, rows: e.rows } : undefined)); // {{SQL CARBON EDIT}} strict-null-checks
}
if (this._pty.onDidChangeName) {
this._pty.onDidChangeName(title => this._onProcessTitleChanged.fire(title));
}
this._pty.open(initialDimensions ? initialDimensions : undefined);
@@ -289,9 +309,12 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
protected _extensionTerminalAwaitingStart: { [id: number]: { initialDimensions: ITerminalDimensionsDto | undefined } | undefined } = {};
protected _getTerminalPromises: { [id: number]: Promise<ExtHostTerminal | undefined> } = {};
protected _environmentVariableCollections: Map<string, EnvironmentVariableCollection> = new Map();
private _defaultProfile: ITerminalProfile | undefined;
private _defaultAutomationProfile: ITerminalProfile | undefined;
private readonly _bufferer: TerminalDataBufferer;
private readonly _linkProviders: Set<vscode.TerminalLinkProvider> = new Set();
private readonly _profileProviders: Map<string, vscode.TerminalProfileProvider> = new Map();
private readonly _terminalLinkCache: Map<number, Map<number, ICachedLinkEntry>> = new Map();
private readonly _terminalLinkCancellationSource: Map<number, CancellationTokenSource> = new Map();
@@ -331,16 +354,22 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
}
public abstract createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal;
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 $getAvailableProfiles(configuredProfilesOnly: boolean): Promise<ITerminalProfile[]>;
public abstract $getDefaultShellAndArgs(useAutomationShell: boolean): Promise<IShellAndArgsDto>;
public abstract createTerminalFromOptions(options: vscode.TerminalOptions, internalOptions?: ITerminalInternalOptions): vscode.Terminal;
public createExtensionTerminal(options: vscode.ExtensionTerminalOptions): vscode.Terminal {
public getDefaultShell(useAutomationShell: boolean): string {
const profile = useAutomationShell ? this._defaultAutomationProfile : this._defaultProfile;
return profile?.path || '';
}
public getDefaultShellArgs(useAutomationShell: boolean): string[] | string {
const profile = useAutomationShell ? this._defaultAutomationProfile : this._defaultProfile;
return profile?.args || [];
}
public createExtensionTerminal(options: vscode.ExtensionTerminalOptions, internalOptions?: ITerminalInternalOptions): vscode.Terminal {
const terminal = new ExtHostTerminal(this._proxy, generateUuid(), options, options.name);
const p = new ExtHostPseudoterminal(options.pty);
terminal.createExtensionTerminal().then(id => {
terminal.createExtensionTerminal(internalOptions?.isSplitTerminal, asTerminalIcon(options.iconPath)).then(id => {
const disposable = this._setupExtHostProcessListeners(id, p);
this._terminalProcessDisposables[id] = disposable;
});
@@ -363,7 +392,7 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
if (id === null) {
this._activeTerminal = undefined;
if (original !== this._activeTerminal) {
this._onDidChangeActiveTerminal.fire(this._activeTerminal.value);
this._onDidChangeActiveTerminal.fire(this._activeTerminal?.value); // {{SQL CARBON EDIT}}
}
return;
}
@@ -555,6 +584,34 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
});
}
public registerProfileProvider(id: string, provider: vscode.TerminalProfileProvider): vscode.Disposable {
if (this._profileProviders.has(id)) {
throw new Error(`Terminal profile provider "${id}" already registered`);
}
this._profileProviders.set(id, provider);
this._proxy.$registerProfileProvider(id);
return new VSCodeDisposable(() => {
this._profileProviders.delete(id);
this._proxy.$unregisterProfileProvider(id);
});
}
public async $createContributedProfileTerminal(id: string, isSplitTerminal: boolean): Promise<void> {
const token = new CancellationTokenSource().token;
const options = await this._profileProviders.get(id)?.provideProfileOptions(token);
if (token.isCancellationRequested) {
return;
}
if (!options) {
throw new Error(`No terminal profile options provided for id "${id}"`);
}
if ('pty' in options) {
this.createExtensionTerminal(options, { isSplitTerminal });
return;
}
this.createTerminalFromOptions(options, { isSplitTerminal });
}
public async $provideLinks(terminalId: number, line: string): Promise<ITerminalLinkDto[]> {
const terminal = this._getTerminalById(terminalId);
if (!terminal) {
@@ -686,6 +743,11 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
});
}
public $acceptDefaultProfile(profile: ITerminalProfile, automationProfile: ITerminalProfile): void {
this._defaultProfile = profile;
this._defaultAutomationProfile = automationProfile;
}
private _setEnvironmentVariableCollection(extensionIdentifier: string, collection: EnvironmentVariableCollection): void {
this._environmentVariableCollections.set(extensionIdentifier, collection);
collection.onDidChangeCollection(() => {
@@ -771,23 +833,20 @@ export class WorkerExtHostTerminalService extends BaseExtHostTerminalService {
throw new NotSupportedError();
}
public createTerminalFromOptions(options: vscode.TerminalOptions): vscode.Terminal {
throw new NotSupportedError();
}
public getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string {
throw new NotSupportedError();
}
public getDefaultShellArgs(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string[] | string {
throw new NotSupportedError();
}
public $getAvailableProfiles(configuredProfilesOnly: boolean): Promise<ITerminalProfile[]> {
throw new NotSupportedError();
}
public async $getDefaultShellAndArgs(useAutomationShell: boolean): Promise<IShellAndArgsDto> {
public createTerminalFromOptions(options: vscode.TerminalOptions, internalOptions?: ITerminalInternalOptions): vscode.Terminal {
throw new NotSupportedError();
}
}
function asTerminalIcon(iconPath?: vscode.Uri | { light: vscode.Uri; dark: vscode.Uri } | vscode.ThemeIcon): TerminalIcon | undefined {
if (!iconPath) {
return undefined;
}
if (!('id' in iconPath)) {
return iconPath;
}
return {
id: iconPath.id,
color: iconPath.color as ThemeColor
};
}

View File

@@ -666,7 +666,7 @@ export class TestItemFilteredWrapper extends TestItemImpl {
}
}
const nowMatches = this.children.size > 0 || this.actual.uri.toString() === this.filterDocument.uri.toString();
const nowMatches = this.children.size > 0 || this.actual.uri?.toString() === this.filterDocument.uri.toString();
this._cachedMatchesFilter = nowMatches;
if (nowMatches !== didMatch) {

View File

@@ -1,6 +1,6 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Emitter } from 'vs/base/common/event';

View File

@@ -15,6 +15,7 @@ import { EndOfLine, Position, Range, Selection, SnippetString, TextEditorLineNum
import type * as vscode from 'vscode';
import { ILogService } from 'vs/platform/log/common/log';
import { Lazy } from 'vs/base/common/lazy';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
export class TextEditorDecorationType {
@@ -22,9 +23,9 @@ export class TextEditorDecorationType {
readonly value: vscode.TextEditorDecorationType;
constructor(proxy: MainThreadTextEditorsShape, options: vscode.DecorationRenderOptions) {
constructor(proxy: MainThreadTextEditorsShape, extension: IExtensionDescription, options: vscode.DecorationRenderOptions) {
const key = TextEditorDecorationType._Keys.nextId();
proxy.$registerTextEditorDecorationType(key, TypeConverters.DecorationRenderOptions.from(options));
proxy.$registerTextEditorDecorationType(extension.identifier, key, TypeConverters.DecorationRenderOptions.from(options));
this.value = Object.freeze({
key,
dispose() {

View File

@@ -11,6 +11,7 @@ import { ExtHostTextEditor, TextEditorDecorationType } from 'vs/workbench/api/co
import * as TypeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import { TextEditorSelectionChangeKind } from 'vs/workbench/api/common/extHostTypes';
import type * as vscode from 'vscode';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
export class ExtHostEditors implements ExtHostEditorsShape {
@@ -91,8 +92,8 @@ export class ExtHostEditors implements ExtHostEditorsShape {
}
}
createTextEditorDecorationType(options: vscode.DecorationRenderOptions): vscode.TextEditorDecorationType {
return new TextEditorDecorationType(this._proxy, options).value;
createTextEditorDecorationType(extension: IExtensionDescription, options: vscode.DecorationRenderOptions): vscode.TextEditorDecorationType {
return new TextEditorDecorationType(this._proxy, extension, options).value;
}
// --- called from main thread

View File

@@ -9,7 +9,7 @@ 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 { isDefined, isNumber, isString } from 'vs/base/common/types';
import { isDefined, isEmptyObject, 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';
@@ -545,7 +545,7 @@ export namespace WorkspaceEdit {
resource: entry.uri,
edit: entry.edit,
notebookMetadata: entry.notebookMetadata,
notebookVersionId: extHostNotebooks?.lookupNotebookDocument(entry.uri)?.apiNotebook.version
notebookVersionId: extHostNotebooks?.getNotebookDocument(entry.uri, true)?.apiNotebook.version
});
} else if (entry._type === types.FileEditType.CellOutput) {
@@ -580,7 +580,7 @@ export namespace WorkspaceEdit {
_type: extHostProtocol.WorkspaceEditType.Cell,
metadata: entry.metadata,
resource: entry.uri,
notebookVersionId: extHostNotebooks?.lookupNotebookDocument(entry.uri)?.apiNotebook.version,
notebookVersionId: extHostNotebooks?.getNotebookDocument(entry.uri, true)?.apiNotebook.version,
edit: {
editType: notebooks.CellEditType.Replace,
index: entry.index,
@@ -1130,37 +1130,35 @@ export namespace SignatureHelp {
}
}
export namespace InlineHint {
export namespace InlayHint {
export function from(hint: vscode.InlineHint): modes.InlineHint {
export function from(hint: vscode.InlayHint): modes.InlayHint {
return {
text: hint.text,
range: Range.from(hint.range),
kind: InlineHintKind.from(hint.kind ?? types.InlineHintKind.Other),
description: hint.description && MarkdownString.fromStrict(hint.description),
position: Position.from(hint.position),
kind: InlayHintKind.from(hint.kind ?? types.InlayHintKind.Other),
whitespaceBefore: hint.whitespaceBefore,
whitespaceAfter: hint.whitespaceAfter
};
}
export function to(hint: modes.InlineHint): vscode.InlineHint {
const res = new types.InlineHint(
export function to(hint: modes.InlayHint): vscode.InlayHint {
const res = new types.InlayHint(
hint.text,
Range.to(hint.range),
InlineHintKind.to(hint.kind)
Position.to(hint.position),
InlayHintKind.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 {
export namespace InlayHintKind {
export function from(kind: vscode.InlayHintKind): modes.InlayHintKind {
return kind;
}
export function to(kind: modes.InlineHintKind): vscode.InlineHintKind {
export function to(kind: modes.InlayHintKind): vscode.InlayHintKind {
return kind;
}
}
@@ -1417,49 +1415,20 @@ export namespace NotebookRange {
}
}
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 {
export namespace NotebookCellExecutionSummary {
export function to(data: notebooks.NotebookCellInternalMetadata): vscode.NotebookCellExecutionSummary {
return {
startTime: data.runStartTime,
endTime: data.runEndTime,
timing: typeof data.runStartTime === 'number' && typeof data.runEndTime === 'number' ? { startTime: data.runStartTime, endTime: data.runEndTime } : undefined,
executionOrder: data.executionOrder,
success: data.lastRunSuccess
};
}
export function from(data: vscode.NotebookCellExecutionSummary): Partial<notebooks.NotebookCellMetadata> {
export function from(data: vscode.NotebookCellExecutionSummary): Partial<notebooks.NotebookCellInternalMetadata> {
return {
lastRunSuccess: data.success,
runStartTime: data.startTime,
runEndTime: data.endTime,
runStartTime: data.timing?.startTime,
runEndTime: data.timing?.endTime,
executionOrder: data.executionOrder
};
}
@@ -1468,8 +1437,8 @@ export namespace NotebookCellPreviousExecutionResult {
export namespace NotebookCellKind {
export function from(data: vscode.NotebookCellKind): notebooks.CellKind {
switch (data) {
case types.NotebookCellKind.Markdown:
return notebooks.CellKind.Markdown;
case types.NotebookCellKind.Markup:
return notebooks.CellKind.Markup;
case types.NotebookCellKind.Code:
default:
return notebooks.CellKind.Code;
@@ -1478,8 +1447,8 @@ export namespace NotebookCellKind {
export function to(data: notebooks.CellKind): vscode.NotebookCellKind {
switch (data) {
case notebooks.CellKind.Markdown:
return types.NotebookCellKind.Markdown;
case notebooks.CellKind.Markup:
return types.NotebookCellKind.Markup;
case notebooks.CellKind.Code:
default:
return types.NotebookCellKind.Code;
@@ -1487,17 +1456,40 @@ export namespace NotebookCellKind {
}
}
export namespace NotebookData {
export function from(data: vscode.NotebookData): notebooks.NotebookDataDto {
const res: notebooks.NotebookDataDto = {
metadata: data.metadata ?? Object.create(null),
cells: [],
};
for (let cell of data.cells) {
types.NotebookCellData.validate(cell);
res.cells.push(NotebookCellData.from(cell));
}
return res;
}
export function to(data: notebooks.NotebookDataDto): vscode.NotebookData {
const res = new types.NotebookData(
data.cells.map(NotebookCellData.to),
);
if (!isEmptyObject(data.metadata)) {
res.metadata = data.metadata;
}
return res;
}
}
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 ?? {})
},
language: data.languageId,
source: data.value,
metadata: data.metadata,
internalMetadata: NotebookCellExecutionSummary.from(data.executionSummary ?? {}),
outputs: data.outputs ? data.outputs.map(NotebookCellOutput.from) : []
};
}
@@ -1508,7 +1500,8 @@ export namespace NotebookCellData {
data.source,
data.language,
data.outputs ? data.outputs.map(NotebookCellOutput.to) : undefined,
data.metadata ? NotebookCellMetadata.to(data.metadata) : undefined,
data.metadata,
data.internalMetadata ? NotebookCellExecutionSummary.to(data.internalMetadata) : undefined
);
}
}
@@ -1517,21 +1510,20 @@ export namespace NotebookCellOutputItem {
export function from(item: types.NotebookCellOutputItem): notebooks.IOutputItemDto {
return {
mime: item.mime,
value: item.value,
metadata: item.metadata
valueBytes: Array.from(item.data), //todo@jrieken this HACKY and SLOW... hoist VSBuffer instead
};
}
export function to(item: notebooks.IOutputItemDto): types.NotebookCellOutputItem {
return new types.NotebookCellOutputItem(item.mime, item.value, item.metadata);
return new types.NotebookCellOutputItem(new Uint8Array(item.valueBytes), item.mime);
}
}
export namespace NotebookCellOutput {
export function from(output: types.NotebookCellOutput): notebooks.IOutputDto {
export function from(output: vscode.NotebookCellOutput): notebooks.IOutputDto {
return {
outputId: output.id,
outputs: output.outputs.map(NotebookCellOutputItem.from),
outputs: output.items.map(NotebookCellOutputItem.from),
metadata: output.metadata
};
}
@@ -1644,35 +1636,22 @@ export namespace NotebookDocumentContentOptions {
export function from(options: vscode.NotebookDocumentContentOptions | undefined): notebooks.TransientOptions {
return {
transientOutputs: options?.transientOutputs ?? false,
transientCellMetadata: {
...options?.transientCellMetadata,
executionOrder: true,
runState: true,
runStartTime: true,
runStartTimeAdjustment: true,
runEndTime: true,
lastRunSuccess: true
},
transientCellMetadata: options?.transientCellMetadata ?? {},
transientDocumentMetadata: options?.transientDocumentMetadata ?? {}
};
}
}
export namespace NotebookKernelPreload {
export function from(preload: vscode.NotebookKernelPreload): { uri: UriComponents; provides: string[] } {
export namespace NotebookRendererScript {
export function from(preload: vscode.NotebookRendererScript): { 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 function to(preload: { uri: UriComponents; provides: string[] }): vscode.NotebookRendererScript {
return new types.NotebookRendererScript(URI.revive(preload.uri), preload.provides);
}
}
export namespace TestMessage {

View File

@@ -3,13 +3,13 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { coalesceInPlace, equals } from 'vs/base/common/arrays';
import { asArray, 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 { ReadonlyMapView, ResourceMap } from 'vs/base/common/map';
import { isFalsyOrWhitespace } from 'vs/base/common/strings';
import { isStringArray } from 'vs/base/common/types';
import { normalizeMimeType } from 'vs/base/common/mime';
import { isArray, 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';
@@ -612,7 +612,7 @@ export interface IFileCellEdit {
_type: FileEditType.Cell;
uri: URI;
edit?: ICellEditOperation;
notebookMetadata?: vscode.NotebookDocumentMetadata;
notebookMetadata?: Record<string, any>;
metadata?: vscode.WorkspaceEditEntryMetadata;
}
@@ -631,7 +631,7 @@ export interface ICellOutputEdit {
index: number;
append: boolean;
newOutputs?: NotebookCellOutput[];
newMetadata?: vscode.NotebookCellMetadata;
newMetadata?: Record<string, any>;
metadata?: vscode.WorkspaceEditEntryMetadata;
}
@@ -674,7 +674,7 @@ export class WorkspaceEdit implements vscode.WorkspaceEdit {
// --- notebook
replaceNotebookMetadata(uri: URI, value: vscode.NotebookDocumentMetadata, metadata?: vscode.WorkspaceEditEntryMetadata): void {
replaceNotebookMetadata(uri: URI, value: Record<string, any>, metadata?: vscode.WorkspaceEditEntryMetadata): void {
this._edits.push({ _type: FileEditType.Cell, metadata, uri, edit: { editType: CellEditType.DocumentMetadata, metadata: value }, notebookMetadata: value });
}
@@ -707,7 +707,7 @@ export class WorkspaceEdit implements vscode.WorkspaceEdit {
}
}
replaceNotebookCellMetadata(uri: URI, index: number, cellMetadata: vscode.NotebookCellMetadata, metadata?: vscode.WorkspaceEditEntryMetadata): void {
replaceNotebookCellMetadata(uri: URI, index: number, cellMetadata: Record<string, any>, metadata?: vscode.WorkspaceEditEntryMetadata): void {
this._edits.push({ _type: FileEditType.Cell, metadata, uri, edit: { editType: CellEditType.PartialMetadata, index, metadata: cellMetadata } });
}
@@ -1420,24 +1420,23 @@ export enum SignatureHelpTriggerKind {
}
export enum InlineHintKind {
export enum InlayHintKind {
Other = 0,
Type = 1,
Parameter = 2,
}
@es5ClassCompat
export class InlineHint {
export class InlayHint {
text: string;
range: Range;
kind?: vscode.InlineHintKind;
description?: string | vscode.MarkdownString;
position: Position;
kind?: vscode.InlayHintKind;
whitespaceBefore?: boolean;
whitespaceAfter?: boolean;
constructor(text: string, range: Range, kind?: vscode.InlineHintKind) {
constructor(text: string, position: Position, kind?: vscode.InlayHintKind) {
this.text = text;
this.range = range;
this.position = position;
this.kind = kind;
}
}
@@ -1548,6 +1547,29 @@ export class CompletionList {
}
}
@es5ClassCompat
export class InlineSuggestion implements vscode.InlineCompletionItem {
text: string;
range?: Range;
command?: vscode.Command;
constructor(text: string, range?: Range, command?: vscode.Command) {
this.text = text;
this.range = range;
this.command = command;
}
}
@es5ClassCompat
export class InlineSuggestions implements vscode.InlineCompletionList {
items: vscode.InlineCompletionItem[];
constructor(items: vscode.InlineCompletionItem[]) {
this.items = items;
}
}
export enum ViewColumn {
Active = -1,
Beside = -2,
@@ -2439,6 +2461,11 @@ export class EvaluatableExpression implements vscode.EvaluatableExpression {
}
}
export enum InlineCompletionTriggerKind {
Automatic = 0,
Explicit = 1,
}
@es5ClassCompat
export class InlineValueText implements vscode.InlineValueText {
readonly range: Range;
@@ -2956,103 +2983,20 @@ export class NotebookRange {
}
}
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 validate(data: NotebookCellData): void {
if (typeof data.kind !== 'number') {
throw new Error('NotebookCellData MUST have \'kind\' property');
}
if (typeof data.value !== 'string') {
throw new Error('NotebookCellData MUST have \'value\' property');
}
if (typeof data.languageId !== 'string') {
throw new Error('NotebookCellData MUST have \'languageId\' property');
}
}
static isNotebookCellDataArray(value: unknown): value is vscode.NotebookCellData[] {
return Array.isArray(value) && (<unknown[]>value).every(elem => NotebookCellData.isNotebookCellData(elem));
}
@@ -3063,30 +3007,31 @@ export class NotebookCellData {
}
kind: NotebookCellKind;
source: string;
language: string;
outputs?: NotebookCellOutput[];
metadata?: NotebookCellMetadata;
latestExecutionSummary?: vscode.NotebookCellExecutionSummary;
value: string;
languageId: string;
outputs?: vscode.NotebookCellOutput[];
metadata?: Record<string, any>;
executionSummary?: vscode.NotebookCellExecutionSummary;
constructor(kind: NotebookCellKind, source: string, language: string, outputs?: NotebookCellOutput[], metadata?: NotebookCellMetadata, latestExecutionSummary?: vscode.NotebookCellExecutionSummary) {
constructor(kind: NotebookCellKind, value: string, languageId: string, outputs?: vscode.NotebookCellOutput[], metadata?: Record<string, any>, executionSummary?: vscode.NotebookCellExecutionSummary) {
this.kind = kind;
this.source = source;
this.language = language;
this.value = value;
this.languageId = languageId;
this.outputs = outputs ?? [];
this.metadata = metadata;
this.latestExecutionSummary = latestExecutionSummary;
this.executionSummary = executionSummary;
NotebookCellData.validate(this);
}
}
export class NotebookData {
cells: NotebookCellData[];
metadata: NotebookDocumentMetadata;
metadata?: { [key: string]: any };
constructor(cells: NotebookCellData[], metadata?: NotebookDocumentMetadata) {
constructor(cells: NotebookCellData[]) {
this.cells = cells;
this.metadata = metadata ?? new NotebookDocumentMetadata();
}
}
@@ -3094,32 +3039,105 @@ export class NotebookData {
export class NotebookCellOutputItem {
static isNotebookCellOutputItem(obj: unknown): obj is vscode.NotebookCellOutputItem {
return obj instanceof NotebookCellOutputItem;
if (obj instanceof NotebookCellOutputItem) {
return true;
}
if (!obj) {
return false;
}
return typeof (<vscode.NotebookCellOutputItem>obj).mime === 'string'
&& (<vscode.NotebookCellOutputItem>obj).data instanceof Uint8Array;
}
static error(err: Error | { name: string, message?: string, stack?: string }): NotebookCellOutputItem {
const obj = {
name: err.name,
message: err.message,
stack: err.stack
};
return NotebookCellOutputItem.json(obj, 'application/vnd.code.notebook.error');
}
static stdout(value: string): NotebookCellOutputItem {
return NotebookCellOutputItem.text(value, 'application/vnd.code.notebook.stdout');
}
static stderr(value: string): NotebookCellOutputItem {
return NotebookCellOutputItem.text(value, 'application/vnd.code.notebook.stderr');
}
static bytes(value: Uint8Array, mime: string = 'application/octet-stream'): NotebookCellOutputItem {
return new NotebookCellOutputItem(value, mime);
}
static #encoder = new TextEncoder();
static text(value: string, mime: string = 'text/plain'): NotebookCellOutputItem {
const bytes = NotebookCellOutputItem.#encoder.encode(String(value));
return new NotebookCellOutputItem(bytes, mime);
}
static json(value: any, mime: string = 'application/json'): NotebookCellOutputItem {
const rawStr = JSON.stringify(value, undefined, '\t');
return NotebookCellOutputItem.text(rawStr, mime);
}
constructor(
public data: Uint8Array,
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');
const mimeNormalized = normalizeMimeType(mime, true);
if (!mimeNormalized) {
throw new Error('INVALID mime type, must not be empty or falsy: ' + mime);
}
this.mime = mimeNormalized;
}
}
export class NotebookCellOutput {
static isNotebookCellOutput(candidate: any): candidate is vscode.NotebookCellOutput {
if (candidate instanceof NotebookCellOutput) {
return true;
}
if (!candidate || typeof candidate !== 'object') {
return false;
}
return typeof (<NotebookCellOutput>candidate).id === 'string' && isArray((<NotebookCellOutput>candidate).items);
}
static ensureUniqueMimeTypes(items: NotebookCellOutputItem[], warn: boolean = false): NotebookCellOutputItem[] {
const seen = new Set<string>();
const removeIdx = new Set<number>();
for (let i = 0; i < items.length; i++) {
const item = items[i];
const normalMime = normalizeMimeType(item.mime);
if (!seen.has(normalMime)) {
seen.add(normalMime);
continue;
}
// duplicated mime types... first has won
removeIdx.add(i);
if (warn) {
console.warn(`DUPLICATED mime type '${item.mime}' will be dropped`);
}
}
if (removeIdx.size === 0) {
return items;
}
return items.filter((_item, index) => !removeIdx.has(index));
}
id: string;
outputs: NotebookCellOutputItem[];
items: NotebookCellOutputItem[];
metadata?: Record<string, any>;
constructor(
outputs: NotebookCellOutputItem[],
items: NotebookCellOutputItem[],
idOrMetadata?: string | Record<string, any>,
metadata?: Record<string, any>
) {
this.outputs = outputs;
this.items = NotebookCellOutput.ensureUniqueMimeTypes(items, true);
if (typeof idOrMetadata === 'string') {
this.id = idOrMetadata;
this.metadata = metadata;
@@ -3131,7 +3149,7 @@ export class NotebookCellOutput {
}
export enum NotebookCellKind {
Markdown = 1,
Markup = 1,
Code = 2
}
@@ -3156,11 +3174,7 @@ export enum NotebookEditorRevealType {
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) { }
public alignment: NotebookCellStatusBarAlignment) { }
}
@@ -3169,6 +3183,18 @@ export enum NotebookControllerAffinity {
Preferred = 2
}
export class NotebookRendererScript {
public provides: string[];
constructor(
public uri: vscode.Uri,
provides: string | string[] = []
) {
this.provides = asArray(provides);
}
}
//#endregion
//#region Timeline
@@ -3228,6 +3254,25 @@ export class LinkedEditingRanges {
}
}
//#region ports
export class PortAttributes {
private _port: number;
private _autoForwardAction: PortAutoForwardAction;
constructor(port: number, autoForwardAction: PortAutoForwardAction) {
this._port = port;
this._autoForwardAction = autoForwardAction;
}
get port(): number {
return this._port;
}
get autoForwardAction(): PortAutoForwardAction {
return this._autoForwardAction;
}
}
//#endregion ports
//#region Testing
export enum TestResultState {
Unset = 0,
@@ -3282,7 +3327,7 @@ const rangeComparator = (a: vscode.Range | undefined, b: vscode.Range | undefine
export class TestItemImpl implements vscode.TestItem<unknown> {
public readonly id!: string;
public readonly uri!: vscode.Uri;
public readonly uri!: vscode.Uri | undefined;
public readonly children!: ReadonlyMap<string, TestItemImpl>;
public readonly parent!: TestItemImpl | undefined;
@@ -3296,7 +3341,7 @@ export class TestItemImpl implements vscode.TestItem<unknown> {
/** Extension-owned resolve handler */
public resolveHandler?: (token: vscode.CancellationToken) => void;
constructor(id: string, public label: string, uri: vscode.Uri, public data: unknown) {
constructor(id: string, public label: string, uri: vscode.Uri | undefined, public data: unknown) {
const api = getPrivateApiFor(this);
Object.defineProperties(this, {
@@ -3322,7 +3367,7 @@ export class TestItemImpl implements vscode.TestItem<unknown> {
range: testItemPropAccessor(api, 'range', undefined, rangeComparator),
description: testItemPropAccessor(api, 'description', undefined, strictEqualComparator),
runnable: testItemPropAccessor(api, 'runnable', true, strictEqualComparator),
debuggable: testItemPropAccessor(api, 'debuggable', true, strictEqualComparator),
debuggable: testItemPropAccessor(api, 'debuggable', false, strictEqualComparator),
status: testItemPropAccessor(api, 'status', TestItemStatus.Resolved, strictEqualComparator),
error: testItemPropAccessor(api, 'error', undefined, strictEqualComparator),
});

View File

@@ -10,9 +10,9 @@ 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 { serializeWebviewMessage, 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 { asWebviewUri, webviewGenericCspSource, WebviewInitData } from 'vs/workbench/api/common/shared/webview';
import type * as vscode from 'vscode';
import * as extHostProtocol from './extHost.protocol';
@@ -69,12 +69,11 @@ export class ExtHostWebview implements vscode.Webview {
public asWebviewUri(resource: vscode.Uri): vscode.Uri {
this.#hasCalledAsWebviewUri = true;
return asWebviewUri(this.#initData, this.#handle, resource);
return asWebviewUri(resource, this.#initData.remote);
}
public get cspSource(): string {
return this.#initData.webviewCspSource
.replace('{{uuid}}', this.#handle);
return webviewGenericCspSource;
}
public get html(): string {
@@ -110,7 +109,7 @@ export class ExtHostWebview implements vscode.Webview {
if (this.#isDisposed) {
return false;
}
const serialized = serializeMessage(message, { serializeBuffersForPostMessage: this.#serializeBuffersForPostMessage });
const serialized = serializeWebviewMessage(message, { serializeBuffersForPostMessage: this.#serializeBuffersForPostMessage });
return this.#proxy.$postMessage(this.#handle, serialized.message, ...serialized.buffers);
}
@@ -122,48 +121,14 @@ 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;
return !!version && version.majorBase >= 1 && version.minorBase >= 57;
} 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;

View File

@@ -1,6 +1,6 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { VSBuffer } from 'vs/base/common/buffer';
@@ -21,9 +21,9 @@ class ArrayBufferSet {
export function serializeWebviewMessage(
message: any,
transfer?: readonly ArrayBuffer[]
options: { serializeBuffersForPostMessage?: boolean }
): { message: string, buffers: VSBuffer[] } {
if (transfer) {
if (options.serializeBuffersForPostMessage) {
// Extract all ArrayBuffers from the message and replace them with references.
const arrayBuffers = new ArrayBufferSet();

View File

@@ -61,8 +61,6 @@ export class ExtHostWindow implements ExtHostWindowShape {
async asExternalUri(uri: URI, options: IOpenUriOptions): Promise<URI> {
if (isFalsyOrWhitespace(uri.scheme)) {
return Promise.reject('Invalid scheme - cannot be empty');
} else if (!new Set([Schemas.http, Schemas.https]).has(uri.scheme)) {
return Promise.reject(`Invalid scheme '${uri.scheme}'`);
}
const result = await this._proxy.$asExternalUri(uri, options);

View File

@@ -563,8 +563,7 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac
}
requestWorkspaceTrust(options?: vscode.WorkspaceTrustRequestOptions): Promise<boolean | undefined> {
const promise = this._proxy.$requestWorkspaceTrust(options);
return options?.modal ? promise : Promise.resolve(this._trusted);
return this._proxy.$requestWorkspaceTrust(options);
}
$onDidGrantWorkspaceTrust(): void {

View File

@@ -24,6 +24,7 @@ interface IAPIMenu {
readonly description: string;
readonly proposed?: boolean; // defaults to false
readonly supportsSubmenus?: boolean; // defaults to true
readonly deprecationMessage?: string;
}
const apiMenus: IAPIMenu[] = [
@@ -137,7 +138,8 @@ const apiMenus: IAPIMenu[] = [
id: MenuId.StatusBarWindowIndicatorMenu,
description: localize('menus.statusBarWindowIndicator', "The window indicator menu in the status bar"),
proposed: true,
supportsSubmenus: false
supportsSubmenus: false,
deprecationMessage: localize('menus.statusBarWindowIndicator.deprecated', "Use menu 'statusBar/remoteIndicator' instead."),
},
{
key: 'statusBar/remoteIndicator',
@@ -185,6 +187,12 @@ const apiMenus: IAPIMenu[] = [
proposed: true
},
*/
{
key: 'notebook/toolbar/right',
id: MenuId.NotebookRightToolbar,
description: localize('notebook.toolbar.right', "The contributed notebook right toolbar menu"),
proposed: true
},
{
key: 'notebook/cell/title',
id: MenuId.NotebookCellTitle,
@@ -272,8 +280,15 @@ const apiMenus: IAPIMenu[] = [
key: 'dataGrid/item/context',
id: MenuId.DataGridItemContext,
description: locConstants.menusExtensionPointDataGridContext
}
},
// {{SQL CARBON EDIT}} end menu entries
{
key: 'editor/inlineCompletions/actions',
id: MenuId.InlineCompletionsActions,
description: localize('inlineCompletions.actions', "The actions shown when hovering on an inline completion"),
supportsSubmenus: false,
proposed: true
},
];
namespace schema {
@@ -461,6 +476,7 @@ namespace schema {
type: 'object',
properties: index(apiMenus, menu => menu.key, menu => ({
description: menu.proposed ? `(${localize('proposed', "Proposed API")}) ${menu.description}` : menu.description,
deprecationMessage: menu.deprecationMessage,
type: 'array',
items: menu.supportsSubmenus === false ? menuItem : { oneOf: [menuItem, submenuItem] }
})),
@@ -482,6 +498,7 @@ namespace schema {
export interface IUserFriendlyCommand {
command: string;
title: string | ILocalizedString;
shortTitle?: string | ILocalizedString;
enablement?: string;
category?: string | ILocalizedString;
icon?: IUserFriendlyIcon;
@@ -501,6 +518,9 @@ namespace schema {
if (!isValidLocalizedString(command.title, collector, 'title')) {
return false;
}
if (command.shortTitle && !isValidLocalizedString(command.shortTitle, collector, 'shortTitle')) {
return false;
}
if (command.enablement && typeof command.enablement !== 'string') {
collector.error(localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'precondition'));
return false;
@@ -554,6 +574,10 @@ namespace schema {
description: localize('vscode.extension.contributes.commandType.title', 'Title by which the command is represented in the UI'),
type: 'string'
},
shortTitle: {
description: localize('vscode.extension.contributes.commandType.shortTitle', 'Short title by which the command is represented in the UI'),
type: 'string'
},
category: {
description: localize('vscode.extension.contributes.commandType.category', '(Optional) Category string by the command is grouped in the UI'),
type: 'string'
@@ -611,7 +635,7 @@ commandsExtensionPoint.setHandler(extensions => {
return;
}
const { icon, enablement, category, title, command } = userFriendlyCommand;
const { icon, enablement, category, title, shortTitle, command } = userFriendlyCommand;
let absoluteIcon: { dark: URI; light?: URI; } | ThemeIcon | undefined;
if (icon) {
@@ -632,6 +656,7 @@ commandsExtensionPoint.setHandler(extensions => {
bucket.push({
id: command,
title,
shortTitle: extension.description.enableProposedApi ? shortTitle : undefined,
category,
precondition: ContextKeyExpr.deserialize(enablement),
icon: absoluteIcon

View File

@@ -19,6 +19,7 @@ export interface TaskPresentationOptionsDTO {
showReuseMessage?: boolean;
clear?: boolean;
group?: string;
close?: boolean;
}
export interface RunOptionsDTO {

View File

@@ -1,6 +1,6 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ITreeDataTransfer, ITreeDataTransferItem } from 'vs/workbench/common/views';

View File

@@ -3,28 +3,63 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Schemas } from 'vs/base/common/network';
import { URI } from 'vs/base/common/uri';
import type * as vscode from 'vscode';
export interface WebviewInitData {
readonly isExtensionDevelopmentDebug: boolean;
readonly webviewResourceRoot: string;
readonly webviewCspSource: string;
readonly remote: {
readonly isRemote: boolean;
readonly authority: string | undefined
};
}
/**
* Root from which resources in webviews are loaded.
*
* This is hardcoded because we never expect to actually hit it. Instead these requests
* should always go to a service worker.
*/
export const webviewResourceBaseHost = 'vscode-webview.net';
export const webviewRootResourceAuthority = `vscode-resource.${webviewResourceBaseHost}`;
export const webviewGenericCspSource = `https://*.${webviewResourceBaseHost}`;
/**
* Construct a uri that can load resources inside a webview
*
* We encode the resource component of the uri so that on the main thread
* we know where to load the resource from (remote or truly local):
*
* ```txt
* ${scheme}+${resource-authority}.vscode-resource.vscode-webview.net/${path}
* ```
*
* @param resource Uri of the resource to load.
* @param remoteInfo Optional information about the remote that specifies where `resource` should be resolved from.
*/
export function asWebviewUri(
initData: WebviewInitData,
uuid: string,
resource: vscode.Uri,
remoteInfo?: { authority: string | undefined, isRemote: boolean }
): vscode.Uri {
const uri = initData.webviewResourceRoot
// Make sure we preserve the scheme of the resource but convert it into a normal path segment
// The scheme is important as we need to know if we are requesting a local or a remote resource.
.replace('{{resource}}', resource.scheme + withoutScheme(resource))
.replace('{{uuid}}', uuid);
return URI.parse(uri);
}
if (resource.scheme === Schemas.http || resource.scheme === Schemas.https) {
return resource;
}
function withoutScheme(resource: vscode.Uri): string {
return resource.toString().replace(/^\S+?:/, '');
if (remoteInfo && remoteInfo.authority && remoteInfo.isRemote && resource.scheme === Schemas.file) {
resource = URI.from({
scheme: Schemas.vscodeRemote,
authority: remoteInfo.authority,
path: resource.path,
});
}
return URI.from({
scheme: Schemas.https,
authority: `${resource.scheme}+${resource.authority}.${webviewRootResourceAuthority}`,
path: resource.path,
fragment: resource.fragment,
query: resource.query,
});
}

View File

@@ -7,12 +7,12 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ExtHostOutputService2 } from 'vs/workbench/api/node/extHostOutputService';
import { ExtHostTerminalService } from 'vs/workbench/api/node/extHostTerminalService';
import { ExtHostTask } from 'vs/workbench/api/node/extHostTask';
// import { ExtHostDebugService } from 'vs/workbench/api/node/extHostDebugService';
// import { ExtHostDebugService } from 'vs/workbench/api/node/extHostDebugService'; {{SQL CARBON EDIT}}
import { NativeExtHostSearch } from 'vs/workbench/api/node/extHostSearch';
import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService';
import { ExtHostLogService } from 'vs/workbench/api/node/extHostLogService';
import { ExtHostTunnelService } from 'vs/workbench/api/node/extHostTunnelService';
// import { IExtHostDebugService } from 'vs/workbench/api/common/extHostDebugService';
// import { IExtHostDebugService } from 'vs/workbench/api/common/extHostDebugService'; {{SQL CARBON EDIT}}
import { IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
import { IExtHostOutputService } from 'vs/workbench/api/common/extHostOutput';
import { IExtHostSearch } from 'vs/workbench/api/common/extHostSearch';
@@ -30,7 +30,7 @@ import { ILogService } from 'vs/platform/log/common/log';
registerSingleton(IExtHostExtensionService, ExtHostExtensionService);
registerSingleton(ILogService, ExtHostLogService);
// registerSingleton(IExtHostDebugService, ExtHostDebugService);
// registerSingleton(IExtHostDebugService, ExtHostDebugService); {{SQL CARBON EDIT}}
registerSingleton(IExtHostOutputService, ExtHostOutputService2);
registerSingleton(IExtHostSearch, NativeExtHostSearch);
registerSingleton(IExtHostTask, ExtHostTask);

View File

@@ -20,10 +20,11 @@ import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { ExtHostDebugServiceBase, ExtHostDebugSession, ExtHostVariableResolverService } from 'vs/workbench/api/common/extHostDebugService';
import { ISignService } from 'vs/platform/sign/common/sign';
import { SignService } from 'vs/platform/sign/node/signService';
import { hasChildProcesses, prepareCommand, runInExternalTerminal } from 'vs/workbench/contrib/debug/node/terminals';
import { IDisposable } from 'vs/base/common/lifecycle';
import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/common/variableResolver';
import { createCancelablePromise, firstParallel } from 'vs/base/common/async';
import { hasChildProcesses, prepareCommand, runInExternalTerminal } from 'vs/workbench/contrib/debug/node/terminals';
import { IExtHostEditorTabs } from 'vs/workbench/api/common/extHostEditorTabs';
export class ExtHostDebugService extends ExtHostDebugServiceBase {
@@ -38,9 +39,10 @@ export class ExtHostDebugService extends ExtHostDebugServiceBase {
@IExtHostExtensionService extensionService: IExtHostExtensionService,
@IExtHostDocumentsAndEditors editorsService: IExtHostDocumentsAndEditors,
@IExtHostConfiguration configurationService: IExtHostConfiguration,
@IExtHostTerminalService private _terminalService: IExtHostTerminalService
@IExtHostTerminalService private _terminalService: IExtHostTerminalService,
@IExtHostEditorTabs editorTabs: IExtHostEditorTabs
) {
super(extHostRpcService, workspaceService, extensionService, editorsService, configurationService);
super(extHostRpcService, workspaceService, extensionService, editorsService, configurationService, editorTabs);
}
protected override createDebugAdapter(adapter: IAdapterDescriptor, session: ExtHostDebugSession): AbstractDebugAdapter | undefined {
@@ -79,11 +81,13 @@ export class ExtHostDebugService extends ExtHostDebugServiceBase {
}
const configProvider = await this._configurationService.getConfigProvider();
const shell = this._terminalService.getDefaultShell(true, configProvider);
const shellArgs = this._terminalService.getDefaultShellArgs(true, configProvider);
const shell = this._terminalService.getDefaultShell(true);
const shellArgs = this._terminalService.getDefaultShellArgs(true);
const terminalName = args.title || nls.localize('debug.terminal.title', "Debug Process");
const shellConfig = JSON.stringify({ shell, shellArgs });
let terminal = await this._integratedTerminalInstances.checkout(shellConfig);
let terminal = await this._integratedTerminalInstances.checkout(shellConfig, terminalName);
let cwdForPrepareCommand: string | undefined;
let giveShellTimeToInitialize = false;
@@ -93,10 +97,13 @@ export class ExtHostDebugService extends ExtHostDebugServiceBase {
shellPath: shell,
shellArgs: shellArgs,
cwd: args.cwd,
name: args.title || nls.localize('debug.terminal.title', "debuggee"),
name: terminalName,
};
giveShellTimeToInitialize = true;
terminal = this._terminalService.createTerminalFromOptions(options, true);
terminal = this._terminalService.createTerminalFromOptions(options, {
isFeatureTerminal: true,
useShellEnvironment: true
});
this._integratedTerminalInstances.insert(terminal, shellConfig);
} else {
@@ -139,14 +146,13 @@ export class ExtHostDebugService extends ExtHostDebugServiceBase {
return shellProcessId;
} else if (args.kind === 'external') {
return runInExternalTerminal(args, await this._configurationService.getConfigProvider());
}
return super.$runInTerminal(args, sessionId);
}
protected createVariableResolver(folders: vscode.WorkspaceFolder[], editorService: ExtHostDocumentsAndEditors, configurationService: ExtHostConfigProvider): AbstractVariableResolverService {
return new ExtHostVariableResolverService(folders, editorService, configurationService, this._workspaceService);
return new ExtHostVariableResolverService(folders, editorService, configurationService, this._editorTabs, this._workspaceService);
}
}
@@ -158,9 +164,15 @@ class DebugTerminalCollection {
private _terminalInstances = new Map<vscode.Terminal, { lastUsedAt: number, config: string }>();
public async checkout(config: string) {
public async checkout(config: string, name: string) {
const entries = [...this._terminalInstances.entries()];
const promises = entries.map(([terminal, termInfo]) => createCancelablePromise(async ct => {
// Only allow terminals that match the title. See #123189
if (terminal.name !== name) {
return null;
}
if (termInfo.lastUsedAt !== -1 && await hasChildProcesses(await terminal.processId)) {
return null;
}

View File

@@ -8,26 +8,27 @@ import type * as vscode from 'vscode';
import { URI } from 'vs/base/common/uri';
import { join } from 'vs/base/common/path';
import { toLocalISOString } from 'vs/base/common/date';
import { SymlinkSupport } from 'vs/base/node/pfs';
import { promises } from 'fs';
import { Promises, SymlinkSupport } from 'vs/base/node/pfs';
import { AbstractExtHostOutputChannel, ExtHostPushOutputChannel, ExtHostOutputService, LazyOutputChannel } from 'vs/workbench/api/common/extHostOutput';
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { MutableDisposable } from 'vs/base/common/lifecycle';
import { ILogService } from 'vs/platform/log/common/log';
import { createRotatingLogger } from 'vs/platform/log/node/spdlogLog';
import { RotatingLogger } from 'spdlog';
import { Logger } from 'spdlog';
import { ByteSize } from 'vs/platform/files/common/files';
class OutputAppender {
private appender: RotatingLogger;
static async create(name: string, file: string): Promise<OutputAppender> {
const appender = await createRotatingLogger(name, file, 30 * ByteSize.MB, 1);
appender.clearFormatters();
constructor(name: string, readonly file: string) {
this.appender = createRotatingLogger(name, file, 30 * ByteSize.MB, 1);
this.appender.clearFormatters();
return new OutputAppender(name, file, appender);
}
private constructor(readonly name: string, readonly file: string, private readonly appender: Logger) { }
append(content: string): void {
this.appender.critical(content);
}
@@ -38,7 +39,7 @@ class OutputAppender {
}
export class ExtHostOutputChannelBackedByFile extends AbstractExtHostOutputChannel {
class ExtHostOutputChannelBackedByFile extends AbstractExtHostOutputChannel {
private _appender: OutputAppender;
@@ -109,11 +110,11 @@ export class ExtHostOutputService2 extends ExtHostOutputService {
const outputDirPath = join(this._logsLocation.fsPath, `output_logging_${toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')}`);
const exists = await SymlinkSupport.existsDirectory(outputDirPath);
if (!exists) {
await promises.mkdir(outputDirPath, { recursive: true });
await Promises.mkdir(outputDirPath, { recursive: true });
}
const fileName = `${this._namePool++}-${name.replace(/[\\/:\*\?"<>\|]/g, '')}`;
const file = URI.file(join(outputDirPath, `${fileName}.log`));
const appender = new OutputAppender(fileName, file.fsPath);
const appender = await OutputAppender.create(fileName, file.fsPath);
return new ExtHostOutputChannelBackedByFile(name, appender, this._proxy);
} catch (error) {
// Do not crash if logger cannot be created

View File

@@ -14,6 +14,7 @@ import * as tasks from '../common/shared/tasks';
import { ExtHostVariableResolverService } from 'vs/workbench/api/common/extHostDebugService';
import { IExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { IExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { IExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
@@ -22,7 +23,7 @@ import { ExtHostTaskBase, TaskHandleDTO, TaskDTO, CustomExecutionDTO, HandlerDat
import { Schemas } from 'vs/base/common/network';
import { ILogService } from 'vs/platform/log/common/log';
import { IExtHostApiDeprecationService } from 'vs/workbench/api/common/extHostApiDeprecationService';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { IExtHostEditorTabs } from 'vs/workbench/api/common/extHostEditorTabs';
export class ExtHostTask extends ExtHostTaskBase {
private _variableResolver: ExtHostVariableResolverService | undefined;
@@ -35,7 +36,8 @@ export class ExtHostTask extends ExtHostTaskBase {
@IExtHostConfiguration configurationService: IExtHostConfiguration,
@IExtHostTerminalService extHostTerminalService: IExtHostTerminalService,
@ILogService logService: ILogService,
@IExtHostApiDeprecationService deprecationService: IExtHostApiDeprecationService
@IExtHostApiDeprecationService deprecationService: IExtHostApiDeprecationService,
@IExtHostEditorTabs private readonly editorTabs: IExtHostEditorTabs
) {
super(extHostRpc, initData, workspaceService, editorService, configurationService, extHostTerminalService, logService, deprecationService);
if (initData.remote.isRemote && initData.remote.authority) {
@@ -124,11 +126,10 @@ export class ExtHostTask extends ExtHostTaskBase {
return resolvedTaskDTO;
}
private async getVariableResolver(workspaceFolders: vscode.WorkspaceFolder[]): Promise<ExtHostVariableResolverService> {
if (this._variableResolver === undefined) {
const configProvider = await this._configurationService.getConfigProvider();
this._variableResolver = new ExtHostVariableResolverService(workspaceFolders, this._editorService, configProvider, this.workspaceService);
this._variableResolver = new ExtHostVariableResolverService(workspaceFolders, this._editorService, configProvider, this.editorTabs, this.workspaceService);
}
return this._variableResolver;
}
@@ -173,10 +174,6 @@ export class ExtHostTask extends ExtHostTaskBase {
return result;
}
public $getDefaultShellAndArgs(): Promise<{ shell: string, args: string[] | string | undefined }> {
return this._terminalService.$getDefaultShellAndArgs(true);
}
public async $jsonTasksSupported(): Promise<boolean> {
return true;
}

View File

@@ -3,143 +3,27 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as platform from 'vs/base/common/platform';
import { withNullAsUndefined } from 'vs/base/common/types';
import { generateUuid } from 'vs/base/common/uuid';
import { getSystemShell, getSystemShellSync } from 'vs/base/node/shell';
import { ILogService } from 'vs/platform/log/common/log';
import { SafeConfigProvider } from 'vs/platform/terminal/common/terminal';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { IShellAndArgsDto } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostConfigProvider, ExtHostConfiguration, IExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
import { ExtHostVariableResolverService } from 'vs/workbench/api/common/extHostDebugService';
import { ExtHostDocumentsAndEditors, IExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { BaseExtHostTerminalService, ExtHostTerminal } from 'vs/workbench/api/common/extHostTerminalService';
import { ExtHostWorkspace, IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
import { ITerminalProfile } from 'vs/workbench/contrib/terminal/common/terminal';
import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
import { detectAvailableProfiles } from 'vs/workbench/contrib/terminal/node/terminalProfiles';
import { BaseExtHostTerminalService, ExtHostTerminal, ITerminalInternalOptions } from 'vs/workbench/api/common/extHostTerminalService';
import type * as vscode from 'vscode';
export class ExtHostTerminalService extends BaseExtHostTerminalService {
private _variableResolver: ExtHostVariableResolverService | undefined;
private _variableResolverPromise: Promise<ExtHostVariableResolverService>;
private _lastActiveWorkspace: IWorkspaceFolder | undefined;
private _defaultShell: string | undefined;
constructor(
@IExtHostRpcService extHostRpc: IExtHostRpcService,
@IExtHostConfiguration private _extHostConfiguration: ExtHostConfiguration,
@IExtHostWorkspace private _extHostWorkspace: ExtHostWorkspace,
@IExtHostDocumentsAndEditors private _extHostDocumentsAndEditors: ExtHostDocumentsAndEditors,
@ILogService private _logService: ILogService
@IExtHostRpcService extHostRpc: IExtHostRpcService
) {
super(true, extHostRpc);
// Getting the SystemShell is an async operation, however, the ExtHost terminal service is mostly synchronous
// and the API `vscode.env.shell` is also synchronous. The default shell _should_ be set when extensions are
// starting up but if not, we run getSystemShellSync below which gets a sane default.
getSystemShell(platform.OS, process.env as platform.IProcessEnvironment).then(s => this._defaultShell = s);
this._updateLastActiveWorkspace();
this._variableResolverPromise = this._updateVariableResolver();
this._registerListeners();
}
public createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal {
const terminal = new ExtHostTerminal(this._proxy, generateUuid(), { name, shellPath, shellArgs }, name);
this._terminals.push(terminal);
terminal.create(shellPath, shellArgs);
return terminal.value;
return this.createTerminalFromOptions({ name, shellPath, shellArgs });
}
public createTerminalFromOptions(options: vscode.TerminalOptions, isFeatureTerminal?: boolean): vscode.Terminal {
public createTerminalFromOptions(options: vscode.TerminalOptions, internalOptions?: ITerminalInternalOptions): vscode.Terminal {
const terminal = new ExtHostTerminal(this._proxy, generateUuid(), options, options.name);
this._terminals.push(terminal);
terminal.create(
withNullAsUndefined(options.shellPath),
withNullAsUndefined(options.shellArgs),
withNullAsUndefined(options.cwd),
withNullAsUndefined(options.env),
withNullAsUndefined(options.icon),
withNullAsUndefined(options.message),
/*options.waitOnExit*/ undefined,
withNullAsUndefined(options.strictEnv),
withNullAsUndefined(options.hideFromUser),
withNullAsUndefined(isFeatureTerminal),
true
);
terminal.create(options, internalOptions);
return terminal.value;
}
public getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string {
return terminalEnvironment.getDefaultShell(
this._buildSafeConfigProvider(configProvider),
this._defaultShell ?? getSystemShellSync(platform.OS, process.env as platform.IProcessEnvironment),
process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432'),
process.env.windir,
terminalEnvironment.createVariableResolver(this._lastActiveWorkspace, process.env, this._variableResolver),
this._logService,
useAutomationShell
);
}
public getDefaultShellArgs(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string[] | string {
return terminalEnvironment.getDefaultShellArgs(
this._buildSafeConfigProvider(configProvider),
useAutomationShell,
terminalEnvironment.createVariableResolver(this._lastActiveWorkspace, process.env, this._variableResolver),
this._logService
);
}
private _registerListeners(): void {
this._extHostDocumentsAndEditors.onDidChangeActiveTextEditor(() => this._updateLastActiveWorkspace());
this._extHostWorkspace.onDidChangeWorkspace(() => {
this._variableResolverPromise = this._updateVariableResolver();
});
}
private _updateLastActiveWorkspace(): void {
const activeEditor = this._extHostDocumentsAndEditors.activeEditor();
if (activeEditor) {
this._lastActiveWorkspace = this._extHostWorkspace.getWorkspaceFolder(activeEditor.document.uri) as IWorkspaceFolder;
}
}
private async _updateVariableResolver(): Promise<ExtHostVariableResolverService> {
const configProvider = await this._extHostConfiguration.getConfigProvider();
const workspaceFolders = await this._extHostWorkspace.getWorkspaceFolders2();
this._variableResolver = new ExtHostVariableResolverService(workspaceFolders || [], this._extHostDocumentsAndEditors, configProvider);
return this._variableResolver;
}
public async $getAvailableProfiles(configuredProfilesOnly: boolean): Promise<ITerminalProfile[]> {
const safeConfigProvider = this._buildSafeConfigProvider(await this._extHostConfiguration.getConfigProvider());
return detectAvailableProfiles(configuredProfilesOnly, safeConfigProvider, undefined, this._logService, await this._variableResolverPromise, this._lastActiveWorkspace);
}
public async $getDefaultShellAndArgs(useAutomationShell: boolean): Promise<IShellAndArgsDto> {
const configProvider = await this._extHostConfiguration.getConfigProvider();
return {
shell: this.getDefaultShell(useAutomationShell, configProvider),
args: this.getDefaultShellArgs(useAutomationShell, configProvider)
};
}
// TODO: Remove when workspace trust is enabled
private _buildSafeConfigProvider(configProvider: ExtHostConfigProvider): SafeConfigProvider {
const config = configProvider.getConfiguration();
return (key: string) => {
const isWorkspaceConfigAllowed = config.get('terminal.integrated.allowWorkspaceConfiguration');
if (isWorkspaceConfigAllowed) {
return config.get(key) as any;
}
const inspected = config.inspect(key);
return inspected?.globalValue || inspected?.defaultValue;
};
}
}

View File

@@ -11,7 +11,6 @@ import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitData
import { URI } from 'vs/base/common/uri';
import { exec } from 'child_process';
import * as resources from 'vs/base/common/resources';
import * as fs from 'fs';
import * as pfs from 'vs/base/node/pfs';
import * as types from 'vs/workbench/api/common/extHostTypes';
import { isLinux } from 'vs/base/common/platform';
@@ -365,8 +364,8 @@ export class ExtHostTunnelService extends Disposable implements IExtHostTunnelSe
let tcp: string = '';
let tcp6: string = '';
try {
tcp = await fs.promises.readFile('/proc/net/tcp', 'utf8');
tcp6 = await fs.promises.readFile('/proc/net/tcp6', 'utf8');
tcp = await pfs.Promises.readFile('/proc/net/tcp', 'utf8');
tcp6 = await pfs.Promises.readFile('/proc/net/tcp6', 'utf8');
} catch (e) {
// File reading error. No additional handling needed.
}
@@ -379,7 +378,7 @@ export class ExtHostTunnelService extends Disposable implements IExtHostTunnelSe
}));
const socketMap = getSockets(procSockets);
const procChildren = await pfs.readdir('/proc');
const procChildren = await pfs.Promises.readdir('/proc');
const processes: {
pid: number, cwd: string, cmd: string
}[] = [];
@@ -387,10 +386,10 @@ export class ExtHostTunnelService extends Disposable implements IExtHostTunnelSe
try {
const pid: number = Number(childName);
const childUri = resources.joinPath(URI.file('/proc'), childName);
const childStat = await fs.promises.stat(childUri.fsPath);
const childStat = await pfs.Promises.stat(childUri.fsPath);
if (childStat.isDirectory() && !isNaN(pid)) {
const cwd = await fs.promises.readlink(resources.joinPath(childUri, 'cwd').fsPath);
const cmd = await fs.promises.readFile(resources.joinPath(childUri, 'cmdline').fsPath, 'utf8');
const cwd = await pfs.Promises.readlink(resources.joinPath(childUri, 'cwd').fsPath);
const cmd = await pfs.Promises.readFile(resources.joinPath(childUri, 'cmdline').fsPath, 'utf8');
processes.push({ pid, cwd, cmd });
}
} catch (e) {