mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-04 17:23:45 -05:00
Merge from vscode 0a7364f00514c46c9caceece15e1f82f82e3712f
This commit is contained in:
@@ -17,6 +17,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
|
||||
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import { fromNow } from 'vs/base/common/date';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
|
||||
const VSO_ALLOWED_EXTENSIONS = ['github.vscode-pull-request-github', 'github.vscode-pull-request-github-insiders', 'vscode.git', 'ms-vsonline.vsonline', 'vscode.github-browser'];
|
||||
|
||||
@@ -213,7 +214,8 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
|
||||
@INotificationService private readonly notificationService: INotificationService,
|
||||
@IStorageKeysSyncRegistryService private readonly storageKeysSyncRegistryService: IStorageKeysSyncRegistryService,
|
||||
@IRemoteAgentService private readonly remoteAgentService: IRemoteAgentService,
|
||||
@IQuickInputService private readonly quickInputService: IQuickInputService
|
||||
@IQuickInputService private readonly quickInputService: IQuickInputService,
|
||||
@IExtensionService private readonly extensionService: IExtensionService
|
||||
) {
|
||||
super();
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostAuthentication);
|
||||
@@ -292,7 +294,7 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
|
||||
}
|
||||
|
||||
const session = await this.authenticationService.login(providerId, scopes);
|
||||
await this.$setTrustedExtension(providerId, session.account.label, extensionId, extensionName);
|
||||
await this.$setTrustedExtensionAndAccountPreference(providerId, session.account.label, extensionId, extensionName, session.id);
|
||||
return session;
|
||||
} else {
|
||||
await this.$requestNewSession(providerId, scopes, extensionId, extensionName);
|
||||
@@ -378,6 +380,8 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
|
||||
}
|
||||
|
||||
async $getSessionsPrompt(providerId: string, accountName: string, providerName: string, extensionId: string, extensionName: string): Promise<boolean> {
|
||||
await this.extensionService.activateByEvent(`onAuthenticationRequest:${providerId}`);
|
||||
|
||||
const allowList = readAllowedExtensions(this.storageService, providerId, accountName);
|
||||
const extensionData = allowList.find(extension => extension.id === extensionId);
|
||||
if (extensionData) {
|
||||
@@ -423,11 +427,13 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
|
||||
return choice === 0;
|
||||
}
|
||||
|
||||
async $setTrustedExtension(providerId: string, accountName: string, extensionId: string, extensionName: string): Promise<void> {
|
||||
async $setTrustedExtensionAndAccountPreference(providerId: string, accountName: string, extensionId: string, extensionName: string, sessionId: string): Promise<void> {
|
||||
const allowList = readAllowedExtensions(this.storageService, providerId, accountName);
|
||||
if (!allowList.find(allowed => allowed.id === extensionId)) {
|
||||
allowList.push({ id: extensionId, name: extensionName });
|
||||
this.storageService.store(`${providerId}-${accountName}`, JSON.stringify(allowList), StorageScope.GLOBAL);
|
||||
}
|
||||
|
||||
this.storageService.store(`${extensionName}-${providerId}`, sessionId, StorageScope.GLOBAL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,14 +3,13 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { MainContext, MainThreadNotebookShape, NotebookExtensionDescription, IExtHostContext, ExtHostNotebookShape, ExtHostContext, INotebookDocumentsAndEditorsDelta, INotebookModelAddedData } from '../common/extHost.protocol';
|
||||
import { Disposable, IDisposable, combinedDisposable } from 'vs/base/common/lifecycle';
|
||||
import { MainContext, MainThreadNotebookShape, NotebookExtensionDescription, IExtHostContext, ExtHostNotebookShape, ExtHostContext, INotebookDocumentsAndEditorsDelta } from '../common/extHost.protocol';
|
||||
import { Disposable, IDisposable, combinedDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { INotebookService, IMainNotebookController } from 'vs/workbench/contrib/notebook/common/notebookService';
|
||||
import { INotebookTextModel, INotebookMimeTypeSelector, NOTEBOOK_DISPLAY_ORDER, NotebookCellOutputsSplice, NotebookDocumentMetadata, NotebookCellMetadata, ICellEditOperation, ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, CellEditType, CellKind, INotebookKernelInfo, INotebookKernelInfoDto, INotebookTextModelBackup, IEditor, INotebookRendererInfo, IOutputRenderRequest, IOutputRenderResponse } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { INotebookMimeTypeSelector, NOTEBOOK_DISPLAY_ORDER, NotebookCellOutputsSplice, NotebookDocumentMetadata, NotebookCellMetadata, ICellEditOperation, ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, CellEditType, CellKind, INotebookKernelInfo, INotebookKernelInfoDto, IEditor, INotebookRendererInfo, IOutputRenderRequest, IOutputRenderResponse, INotebookDocumentFilter } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
@@ -19,9 +18,9 @@ import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
|
||||
import { IRelativePattern } from 'vs/base/common/glob';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IUndoRedoService, UndoRedoElementType } from 'vs/platform/undoRedo/common/undoRedo';
|
||||
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
|
||||
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
|
||||
export class MainThreadNotebookDocument extends Disposable {
|
||||
private _textModel: NotebookTextModel;
|
||||
@@ -54,42 +53,8 @@ export class MainThreadNotebookDocument extends Disposable {
|
||||
}));
|
||||
}
|
||||
|
||||
async applyEdit(modelVersionId: number, edits: ICellEditOperation[], emitToExtHost: boolean, synchronous: boolean): Promise<boolean> {
|
||||
await this.notebookService.transformEditsOutputs(this.textModel, edits);
|
||||
if (synchronous) {
|
||||
return this._textModel.$applyEdit(modelVersionId, edits, emitToExtHost, synchronous);
|
||||
} else {
|
||||
return new Promise(resolve => {
|
||||
this._register(DOM.scheduleAtNextAnimationFrame(() => {
|
||||
const ret = this._textModel.$applyEdit(modelVersionId, edits, emitToExtHost, true);
|
||||
resolve(ret);
|
||||
}));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async spliceNotebookCellOutputs(cellHandle: number, splices: NotebookCellOutputsSplice[]) {
|
||||
await this.notebookService.transformSpliceOutputs(this.textModel, splices);
|
||||
this._textModel.$spliceNotebookCellOutputs(cellHandle, splices);
|
||||
}
|
||||
|
||||
handleEdit(editId: number, label: string | undefined): void {
|
||||
this.undoRedoService.pushElement({
|
||||
type: UndoRedoElementType.Resource,
|
||||
resource: this._textModel.uri,
|
||||
label: label ?? nls.localize('defaultEditLabel', "Edit"),
|
||||
undo: async () => {
|
||||
await this._proxy.$undoNotebook(this._textModel.viewType, this._textModel.uri, editId, this._textModel.isDirty);
|
||||
},
|
||||
redo: async () => {
|
||||
await this._proxy.$redoNotebook(this._textModel.viewType, this._textModel.uri, editId, this._textModel.isDirty);
|
||||
},
|
||||
});
|
||||
this._textModel.setDirty(true);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._textModel.dispose();
|
||||
// this._textModel.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -168,6 +133,7 @@ class DocumentAndEditorState {
|
||||
handle: cell.handle,
|
||||
uri: cell.uri,
|
||||
source: cell.textBuffer.getLinesContent(),
|
||||
eol: cell.textBuffer.getEOL(),
|
||||
language: cell.language,
|
||||
cellKind: cell.cellKind,
|
||||
outputs: cell.outputs,
|
||||
@@ -201,20 +167,21 @@ class DocumentAndEditorState {
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadNotebook)
|
||||
export class MainThreadNotebooks extends Disposable implements MainThreadNotebookShape {
|
||||
private readonly _notebookProviders = new Map<string, MainThreadNotebookController>();
|
||||
private readonly _notebookProviders = new Map<string, IMainNotebookController>();
|
||||
private readonly _notebookKernels = new Map<string, MainThreadNotebookKernel>();
|
||||
private readonly _notebookKernelProviders = new Map<number, { extension: NotebookExtensionDescription, emitter: Emitter<void>, provider: IDisposable }>();
|
||||
private readonly _notebookRenderers = new Map<string, MainThreadNotebookRenderer>();
|
||||
private readonly _proxy: ExtHostNotebookShape;
|
||||
private _toDisposeOnEditorRemove = new Map<string, IDisposable>();
|
||||
private _currentState?: DocumentAndEditorState;
|
||||
private _editorEventListenersMapping: Map<string, DisposableStore> = new Map();
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@INotebookService private _notebookService: INotebookService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@IAccessibilityService private readonly accessibilityService: IAccessibilityService,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService
|
||||
@IAccessibilityService private readonly accessibilityService: IAccessibilityService
|
||||
|
||||
) {
|
||||
super();
|
||||
@@ -223,15 +190,23 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
|
||||
}
|
||||
|
||||
async $tryApplyEdits(viewType: string, resource: UriComponents, modelVersionId: number, edits: ICellEditOperation[], renderers: number[]): Promise<boolean> {
|
||||
let controller = this._notebookProviders.get(viewType);
|
||||
|
||||
if (controller) {
|
||||
return controller.tryApplyEdits(resource, modelVersionId, edits, renderers);
|
||||
const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
|
||||
if (textModel) {
|
||||
await this._notebookService.transformEditsOutputs(textModel, edits);
|
||||
return textModel.$applyEdit(modelVersionId, edits, true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
async removeNotebookTextModel(uri: URI): Promise<void> {
|
||||
// TODO@rebornix, remove cell should use emitDelta as well to ensure document/editor events are sent together
|
||||
await this._proxy.$acceptDocumentAndEditorsDelta({ removedDocuments: [uri] });
|
||||
let textModelDisposableStore = this._editorEventListenersMapping.get(uri.toString());
|
||||
textModelDisposableStore?.dispose();
|
||||
this._editorEventListenersMapping.delete(URI.from(uri).toString());
|
||||
}
|
||||
|
||||
private _isDeltaEmpty(delta: INotebookDocumentsAndEditorsDelta) {
|
||||
if (delta.addedDocuments !== undefined && delta.addedDocuments.length > 0) {
|
||||
return false;
|
||||
@@ -297,14 +272,39 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
|
||||
this._removeNotebookEditor(editors);
|
||||
}));
|
||||
|
||||
this._register(this._notebookService.onNotebookDocumentAdd(() => {
|
||||
this._register(this._notebookService.onNotebookDocumentAdd((documents) => {
|
||||
documents.forEach(doc => {
|
||||
if (!this._editorEventListenersMapping.has(doc.toString())) {
|
||||
const disposableStore = new DisposableStore();
|
||||
const textModel = this._notebookService.getNotebookTextModel(doc);
|
||||
disposableStore.add(textModel!.onDidModelChangeProxy(e => {
|
||||
this._proxy.$acceptModelChanged(textModel!.uri, e);
|
||||
this._proxy.$acceptEditorPropertiesChanged(doc, { selections: { selections: textModel!.selections }, metadata: null });
|
||||
}));
|
||||
disposableStore.add(textModel!.onDidSelectionChange(e => {
|
||||
const selectionsChange = e ? { selections: e } : null;
|
||||
this._proxy.$acceptEditorPropertiesChanged(doc, { selections: selectionsChange, metadata: null });
|
||||
}));
|
||||
|
||||
this._editorEventListenersMapping.set(textModel!.uri.toString(), disposableStore);
|
||||
}
|
||||
});
|
||||
this._updateState();
|
||||
}));
|
||||
|
||||
this._register(this._notebookService.onNotebookDocumentRemove(() => {
|
||||
this._register(this._notebookService.onNotebookDocumentRemove((documents) => {
|
||||
documents.forEach(doc => {
|
||||
this._editorEventListenersMapping.get(doc.toString())?.dispose();
|
||||
this._editorEventListenersMapping.delete(doc.toString());
|
||||
});
|
||||
|
||||
this._updateState();
|
||||
}));
|
||||
|
||||
this._register(this._notebookService.onDidChangeNotebookActiveKernel(e => {
|
||||
this._proxy.$acceptNotebookActiveKernelChange(e);
|
||||
}));
|
||||
|
||||
const updateOrder = () => {
|
||||
let userOrder = this.configurationService.getValue<string[]>('notebook.displayOrder');
|
||||
this._proxy.$acceptDisplayOrder({
|
||||
@@ -330,10 +330,6 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
|
||||
this._updateState(notebookEditor);
|
||||
}
|
||||
|
||||
async addNotebookDocument(data: INotebookModelAddedData) {
|
||||
this._updateState();
|
||||
}
|
||||
|
||||
private _addNotebookEditor(e: IEditor) {
|
||||
this._toDisposeOnEditorRemove.set(e.getId(), combinedDisposable(
|
||||
e.onDidChangeModel(() => this._updateState()),
|
||||
@@ -422,18 +418,92 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
|
||||
this._notebookService.unregisterNotebookRenderer(id);
|
||||
}
|
||||
|
||||
async $registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, supportBackup: boolean, kernel: INotebookKernelInfoDto | undefined): Promise<void> {
|
||||
let controller = new MainThreadNotebookController(this._proxy, this, viewType, supportBackup, kernel, this._notebookService, this._instantiationService);
|
||||
this._notebookProviders.set(viewType, controller);
|
||||
this._notebookService.registerNotebookController(viewType, extension, controller);
|
||||
async $registerNotebookProvider(_extension: NotebookExtensionDescription, _viewType: string, _supportBackup: boolean, _kernel: INotebookKernelInfoDto | undefined): Promise<void> {
|
||||
const controller: IMainNotebookController = {
|
||||
kernel: _kernel,
|
||||
supportBackup: _supportBackup,
|
||||
reloadNotebook: async (mainthreadTextModel: NotebookTextModel) => {
|
||||
const data = await this._proxy.$resolveNotebookData(_viewType, mainthreadTextModel.uri);
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
mainthreadTextModel.languages = data.languages;
|
||||
mainthreadTextModel.metadata = data.metadata;
|
||||
|
||||
const edits: ICellEditOperation[] = [
|
||||
{ editType: CellEditType.Delete, count: mainthreadTextModel.cells.length, index: 0 },
|
||||
{ editType: CellEditType.Insert, index: 0, cells: data.cells }
|
||||
];
|
||||
|
||||
await this._notebookService.transformEditsOutputs(mainthreadTextModel, edits);
|
||||
await new Promise(resolve => {
|
||||
DOM.scheduleAtNextAnimationFrame(() => {
|
||||
const ret = mainthreadTextModel!.$applyEdit(mainthreadTextModel!.versionId, edits, true);
|
||||
resolve(ret);
|
||||
});
|
||||
});
|
||||
},
|
||||
createNotebook: async (textModel: NotebookTextModel, backupId?: string) => {
|
||||
// open notebook document
|
||||
const data = await this._proxy.$resolveNotebookData(textModel.viewType, textModel.uri, backupId);
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
textModel.languages = data.languages;
|
||||
textModel.metadata = data.metadata;
|
||||
|
||||
if (data.cells.length) {
|
||||
textModel.initialize(data!.cells);
|
||||
} else {
|
||||
const mainCell = textModel.createCellTextModel([''], textModel.languages.length ? textModel.languages[0] : '', CellKind.Code, [], undefined);
|
||||
textModel.insertTemplateCell(mainCell);
|
||||
}
|
||||
|
||||
this._proxy.$acceptEditorPropertiesChanged(textModel.uri, { selections: null, metadata: textModel.metadata });
|
||||
return;
|
||||
},
|
||||
resolveNotebookEditor: async (viewType: string, uri: URI, editorId: string) => {
|
||||
await this._proxy.$resolveNotebookEditor(viewType, uri, editorId);
|
||||
},
|
||||
executeNotebookByAttachedKernel: async (viewType: string, uri: URI) => {
|
||||
return this.executeNotebookByAttachedKernel(viewType, uri);
|
||||
},
|
||||
cancelNotebookByAttachedKernel: async (viewType: string, uri: URI) => {
|
||||
return this.cancelNotebookByAttachedKernel(viewType, uri);
|
||||
},
|
||||
onDidReceiveMessage: (editorId: string, rendererType: string | undefined, message: unknown) => {
|
||||
this._proxy.$onDidReceiveMessage(editorId, rendererType, message);
|
||||
},
|
||||
removeNotebookDocument: async (uri: URI) => {
|
||||
return this.removeNotebookTextModel(uri);
|
||||
},
|
||||
executeNotebookCell: async (uri: URI, handle: number) => {
|
||||
return this._proxy.$executeNotebookByAttachedKernel(_viewType, uri, handle);
|
||||
},
|
||||
cancelNotebookCell: async (uri: URI, handle: number) => {
|
||||
return this._proxy.$cancelNotebookByAttachedKernel(_viewType, uri, handle);
|
||||
},
|
||||
save: async (uri: URI, token: CancellationToken) => {
|
||||
return this._proxy.$saveNotebook(_viewType, uri, token);
|
||||
},
|
||||
saveAs: async (uri: URI, target: URI, token: CancellationToken) => {
|
||||
return this._proxy.$saveNotebookAs(_viewType, uri, target, token);
|
||||
},
|
||||
backup: async (uri: URI, token: CancellationToken) => {
|
||||
return this._proxy.$backup(_viewType, uri, token);
|
||||
}
|
||||
};
|
||||
|
||||
this._notebookProviders.set(_viewType, controller);
|
||||
this._notebookService.registerNotebookController(_viewType, _extension, controller);
|
||||
return;
|
||||
}
|
||||
|
||||
async $onNotebookChange(viewType: string, uri: UriComponents): Promise<void> {
|
||||
let controller = this._notebookProviders.get(viewType);
|
||||
if (controller) {
|
||||
controller.handleNotebookChange(uri);
|
||||
}
|
||||
const textModel = this._notebookService.getNotebookTextModel(URI.from(uri));
|
||||
textModel?.handleUnknownChange();
|
||||
}
|
||||
|
||||
async $unregisterNotebookProvider(viewType: string): Promise<void> {
|
||||
@@ -455,37 +525,85 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
|
||||
return;
|
||||
}
|
||||
|
||||
async $updateNotebookLanguages(viewType: string, resource: UriComponents, languages: string[]): Promise<void> {
|
||||
let controller = this._notebookProviders.get(viewType);
|
||||
async $registerNotebookKernelProvider(extension: NotebookExtensionDescription, handle: number, documentFilter: INotebookDocumentFilter): Promise<void> {
|
||||
const emitter = new Emitter<void>();
|
||||
const that = this;
|
||||
const provider = this._notebookService.registerNotebookKernelProvider({
|
||||
providerExtensionId: extension.id.value,
|
||||
providerDescription: extension.description,
|
||||
onDidChangeKernels: emitter.event,
|
||||
selector: documentFilter,
|
||||
provideKernels: async (uri: URI, token: CancellationToken) => {
|
||||
const kernels = await that._proxy.$provideNotebookKernels(handle, uri, token);
|
||||
return kernels.map(kernel => {
|
||||
return {
|
||||
...kernel,
|
||||
providerHandle: handle
|
||||
};
|
||||
});
|
||||
},
|
||||
resolveKernel: (editorId: string, uri: URI, kernelId: string, token: CancellationToken) => {
|
||||
return that._proxy.$resolveNotebookKernel(handle, editorId, uri, kernelId, token);
|
||||
},
|
||||
executeNotebook: (uri: URI, kernelId: string, cellHandle: number | undefined) => {
|
||||
return that._proxy.$executeNotebookKernelFromProvider(handle, uri, kernelId, cellHandle);
|
||||
}
|
||||
});
|
||||
this._notebookKernelProviders.set(handle, {
|
||||
extension,
|
||||
emitter,
|
||||
provider
|
||||
});
|
||||
|
||||
if (controller) {
|
||||
controller.updateLanguages(resource, languages);
|
||||
return;
|
||||
}
|
||||
|
||||
async $unregisterNotebookKernelProvider(handle: number): Promise<void> {
|
||||
const entry = this._notebookKernelProviders.get(handle);
|
||||
|
||||
if (entry) {
|
||||
entry.emitter.dispose();
|
||||
entry.provider.dispose();
|
||||
this._notebookKernelProviders.delete(handle);
|
||||
}
|
||||
}
|
||||
|
||||
$onNotebookKernelChange(handle: number): void {
|
||||
const entry = this._notebookKernelProviders.get(handle);
|
||||
|
||||
entry?.emitter.fire();
|
||||
}
|
||||
|
||||
async $updateNotebookLanguages(viewType: string, resource: UriComponents, languages: string[]): Promise<void> {
|
||||
const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
|
||||
textModel?.updateLanguages(languages);
|
||||
}
|
||||
|
||||
async $updateNotebookMetadata(viewType: string, resource: UriComponents, metadata: NotebookDocumentMetadata): Promise<void> {
|
||||
let controller = this._notebookProviders.get(viewType);
|
||||
|
||||
if (controller) {
|
||||
controller.updateNotebookMetadata(resource, metadata);
|
||||
}
|
||||
const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
|
||||
textModel?.updateNotebookMetadata(metadata);
|
||||
}
|
||||
|
||||
async $updateNotebookCellMetadata(viewType: string, resource: UriComponents, handle: number, metadata: NotebookCellMetadata): Promise<void> {
|
||||
let controller = this._notebookProviders.get(viewType);
|
||||
|
||||
if (controller) {
|
||||
controller.updateNotebookCellMetadata(resource, handle, metadata);
|
||||
}
|
||||
const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
|
||||
textModel?.updateNotebookCellMetadata(handle, metadata);
|
||||
}
|
||||
|
||||
async $spliceNotebookCellOutputs(viewType: string, resource: UriComponents, cellHandle: number, splices: NotebookCellOutputsSplice[], renderers: number[]): Promise<void> {
|
||||
let controller = this._notebookProviders.get(viewType);
|
||||
await controller?.spliceNotebookCellOutputs(resource, cellHandle, splices, renderers);
|
||||
const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
|
||||
|
||||
if (textModel) {
|
||||
await this._notebookService.transformSpliceOutputs(textModel, splices);
|
||||
textModel.$spliceNotebookCellOutputs(cellHandle, splices);
|
||||
}
|
||||
}
|
||||
|
||||
async executeNotebook(viewType: string, uri: URI, useAttachedKernel: boolean, token: CancellationToken): Promise<void> {
|
||||
return this._proxy.$executeNotebook(viewType, uri, undefined, useAttachedKernel, token);
|
||||
async executeNotebookByAttachedKernel(viewType: string, uri: URI): Promise<void> {
|
||||
return this._proxy.$executeNotebookByAttachedKernel(viewType, uri, undefined);
|
||||
}
|
||||
|
||||
async cancelNotebookByAttachedKernel(viewType: string, uri: URI): Promise<void> {
|
||||
return this._proxy.$cancelNotebookByAttachedKernel(viewType, uri, undefined);
|
||||
}
|
||||
|
||||
async $postMessage(editorId: string, forRendererId: string | undefined, value: any): Promise<boolean> {
|
||||
@@ -499,218 +617,20 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
|
||||
}
|
||||
|
||||
$onDidEdit(resource: UriComponents, viewType: string, editId: number, label: string | undefined): void {
|
||||
let controller = this._notebookProviders.get(viewType);
|
||||
controller?.handleEdit(resource, editId, label);
|
||||
const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
|
||||
|
||||
if (textModel) {
|
||||
textModel.$handleEdit(label, () => {
|
||||
return this._proxy.$undoNotebook(textModel.viewType, textModel.uri, editId, textModel.isDirty);
|
||||
}, () => {
|
||||
return this._proxy.$redoNotebook(textModel.viewType, textModel.uri, editId, textModel.isDirty);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$onContentChange(resource: UriComponents, viewType: string): void {
|
||||
let controller = this._notebookProviders.get(viewType);
|
||||
controller?.handleNotebookChange(resource);
|
||||
}
|
||||
}
|
||||
|
||||
export class MainThreadNotebookController implements IMainNotebookController {
|
||||
private _mapping: Map<string, MainThreadNotebookDocument> = new Map();
|
||||
static documentHandle: number = 0;
|
||||
|
||||
constructor(
|
||||
private readonly _proxy: ExtHostNotebookShape,
|
||||
private _mainThreadNotebook: MainThreadNotebooks,
|
||||
private _viewType: string,
|
||||
private _supportBackup: boolean,
|
||||
readonly kernel: INotebookKernelInfoDto | undefined,
|
||||
readonly notebookService: INotebookService,
|
||||
readonly _instantiationService: IInstantiationService
|
||||
|
||||
) {
|
||||
}
|
||||
|
||||
async createNotebook(viewType: string, uri: URI, backup: INotebookTextModelBackup | undefined, forceReload: boolean, editorId?: string, backupId?: string): Promise<NotebookTextModel | undefined> {
|
||||
let mainthreadNotebook = this._mapping.get(URI.from(uri).toString());
|
||||
|
||||
if (mainthreadNotebook) {
|
||||
if (forceReload) {
|
||||
const data = await this._proxy.$resolveNotebookData(viewType, uri);
|
||||
if (!data) {
|
||||
return undefined; // {{SQL CARBON EDIT}}
|
||||
}
|
||||
|
||||
mainthreadNotebook.textModel.languages = data.languages;
|
||||
mainthreadNotebook.textModel.metadata = data.metadata;
|
||||
await mainthreadNotebook.applyEdit(mainthreadNotebook.textModel.versionId, [
|
||||
{ editType: CellEditType.Delete, count: mainthreadNotebook.textModel.cells.length, index: 0 },
|
||||
{ editType: CellEditType.Insert, index: 0, cells: data.cells }
|
||||
], true, false);
|
||||
}
|
||||
return mainthreadNotebook.textModel;
|
||||
}
|
||||
|
||||
let document = this._instantiationService.createInstance(MainThreadNotebookDocument, this._proxy, MainThreadNotebookController.documentHandle++, viewType, this._supportBackup, uri);
|
||||
this._mapping.set(document.uri.toString(), document);
|
||||
|
||||
if (backup) {
|
||||
// trigger events
|
||||
document.textModel.metadata = backup.metadata;
|
||||
document.textModel.languages = backup.languages;
|
||||
|
||||
// restored from backup, update the text model without emitting any event to exthost
|
||||
await document.applyEdit(document.textModel.versionId, [
|
||||
{
|
||||
editType: CellEditType.Insert,
|
||||
index: 0,
|
||||
cells: backup.cells || []
|
||||
}
|
||||
], false, true);
|
||||
|
||||
// create document in ext host with cells data
|
||||
await this._mainThreadNotebook.addNotebookDocument({
|
||||
viewType: document.viewType,
|
||||
handle: document.handle,
|
||||
uri: document.uri,
|
||||
metadata: document.textModel.metadata,
|
||||
versionId: document.textModel.versionId,
|
||||
cells: document.textModel.cells.map(cell => ({
|
||||
handle: cell.handle,
|
||||
uri: cell.uri,
|
||||
source: cell.textBuffer.getLinesContent(),
|
||||
language: cell.language,
|
||||
cellKind: cell.cellKind,
|
||||
outputs: cell.outputs,
|
||||
metadata: cell.metadata
|
||||
})),
|
||||
attachedEditor: editorId ? {
|
||||
id: editorId,
|
||||
selections: document.textModel.selections
|
||||
} : undefined
|
||||
});
|
||||
|
||||
return document.textModel;
|
||||
}
|
||||
|
||||
// open notebook document
|
||||
const data = await this._proxy.$resolveNotebookData(viewType, uri, backupId);
|
||||
if (!data) {
|
||||
return undefined; // {{SQL CARBON EDIT}}
|
||||
}
|
||||
|
||||
document.textModel.languages = data.languages;
|
||||
document.textModel.metadata = data.metadata;
|
||||
|
||||
if (data.cells.length) {
|
||||
document.textModel.initialize(data!.cells);
|
||||
} else {
|
||||
const mainCell = document.textModel.createCellTextModel([''], document.textModel.languages.length ? document.textModel.languages[0] : '', CellKind.Code, [], undefined);
|
||||
document.textModel.insertTemplateCell(mainCell);
|
||||
}
|
||||
|
||||
await this._mainThreadNotebook.addNotebookDocument({
|
||||
viewType: document.viewType,
|
||||
handle: document.handle,
|
||||
uri: document.uri,
|
||||
metadata: document.textModel.metadata,
|
||||
versionId: document.textModel.versionId,
|
||||
cells: document.textModel.cells.map(cell => ({
|
||||
handle: cell.handle,
|
||||
uri: cell.uri,
|
||||
source: cell.textBuffer.getLinesContent(),
|
||||
language: cell.language,
|
||||
cellKind: cell.cellKind,
|
||||
outputs: cell.outputs,
|
||||
metadata: cell.metadata
|
||||
})),
|
||||
attachedEditor: editorId ? {
|
||||
id: editorId,
|
||||
selections: document.textModel.selections
|
||||
} : undefined
|
||||
});
|
||||
|
||||
this._proxy.$acceptEditorPropertiesChanged(uri, { selections: null, metadata: document.textModel.metadata });
|
||||
|
||||
return document.textModel;
|
||||
}
|
||||
|
||||
async resolveNotebookEditor(viewType: string, uri: URI, editorId: string) {
|
||||
await this._proxy.$resolveNotebookEditor(viewType, uri, editorId);
|
||||
}
|
||||
|
||||
async tryApplyEdits(resource: UriComponents, modelVersionId: number, edits: ICellEditOperation[], renderers: number[]): Promise<boolean> {
|
||||
let mainthreadNotebook = this._mapping.get(URI.from(resource).toString());
|
||||
|
||||
if (mainthreadNotebook) {
|
||||
return await mainthreadNotebook.applyEdit(modelVersionId, edits, true, true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
async spliceNotebookCellOutputs(resource: UriComponents, cellHandle: number, splices: NotebookCellOutputsSplice[], renderers: number[]): Promise<void> {
|
||||
let mainthreadNotebook = this._mapping.get(URI.from(resource).toString());
|
||||
await mainthreadNotebook?.spliceNotebookCellOutputs(cellHandle, splices);
|
||||
}
|
||||
|
||||
async executeNotebook(viewType: string, uri: URI, useAttachedKernel: boolean, token: CancellationToken): Promise<void> {
|
||||
return this._mainThreadNotebook.executeNotebook(viewType, uri, useAttachedKernel, token);
|
||||
}
|
||||
|
||||
onDidReceiveMessage(editorId: string, rendererType: string | undefined, message: unknown): void {
|
||||
this._proxy.$onDidReceiveMessage(editorId, rendererType, message);
|
||||
}
|
||||
|
||||
async removeNotebookDocument(notebook: INotebookTextModel): Promise<void> {
|
||||
let document = this._mapping.get(URI.from(notebook.uri).toString());
|
||||
|
||||
if (!document) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO@rebornix, remove cell should use emitDelta as well to ensure document/editor events are sent together
|
||||
await this._proxy.$acceptDocumentAndEditorsDelta({ removedDocuments: [notebook.uri] });
|
||||
document.dispose();
|
||||
this._mapping.delete(URI.from(notebook.uri).toString());
|
||||
}
|
||||
|
||||
// Methods for ExtHost
|
||||
|
||||
handleNotebookChange(resource: UriComponents) {
|
||||
let document = this._mapping.get(URI.from(resource).toString());
|
||||
document?.textModel.handleUnknownChange();
|
||||
}
|
||||
|
||||
handleEdit(resource: UriComponents, editId: number, label: string | undefined): void {
|
||||
let document = this._mapping.get(URI.from(resource).toString());
|
||||
document?.handleEdit(editId, label);
|
||||
}
|
||||
|
||||
updateLanguages(resource: UriComponents, languages: string[]) {
|
||||
let document = this._mapping.get(URI.from(resource).toString());
|
||||
document?.textModel.updateLanguages(languages);
|
||||
}
|
||||
|
||||
updateNotebookMetadata(resource: UriComponents, metadata: NotebookDocumentMetadata) {
|
||||
let document = this._mapping.get(URI.from(resource).toString());
|
||||
document?.textModel.updateNotebookMetadata(metadata);
|
||||
}
|
||||
|
||||
updateNotebookCellMetadata(resource: UriComponents, handle: number, metadata: NotebookCellMetadata) {
|
||||
let document = this._mapping.get(URI.from(resource).toString());
|
||||
document?.textModel.updateNotebookCellMetadata(handle, metadata);
|
||||
}
|
||||
|
||||
async executeNotebookCell(uri: URI, handle: number, useAttachedKernel: boolean, token: CancellationToken): Promise<void> {
|
||||
return this._proxy.$executeNotebook(this._viewType, uri, handle, useAttachedKernel, token);
|
||||
}
|
||||
|
||||
async save(uri: URI, token: CancellationToken): Promise<boolean> {
|
||||
return this._proxy.$saveNotebook(this._viewType, uri, token);
|
||||
}
|
||||
|
||||
async saveAs(uri: URI, target: URI, token: CancellationToken): Promise<boolean> {
|
||||
return this._proxy.$saveNotebookAs(this._viewType, uri, target, token);
|
||||
}
|
||||
|
||||
async backup(uri: URI, token: CancellationToken): Promise<string | undefined> {
|
||||
const backupId = await this._proxy.$backup(this._viewType, uri, token);
|
||||
return backupId;
|
||||
const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
|
||||
textModel?.handleUnknownChange();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -726,8 +646,8 @@ export class MainThreadNotebookKernel implements INotebookKernelInfo {
|
||||
) {
|
||||
}
|
||||
|
||||
async executeNotebook(viewType: string, uri: URI, handle: number | undefined, token: CancellationToken): Promise<void> {
|
||||
return this._proxy.$executeNotebook2(this.id, viewType, uri, handle, token);
|
||||
async executeNotebook(viewType: string, uri: URI, handle: number | undefined): Promise<void> {
|
||||
return this._proxy.$executeNotebook2(this.id, viewType, uri, handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -613,6 +613,9 @@ export class MainThreadTask implements MainThreadTaskShape {
|
||||
public $registerTaskSystem(key: string, info: TaskSystemInfoDTO): void {
|
||||
let platform: Platform.Platform;
|
||||
switch (info.platform) {
|
||||
case 'Web':
|
||||
platform = Platform.Platform.Web;
|
||||
break;
|
||||
case 'win32':
|
||||
platform = Platform.Platform.Windows;
|
||||
break;
|
||||
|
||||
@@ -84,12 +84,19 @@ interface IUserFriendlyViewDescriptor {
|
||||
|
||||
icon?: string;
|
||||
contextualTitle?: string;
|
||||
visibility?: string;
|
||||
|
||||
// From 'remoteViewDescriptor' type
|
||||
group?: string;
|
||||
remoteName?: string | string[];
|
||||
}
|
||||
|
||||
enum InitialVisibility {
|
||||
Visible = 'visible',
|
||||
Hidden = 'hidden',
|
||||
Collapsed = 'collapsed'
|
||||
}
|
||||
|
||||
const viewDescriptor: IJSONSchema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
@@ -113,6 +120,20 @@ const viewDescriptor: IJSONSchema = {
|
||||
description: localize('vscode.extension.contributes.view.contextualTitle', "Human-readable context for when the view is moved out of its original location. By default, the view's container name will be used. Will be shown"),
|
||||
type: 'string'
|
||||
},
|
||||
visibility: {
|
||||
description: localize('vscode.extension.contributes.view.initialState', "Initial state of the view when the extension is first installed. Once the user has changed the view state by collapsing, moving, or hiding the view, the initial state will not be used again."),
|
||||
type: 'string',
|
||||
enum: [
|
||||
'visible',
|
||||
'hidden',
|
||||
'collapsed'
|
||||
],
|
||||
enumDescriptions: [
|
||||
localize('vscode.extension.contributes.view.initialState.visible', "The default initial state for view. The view will be expanded. This may have different behavior when the view container that the view is in is built in."),
|
||||
localize('vscode.extension.contributes.view.initialState.hidden', "The view will not be shown in the view container, but will be discoverable through the views menu and other view entry points and can be un-hidden by the user."),
|
||||
localize('vscode.extension.contributes.view.initialState.collapsed', "The view will show in the view container, but will be collapsed.")
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -427,6 +448,7 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
|
||||
: undefined;
|
||||
|
||||
const icon = item.icon ? resources.joinPath(extension.description.extensionLocation, item.icon) : undefined;
|
||||
const initialVisibility = this.convertInitialVisibility(item.visibility);
|
||||
const viewDescriptor = <ICustomViewDescriptor>{
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
@@ -437,12 +459,13 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
|
||||
canToggleVisibility: true,
|
||||
canMoveView: true,
|
||||
treeView: this.instantiationService.createInstance(CustomTreeView, item.id, item.name),
|
||||
collapsed: this.showCollapsed(container),
|
||||
collapsed: this.showCollapsed(container) || initialVisibility === InitialVisibility.Collapsed,
|
||||
order: order,
|
||||
extensionId: extension.description.identifier,
|
||||
originalContainerId: entry.key,
|
||||
group: item.group,
|
||||
remoteAuthority: item.remoteName || (<any>item).remoteAuthority // TODO@roblou - delete after remote extensions are updated
|
||||
remoteAuthority: item.remoteName || (<any>item).remoteAuthority, // TODO@roblou - delete after remote extensions are updated
|
||||
hideByDefault: initialVisibility === InitialVisibility.Hidden
|
||||
};
|
||||
|
||||
viewIds.add(viewDescriptor.id);
|
||||
@@ -471,6 +494,13 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
|
||||
}
|
||||
}
|
||||
|
||||
private convertInitialVisibility(value: any): InitialVisibility | undefined {
|
||||
if (Object.values(InitialVisibility).includes(value)) {
|
||||
return value;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private isValidViewDescriptors(viewDescriptors: IUserFriendlyViewDescriptor[], collector: ExtensionMessageCollector): boolean {
|
||||
if (!Array.isArray(viewDescriptors)) {
|
||||
collector.error(localize('requirearray', "views must be an array"));
|
||||
@@ -498,6 +528,10 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
|
||||
collector.error(localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'contextualTitle'));
|
||||
return false;
|
||||
}
|
||||
if (descriptor.visibility && !this.convertInitialVisibility(descriptor.visibility)) {
|
||||
collector.error(localize('optenum', "property `{0}` can be omitted or must be one of {1}", 'visibility', Object.values(InitialVisibility).join(', ')));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -8,7 +8,7 @@ import * as objects from 'vs/base/common/objects';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
||||
import { ExtensionsRegistry, IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
||||
import { IConfigurationNode, IConfigurationRegistry, Extensions, resourceLanguageSettingsSchemaId, IDefaultConfigurationExtension, validateProperty, ConfigurationScope, OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { IConfigurationNode, IConfigurationRegistry, Extensions, resourceLanguageSettingsSchemaId, validateProperty, ConfigurationScope, OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
|
||||
import { workspaceSettingsSchemaId, launchSchemaId, tasksSchemaId } from 'vs/workbench/services/configuration/common/configuration';
|
||||
import { isObject } from 'vs/base/common/types';
|
||||
@@ -105,20 +105,11 @@ const defaultConfigurationExtPoint = ExtensionsRegistry.registerExtensionPoint<I
|
||||
});
|
||||
defaultConfigurationExtPoint.setHandler((extensions, { added, removed }) => {
|
||||
if (removed.length) {
|
||||
const removedDefaultConfigurations: IDefaultConfigurationExtension[] = removed.map(extension => {
|
||||
const id = extension.description.identifier;
|
||||
const name = extension.description.name;
|
||||
const defaults = objects.deepClone(extension.value);
|
||||
return <IDefaultConfigurationExtension>{
|
||||
id, name, defaults
|
||||
};
|
||||
});
|
||||
const removedDefaultConfigurations = removed.map<IStringDictionary<any>>(extension => objects.deepClone(extension.value));
|
||||
configurationRegistry.deregisterDefaultConfigurations(removedDefaultConfigurations);
|
||||
}
|
||||
if (added.length) {
|
||||
const addedDefaultConfigurations = added.map(extension => {
|
||||
const id = extension.description.identifier;
|
||||
const name = extension.description.name;
|
||||
const addedDefaultConfigurations = added.map<IStringDictionary<any>>(extension => {
|
||||
const defaults: IStringDictionary<any> = objects.deepClone(extension.value);
|
||||
for (const key of Object.keys(defaults)) {
|
||||
if (!OVERRIDE_PROPERTY_PATTERN.test(key) || typeof defaults[key] !== 'object') {
|
||||
@@ -126,9 +117,7 @@ defaultConfigurationExtPoint.setHandler((extensions, { added, removed }) => {
|
||||
delete defaults[key];
|
||||
}
|
||||
}
|
||||
return <IDefaultConfigurationExtension>{
|
||||
id, name, defaults
|
||||
};
|
||||
return defaults;
|
||||
});
|
||||
configurationRegistry.registerDefaultConfigurations(addedDefaultConfigurations);
|
||||
}
|
||||
|
||||
@@ -208,9 +208,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
get providers(): ReadonlyArray<vscode.AuthenticationProviderInformation> {
|
||||
return extHostAuthentication.providers;
|
||||
},
|
||||
hasSessions(providerId: string, scopes: string[]): Thenable<boolean> {
|
||||
return extHostAuthentication.hasSessions(providerId, scopes);
|
||||
},
|
||||
getSession(providerId: string, scopes: string[], options: vscode.AuthenticationGetSessionOptions) {
|
||||
return extHostAuthentication.getSession(extension, providerId, scopes, options as any);
|
||||
},
|
||||
@@ -958,6 +955,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostNotebook.onDidChangeVisibleNotebookEditors;
|
||||
},
|
||||
get onDidChangeActiveNotebookKernel() {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostNotebook.onDidChangeActiveNotebookKernel;
|
||||
},
|
||||
registerNotebookContentProvider: (viewType: string, provider: vscode.NotebookContentProvider) => {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostNotebook.registerNotebookContentProvider(extension, viewType, provider);
|
||||
@@ -966,6 +967,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostNotebook.registerNotebookKernel(extension, id, selector, kernel);
|
||||
},
|
||||
registerNotebookKernelProvider: (selector: vscode.NotebookDocumentFilter, provider: vscode.NotebookKernelProvider) => {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostNotebook.registerNotebookKernelProvider(extension, selector, provider);
|
||||
},
|
||||
registerNotebookOutputRenderer: (type: string, outputFilter: vscode.NotebookOutputSelector, renderer: vscode.NotebookOutputRenderer) => {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostNotebook.registerNotebookOutputRenderer(type, extension, outputFilter, renderer);
|
||||
@@ -1127,7 +1132,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
CellKind: extHostTypes.CellKind,
|
||||
CellOutputKind: extHostTypes.CellOutputKind,
|
||||
NotebookCellRunState: extHostTypes.NotebookCellRunState,
|
||||
AuthenticationSession: extHostTypes.AuthenticationSession
|
||||
NotebookRunState: extHostTypes.NotebookRunState
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService';
|
||||
import { TunnelOptions } 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 { INotebookMimeTypeSelector, IProcessedOutput, INotebookDisplayOrder, NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEvent, NotebookDataDto, INotebookKernelInfoDto, IMainCellDto, IOutputRenderRequest, IOutputRenderResponse } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { INotebookMimeTypeSelector, IProcessedOutput, INotebookDisplayOrder, NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEvent, NotebookDataDto, INotebookKernelInfoDto, IMainCellDto, IOutputRenderRequest, IOutputRenderResponse, INotebookDocumentFilter, INotebookKernelInfoDto2 } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
|
||||
import { Dto } from 'vs/base/common/types';
|
||||
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
|
||||
@@ -169,7 +169,7 @@ export interface MainThreadAuthenticationShape extends IDisposable {
|
||||
$selectSession(providerId: string, providerName: string, extensionId: string, extensionName: string, potentialSessions: modes.AuthenticationSession[], scopes: string[], clearSessionPreference: boolean): Promise<modes.AuthenticationSession>;
|
||||
$getSessionsPrompt(providerId: string, accountName: string, providerName: string, extensionId: string, extensionName: string): Promise<boolean>;
|
||||
$loginPrompt(providerName: string, extensionName: string): Promise<boolean>;
|
||||
$setTrustedExtension(providerId: string, accountName: string, extensionId: string, extensionName: string): Promise<void>;
|
||||
$setTrustedExtensionAndAccountPreference(providerId: string, accountName: string, extensionId: string, extensionName: string, sessionId: string): Promise<void>;
|
||||
$requestNewSession(providerId: string, scopes: string[], extensionId: string, extensionName: string): Promise<void>;
|
||||
|
||||
$getSessions(providerId: string): Promise<ReadonlyArray<modes.AuthenticationSession>>;
|
||||
@@ -601,6 +601,7 @@ export interface WebviewExtensionDescription {
|
||||
export interface NotebookExtensionDescription {
|
||||
readonly id: ExtensionIdentifier;
|
||||
readonly location: UriComponents;
|
||||
readonly description?: string;
|
||||
}
|
||||
|
||||
export enum WebviewEditorCapabilities {
|
||||
@@ -708,6 +709,9 @@ export interface MainThreadNotebookShape extends IDisposable {
|
||||
$registerNotebookRenderer(extension: NotebookExtensionDescription, type: string, selectors: INotebookMimeTypeSelector, preloads: UriComponents[]): Promise<void>;
|
||||
$unregisterNotebookRenderer(id: string): Promise<void>;
|
||||
$registerNotebookKernel(extension: NotebookExtensionDescription, id: string, label: string, selectors: (string | IRelativePattern)[], preloads: UriComponents[]): Promise<void>;
|
||||
$registerNotebookKernelProvider(extension: NotebookExtensionDescription, handle: number, documentFilter: INotebookDocumentFilter): Promise<void>;
|
||||
$unregisterNotebookKernelProvider(handle: number): Promise<void>;
|
||||
$onNotebookKernelChange(handle: number): void;
|
||||
$unregisterNotebookKernel(id: string): Promise<void>;
|
||||
$tryApplyEdits(viewType: string, resource: UriComponents, modelVersionId: number, edits: ICellEditOperation[], renderers: number[]): Promise<boolean>;
|
||||
$updateNotebookLanguages(viewType: string, resource: UriComponents, languages: string[]): Promise<void>;
|
||||
@@ -1615,12 +1619,17 @@ export interface INotebookDocumentsAndEditorsDelta {
|
||||
export interface ExtHostNotebookShape {
|
||||
$resolveNotebookData(viewType: string, uri: UriComponents, backupId?: string): Promise<NotebookDataDto | undefined>;
|
||||
$resolveNotebookEditor(viewType: string, uri: UriComponents, editorId: string): Promise<void>;
|
||||
$executeNotebook(viewType: string, uri: UriComponents, cellHandle: number | undefined, useAttachedKernel: boolean, token: CancellationToken): Promise<void>;
|
||||
$executeNotebook2(kernelId: string, viewType: string, uri: UriComponents, cellHandle: number | undefined, token: CancellationToken): Promise<void>;
|
||||
$provideNotebookKernels(handle: number, uri: UriComponents, token: CancellationToken): Promise<INotebookKernelInfoDto2[]>;
|
||||
$resolveNotebookKernel(handle: number, editorId: string, uri: UriComponents, kernelId: string, token: CancellationToken): Promise<void>;
|
||||
$executeNotebookByAttachedKernel(viewType: string, uri: UriComponents, cellHandle: number | undefined): Promise<void>;
|
||||
$cancelNotebookByAttachedKernel(viewType: string, uri: UriComponents, cellHandle: number | undefined): Promise<void>;
|
||||
$executeNotebookKernelFromProvider(handle: number, uri: UriComponents, kernelId: string, cellHandle: number | undefined): Promise<void>;
|
||||
$executeNotebook2(kernelId: string, viewType: string, uri: UriComponents, cellHandle: number | undefined): Promise<void>;
|
||||
$saveNotebook(viewType: string, uri: UriComponents, token: CancellationToken): Promise<boolean>;
|
||||
$saveNotebookAs(viewType: string, uri: UriComponents, target: UriComponents, token: CancellationToken): Promise<boolean>;
|
||||
$backup(viewType: string, uri: UriComponents, cancellation: CancellationToken): Promise<string | undefined>;
|
||||
$acceptDisplayOrder(displayOrder: INotebookDisplayOrder): void;
|
||||
$acceptNotebookActiveKernelChange(event: { uri: UriComponents, providerHandle: number | undefined, kernelId: string | undefined }): void;
|
||||
$renderOutputs(uriComponents: UriComponents, id: string, request: IOutputRenderRequest<UriComponents>): Promise<IOutputRenderResponse<UriComponents> | undefined>;
|
||||
$renderOutputs2<T>(uriComponents: UriComponents, id: string, request: IOutputRenderRequest<T>): Promise<IOutputRenderResponse<T> | undefined>;
|
||||
$onDidReceiveMessage(editorId: string, rendererId: string | undefined, message: unknown): void;
|
||||
|
||||
@@ -215,6 +215,20 @@ const newCommands: ApiCommand[] = [
|
||||
[ApiCommandArgument.CallHierarchyItem],
|
||||
new ApiCommandResult<IOutgoingCallDto[], types.CallHierarchyOutgoingCall[]>('A CallHierarchyItem or undefined', v => v.map(typeConverters.CallHierarchyOutgoingCall.to))
|
||||
),
|
||||
// --- rename
|
||||
new ApiCommand(
|
||||
'vscode.executeDocumentRenameProvider', '_executeDocumentRenameProvider', 'Execute rename provider.',
|
||||
[ApiCommandArgument.Uri, ApiCommandArgument.Position, new ApiCommandArgument('newName', 'The new symbol name', v => typeof v === 'string', v => v)],
|
||||
new ApiCommandResult<IWorkspaceEditDto, types.WorkspaceEdit | undefined>('A promise that resolves to a WorkspaceEdit.', value => {
|
||||
if (!value) {
|
||||
return undefined;
|
||||
}
|
||||
if (value.rejectReason) {
|
||||
throw new Error(value.rejectReason);
|
||||
}
|
||||
return typeConverters.WorkspaceEdit.to(value);
|
||||
})
|
||||
)
|
||||
];
|
||||
|
||||
|
||||
@@ -238,15 +252,6 @@ export class ExtHostApiCommands {
|
||||
}
|
||||
|
||||
registerCommands() {
|
||||
this._register('vscode.executeDocumentRenameProvider', this._executeDocumentRenameProvider, {
|
||||
description: 'Execute rename provider.',
|
||||
args: [
|
||||
{ name: 'uri', description: 'Uri of a text document', constraint: URI },
|
||||
{ name: 'position', description: 'Position in a text document', constraint: types.Position },
|
||||
{ name: 'newName', description: 'The new symbol name', constraint: String }
|
||||
],
|
||||
returns: 'A promise that resolves to a WorkspaceEdit.'
|
||||
});
|
||||
this._register('vscode.executeSignatureHelpProvider', this._executeSignatureHelpProvider, {
|
||||
description: 'Execute signature help provider.',
|
||||
args: [
|
||||
@@ -376,23 +381,6 @@ export class ExtHostApiCommands {
|
||||
this._disposables.add(disposable);
|
||||
}
|
||||
|
||||
private _executeDocumentRenameProvider(resource: URI, position: types.Position, newName: string): Promise<types.WorkspaceEdit> {
|
||||
const args = {
|
||||
resource,
|
||||
position: position && typeConverters.Position.from(position),
|
||||
newName
|
||||
};
|
||||
return this._commands.executeCommand<IWorkspaceEditDto>('_executeDocumentRenameProvider', args).then(value => {
|
||||
if (!value) {
|
||||
return undefined;
|
||||
}
|
||||
if (value.rejectReason) {
|
||||
return Promise.reject<any>(new Error(value.rejectReason));
|
||||
}
|
||||
return typeConverters.WorkspaceEdit.to(value);
|
||||
});
|
||||
}
|
||||
|
||||
private _executeSignatureHelpProvider(resource: URI, position: types.Position, triggerCharacter: string): Promise<types.SignatureHelp | undefined> {
|
||||
const args = {
|
||||
resource,
|
||||
|
||||
@@ -37,26 +37,7 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
|
||||
}
|
||||
|
||||
get providers(): ReadonlyArray<vscode.AuthenticationProviderInformation> {
|
||||
return Object.freeze(this._providers);
|
||||
}
|
||||
|
||||
private async resolveSessions(providerId: string): Promise<ReadonlyArray<modes.AuthenticationSession>> {
|
||||
const provider = this._authenticationProviders.get(providerId);
|
||||
|
||||
let sessions;
|
||||
if (!provider) {
|
||||
sessions = await this._proxy.$getSessions(providerId);
|
||||
} else {
|
||||
sessions = await provider.getSessions();
|
||||
}
|
||||
|
||||
return sessions;
|
||||
}
|
||||
|
||||
async hasSessions(providerId: string, scopes: string[]): Promise<boolean> {
|
||||
const orderedScopes = scopes.sort().join(' ');
|
||||
const sessions = await this.resolveSessions(providerId);
|
||||
return !!(sessions.filter(session => session.scopes.slice().sort().join(' ') === orderedScopes).length);
|
||||
return Object.freeze(this._providers.slice());
|
||||
}
|
||||
|
||||
async getSession(requestingExtension: IExtensionDescription, providerId: string, scopes: string[], options: vscode.AuthenticationGetSessionOptions & { createIfNone: true }): Promise<vscode.AuthenticationSession>;
|
||||
@@ -94,7 +75,7 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
|
||||
}
|
||||
|
||||
const session = await provider.login(scopes);
|
||||
await this._proxy.$setTrustedExtension(providerId, session.account.label, extensionId, extensionName);
|
||||
await this._proxy.$setTrustedExtensionAndAccountPreference(providerId, session.account.label, extensionId, extensionName, session.id);
|
||||
return session;
|
||||
} else {
|
||||
await this._proxy.$requestNewSession(providerId, scopes, extensionId, extensionName);
|
||||
|
||||
@@ -9,13 +9,14 @@ import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { ISplice } from 'vs/base/common/sequence';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import * as UUID from 'vs/base/common/uuid';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { CellKind, ExtHostNotebookShape, IMainContext, MainContext, MainThreadNotebookShape, NotebookCellOutputsSplice, MainThreadDocumentsShape, INotebookEditorPropertiesChangeData, INotebookDocumentsAndEditorsDelta } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { CellEditType, CellUri, diff, ICellEditOperation, ICellInsertEdit, INotebookDisplayOrder, INotebookEditData, NotebookCellsChangedEvent, NotebookCellsSplice2, ICellDeleteEdit, notebookDocumentMetadataDefaults, NotebookCellsChangeType, NotebookDataDto, IOutputRenderRequest, IOutputRenderResponse, IOutputRenderResponseOutputInfo, IOutputRenderResponseCellInfo, IRawOutput, CellOutputKind, IProcessedOutput } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CellEditType, diff, ICellEditOperation, ICellInsertEdit, INotebookDisplayOrder, INotebookEditData, NotebookCellsChangedEvent, NotebookCellsSplice2, ICellDeleteEdit, notebookDocumentMetadataDefaults, NotebookCellsChangeType, NotebookDataDto, IOutputRenderRequest, IOutputRenderResponse, IOutputRenderResponseOutputInfo, IOutputRenderResponseCellInfo, IRawOutput, CellOutputKind, IProcessedOutput, INotebookKernelInfoDto2, IMainCellDto } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { ExtHostDocumentData } from 'vs/workbench/api/common/extHostDocumentData';
|
||||
import { NotImplementedProxy } from 'vs/base/common/types';
|
||||
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
@@ -24,7 +25,6 @@ import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePa
|
||||
import { joinPath } from 'vs/base/common/resources';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { hash } from 'vs/base/common/hash';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { Cache } from './cache';
|
||||
|
||||
interface IObservable<T> {
|
||||
@@ -54,64 +54,85 @@ interface INotebookEventEmitter {
|
||||
emitCellLanguageChange(event: vscode.NotebookCellLanguageChangeEvent): void;
|
||||
}
|
||||
|
||||
const addIdToOutput = (output: IRawOutput, id = generateUuid()): IProcessedOutput => output.outputKind === CellOutputKind.Rich
|
||||
const addIdToOutput = (output: IRawOutput, id = UUID.generateUuid()): IProcessedOutput => output.outputKind === CellOutputKind.Rich
|
||||
? ({ ...output, outputId: id }) : output;
|
||||
|
||||
class DettachedCellDocumentData extends ExtHostDocumentData {
|
||||
|
||||
private static readonly _fakeProxy = new class extends NotImplementedProxy<MainThreadDocumentsShape>('document') {
|
||||
$trySaveDocument() {
|
||||
return Promise.reject('Cell-document cannot be saved');
|
||||
}
|
||||
};
|
||||
|
||||
constructor(cell: IMainCellDto) {
|
||||
super(DettachedCellDocumentData._fakeProxy,
|
||||
URI.revive(cell.uri),
|
||||
cell.source,
|
||||
cell.eol,
|
||||
cell.language,
|
||||
0,
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostCell extends Disposable implements vscode.NotebookCell {
|
||||
|
||||
// private originalSource: string[];
|
||||
private _outputs: any[];
|
||||
private _onDidChangeOutputs = new Emitter<ISplice<IProcessedOutput>[]>();
|
||||
onDidChangeOutputs: Event<ISplice<IProcessedOutput>[]> = this._onDidChangeOutputs.event;
|
||||
// private _textDocument: vscode.TextDocument | undefined;
|
||||
// private _initalVersion: number = -1;
|
||||
private _outputMapping = new WeakMap<vscode.CellOutput, string | undefined /* output ID */>();
|
||||
private _metadata: vscode.NotebookCellMetadata;
|
||||
readonly onDidChangeOutputs: Event<ISplice<IProcessedOutput>[]> = this._onDidChangeOutputs.event;
|
||||
|
||||
private _outputs: any[];
|
||||
private _outputMapping = new WeakMap<vscode.CellOutput, string | undefined /* output ID */>();
|
||||
|
||||
private _metadata: vscode.NotebookCellMetadata;
|
||||
private _metadataChangeListener: IDisposable;
|
||||
|
||||
private _documentData: ExtHostDocumentData;
|
||||
readonly handle: number;
|
||||
readonly uri: URI;
|
||||
readonly cellKind: CellKind;
|
||||
|
||||
get document(): vscode.TextDocument {
|
||||
return this._documentData.document;
|
||||
}
|
||||
|
||||
get notebook(): vscode.NotebookDocument {
|
||||
return this._notebook;
|
||||
}
|
||||
// todo@jrieken this is a little fish because we have
|
||||
// vscode.TextDocument for which we never fired an onDidOpen
|
||||
// event and which doesn't appear in the list of documents.
|
||||
// this will change once the "real" document comes along. We
|
||||
// should come up with a better approach here...
|
||||
readonly defaultDocument: DettachedCellDocumentData;
|
||||
|
||||
constructor(
|
||||
private readonly _notebook: ExtHostNotebookDocument,
|
||||
readonly handle: number,
|
||||
readonly uri: URI,
|
||||
content: string,
|
||||
public readonly cellKind: CellKind,
|
||||
public language: string,
|
||||
outputs: any[],
|
||||
_metadata: vscode.NotebookCellMetadata | undefined,
|
||||
private _proxy: MainThreadNotebookShape,
|
||||
readonly notebook: ExtHostNotebookDocument,
|
||||
private _extHostDocument: ExtHostDocumentsAndEditors,
|
||||
cell: IMainCellDto,
|
||||
) {
|
||||
super();
|
||||
this._documentData = new ExtHostDocumentData(
|
||||
new class extends NotImplementedProxy<MainThreadDocumentsShape>('document') { },
|
||||
uri,
|
||||
content.split(/\r|\n|\r\n/g), '\n',
|
||||
language, 0, false
|
||||
);
|
||||
|
||||
this._outputs = outputs;
|
||||
this.handle = cell.handle;
|
||||
this.uri = URI.revive(cell.uri);
|
||||
this.cellKind = cell.cellKind;
|
||||
this.defaultDocument = new DettachedCellDocumentData(cell);
|
||||
|
||||
this._outputs = cell.outputs;
|
||||
for (const output of this._outputs) {
|
||||
this._outputMapping.set(output, output.outputId);
|
||||
delete output.outputId;
|
||||
}
|
||||
|
||||
const observableMetadata = getObservable(_metadata || {});
|
||||
const observableMetadata = getObservable(cell.metadata ?? {});
|
||||
this._metadata = observableMetadata.proxy;
|
||||
this._metadataChangeListener = this._register(observableMetadata.onDidChange(() => {
|
||||
this.updateMetadata();
|
||||
this._updateMetadata();
|
||||
}));
|
||||
}
|
||||
|
||||
get document(): vscode.TextDocument {
|
||||
return this._extHostDocument.getDocument(this.uri)?.document ?? this.defaultDocument.document;
|
||||
}
|
||||
|
||||
get language(): string {
|
||||
return this.document.languageId;
|
||||
}
|
||||
|
||||
get outputs() {
|
||||
return this._outputs;
|
||||
}
|
||||
@@ -131,7 +152,7 @@ export class ExtHostCell extends Disposable implements vscode.NotebookCell {
|
||||
start: diff.start,
|
||||
toInsert: diff.toInsert.map((output): IProcessedOutput => {
|
||||
if (output.outputKind === CellOutputKind.Rich) {
|
||||
const uuid = generateUuid();
|
||||
const uuid = UUID.generateUuid();
|
||||
this._outputMapping.set(output, uuid);
|
||||
return { ...output, outputId: uuid };
|
||||
}
|
||||
@@ -156,29 +177,14 @@ export class ExtHostCell extends Disposable implements vscode.NotebookCell {
|
||||
const observableMetadata = getObservable(newMetadata);
|
||||
this._metadata = observableMetadata.proxy;
|
||||
this._metadataChangeListener = this._register(observableMetadata.onDidChange(() => {
|
||||
this.updateMetadata();
|
||||
this._updateMetadata();
|
||||
}));
|
||||
|
||||
this.updateMetadata();
|
||||
this._updateMetadata();
|
||||
}
|
||||
|
||||
private updateMetadata(): Promise<void> {
|
||||
return this._proxy.$updateNotebookCellMetadata(this._notebook.viewType, this._notebook.uri, this.handle, this._metadata);
|
||||
}
|
||||
|
||||
attachTextDocument(document: ExtHostDocumentData) {
|
||||
this._documentData = document;
|
||||
// this._initalVersion = this._documentData.version;
|
||||
}
|
||||
|
||||
detachTextDocument() {
|
||||
// no-op? keep stale document until new comes along?
|
||||
|
||||
// if (this._textDocument && this._textDocument.version !== this._initalVersion) {
|
||||
// this.originalSource = this._textDocument.getText().split(/\r|\n|\r\n/g);
|
||||
// }
|
||||
// this._textDocument = undefined;
|
||||
// this._initalVersion = -1;
|
||||
private _updateMetadata(): Promise<void> {
|
||||
return this._proxy.$updateNotebookCellMetadata(this.notebook.viewType, this.notebook.uri, this.handle, this._metadata);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -367,12 +373,8 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
|
||||
splices.reverse().forEach(splice => {
|
||||
let cellDtos = splice[2];
|
||||
let newCells = cellDtos.map(cell => {
|
||||
const extCell = new ExtHostCell(this, cell.handle, URI.revive(cell.uri), cell.source.join('\n'), cell.cellKind, cell.language, cell.outputs, cell.metadata, this._proxy);
|
||||
const documentData = this._documentsAndEditors.getDocument(URI.revive(cell.uri));
|
||||
|
||||
if (documentData) {
|
||||
extCell.attachTextDocument(documentData);
|
||||
}
|
||||
const extCell = new ExtHostCell(this._proxy, this, this._documentsAndEditors, cell);
|
||||
|
||||
if (!this._cellDisposableMapping.has(extCell.handle)) {
|
||||
this._cellDisposableMapping.set(extCell.handle, new DisposableStore());
|
||||
@@ -454,7 +456,7 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
|
||||
|
||||
private $changeCellLanguage(index: number, language: string): void {
|
||||
const cell = this.cells[index];
|
||||
cell.language = language;
|
||||
cell.defaultDocument._acceptLanguageId(language);
|
||||
const event: vscode.NotebookCellLanguageChangeEvent = { document: this, cell, language };
|
||||
this._emitter.emitCellLanguageChange(event);
|
||||
}
|
||||
@@ -480,20 +482,6 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
|
||||
getCell2(cellUri: UriComponents) {
|
||||
return this.cells.find(cell => cell.uri.fragment === cellUri.fragment);
|
||||
}
|
||||
|
||||
attachCellTextDocument(textDocument: ExtHostDocumentData) {
|
||||
let cell = this.cells.find(cell => cell.uri.toString() === textDocument.document.uri.toString());
|
||||
if (cell) {
|
||||
cell.attachTextDocument(textDocument);
|
||||
}
|
||||
}
|
||||
|
||||
detachCellTextDocument(textDocument: ExtHostDocumentData) {
|
||||
let cell = this.cells.find(cell => cell.uri.toString() === textDocument.document.uri.toString());
|
||||
if (cell) {
|
||||
cell.detachTextDocument();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class NotebookEditorCellEditBuilder implements vscode.NotebookEditorCellEdit {
|
||||
@@ -629,6 +617,16 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook
|
||||
this._active = value;
|
||||
}
|
||||
|
||||
private _kernel?: vscode.NotebookKernel;
|
||||
|
||||
get kernel() {
|
||||
return this._kernel;
|
||||
}
|
||||
|
||||
set kernel(_kernel: vscode.NotebookKernel | undefined) {
|
||||
throw readonly('kernel');
|
||||
}
|
||||
|
||||
private _onDidDispose = new Emitter<void>();
|
||||
readonly onDidDispose: Event<void> = this._onDidDispose.event;
|
||||
private _onDidReceiveMessage = new Emitter<any>();
|
||||
@@ -641,31 +639,8 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook
|
||||
private _proxy: MainThreadNotebookShape,
|
||||
private _webComm: vscode.NotebookCommunication,
|
||||
public document: ExtHostNotebookDocument,
|
||||
private _documentsAndEditors: ExtHostDocumentsAndEditors
|
||||
) {
|
||||
super();
|
||||
this._register(this._documentsAndEditors.onDidAddDocuments(documents => {
|
||||
for (const documentData of documents) {
|
||||
let data = CellUri.parse(documentData.document.uri);
|
||||
if (data) {
|
||||
if (this.document.uri.fsPath === data.notebook.fsPath) {
|
||||
document.attachCellTextDocument(documentData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(this._documentsAndEditors.onDidRemoveDocuments(documents => {
|
||||
for (const documentData of documents) {
|
||||
let data = CellUri.parse(documentData.document.uri);
|
||||
if (data) {
|
||||
if (this.document.uri.fsPath === data.notebook.fsPath) {
|
||||
document.detachCellTextDocument(documentData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(this._webComm.onDidReceiveMessage(e => {
|
||||
this._onDidReceiveMessage.fire(e);
|
||||
}));
|
||||
@@ -727,6 +702,9 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook
|
||||
throw readonly('viewColumn');
|
||||
}
|
||||
|
||||
updateActiveKernel(kernel?: vscode.NotebookKernel) {
|
||||
this._kernel = kernel;
|
||||
}
|
||||
async postMessage(message: any): Promise<boolean> {
|
||||
return this._webComm.postMessage(message);
|
||||
}
|
||||
@@ -780,10 +758,124 @@ export interface ExtHostNotebookOutputRenderingHandler {
|
||||
findBestMatchedRenderer(mimeType: string): ExtHostNotebookOutputRenderer[];
|
||||
}
|
||||
|
||||
export class ExtHostNotebookKernelProviderAdapter extends Disposable {
|
||||
private _kernelToId = new Map<vscode.NotebookKernel, string>();
|
||||
private _idToKernel = new Map<string, vscode.NotebookKernel>();
|
||||
constructor(
|
||||
private readonly _proxy: MainThreadNotebookShape,
|
||||
private readonly _handle: number,
|
||||
private readonly _extension: IExtensionDescription,
|
||||
private readonly _provider: vscode.NotebookKernelProvider
|
||||
) {
|
||||
super();
|
||||
|
||||
if (this._provider.onDidChangeKernels) {
|
||||
this._register(this._provider.onDidChangeKernels(() => {
|
||||
this._proxy.$onNotebookKernelChange(this._handle);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
async provideKernels(document: ExtHostNotebookDocument, token: vscode.CancellationToken): Promise<INotebookKernelInfoDto2[]> {
|
||||
const data = await this._provider.provideKernels(document, token) || [];
|
||||
|
||||
const newMap = new Map<vscode.NotebookKernel, string>();
|
||||
let kernel_unique_pool = 0;
|
||||
let kernelIdCache = new Set<string>();
|
||||
|
||||
const transformedData: INotebookKernelInfoDto2[] = data.map(kernel => {
|
||||
let id = this._kernelToId.get(kernel);
|
||||
if (id === undefined) {
|
||||
if (kernel.id && kernelIdCache.has(kernel.id)) {
|
||||
id = `${this._extension.identifier.value}_${kernel.id}_${kernel_unique_pool++}`;
|
||||
} else {
|
||||
id = `${this._extension.identifier.value}_${kernel.id || UUID.generateUuid()}`;
|
||||
}
|
||||
|
||||
this._kernelToId.set(kernel, id);
|
||||
}
|
||||
|
||||
newMap.set(kernel, id);
|
||||
|
||||
return {
|
||||
id,
|
||||
label: kernel.label,
|
||||
extension: this._extension.identifier,
|
||||
extensionLocation: this._extension.extensionLocation,
|
||||
description: kernel.description,
|
||||
isPreferred: kernel.isPreferred,
|
||||
preloads: kernel.preloads
|
||||
};
|
||||
});
|
||||
|
||||
this._kernelToId = newMap;
|
||||
|
||||
this._idToKernel.clear();
|
||||
this._kernelToId.forEach((value, key) => {
|
||||
this._idToKernel.set(value, key);
|
||||
});
|
||||
|
||||
return transformedData;
|
||||
}
|
||||
|
||||
getKernel(kernelId: string) {
|
||||
return this._idToKernel.get(kernelId);
|
||||
}
|
||||
|
||||
async resolveNotebook(kernelId: string, document: ExtHostNotebookDocument, webview: vscode.NotebookCommunication, token: CancellationToken) {
|
||||
const kernel = this._idToKernel.get(kernelId);
|
||||
|
||||
if (kernel && this._provider.resolveKernel) {
|
||||
return this._provider.resolveKernel(kernel, document, webview, token);
|
||||
}
|
||||
}
|
||||
|
||||
async executeNotebook(kernelId: string, document: ExtHostNotebookDocument, cell: ExtHostCell | undefined) {
|
||||
const kernel = this._idToKernel.get(kernelId);
|
||||
|
||||
if (!kernel) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cell) {
|
||||
return withToken(token => (kernel.executeCell as any)(document, cell, token));
|
||||
} else {
|
||||
return withToken(token => (kernel.executeAllCells as any)(document, token));
|
||||
}
|
||||
}
|
||||
|
||||
async cancelNotebook(kernelId: string, document: ExtHostNotebookDocument, cell: ExtHostCell | undefined) {
|
||||
const kernel = this._idToKernel.get(kernelId);
|
||||
|
||||
if (!kernel) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cell) {
|
||||
return kernel.cancelCellExecution(document, cell);
|
||||
} else {
|
||||
return kernel.cancelAllCellsExecution(document);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO@roblou remove 'token' passed to all execute APIs once extensions are updated
|
||||
async function withToken(cb: (token: CancellationToken) => any) {
|
||||
const source = new CancellationTokenSource();
|
||||
try {
|
||||
await cb(source.token);
|
||||
} finally {
|
||||
source.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostNotebookOutputRenderingHandler {
|
||||
private static _notebookKernelProviderHandlePool: number = 0;
|
||||
|
||||
private readonly _proxy: MainThreadNotebookShape;
|
||||
private readonly _notebookContentProviders = new Map<string, { readonly provider: vscode.NotebookContentProvider, readonly extension: IExtensionDescription; }>();
|
||||
private readonly _notebookKernels = new Map<string, { readonly kernel: vscode.NotebookKernel, readonly extension: IExtensionDescription; }>();
|
||||
private readonly _notebookKernelProviders = new Map<number, ExtHostNotebookKernelProviderAdapter>();
|
||||
private readonly _documents = new Map<string, ExtHostNotebookDocument>();
|
||||
private readonly _unInitializedDocuments = new Map<string, ExtHostNotebookDocument>();
|
||||
private readonly _editors = new Map<string, { editor: ExtHostNotebookEditor }>();
|
||||
@@ -820,6 +912,8 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
private _onDidCloseNotebookDocument = new Emitter<vscode.NotebookDocument>();
|
||||
onDidCloseNotebookDocument: Event<vscode.NotebookDocument> = this._onDidCloseNotebookDocument.event;
|
||||
visibleNotebookEditors: ExtHostNotebookEditor[] = [];
|
||||
private _onDidChangeActiveNotebookKernel = new Emitter<{ document: ExtHostNotebookDocument, kernel: vscode.NotebookKernel | undefined }>();
|
||||
onDidChangeActiveNotebookKernel = this._onDidChangeActiveNotebookKernel.event;
|
||||
private _onDidChangeVisibleNotebookEditors = new Emitter<vscode.NotebookEditor[]>();
|
||||
onDidChangeVisibleNotebookEditors = this._onDidChangeVisibleNotebookEditors.event;
|
||||
|
||||
@@ -864,7 +958,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
|
||||
let extHostRenderer = new ExtHostNotebookOutputRenderer(type, filter, renderer);
|
||||
this._notebookOutputRenderers.set(extHostRenderer.type, extHostRenderer);
|
||||
this._proxy.$registerNotebookRenderer({ id: extension.identifier, location: extension.extensionLocation }, type, filter, renderer.preloads || []);
|
||||
this._proxy.$registerNotebookRenderer({ id: extension.identifier, location: extension.extensionLocation, description: extension.description }, type, filter, renderer.preloads || []);
|
||||
return new extHostTypes.Disposable(() => {
|
||||
this._notebookOutputRenderers.delete(extHostRenderer.type);
|
||||
this._proxy.$unregisterNotebookRenderer(extHostRenderer.type);
|
||||
@@ -989,7 +1083,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
|
||||
const supportBackup = !!provider.backupNotebook;
|
||||
|
||||
this._proxy.$registerNotebookProvider({ id: extension.identifier, location: extension.extensionLocation }, viewType, supportBackup, provider.kernel ? { id: viewType, label: provider.kernel.label, extensionLocation: extension.extensionLocation, preloads: provider.kernel.preloads } : undefined);
|
||||
this._proxy.$registerNotebookProvider({ id: extension.identifier, location: extension.extensionLocation, description: extension.description }, viewType, supportBackup, provider.kernel ? { id: viewType, label: provider.kernel.label, extensionLocation: extension.extensionLocation, preloads: provider.kernel.preloads } : undefined);
|
||||
|
||||
return new extHostTypes.Disposable(() => {
|
||||
listener.dispose();
|
||||
@@ -998,6 +1092,55 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
});
|
||||
}
|
||||
|
||||
registerNotebookKernelProvider(extension: IExtensionDescription, selector: vscode.NotebookDocumentFilter, provider: vscode.NotebookKernelProvider) {
|
||||
const handle = ExtHostNotebookController._notebookKernelProviderHandlePool++;
|
||||
const adapter = new ExtHostNotebookKernelProviderAdapter(this._proxy, handle, extension, provider);
|
||||
this._notebookKernelProviders.set(handle, adapter);
|
||||
this._proxy.$registerNotebookKernelProvider({ id: extension.identifier, location: extension.extensionLocation, description: extension.description }, handle, {
|
||||
viewType: selector.viewType,
|
||||
filenamePattern: selector.filenamePattern ? typeConverters.GlobPattern.from(selector.filenamePattern) : undefined,
|
||||
excludeFileNamePattern: selector.excludeFileNamePattern ? typeConverters.GlobPattern.from(selector.excludeFileNamePattern) : undefined,
|
||||
});
|
||||
|
||||
return new extHostTypes.Disposable(() => {
|
||||
adapter.dispose();
|
||||
this._notebookKernelProviders.delete(handle);
|
||||
this._proxy.$unregisterNotebookKernelProvider(handle);
|
||||
});
|
||||
}
|
||||
|
||||
private _withAdapter<T>(handle: number, uri: UriComponents, callback: (adapter: ExtHostNotebookKernelProviderAdapter, document: ExtHostNotebookDocument) => Promise<T>) {
|
||||
const document = this._documents.get(URI.revive(uri).toString());
|
||||
|
||||
if (!document) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const provider = this._notebookKernelProviders.get(handle);
|
||||
|
||||
if (!provider) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return callback(provider, document);
|
||||
}
|
||||
|
||||
async $provideNotebookKernels(handle: number, uri: UriComponents, token: CancellationToken): Promise<INotebookKernelInfoDto2[]> {
|
||||
return this._withAdapter<INotebookKernelInfoDto2[]>(handle, uri, (adapter, document) => {
|
||||
return adapter.provideKernels(document, token);
|
||||
});
|
||||
}
|
||||
|
||||
async $resolveNotebookKernel(handle: number, editorId: string, uri: UriComponents, kernelId: string, token: CancellationToken): Promise<void> {
|
||||
await this._withAdapter<void>(handle, uri, async (adapter, document) => {
|
||||
let webComm = this._webviewComm.get(editorId);
|
||||
|
||||
if (webComm) {
|
||||
await adapter.resolveNotebook(kernelId, document, webComm.contentProviderComm, token);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
registerNotebookKernel(extension: IExtensionDescription, id: string, selectors: vscode.GlobPattern[], kernel: vscode.NotebookKernel): vscode.Disposable {
|
||||
if (this._notebookKernels.has(id)) {
|
||||
throw new Error(`Notebook kernel for '${id}' already registered`);
|
||||
@@ -1006,7 +1149,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
this._notebookKernels.set(id, { kernel, extension });
|
||||
const transformedSelectors = selectors.map(selector => typeConverters.GlobPattern.from(selector));
|
||||
|
||||
this._proxy.$registerNotebookKernel({ id: extension.identifier, location: extension.extensionLocation }, id, kernel.label, transformedSelectors, kernel.preloads || []);
|
||||
this._proxy.$registerNotebookKernel({ id: extension.identifier, location: extension.extensionLocation, description: extension.description }, id, kernel.label, transformedSelectors, kernel.preloads || []);
|
||||
return new extHostTypes.Disposable(() => {
|
||||
this._notebookKernels.delete(id);
|
||||
this._proxy.$unregisterNotebookKernel(id);
|
||||
@@ -1101,7 +1244,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
}
|
||||
}
|
||||
|
||||
async $executeNotebook(viewType: string, uri: UriComponents, cellHandle: number | undefined, useAttachedKernel: boolean, token: CancellationToken): Promise<void> {
|
||||
async $executeNotebookByAttachedKernel(viewType: string, uri: UriComponents, cellHandle: number | undefined): Promise<void> {
|
||||
let document = this._documents.get(URI.revive(uri).toString());
|
||||
|
||||
if (!document) {
|
||||
@@ -1112,17 +1255,46 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
const cell = cellHandle !== undefined ? document.getCell(cellHandle) : undefined;
|
||||
const provider = this._notebookContentProviders.get(viewType)!.provider;
|
||||
|
||||
if (provider.kernel && useAttachedKernel) {
|
||||
if (provider.kernel) {
|
||||
if (cell) {
|
||||
return provider.kernel.executeCell(document, cell, token);
|
||||
return withToken(token => (provider.kernel!.executeCell as any)(document, cell, token));
|
||||
} else {
|
||||
return provider.kernel.executeAllCells(document, token);
|
||||
return withToken(token => (provider.kernel!.executeAllCells as any)(document, token));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async $executeNotebook2(kernelId: string, viewType: string, uri: UriComponents, cellHandle: number | undefined, token: CancellationToken): Promise<void> {
|
||||
async $cancelNotebookByAttachedKernel(viewType: string, uri: UriComponents, cellHandle: number | undefined): Promise<void> {
|
||||
const document = this._documents.get(URI.revive(uri).toString());
|
||||
|
||||
if (!document) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._notebookContentProviders.has(viewType)) {
|
||||
const cell = cellHandle !== undefined ? document.getCell(cellHandle) : undefined;
|
||||
const provider = this._notebookContentProviders.get(viewType)!.provider;
|
||||
|
||||
if (provider.kernel) {
|
||||
if (cell) {
|
||||
return provider.kernel.cancelCellExecution(document, cell);
|
||||
} else {
|
||||
return provider.kernel.cancelAllCellsExecution(document);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async $executeNotebookKernelFromProvider(handle: number, uri: UriComponents, kernelId: string, cellHandle: number | undefined): Promise<void> {
|
||||
await this._withAdapter(handle, uri, async (adapter, document) => {
|
||||
let cell = cellHandle !== undefined ? document.getCell(cellHandle) : undefined;
|
||||
|
||||
return adapter.executeNotebook(kernelId, document, cell);
|
||||
});
|
||||
}
|
||||
|
||||
async $executeNotebook2(kernelId: string, viewType: string, uri: UriComponents, cellHandle: number | undefined): Promise<void> {
|
||||
let document = this._documents.get(URI.revive(uri).toString());
|
||||
|
||||
if (!document || document.viewType !== viewType) {
|
||||
@@ -1138,9 +1310,9 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
let cell = cellHandle !== undefined ? document.getCell(cellHandle) : undefined;
|
||||
|
||||
if (cell) {
|
||||
return kernelInfo.kernel.executeCell(document, cell, token);
|
||||
return withToken(token => (kernelInfo!.kernel.executeCell as any)(document, cell, token));
|
||||
} else {
|
||||
return kernelInfo.kernel.executeAllCells(document, token);
|
||||
return withToken(token => (kernelInfo!.kernel.executeAllCells as any)(document, token));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1209,6 +1381,20 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
this._outputDisplayOrder = displayOrder;
|
||||
}
|
||||
|
||||
$acceptNotebookActiveKernelChange(event: { uri: UriComponents, providerHandle: number | undefined, kernelId: string | undefined }) {
|
||||
if (event.providerHandle !== undefined) {
|
||||
this._withAdapter(event.providerHandle, event.uri, async (adapter, document) => {
|
||||
const kernel = event.kernelId ? adapter.getKernel(event.kernelId) : undefined;
|
||||
this._editors.forEach(editor => {
|
||||
if (editor.editor.document === document) {
|
||||
editor.editor.updateActiveKernel(kernel);
|
||||
}
|
||||
});
|
||||
this._onDidChangeActiveNotebookKernel.fire({ document, kernel });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: remove document - editor one on one mapping
|
||||
private _getEditorFromURI(uriComponents: UriComponents) {
|
||||
const uriStr = URI.revive(uriComponents).toString();
|
||||
@@ -1275,8 +1461,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
|
||||
revivedUri,
|
||||
this._proxy,
|
||||
webComm.contentProviderComm,
|
||||
document,
|
||||
this._documentsAndEditors
|
||||
document
|
||||
);
|
||||
|
||||
const cells = editor.document.cells;
|
||||
|
||||
@@ -13,6 +13,8 @@ import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { score } from 'vs/editor/common/modes/languageSelector';
|
||||
import { CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { ResourceMap } from 'vs/base/common/map';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
|
||||
export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextDocument {
|
||||
|
||||
@@ -28,6 +30,8 @@ export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextD
|
||||
private readonly _onDidChange = new Emitter<void>();
|
||||
readonly onDidChange: Event<void> = this._onDidChange.event;
|
||||
|
||||
readonly uri = URI.from({ scheme: 'vscode-concat-doc', path: generateUuid() });
|
||||
|
||||
constructor(
|
||||
extHostNotebooks: ExtHostNotebookController,
|
||||
extHostDocuments: ExtHostDocuments,
|
||||
|
||||
@@ -696,13 +696,11 @@ export class WorkerExtHostTask extends ExtHostTaskBase {
|
||||
@IExtHostApiDeprecationService deprecationService: IExtHostApiDeprecationService
|
||||
) {
|
||||
super(extHostRpc, initData, workspaceService, editorService, configurationService, extHostTerminalService, logService, deprecationService);
|
||||
if (initData.remote.isRemote && initData.remote.authority) {
|
||||
this.registerTaskSystem(Schemas.vscodeRemote, {
|
||||
scheme: Schemas.vscodeRemote,
|
||||
authority: initData.remote.authority,
|
||||
platform: Platform.PlatformToString(Platform.Platform.Web)
|
||||
});
|
||||
}
|
||||
this.registerTaskSystem(Schemas.vscodeRemote, {
|
||||
scheme: Schemas.vscodeRemote,
|
||||
authority: '',
|
||||
platform: Platform.PlatformToString(Platform.Platform.Web)
|
||||
});
|
||||
}
|
||||
|
||||
public async executeTask(extension: IExtensionDescription, task: vscode.Task): Promise<vscode.TaskExecution> {
|
||||
|
||||
@@ -2739,6 +2739,11 @@ export enum NotebookCellRunState {
|
||||
Error = 4
|
||||
}
|
||||
|
||||
export enum NotebookRunState {
|
||||
Running = 1,
|
||||
Idle = 2
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Timeline
|
||||
@@ -2774,13 +2779,6 @@ export enum ExtensionMode {
|
||||
|
||||
//#endregion ExtensionContext
|
||||
|
||||
|
||||
//#region Authentication
|
||||
export class AuthenticationSession implements vscode.AuthenticationSession {
|
||||
constructor(public id: string, public accessToken: string, public account: { label: string, id: string }, public scopes: string[]) { }
|
||||
}
|
||||
|
||||
//#endregion Authentication
|
||||
export enum StandardTokenType {
|
||||
Other = 0,
|
||||
Comment = 1,
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace schema {
|
||||
case 'menuBar/webNavigation': return MenuId.MenubarWebNavigationMenu;
|
||||
case 'scm/title': return MenuId.SCMTitle;
|
||||
case 'scm/sourceControl': return MenuId.SCMSourceControl;
|
||||
case 'scm/resourceState/context': return MenuId.SCMResourceContext;//
|
||||
case 'scm/resourceState/context': return MenuId.SCMResourceContext;
|
||||
case 'scm/resourceFolder/context': return MenuId.SCMResourceFolderContext;
|
||||
case 'scm/resourceGroup/context': return MenuId.SCMResourceGroupContext;
|
||||
case 'scm/change/title': return MenuId.SCMChangeContext;//
|
||||
|
||||
Reference in New Issue
Block a user