mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-01 01:25:38 -05:00
Merge from vscode 7eaf220cafb9d9e901370ffce02229171cbf3ea6
This commit is contained in:
committed by
Anthony Dresser
parent
39d9eed585
commit
a63578e6f7
@@ -54,7 +54,7 @@ import './mainThreadTreeViews';
|
||||
import './mainThreadDownloadService';
|
||||
import './mainThreadUrls';
|
||||
import './mainThreadWindow';
|
||||
import './mainThreadWebview';
|
||||
import './mainThreadWebviewManager';
|
||||
import './mainThreadWorkspace';
|
||||
import './mainThreadComments';
|
||||
import './mainThreadNotebook';
|
||||
|
||||
@@ -17,7 +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';
|
||||
import { ActivationKind, IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { Platform, platform } from 'vs/base/common/platform';
|
||||
|
||||
const VSO_ALLOWED_EXTENSIONS = ['github.vscode-pull-request-github', 'github.vscode-pull-request-github-insiders', 'vscode.git', 'ms-vsonline.vsonline', 'vscode.github-browser'];
|
||||
@@ -132,8 +132,12 @@ export class MainThreadAuthenticationProvider extends Disposable {
|
||||
}
|
||||
|
||||
private async registerCommandsAndContextMenuItems(): Promise<void> {
|
||||
const sessions = await this._proxy.$getSessions(this.id);
|
||||
sessions.forEach(session => this.registerSession(session));
|
||||
try {
|
||||
const sessions = await this._proxy.$getSessions(this.id);
|
||||
sessions.forEach(session => this.registerSession(session));
|
||||
} catch (_) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
private registerSession(session: modes.AuthenticationSession) {
|
||||
@@ -232,6 +236,12 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
|
||||
this._register(this.authenticationService.onDidUnregisterAuthenticationProvider(info => {
|
||||
this._proxy.$onDidChangeAuthenticationProviders([], [info]);
|
||||
}));
|
||||
|
||||
this._proxy.$setProviders(this.authenticationService.declaredProviders);
|
||||
|
||||
this._register(this.authenticationService.onDidChangeDeclaredProviders(e => {
|
||||
this._proxy.$setProviders(e);
|
||||
}));
|
||||
}
|
||||
|
||||
$getProviderIds(): Promise<string[]> {
|
||||
@@ -249,7 +259,7 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
|
||||
}
|
||||
|
||||
$ensureProvider(id: string): Promise<void> {
|
||||
return this.extensionService.activateByEvent(getAuthenticationProviderActivationEvent(id));
|
||||
return this.extensionService.activateByEvent(getAuthenticationProviderActivationEvent(id), ActivationKind.Immediate);
|
||||
}
|
||||
|
||||
$sendDidChangeSessions(id: string, event: modes.AuthenticationSessionsChangeEvent): void {
|
||||
|
||||
@@ -19,7 +19,8 @@ import { 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';
|
||||
import type { MainThreadWebviews } from 'vs/workbench/api/browser/mainThreadWebview';
|
||||
import { MainThreadWebviewPanels } from 'vs/workbench/api/browser/mainThreadWebviewPanels';
|
||||
import { MainThreadWebviews, reviveWebviewExtension } from 'vs/workbench/api/browser/mainThreadWebviews';
|
||||
import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { editorGroupToViewColumn } from 'vs/workbench/api/common/shared/editor';
|
||||
import { IRevertOptions, ISaveOptions } from 'vs/workbench/common/editor';
|
||||
@@ -28,27 +29,31 @@ import { CustomDocumentBackupData } from 'vs/workbench/contrib/customEditor/brow
|
||||
import { ICustomEditorModel, ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor';
|
||||
import { CustomTextEditorModel } from 'vs/workbench/contrib/customEditor/common/customTextEditorModel';
|
||||
import { WebviewExtensionDescription } from 'vs/workbench/contrib/webview/browser/webview';
|
||||
import { WebviewInput } from 'vs/workbench/contrib/webview/browser/webviewEditorInput';
|
||||
import { IWebviewWorkbenchService } from 'vs/workbench/contrib/webview/browser/webviewWorkbenchService';
|
||||
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
|
||||
import { IWorkingCopy, IWorkingCopyBackup, IWorkingCopyService, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopyService';
|
||||
|
||||
export const enum CustomEditorModelType {
|
||||
const enum CustomEditorModelType {
|
||||
Custom,
|
||||
Text,
|
||||
}
|
||||
|
||||
export class MainThreadCustomEditors extends Disposable {
|
||||
export class MainThreadCustomEditors extends Disposable implements extHostProtocol.MainThreadCustomEditorsShape {
|
||||
|
||||
private readonly _proxyCustomEditors: extHostProtocol.ExtHostCustomEditorsShape;
|
||||
|
||||
private readonly _editorProviders = new Map<string, IDisposable>();
|
||||
|
||||
constructor(
|
||||
private readonly mainThreadWebviews: MainThreadWebviews,
|
||||
context: extHostProtocol.IExtHostContext,
|
||||
private readonly mainThreadWebview: MainThreadWebviews,
|
||||
private readonly mainThreadWebviewPanels: MainThreadWebviewPanels,
|
||||
@IExtensionService extensionService: IExtensionService,
|
||||
@IWorkingCopyService workingCopyService: IWorkingCopyService,
|
||||
@IWorkingCopyFileService workingCopyFileService: IWorkingCopyFileService,
|
||||
@ICustomEditorService private readonly _customEditorService: ICustomEditorService,
|
||||
@@ -61,7 +66,7 @@ export class MainThreadCustomEditors extends Disposable {
|
||||
|
||||
this._proxyCustomEditors = context.getProxy(extHostProtocol.ExtHostContext.ExtHostCustomEditors);
|
||||
|
||||
workingCopyFileService.registerWorkingCopyProvider((editorResource) => {
|
||||
this._register(workingCopyFileService.registerWorkingCopyProvider((editorResource) => {
|
||||
const matchedWorkingCopies: IWorkingCopy[] = [];
|
||||
|
||||
for (const workingCopy of workingCopyService.workingCopies) {
|
||||
@@ -72,7 +77,18 @@ export class MainThreadCustomEditors extends Disposable {
|
||||
}
|
||||
}
|
||||
return matchedWorkingCopies;
|
||||
});
|
||||
}));
|
||||
|
||||
// This reviver's only job is to activate custom editor extensions.
|
||||
this._register(_webviewWorkbenchService.registerResolver({
|
||||
canResolve: (webview: WebviewInput) => {
|
||||
if (webview instanceof CustomEditorInput) {
|
||||
extensionService.activateByEvent(`onCustomEditor:${webview.viewType}`);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
resolveWebview: () => { throw new Error('not implemented'); }
|
||||
}));
|
||||
}
|
||||
|
||||
dispose() {
|
||||
@@ -85,7 +101,15 @@ export class MainThreadCustomEditors extends Disposable {
|
||||
this._editorProviders.clear();
|
||||
}
|
||||
|
||||
public registerEditorProvider(
|
||||
public $registerTextEditorProvider(extensionData: extHostProtocol.WebviewExtensionDescription, viewType: string, options: modes.IWebviewPanelOptions, capabilities: extHostProtocol.CustomTextEditorCapabilities): void {
|
||||
this.registerEditorProvider(CustomEditorModelType.Text, reviveWebviewExtension(extensionData), viewType, options, capabilities, true);
|
||||
}
|
||||
|
||||
public $registerCustomEditorProvider(extensionData: extHostProtocol.WebviewExtensionDescription, viewType: string, options: modes.IWebviewPanelOptions, supportsMultipleEditorsPerDocument: boolean): void {
|
||||
this.registerEditorProvider(CustomEditorModelType.Custom, reviveWebviewExtension(extensionData), viewType, options, {}, supportsMultipleEditorsPerDocument);
|
||||
}
|
||||
|
||||
private registerEditorProvider(
|
||||
modelType: CustomEditorModelType,
|
||||
extension: WebviewExtensionDescription,
|
||||
viewType: string,
|
||||
@@ -111,7 +135,7 @@ export class MainThreadCustomEditors extends Disposable {
|
||||
const handle = webviewInput.id;
|
||||
const resource = webviewInput.resource;
|
||||
|
||||
this.mainThreadWebviews.addWebviewInput(handle, webviewInput);
|
||||
this.mainThreadWebviewPanels.addWebviewInput(handle, webviewInput);
|
||||
webviewInput.webview.options = options;
|
||||
webviewInput.webview.extension = extension;
|
||||
|
||||
@@ -120,7 +144,7 @@ export class MainThreadCustomEditors extends Disposable {
|
||||
modelRef = await this.getOrCreateCustomEditorModel(modelType, resource, viewType, { backupId: webviewInput.backupId }, cancellation);
|
||||
} catch (error) {
|
||||
onUnexpectedError(error);
|
||||
webviewInput.webview.html = this.mainThreadWebviews.getWebviewResolvedFailedContent(viewType);
|
||||
webviewInput.webview.html = this.mainThreadWebview.getWebviewResolvedFailedContent(viewType);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -157,7 +181,7 @@ export class MainThreadCustomEditors extends Disposable {
|
||||
await this._proxyCustomEditors.$resolveWebviewEditor(resource, handle, viewType, webviewInput.getTitle(), editorGroupToViewColumn(this._editorGroupService, webviewInput.group || 0), webviewInput.webview.options, cancellation);
|
||||
} catch (error) {
|
||||
onUnexpectedError(error);
|
||||
webviewInput.webview.html = this.mainThreadWebviews.getWebviewResolvedFailedContent(viewType);
|
||||
webviewInput.webview.html = this.mainThreadWebview.getWebviewResolvedFailedContent(viewType);
|
||||
modelRef.dispose();
|
||||
return;
|
||||
}
|
||||
@@ -200,7 +224,7 @@ export class MainThreadCustomEditors extends Disposable {
|
||||
case CustomEditorModelType.Custom:
|
||||
{
|
||||
const model = MainThreadCustomEditorModel.create(this._instantiationService, this._proxyCustomEditors, viewType, resource, options, () => {
|
||||
return Array.from(this.mainThreadWebviews.webviewInputs)
|
||||
return Array.from(this.mainThreadWebviewPanels.webviewInputs)
|
||||
.filter(editor => editor instanceof CustomEditorInput && isEqual(editor.resource, resource)) as CustomEditorInput[];
|
||||
}, cancellation, this._backupService);
|
||||
return this._customEditorService.models.add(resource, viewType, model);
|
||||
@@ -333,7 +357,7 @@ class MainThreadCustomEditorModel extends Disposable implements ICustomEditorMod
|
||||
}
|
||||
|
||||
public get capabilities(): WorkingCopyCapabilities {
|
||||
return 0;
|
||||
return WorkingCopyCapabilities.None;
|
||||
}
|
||||
|
||||
public isDirty(): boolean {
|
||||
|
||||
@@ -8,7 +8,7 @@ import { disposed } from 'vs/base/common/errors';
|
||||
import { IDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { equals as objectEquals } from 'vs/base/common/objects';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
|
||||
import { IBulkEditService, ResourceEdit, ResourceFileEdit, ResourceTextEdit } from 'vs/editor/browser/services/bulkEditService';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { IRange } from 'vs/editor/common/core/range';
|
||||
import { ISelection } from 'vs/editor/common/core/selection';
|
||||
@@ -20,7 +20,7 @@ import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { MainThreadDocumentsAndEditors } from 'vs/workbench/api/browser/mainThreadDocumentsAndEditors';
|
||||
import { MainThreadTextEditor } from 'vs/workbench/api/browser/mainThreadEditor';
|
||||
import { ExtHostContext, ExtHostEditorsShape, IApplyEditsOptions, IExtHostContext, ITextDocumentShowOptions, ITextEditorConfigurationUpdate, ITextEditorPositionData, IUndoStopOptions, MainThreadTextEditorsShape, TextEditorRevealType, IWorkspaceEditDto, reviveWorkspaceEditDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostContext, ExtHostEditorsShape, IApplyEditsOptions, IExtHostContext, ITextDocumentShowOptions, ITextEditorConfigurationUpdate, ITextEditorPositionData, IUndoStopOptions, MainThreadTextEditorsShape, TextEditorRevealType, IWorkspaceEditDto, WorkspaceEditType } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { EditorViewColumn, editorGroupToViewColumn, viewColumnToEditorGroup } from 'vs/workbench/api/common/shared/editor';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
@@ -29,6 +29,26 @@ import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { openEditorWith } from 'vs/workbench/services/editor/common/editorOpenWith';
|
||||
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';
|
||||
|
||||
function reviveWorkspaceEditDto2(data: IWorkspaceEditDto | undefined): ResourceEdit[] {
|
||||
if (!data?.edits) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const result: ResourceEdit[] = [];
|
||||
for (let edit of revive<IWorkspaceEditDto>(data).edits) {
|
||||
if (edit._type === WorkspaceEditType.File) {
|
||||
result.push(new ResourceFileEdit(edit.oldUri, edit.newUri, edit.options, edit.metadata));
|
||||
} else if (edit._type === WorkspaceEditType.Text) {
|
||||
result.push(new ResourceTextEdit(edit.resource, edit.edit, edit.modelVersionId, edit.metadata));
|
||||
} else if (edit._type === WorkspaceEditType.Cell) {
|
||||
result.push(new ResourceNotebookCellEdit(edit.resource, edit.edit, edit.modelVersionId, edit.metadata));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export class MainThreadTextEditors implements MainThreadTextEditorsShape {
|
||||
|
||||
@@ -222,8 +242,8 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape {
|
||||
}
|
||||
|
||||
$tryApplyWorkspaceEdit(dto: IWorkspaceEditDto): Promise<boolean> {
|
||||
const { edits } = reviveWorkspaceEditDto(dto)!;
|
||||
return this._bulkEditService.apply({ edits }).then(() => true, _err => false);
|
||||
const edits = reviveWorkspaceEditDto2(dto);
|
||||
return this._bulkEditService.apply(edits).then(() => true, _err => false);
|
||||
}
|
||||
|
||||
$tryInsertSnippet(id: string, template: string, ranges: readonly IRange[], opts: IUndoStopOptions): Promise<boolean> {
|
||||
|
||||
@@ -127,10 +127,13 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
}
|
||||
|
||||
private static _reviveCodeActionDto(data: ReadonlyArray<ICodeActionDto>): modes.CodeAction[] {
|
||||
if (data) {
|
||||
let dataCast = data as unknown; // {{ SQL CARBON EDIT }}
|
||||
let returnval = dataCast as modes.CodeAction[]; // {{ SQL CARBON EDIT }}
|
||||
if (returnval) {
|
||||
data.forEach(code => reviveWorkspaceEditDto(code.edit));
|
||||
}
|
||||
return <modes.CodeAction[]>data;
|
||||
|
||||
return <modes.CodeAction[]>returnval; // {{ SQL CARBON EDIT }}
|
||||
}
|
||||
|
||||
private static _reviveLinkDTO(data: ILinkDto): modes.ILink {
|
||||
|
||||
@@ -4,61 +4,21 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
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 { NOTEBOOK_DISPLAY_ORDER, NotebookCellOutputsSplice, NotebookDocumentMetadata, NotebookCellMetadata, ICellEditOperation, ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, CellEditType, CellKind, INotebookKernelInfo, INotebookKernelInfoDto, IEditor, INotebookDocumentFilter, DisplayOrderKey } 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';
|
||||
import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
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 { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
|
||||
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { combinedDisposable, Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
|
||||
export class MainThreadNotebookDocument extends Disposable {
|
||||
private _textModel: NotebookTextModel;
|
||||
|
||||
get textModel() {
|
||||
return this._textModel;
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly _proxy: ExtHostNotebookShape,
|
||||
public handle: number,
|
||||
public viewType: string,
|
||||
public supportBackup: boolean,
|
||||
public uri: URI,
|
||||
@INotebookService readonly notebookService: INotebookService,
|
||||
@IUndoRedoService readonly undoRedoService: IUndoRedoService,
|
||||
@ITextModelService modelService: ITextModelService
|
||||
|
||||
) {
|
||||
super();
|
||||
|
||||
this._textModel = new NotebookTextModel(handle, viewType, supportBackup, uri, undoRedoService, modelService);
|
||||
this._register(this._textModel.onDidModelChangeProxy(e => {
|
||||
this._proxy.$acceptModelChanged(this.uri, e);
|
||||
this._proxy.$acceptEditorPropertiesChanged(uri, { selections: { selections: this._textModel.selections }, metadata: null });
|
||||
}));
|
||||
this._register(this._textModel.onDidSelectionChange(e => {
|
||||
const selectionsChange = e ? { selections: e } : null;
|
||||
this._proxy.$acceptEditorPropertiesChanged(uri, { selections: selectionsChange, metadata: null });
|
||||
}));
|
||||
}
|
||||
|
||||
dispose() {
|
||||
// this._textModel.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
|
||||
import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService';
|
||||
import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, CellEditType, CellKind, DisplayOrderKey, ICellEditOperation, ICellRange, IEditor, INotebookDocumentFilter, NotebookCellMetadata, NotebookCellOutputsSplice, NotebookDocumentMetadata, NOTEBOOK_DISPLAY_ORDER, TransientMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { IMainNotebookController, INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { ExtHostContext, ExtHostNotebookShape, IExtHostContext, INotebookCellStatusBarEntryDto, INotebookDocumentsAndEditorsDelta, MainContext, MainThreadNotebookShape, NotebookEditorRevealType, NotebookExtensionDescription } from '../common/extHost.protocol';
|
||||
|
||||
class DocumentAndEditorState {
|
||||
static ofSets<T>(before: Set<T>, after: Set<T>): { removed: T[], added: T[] } {
|
||||
@@ -98,7 +58,7 @@ class DocumentAndEditorState {
|
||||
const apiEditors = [];
|
||||
for (let id in after.textEditors) {
|
||||
const editor = after.textEditors.get(id)!;
|
||||
apiEditors.push({ id, documentUri: editor.uri!, selections: editor!.textModel!.selections });
|
||||
apiEditors.push({ id, documentUri: editor.uri!, selections: editor!.textModel!.selections, visibleRanges: editor.visibleRanges });
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -112,7 +72,8 @@ class DocumentAndEditorState {
|
||||
const addedAPIEditors = editorDelta.added.map(add => ({
|
||||
id: add.getId(),
|
||||
documentUri: add.uri!,
|
||||
selections: add.textModel!.selections || []
|
||||
selections: add.textModel!.selections || [],
|
||||
visibleRanges: add.visibleRanges
|
||||
}));
|
||||
|
||||
const removedAPIEditors = editorDelta.removed.map(removed => removed.getId());
|
||||
@@ -169,12 +130,13 @@ class DocumentAndEditorState {
|
||||
@extHostNamedCustomer(MainContext.MainThreadNotebook)
|
||||
export class MainThreadNotebooks extends Disposable implements MainThreadNotebookShape {
|
||||
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 _notebookKernelProviders = new Map<number, { extension: NotebookExtensionDescription, emitter: Emitter<URI | undefined>, provider: IDisposable }>();
|
||||
private readonly _proxy: ExtHostNotebookShape;
|
||||
private _toDisposeOnEditorRemove = new Map<string, IDisposable>();
|
||||
private _currentState?: DocumentAndEditorState;
|
||||
private _editorEventListenersMapping: Map<string, DisposableStore> = new Map();
|
||||
private _documentEventListenersMapping: Map<string, DisposableStore> = new Map();
|
||||
private readonly _cellStatusBarEntries: Map<number, IDisposable> = new Map();
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@@ -182,8 +144,8 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@IAccessibilityService private readonly accessibilityService: IAccessibilityService,
|
||||
@ILogService private readonly logService: ILogService
|
||||
|
||||
@ILogService private readonly logService: ILogService,
|
||||
@INotebookCellStatusBarService private readonly cellStatusBarService: INotebookCellStatusBarService
|
||||
) {
|
||||
super();
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostNotebook);
|
||||
@@ -194,7 +156,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
|
||||
const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
|
||||
if (textModel) {
|
||||
this._notebookService.transformEditsOutputs(textModel, edits);
|
||||
return textModel.$applyEdit(modelVersionId, edits, true);
|
||||
return textModel.applyEdit(modelVersionId, edits, true);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -203,9 +165,9 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
|
||||
async removeNotebookTextModel(uri: URI): Promise<void> {
|
||||
// TODO@rebornix, remove cell should use emitDelta as well to ensure document/editor events are sent together
|
||||
this._proxy.$acceptDocumentAndEditorsDelta({ removedDocuments: [uri] });
|
||||
let textModelDisposableStore = this._editorEventListenersMapping.get(uri.toString());
|
||||
let textModelDisposableStore = this._documentEventListenersMapping.get(uri.toString());
|
||||
textModelDisposableStore?.dispose();
|
||||
this._editorEventListenersMapping.delete(URI.from(uri).toString());
|
||||
this._documentEventListenersMapping.delete(URI.from(uri).toString());
|
||||
}
|
||||
|
||||
private _isDeltaEmpty(delta: INotebookDocumentsAndEditorsDelta) {
|
||||
@@ -265,38 +227,67 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
|
||||
}
|
||||
}));
|
||||
|
||||
const notebookEditorAddedHandler = (editor: IEditor) => {
|
||||
if (!this._editorEventListenersMapping.has(editor.getId())) {
|
||||
const disposableStore = new DisposableStore();
|
||||
disposableStore.add(editor.onDidChangeVisibleRanges(() => {
|
||||
this._proxy.$acceptEditorPropertiesChanged(editor.getId(), { visibleRanges: { ranges: editor.visibleRanges } });
|
||||
}));
|
||||
|
||||
this._editorEventListenersMapping.set(editor.getId(), disposableStore);
|
||||
}
|
||||
};
|
||||
|
||||
this._register(this._notebookService.onNotebookEditorAdd(editor => {
|
||||
notebookEditorAddedHandler(editor);
|
||||
this._addNotebookEditor(editor);
|
||||
}));
|
||||
|
||||
this._register(this._notebookService.onNotebookEditorsRemove(editors => {
|
||||
this._removeNotebookEditor(editors);
|
||||
|
||||
editors.forEach(editor => {
|
||||
this._editorEventListenersMapping.get(editor.getId())?.dispose();
|
||||
this._editorEventListenersMapping.delete(editor.getId());
|
||||
});
|
||||
}));
|
||||
|
||||
this._notebookService.listNotebookEditors().forEach(editor => {
|
||||
notebookEditorAddedHandler(editor);
|
||||
});
|
||||
|
||||
const notebookDocumentAddedHandler = (doc: URI) => {
|
||||
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, textModel!.isDirty);
|
||||
this._proxy.$acceptDocumentPropertiesChanged(doc, { selections: { selections: textModel!.selections }, metadata: null });
|
||||
}));
|
||||
disposableStore.add(textModel!.onDidSelectionChange(e => {
|
||||
const selectionsChange = e ? { selections: e } : null;
|
||||
this._proxy.$acceptDocumentPropertiesChanged(doc, { selections: selectionsChange, metadata: null });
|
||||
}));
|
||||
|
||||
this._editorEventListenersMapping.set(textModel!.uri.toString(), disposableStore);
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
notebookDocumentAddedHandler(doc);
|
||||
});
|
||||
this._updateState();
|
||||
}));
|
||||
|
||||
this._notebookService.listNotebookDocuments().forEach((doc) => {
|
||||
notebookDocumentAddedHandler(doc.uri);
|
||||
});
|
||||
|
||||
this._register(this._notebookService.onNotebookDocumentRemove((documents) => {
|
||||
documents.forEach(doc => {
|
||||
this._editorEventListenersMapping.get(doc.toString())?.dispose();
|
||||
this._editorEventListenersMapping.delete(doc.toString());
|
||||
this._documentEventListenersMapping.get(doc.toString())?.dispose();
|
||||
this._documentEventListenersMapping.delete(doc.toString());
|
||||
});
|
||||
|
||||
this._updateState();
|
||||
@@ -413,28 +404,28 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
|
||||
// }
|
||||
}
|
||||
|
||||
async $registerNotebookProvider(_extension: NotebookExtensionDescription, _viewType: string, _supportBackup: boolean, _kernel: INotebookKernelInfoDto | undefined): Promise<void> {
|
||||
async $registerNotebookProvider(_extension: NotebookExtensionDescription, _viewType: string, _supportBackup: boolean, options: { transientOutputs: boolean; transientMetadata: TransientMetadata }): Promise<void> {
|
||||
const controller: IMainNotebookController = {
|
||||
kernel: _kernel,
|
||||
supportBackup: _supportBackup,
|
||||
options: options,
|
||||
reloadNotebook: async (mainthreadTextModel: NotebookTextModel) => {
|
||||
const data = await this._proxy.$resolveNotebookData(_viewType, mainthreadTextModel.uri);
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
mainthreadTextModel.languages = data.languages;
|
||||
mainthreadTextModel.updateLanguages(data.languages);
|
||||
mainthreadTextModel.metadata = data.metadata;
|
||||
mainthreadTextModel.transientOptions = options;
|
||||
|
||||
const edits: ICellEditOperation[] = [
|
||||
{ editType: CellEditType.Delete, count: mainthreadTextModel.cells.length, index: 0 },
|
||||
{ editType: CellEditType.Insert, index: 0, cells: data.cells }
|
||||
{ editType: CellEditType.Replace, index: 0, count: mainthreadTextModel.cells.length, cells: data.cells }
|
||||
];
|
||||
|
||||
this._notebookService.transformEditsOutputs(mainthreadTextModel, edits);
|
||||
await new Promise(resolve => {
|
||||
DOM.scheduleAtNextAnimationFrame(() => {
|
||||
const ret = mainthreadTextModel!.$applyEdit(mainthreadTextModel!.versionId, edits, true);
|
||||
const ret = mainthreadTextModel!.applyEdit(mainthreadTextModel!.versionId, edits, true);
|
||||
resolve(ret);
|
||||
});
|
||||
});
|
||||
@@ -446,40 +437,29 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
|
||||
return;
|
||||
}
|
||||
|
||||
textModel.languages = data.languages;
|
||||
textModel.updateLanguages(data.languages);
|
||||
textModel.metadata = data.metadata;
|
||||
textModel.transientOptions = options;
|
||||
|
||||
if (data.cells.length) {
|
||||
textModel.initialize(data!.cells);
|
||||
} else {
|
||||
const mainCell = textModel.createCellTextModel([''], textModel.languages.length ? textModel.languages[0] : '', CellKind.Code, [], undefined);
|
||||
const mainCell = textModel.createCellTextModel('', textModel.resolvedLanguages.length ? textModel.resolvedLanguages[0] : '', CellKind.Code, [], undefined);
|
||||
textModel.insertTemplateCell(mainCell);
|
||||
}
|
||||
|
||||
this._proxy.$acceptEditorPropertiesChanged(textModel.uri, { selections: null, metadata: textModel.metadata });
|
||||
this._proxy.$acceptDocumentPropertiesChanged(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, undefined);
|
||||
},
|
||||
cancelNotebookByAttachedKernel: async (viewType: string, uri: URI) => {
|
||||
return this.cancelNotebookByAttachedKernel(viewType, uri, undefined);
|
||||
},
|
||||
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.executeNotebookByAttachedKernel(_viewType, uri, handle);
|
||||
},
|
||||
cancelNotebookCell: async (uri: URI, handle: number) => {
|
||||
return this.cancelNotebookByAttachedKernel(_viewType, uri, handle);
|
||||
},
|
||||
save: async (uri: URI, token: CancellationToken) => {
|
||||
return this._proxy.$saveNotebook(_viewType, uri, token);
|
||||
},
|
||||
@@ -507,21 +487,8 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
|
||||
return;
|
||||
}
|
||||
|
||||
async $registerNotebookKernel(extension: NotebookExtensionDescription, id: string, label: string, selectors: (string | IRelativePattern)[], preloads: UriComponents[]): Promise<void> {
|
||||
const kernel = new MainThreadNotebookKernel(this._proxy, id, label, selectors, extension.id, URI.revive(extension.location), preloads.map(preload => URI.revive(preload)), this.logService);
|
||||
this._notebookKernels.set(id, kernel);
|
||||
this._notebookService.registerNotebookKernel(kernel);
|
||||
return;
|
||||
}
|
||||
|
||||
async $unregisterNotebookKernel(id: string): Promise<void> {
|
||||
this._notebookKernels.delete(id);
|
||||
this._notebookService.unregisterNotebookKernel(id);
|
||||
return;
|
||||
}
|
||||
|
||||
async $registerNotebookKernelProvider(extension: NotebookExtensionDescription, handle: number, documentFilter: INotebookDocumentFilter): Promise<void> {
|
||||
const emitter = new Emitter<void>();
|
||||
const emitter = new Emitter<URI | undefined>();
|
||||
const that = this;
|
||||
const provider = this._notebookService.registerNotebookKernelProvider({
|
||||
providerExtensionId: extension.id.value,
|
||||
@@ -568,10 +535,10 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
|
||||
}
|
||||
}
|
||||
|
||||
$onNotebookKernelChange(handle: number): void {
|
||||
$onNotebookKernelChange(handle: number, uriComponents: UriComponents): void {
|
||||
const entry = this._notebookKernelProviders.get(handle);
|
||||
|
||||
entry?.emitter.fire();
|
||||
entry?.emitter.fire(uriComponents ? URI.revive(uriComponents) : undefined);
|
||||
}
|
||||
|
||||
async $updateNotebookLanguages(viewType: string, resource: UriComponents, languages: string[]): Promise<void> {
|
||||
@@ -589,7 +556,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
|
||||
async $updateNotebookCellMetadata(viewType: string, resource: UriComponents, handle: number, metadata: NotebookCellMetadata): Promise<void> {
|
||||
this.logService.debug('MainThreadNotebooks#updateNotebookCellMetadata', resource.path, handle, metadata);
|
||||
const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
|
||||
textModel?.updateNotebookCellMetadata(handle, metadata);
|
||||
textModel?.changeCellMetadata(handle, metadata, true);
|
||||
}
|
||||
|
||||
async $spliceNotebookCellOutputs(viewType: string, resource: UriComponents, cellHandle: number, splices: NotebookCellOutputsSplice[]): Promise<void> {
|
||||
@@ -598,20 +565,10 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
|
||||
|
||||
if (textModel) {
|
||||
this._notebookService.transformSpliceOutputs(textModel, splices);
|
||||
textModel.$spliceNotebookCellOutputs(cellHandle, splices);
|
||||
textModel.spliceNotebookCellOutputs(cellHandle, splices);
|
||||
}
|
||||
}
|
||||
|
||||
async executeNotebookByAttachedKernel(viewType: string, uri: URI, handle: number | undefined): Promise<void> {
|
||||
this.logService.debug('MainthreadNotebooks#executeNotebookByAttachedKernel', uri.path, handle);
|
||||
return this._proxy.$executeNotebookByAttachedKernel(viewType, uri, handle);
|
||||
}
|
||||
|
||||
async cancelNotebookByAttachedKernel(viewType: string, uri: URI, handle: number | undefined): Promise<void> {
|
||||
this.logService.debug('MainthreadNotebooks#cancelNotebookByAttachedKernel', uri.path, handle);
|
||||
return this._proxy.$cancelNotebookByAttachedKernel(viewType, uri, handle);
|
||||
}
|
||||
|
||||
async $postMessage(editorId: string, forRendererId: string | undefined, value: any): Promise<boolean> {
|
||||
const editor = this._notebookService.getNotebookEditor(editorId) as INotebookEditor | undefined;
|
||||
if (editor?.isNotebookEditor) {
|
||||
@@ -626,7 +583,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
|
||||
const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
|
||||
|
||||
if (textModel) {
|
||||
textModel.$handleEdit(label, () => {
|
||||
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);
|
||||
@@ -638,23 +595,49 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
|
||||
const textModel = this._notebookService.getNotebookTextModel(URI.from(resource));
|
||||
textModel?.handleUnknownChange();
|
||||
}
|
||||
}
|
||||
|
||||
export class MainThreadNotebookKernel implements INotebookKernelInfo {
|
||||
constructor(
|
||||
private readonly _proxy: ExtHostNotebookShape,
|
||||
readonly id: string,
|
||||
readonly label: string,
|
||||
readonly selectors: (string | IRelativePattern)[],
|
||||
readonly extension: ExtensionIdentifier,
|
||||
readonly extensionLocation: URI,
|
||||
readonly preloads: URI[],
|
||||
readonly logService: ILogService
|
||||
) {
|
||||
async $tryRevealRange(id: string, range: ICellRange, revealType: NotebookEditorRevealType) {
|
||||
const editor = this._notebookService.listNotebookEditors().find(editor => editor.getId() === id);
|
||||
if (editor && editor.isNotebookEditor) {
|
||||
const notebookEditor = editor as INotebookEditor;
|
||||
const viewModel = notebookEditor.viewModel;
|
||||
const cell = viewModel?.viewCells[range.start];
|
||||
if (!cell) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (revealType) {
|
||||
case NotebookEditorRevealType.Default:
|
||||
notebookEditor.revealInView(cell);
|
||||
break;
|
||||
case NotebookEditorRevealType.InCenter:
|
||||
notebookEditor.revealInCenter(cell);
|
||||
break;
|
||||
case NotebookEditorRevealType.InCenterIfOutsideViewport:
|
||||
notebookEditor.revealInCenterIfOutsideViewport(cell);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async executeNotebook(viewType: string, uri: URI, handle: number | undefined): Promise<void> {
|
||||
this.logService.debug('MainThreadNotebookKernel#executeNotebook', uri.path, handle);
|
||||
return this._proxy.$executeNotebook2(this.id, viewType, uri, handle);
|
||||
async $setStatusBarEntry(id: number, rawStatusBarEntry: INotebookCellStatusBarEntryDto): Promise<void> {
|
||||
const statusBarEntry = {
|
||||
...rawStatusBarEntry,
|
||||
...{ cellResource: URI.revive(rawStatusBarEntry.cellResource) }
|
||||
};
|
||||
|
||||
const existingEntry = this._cellStatusBarEntries.get(id);
|
||||
if (existingEntry) {
|
||||
existingEntry.dispose();
|
||||
}
|
||||
|
||||
if (statusBarEntry.visible) {
|
||||
this._cellStatusBarEntries.set(
|
||||
id,
|
||||
this.cellStatusBarService.addEntry(statusBarEntry));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -178,6 +178,10 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
||||
this._linkProvider = undefined;
|
||||
}
|
||||
|
||||
public $registerProcessSupport(isSupported: boolean): void {
|
||||
this._terminalService.registerProcessSupport(isSupported);
|
||||
}
|
||||
|
||||
private _onActiveTerminalChanged(terminalId: number | null): void {
|
||||
this._proxy.$acceptActiveTerminalChanged(terminalId);
|
||||
}
|
||||
|
||||
35
src/vs/workbench/api/browser/mainThreadWebviewManager.ts
Normal file
35
src/vs/workbench/api/browser/mainThreadWebviewManager.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { MainThreadCustomEditors } from 'vs/workbench/api/browser/mainThreadCustomEditors';
|
||||
import { MainThreadWebviewPanels } from 'vs/workbench/api/browser/mainThreadWebviewPanels';
|
||||
import { MainThreadWebviews } from 'vs/workbench/api/browser/mainThreadWebviews';
|
||||
import { MainThreadWebviewsViews } from 'vs/workbench/api/browser/mainThreadWebviewViews';
|
||||
import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { extHostCustomer } from '../common/extHostCustomers';
|
||||
|
||||
@extHostCustomer
|
||||
export class MainThreadWebviewManager extends Disposable {
|
||||
constructor(
|
||||
context: extHostProtocol.IExtHostContext,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
) {
|
||||
super();
|
||||
|
||||
const webviews = this._register(instantiationService.createInstance(MainThreadWebviews, context));
|
||||
context.set(extHostProtocol.MainContext.MainThreadWebviews, webviews);
|
||||
|
||||
const webviewPanels = this._register(instantiationService.createInstance(MainThreadWebviewPanels, context, webviews));
|
||||
context.set(extHostProtocol.MainContext.MainThreadWebviewPanels, webviewPanels);
|
||||
|
||||
const customEditors = this._register(instantiationService.createInstance(MainThreadCustomEditors, context, webviews, webviewPanels));
|
||||
context.set(extHostProtocol.MainContext.MainThreadCustomEditors, customEditors);
|
||||
|
||||
const webviewViews = this._register(instantiationService.createInstance(MainThreadWebviewsViews, context, webviews));
|
||||
context.set(extHostProtocol.MainContext.MainThreadWebviewViews, webviewViews);
|
||||
}
|
||||
}
|
||||
@@ -3,31 +3,21 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { Disposable, DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { isWeb } from 'vs/base/common/platform';
|
||||
import { escape } from 'vs/base/common/strings';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { localize } from 'vs/nls';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { CustomEditorModelType, MainThreadCustomEditors } from 'vs/workbench/api/browser/mainThreadCustomEditors';
|
||||
import { MainThreadWebviewSerializers } from 'vs/workbench/api/browser/mainThreadWebviewSerializer';
|
||||
import { MainThreadWebviewsViews } from 'vs/workbench/api/browser/mainThreadWebviewViews';
|
||||
import { MainThreadWebviews, reviveWebviewExtension, reviveWebviewOptions } from 'vs/workbench/api/browser/mainThreadWebviews';
|
||||
import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { editorGroupToViewColumn, EditorViewColumn, viewColumnToEditorGroup } from 'vs/workbench/api/common/shared/editor';
|
||||
import { IEditorInput } from 'vs/workbench/common/editor';
|
||||
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
|
||||
import { Webview, WebviewExtensionDescription, WebviewIcons, WebviewOverlay } from 'vs/workbench/contrib/webview/browser/webview';
|
||||
import { WebviewIcons } from 'vs/workbench/contrib/webview/browser/webview';
|
||||
import { WebviewInput } from 'vs/workbench/contrib/webview/browser/webviewEditorInput';
|
||||
import { ICreateWebViewShowOptions, IWebviewWorkbenchService, WebviewInputOptions } from 'vs/workbench/contrib/webview/browser/webviewWorkbenchService';
|
||||
import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { extHostNamedCustomer } from '../common/extHostCustomers';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
|
||||
/**
|
||||
* Bi-directional map between webview handles and inputs.
|
||||
@@ -82,48 +72,31 @@ class WebviewViewTypeTransformer {
|
||||
}
|
||||
}
|
||||
|
||||
@extHostNamedCustomer(extHostProtocol.MainContext.MainThreadWebviews)
|
||||
export class MainThreadWebviews extends Disposable implements extHostProtocol.MainThreadWebviewsShape {
|
||||
export class MainThreadWebviewPanels extends Disposable implements extHostProtocol.MainThreadWebviewPanelsShape {
|
||||
|
||||
private static readonly standardSupportedLinkSchemes = new Set([
|
||||
Schemas.http,
|
||||
Schemas.https,
|
||||
Schemas.mailto,
|
||||
Schemas.vscode,
|
||||
'vscode-insider',
|
||||
]);
|
||||
private readonly webviewPanelViewType = new WebviewViewTypeTransformer('mainThreadWebview-');
|
||||
|
||||
public readonly webviewPanelViewType = new WebviewViewTypeTransformer('mainThreadWebview-');
|
||||
private readonly _proxy: extHostProtocol.ExtHostWebviewPanelsShape;
|
||||
|
||||
private readonly _proxy: extHostProtocol.ExtHostWebviewsShape;
|
||||
|
||||
private readonly _webviews = new Map<string, Webview>();
|
||||
private readonly _webviewInputs = new WebviewInputStore();
|
||||
|
||||
private readonly _editorProviders = new Map<string, IDisposable>();
|
||||
private readonly _webviewFromDiffEditorHandles = new Set<string>();
|
||||
|
||||
private readonly serializers: MainThreadWebviewSerializers;
|
||||
private readonly customEditors: MainThreadCustomEditors;
|
||||
private readonly webviewViews: MainThreadWebviewsViews;
|
||||
private readonly _revivers = new Map<string, IDisposable>();
|
||||
|
||||
constructor(
|
||||
context: extHostProtocol.IExtHostContext,
|
||||
private readonly _mainThreadWebviews: MainThreadWebviews,
|
||||
@IExtensionService extensionService: IExtensionService,
|
||||
@IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService,
|
||||
@IEditorService private readonly _editorService: IEditorService,
|
||||
@IOpenerService private readonly _openerService: IOpenerService,
|
||||
@IProductService private readonly _productService: IProductService,
|
||||
@ITelemetryService private readonly _telemetryService: ITelemetryService,
|
||||
@IWebviewWorkbenchService private readonly _webviewWorkbenchService: IWebviewWorkbenchService,
|
||||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
) {
|
||||
super();
|
||||
|
||||
this._proxy = context.getProxy(extHostProtocol.ExtHostContext.ExtHostWebviews);
|
||||
|
||||
this.serializers = this._instantiationService.createInstance(MainThreadWebviewSerializers, this, context);
|
||||
this.customEditors = this._instantiationService.createInstance(MainThreadCustomEditors, this, context);
|
||||
this.webviewViews = this._instantiationService.createInstance(MainThreadWebviewsViews, this, context);
|
||||
this._proxy = context.getProxy(extHostProtocol.ExtHostContext.ExtHostWebviewPanels);
|
||||
|
||||
this._register(_editorService.onDidActiveEditorChange(() => {
|
||||
const activeInput = this._editorService.activeEditor;
|
||||
@@ -137,6 +110,19 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
this._register(_editorService.onDidVisibleEditorsChange(() => {
|
||||
this.updateWebviewViewStates(this._editorService.activeEditor);
|
||||
}));
|
||||
|
||||
// This reviver's only job is to activate extensions.
|
||||
// This should trigger the real reviver to be registered from the extension host side.
|
||||
this._register(_webviewWorkbenchService.registerResolver({
|
||||
canResolve: (webview: WebviewInput) => {
|
||||
const viewType = this.webviewPanelViewType.toExternal(webview.viewType);
|
||||
if (typeof viewType === 'string') {
|
||||
extensionService.activateByEvent(`onWebviewPanel:${viewType}`);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
resolveWebview: () => { throw new Error('not implemented'); }
|
||||
}));
|
||||
}
|
||||
|
||||
dispose() {
|
||||
@@ -150,19 +136,20 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
|
||||
public get webviewInputs(): Iterable<WebviewInput> { return this._webviewInputs; }
|
||||
|
||||
public addWebviewInput(handle: extHostProtocol.WebviewPanelHandle, input: WebviewInput): void {
|
||||
public addWebviewInput(handle: extHostProtocol.WebviewHandle, input: WebviewInput): void {
|
||||
this._webviewInputs.add(handle, input);
|
||||
this.addWebview(handle, input.webview);
|
||||
}
|
||||
this._mainThreadWebviews.addWebview(handle, input.webview);
|
||||
|
||||
public addWebview(handle: extHostProtocol.WebviewPanelHandle, webview: WebviewOverlay): void {
|
||||
this._webviews.set(handle, webview);
|
||||
this.hookupWebviewEventDelegate(handle, webview);
|
||||
input.webview.onDispose(() => {
|
||||
this._proxy.$onDidDisposeWebviewPanel(handle).finally(() => {
|
||||
this._webviewInputs.delete(handle);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public $createWebviewPanel(
|
||||
extensionData: extHostProtocol.WebviewExtensionDescription,
|
||||
handle: extHostProtocol.WebviewPanelHandle,
|
||||
handle: extHostProtocol.WebviewHandle,
|
||||
viewType: string,
|
||||
title: string,
|
||||
showOptions: { viewColumn?: EditorViewColumn, preserveFocus?: boolean; },
|
||||
@@ -175,10 +162,9 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
}
|
||||
|
||||
const extension = reviveWebviewExtension(extensionData);
|
||||
const webview = this._webviewWorkbenchService.createWebview(handle, this.webviewPanelViewType.fromExternal(viewType), title, mainThreadShowOptions, reviveWebviewOptions(options), extension);
|
||||
this.hookupWebviewEventDelegate(handle, webview.webview);
|
||||
|
||||
this._webviewInputs.add(handle, webview);
|
||||
const webview = this._webviewWorkbenchService.createWebview(handle, this.webviewPanelViewType.fromExternal(viewType), title, mainThreadShowOptions, reviveWebviewOptions(options), extension);
|
||||
this.addWebviewInput(handle, webview);
|
||||
|
||||
/* __GDPR__
|
||||
"webviews:createWebviewPanel" : {
|
||||
@@ -188,36 +174,23 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
this._telemetryService.publicLog('webviews:createWebviewPanel', { extensionId: extension.id.value });
|
||||
}
|
||||
|
||||
public $disposeWebview(handle: extHostProtocol.WebviewPanelHandle): void {
|
||||
public $disposeWebview(handle: extHostProtocol.WebviewHandle): void {
|
||||
const webview = this.getWebviewInput(handle);
|
||||
webview.dispose();
|
||||
}
|
||||
|
||||
public $setTitle(handle: extHostProtocol.WebviewPanelHandle, value: string): void {
|
||||
public $setTitle(handle: extHostProtocol.WebviewHandle, value: string): void {
|
||||
const webview = this.getWebviewInput(handle);
|
||||
webview.setName(value);
|
||||
}
|
||||
|
||||
public $setWebviewViewTitle(handle: extHostProtocol.WebviewPanelHandle, value: string | undefined): void {
|
||||
this.webviewViews.$setWebviewViewTitle(handle, value);
|
||||
}
|
||||
|
||||
public $setIconPath(handle: extHostProtocol.WebviewPanelHandle, value: { light: UriComponents, dark: UriComponents; } | undefined): void {
|
||||
public $setIconPath(handle: extHostProtocol.WebviewHandle, value: { light: UriComponents, dark: UriComponents; } | undefined): void {
|
||||
const webview = this.getWebviewInput(handle);
|
||||
webview.iconPath = reviveWebviewIcon(value);
|
||||
}
|
||||
|
||||
public $setHtml(handle: extHostProtocol.WebviewPanelHandle, value: string): void {
|
||||
const webview = this.getWebview(handle);
|
||||
webview.html = value;
|
||||
}
|
||||
|
||||
public $setOptions(handle: extHostProtocol.WebviewPanelHandle, options: modes.IWebviewOptions): void {
|
||||
const webview = this.getWebview(handle);
|
||||
webview.contentOptions = reviveWebviewOptions(options);
|
||||
}
|
||||
|
||||
public $reveal(handle: extHostProtocol.WebviewPanelHandle, showOptions: extHostProtocol.WebviewPanelShowOptions): void {
|
||||
public $reveal(handle: extHostProtocol.WebviewHandle, showOptions: extHostProtocol.WebviewPanelShowOptions): void {
|
||||
const webview = this.getWebviewInput(handle);
|
||||
if (webview.isDisposed()) {
|
||||
return;
|
||||
@@ -229,63 +202,55 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
}
|
||||
}
|
||||
|
||||
public async $postMessage(handle: extHostProtocol.WebviewPanelHandle, message: any): Promise<boolean> {
|
||||
const webview = this.getWebview(handle);
|
||||
webview.postMessage(message);
|
||||
return true;
|
||||
}
|
||||
public $registerSerializer(viewType: string)
|
||||
: void {
|
||||
if (this._revivers.has(viewType)) {
|
||||
throw new Error(`Reviver for ${viewType} already registered`);
|
||||
}
|
||||
|
||||
public $registerSerializer(viewType: string): void {
|
||||
this.serializers.$registerSerializer(viewType);
|
||||
this._revivers.set(viewType, this._webviewWorkbenchService.registerResolver({
|
||||
canResolve: (webviewInput) => {
|
||||
return webviewInput.viewType === this.webviewPanelViewType.fromExternal(viewType);
|
||||
},
|
||||
resolveWebview: async (webviewInput): Promise<void> => {
|
||||
const viewType = this.webviewPanelViewType.toExternal(webviewInput.viewType);
|
||||
if (!viewType) {
|
||||
webviewInput.webview.html = this._mainThreadWebviews.getWebviewResolvedFailedContent(webviewInput.viewType);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const handle = webviewInput.id;
|
||||
|
||||
this.addWebviewInput(handle, webviewInput);
|
||||
|
||||
let state = undefined;
|
||||
if (webviewInput.webview.state) {
|
||||
try {
|
||||
state = JSON.parse(webviewInput.webview.state);
|
||||
} catch (e) {
|
||||
console.error('Could not load webview state', e, webviewInput.webview.state);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await this._proxy.$deserializeWebviewPanel(handle, viewType, webviewInput.getTitle(), state, editorGroupToViewColumn(this._editorGroupService, webviewInput.group || 0), webviewInput.webview.options);
|
||||
} catch (error) {
|
||||
onUnexpectedError(error);
|
||||
webviewInput.webview.html = this._mainThreadWebviews.getWebviewResolvedFailedContent(viewType);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public $unregisterSerializer(viewType: string): void {
|
||||
this.serializers.$unregisterSerializer(viewType);
|
||||
}
|
||||
const reviver = this._revivers.get(viewType);
|
||||
if (!reviver) {
|
||||
throw new Error(`No reviver for ${viewType} registered`);
|
||||
}
|
||||
|
||||
public $registerWebviewViewProvider(viewType: string, options?: { retainContextWhenHidden?: boolean }): void {
|
||||
this.webviewViews.$registerWebviewViewProvider(viewType, options);
|
||||
}
|
||||
|
||||
public $unregisterWebviewViewProvider(viewType: string): void {
|
||||
this.webviewViews.$unregisterWebviewViewProvider(viewType);
|
||||
}
|
||||
|
||||
public $registerTextEditorProvider(extensionData: extHostProtocol.WebviewExtensionDescription, viewType: string, options: modes.IWebviewPanelOptions, capabilities: extHostProtocol.CustomTextEditorCapabilities): void {
|
||||
this.customEditors.registerEditorProvider(CustomEditorModelType.Text, reviveWebviewExtension(extensionData), viewType, options, capabilities, true);
|
||||
}
|
||||
|
||||
public $registerCustomEditorProvider(extensionData: extHostProtocol.WebviewExtensionDescription, viewType: string, options: modes.IWebviewPanelOptions, supportsMultipleEditorsPerDocument: boolean): void {
|
||||
this.customEditors.registerEditorProvider(CustomEditorModelType.Custom, reviveWebviewExtension(extensionData), viewType, options, {}, supportsMultipleEditorsPerDocument);
|
||||
}
|
||||
|
||||
public $unregisterEditorProvider(viewType: string): void {
|
||||
this.customEditors.$unregisterEditorProvider(viewType);
|
||||
}
|
||||
|
||||
public async $onDidEdit(resourceComponents: UriComponents, viewType: string, editId: number, label: string | undefined): Promise<void> {
|
||||
this.customEditors.$onDidEdit(resourceComponents, viewType, editId, label);
|
||||
}
|
||||
|
||||
public async $onContentChange(resourceComponents: UriComponents, viewType: string): Promise<void> {
|
||||
this.customEditors.$onContentChange(resourceComponents, viewType);
|
||||
}
|
||||
|
||||
public hookupWebviewEventDelegate(handle: extHostProtocol.WebviewPanelHandle, webview: WebviewOverlay) {
|
||||
const disposables = new DisposableStore();
|
||||
|
||||
disposables.add(webview.onDidClickLink((uri) => this.onDidClickLink(handle, uri)));
|
||||
disposables.add(webview.onMessage((message: any) => { this._proxy.$onMessage(handle, message); }));
|
||||
disposables.add(webview.onMissingCsp((extension: ExtensionIdentifier) => this._proxy.$onMissingCsp(handle, extension.value)));
|
||||
|
||||
disposables.add(webview.onDispose(() => {
|
||||
disposables.dispose();
|
||||
|
||||
this._proxy.$onDidDisposeWebviewPanel(handle).finally(() => {
|
||||
this._webviews.delete(handle);
|
||||
this._webviewInputs.delete(handle);
|
||||
});
|
||||
}));
|
||||
reviver.dispose();
|
||||
this._revivers.delete(viewType);
|
||||
}
|
||||
|
||||
private registerWebviewFromDiffEditorListeners(diffEditorInput: DiffEditorInput): void {
|
||||
@@ -349,32 +314,7 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
}
|
||||
}
|
||||
|
||||
private onDidClickLink(handle: extHostProtocol.WebviewPanelHandle, link: string): void {
|
||||
const webview = this.getWebviewInput(handle);
|
||||
if (this.isSupportedLink(webview, URI.parse(link))) {
|
||||
this._openerService.open(link, { fromUserGesture: true });
|
||||
}
|
||||
}
|
||||
|
||||
private isSupportedLink(webview: WebviewInput, link: URI): boolean {
|
||||
if (MainThreadWebviews.standardSupportedLinkSchemes.has(link.scheme)) {
|
||||
return true;
|
||||
}
|
||||
if (!isWeb && this._productService.urlProtocol === link.scheme) {
|
||||
return true;
|
||||
}
|
||||
return !!webview.webview.contentOptions.enableCommandUris && link.scheme === Schemas.command;
|
||||
}
|
||||
|
||||
private getWebview(handle: extHostProtocol.WebviewPanelHandle): Webview {
|
||||
const webview = this._webviews.get(handle);
|
||||
if (!webview) {
|
||||
throw new Error(`Unknown webview handle:${handle}`);
|
||||
}
|
||||
return webview;
|
||||
}
|
||||
|
||||
private getWebviewInput(handle: extHostProtocol.WebviewPanelHandle): WebviewInput {
|
||||
private getWebviewInput(handle: extHostProtocol.WebviewHandle): WebviewInput {
|
||||
const webview = this.tryGetWebviewInput(handle);
|
||||
if (!webview) {
|
||||
throw new Error(`Unknown webview handle:${handle}`);
|
||||
@@ -382,33 +322,11 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
|
||||
return webview;
|
||||
}
|
||||
|
||||
private tryGetWebviewInput(handle: extHostProtocol.WebviewPanelHandle): WebviewInput | undefined {
|
||||
private tryGetWebviewInput(handle: extHostProtocol.WebviewHandle): WebviewInput | undefined {
|
||||
return this._webviewInputs.getInputForHandle(handle);
|
||||
}
|
||||
|
||||
public getWebviewResolvedFailedContent(viewType: string) {
|
||||
return `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none';">
|
||||
</head>
|
||||
<body>${localize('errorMessage', "An error occurred while loading view: {0}", escape(viewType))}</body>
|
||||
</html>`;
|
||||
}
|
||||
}
|
||||
|
||||
function reviveWebviewExtension(extensionData: extHostProtocol.WebviewExtensionDescription): WebviewExtensionDescription {
|
||||
return { id: extensionData.id, location: URI.revive(extensionData.location) };
|
||||
}
|
||||
|
||||
function reviveWebviewOptions(options: modes.IWebviewOptions): WebviewInputOptions {
|
||||
return {
|
||||
...options,
|
||||
allowScripts: options.enableScripts,
|
||||
localResourceRoots: Array.isArray(options.localResourceRoots) ? options.localResourceRoots.map(r => URI.revive(r)) : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
function reviveWebviewIcon(
|
||||
value: { light: UriComponents, dark: UriComponents; } | undefined
|
||||
@@ -1,102 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import type { MainThreadWebviews } from 'vs/workbench/api/browser/mainThreadWebview';
|
||||
import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { editorGroupToViewColumn } from 'vs/workbench/api/common/shared/editor';
|
||||
import { CustomEditorInput } from 'vs/workbench/contrib/customEditor/browser/customEditorInput';
|
||||
import { WebviewInput } from 'vs/workbench/contrib/webview/browser/webviewEditorInput';
|
||||
import { IWebviewWorkbenchService } from 'vs/workbench/contrib/webview/browser/webviewWorkbenchService';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
|
||||
export class MainThreadWebviewSerializers extends Disposable {
|
||||
|
||||
private readonly _proxy: extHostProtocol.ExtHostWebviewSerializerShape;
|
||||
|
||||
private readonly _revivers = new Map<string, IDisposable>();
|
||||
|
||||
constructor(
|
||||
private readonly mainThreadWebviews: MainThreadWebviews,
|
||||
context: extHostProtocol.IExtHostContext,
|
||||
@IExtensionService extensionService: IExtensionService,
|
||||
@IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService,
|
||||
@IWebviewWorkbenchService private readonly _webviewWorkbenchService: IWebviewWorkbenchService,
|
||||
) {
|
||||
super();
|
||||
|
||||
this._proxy = context.getProxy(extHostProtocol.ExtHostContext.ExtHostWebviewSerializer);
|
||||
|
||||
// This reviver's only job is to activate extensions.
|
||||
// This should trigger the real reviver to be registered from the extension host side.
|
||||
this._register(_webviewWorkbenchService.registerResolver({
|
||||
canResolve: (webview: WebviewInput) => {
|
||||
if (webview instanceof CustomEditorInput) {
|
||||
extensionService.activateByEvent(`onCustomEditor:${webview.viewType}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
const viewType = this.mainThreadWebviews.webviewPanelViewType.toExternal(webview.viewType);
|
||||
if (typeof viewType === 'string') {
|
||||
extensionService.activateByEvent(`onWebviewPanel:${viewType}`);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
resolveWebview: () => { throw new Error('not implemented'); }
|
||||
}));
|
||||
}
|
||||
|
||||
public $registerSerializer(viewType: string): void {
|
||||
if (this._revivers.has(viewType)) {
|
||||
throw new Error(`Reviver for ${viewType} already registered`);
|
||||
}
|
||||
|
||||
this._revivers.set(viewType, this._webviewWorkbenchService.registerResolver({
|
||||
canResolve: (webviewInput) => {
|
||||
return webviewInput.viewType === this.mainThreadWebviews.webviewPanelViewType.fromExternal(viewType);
|
||||
},
|
||||
resolveWebview: async (webviewInput): Promise<void> => {
|
||||
const viewType = this.mainThreadWebviews.webviewPanelViewType.toExternal(webviewInput.viewType);
|
||||
if (!viewType) {
|
||||
webviewInput.webview.html = this.mainThreadWebviews.getWebviewResolvedFailedContent(webviewInput.viewType);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const handle = webviewInput.id;
|
||||
|
||||
this.mainThreadWebviews.addWebviewInput(handle, webviewInput);
|
||||
|
||||
let state = undefined;
|
||||
if (webviewInput.webview.state) {
|
||||
try {
|
||||
state = JSON.parse(webviewInput.webview.state);
|
||||
} catch (e) {
|
||||
console.error('Could not load webview state', e, webviewInput.webview.state);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await this._proxy.$deserializeWebviewPanel(handle, viewType, webviewInput.getTitle(), state, editorGroupToViewColumn(this._editorGroupService, webviewInput.group || 0), webviewInput.webview.options);
|
||||
} catch (error) {
|
||||
onUnexpectedError(error);
|
||||
webviewInput.webview.html = this.mainThreadWebviews.getWebviewResolvedFailedContent(viewType);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public $unregisterSerializer(viewType: string): void {
|
||||
const reviver = this._revivers.get(viewType);
|
||||
if (!reviver) {
|
||||
throw new Error(`No reviver for ${viewType} registered`);
|
||||
}
|
||||
|
||||
reviver.dispose();
|
||||
this._revivers.delete(viewType);
|
||||
}
|
||||
}
|
||||
@@ -6,29 +6,29 @@
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import type { MainThreadWebviews } from 'vs/workbench/api/browser/mainThreadWebview';
|
||||
import { MainThreadWebviews } from 'vs/workbench/api/browser/mainThreadWebviews';
|
||||
import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { IWebviewViewService, WebviewView } from 'vs/workbench/contrib/webviewView/browser/webviewViewService';
|
||||
|
||||
|
||||
export class MainThreadWebviewsViews extends Disposable {
|
||||
export class MainThreadWebviewsViews extends Disposable implements extHostProtocol.MainThreadWebviewViewsShape {
|
||||
|
||||
private readonly _proxyViews: extHostProtocol.ExtHostWebviewViewsShape;
|
||||
private readonly _proxy: extHostProtocol.ExtHostWebviewViewsShape;
|
||||
|
||||
private readonly _webviewViews = new Map<string, WebviewView>();
|
||||
private readonly _webviewViewProviders = new Map<string, IDisposable>();
|
||||
|
||||
constructor(
|
||||
private readonly mainThreadWebviews: MainThreadWebviews,
|
||||
context: extHostProtocol.IExtHostContext,
|
||||
private readonly mainThreadWebviews: MainThreadWebviews,
|
||||
@IWebviewViewService private readonly _webviewViewService: IWebviewViewService,
|
||||
) {
|
||||
super();
|
||||
|
||||
this._proxyViews = context.getProxy(extHostProtocol.ExtHostContext.ExtHostWebviewViews);
|
||||
this._proxy = context.getProxy(extHostProtocol.ExtHostContext.ExtHostWebviewViews);
|
||||
}
|
||||
|
||||
public $setWebviewViewTitle(handle: extHostProtocol.WebviewPanelHandle, value: string | undefined): void {
|
||||
public $setWebviewViewTitle(handle: extHostProtocol.WebviewHandle, value: string | undefined): void {
|
||||
const webviewView = this._webviewViews.get(handle);
|
||||
if (!webviewView) {
|
||||
throw new Error('unknown webview view');
|
||||
@@ -43,9 +43,9 @@ export class MainThreadWebviewsViews extends Disposable {
|
||||
|
||||
this._webviewViewService.register(viewType, {
|
||||
resolve: async (webviewView: WebviewView, cancellation: CancellationToken) => {
|
||||
this._webviewViews.set(viewType, webviewView);
|
||||
|
||||
const handle = webviewView.webview.id;
|
||||
|
||||
this._webviewViews.set(handle, webviewView);
|
||||
this.mainThreadWebviews.addWebview(handle, webviewView.webview);
|
||||
|
||||
let state = undefined;
|
||||
@@ -62,15 +62,16 @@ export class MainThreadWebviewsViews extends Disposable {
|
||||
}
|
||||
|
||||
webviewView.onDidChangeVisibility(visible => {
|
||||
this._proxyViews.$onDidChangeWebviewViewVisibility(handle, visible);
|
||||
this._proxy.$onDidChangeWebviewViewVisibility(handle, visible);
|
||||
});
|
||||
|
||||
webviewView.onDispose(() => {
|
||||
this._proxyViews.$disposeWebviewView(handle);
|
||||
this._proxy.$disposeWebviewView(handle);
|
||||
this._webviewViews.delete(handle);
|
||||
});
|
||||
|
||||
try {
|
||||
await this._proxyViews.$resolveWebviewView(handle, viewType, state, cancellation);
|
||||
await this._proxy.$resolveWebviewView(handle, viewType, state, cancellation);
|
||||
} catch (error) {
|
||||
onUnexpectedError(error);
|
||||
webviewView.webview.html = this.mainThreadWebviews.getWebviewResolvedFailedContent(viewType);
|
||||
|
||||
125
src/vs/workbench/api/browser/mainThreadWebviews.ts
Normal file
125
src/vs/workbench/api/browser/mainThreadWebviews.ts
Normal file
@@ -0,0 +1,125 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { isWeb } from 'vs/base/common/platform';
|
||||
import { escape } from 'vs/base/common/strings';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IWebviewOptions } from 'vs/editor/common/modes';
|
||||
import { localize } from 'vs/nls';
|
||||
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 { Webview, WebviewExtensionDescription, WebviewOverlay } from 'vs/workbench/contrib/webview/browser/webview';
|
||||
import { WebviewInputOptions } from 'vs/workbench/contrib/webview/browser/webviewWorkbenchService';
|
||||
|
||||
export class MainThreadWebviews extends Disposable implements extHostProtocol.MainThreadWebviewsShape {
|
||||
|
||||
private static readonly standardSupportedLinkSchemes = new Set([
|
||||
Schemas.http,
|
||||
Schemas.https,
|
||||
Schemas.mailto,
|
||||
Schemas.vscode,
|
||||
'vscode-insider',
|
||||
]);
|
||||
|
||||
private readonly _proxy: extHostProtocol.ExtHostWebviewsShape;
|
||||
|
||||
private readonly _webviews = new Map<string, Webview>();
|
||||
|
||||
constructor(
|
||||
context: extHostProtocol.IExtHostContext,
|
||||
@IOpenerService private readonly _openerService: IOpenerService,
|
||||
@IProductService private readonly _productService: IProductService,
|
||||
) {
|
||||
super();
|
||||
|
||||
this._proxy = context.getProxy(extHostProtocol.ExtHostContext.ExtHostWebviews);
|
||||
}
|
||||
|
||||
public addWebview(handle: extHostProtocol.WebviewHandle, webview: WebviewOverlay): void {
|
||||
this._webviews.set(handle, webview);
|
||||
this.hookupWebviewEventDelegate(handle, webview);
|
||||
}
|
||||
|
||||
public $setHtml(handle: extHostProtocol.WebviewHandle, value: string): void {
|
||||
const webview = this.getWebview(handle);
|
||||
webview.html = value;
|
||||
}
|
||||
|
||||
public $setOptions(handle: extHostProtocol.WebviewHandle, options: IWebviewOptions): void {
|
||||
const webview = this.getWebview(handle);
|
||||
webview.contentOptions = reviveWebviewOptions(options);
|
||||
}
|
||||
|
||||
public async $postMessage(handle: extHostProtocol.WebviewHandle, message: any): Promise<boolean> {
|
||||
const webview = this.getWebview(handle);
|
||||
webview.postMessage(message);
|
||||
return true;
|
||||
}
|
||||
|
||||
private hookupWebviewEventDelegate(handle: extHostProtocol.WebviewHandle, webview: WebviewOverlay) {
|
||||
const disposables = new DisposableStore();
|
||||
|
||||
disposables.add(webview.onDidClickLink((uri) => this.onDidClickLink(handle, uri)));
|
||||
disposables.add(webview.onMessage((message: any) => { this._proxy.$onMessage(handle, message); }));
|
||||
disposables.add(webview.onMissingCsp((extension: ExtensionIdentifier) => this._proxy.$onMissingCsp(handle, extension.value)));
|
||||
|
||||
disposables.add(webview.onDispose(() => {
|
||||
disposables.dispose();
|
||||
this._webviews.delete(handle);
|
||||
}));
|
||||
}
|
||||
|
||||
private onDidClickLink(handle: extHostProtocol.WebviewHandle, link: string): void {
|
||||
const webview = this.getWebview(handle);
|
||||
if (this.isSupportedLink(webview, URI.parse(link))) {
|
||||
this._openerService.open(link, { fromUserGesture: true });
|
||||
}
|
||||
}
|
||||
|
||||
private isSupportedLink(webview: Webview, link: URI): boolean {
|
||||
if (MainThreadWebviews.standardSupportedLinkSchemes.has(link.scheme)) {
|
||||
return true;
|
||||
}
|
||||
if (!isWeb && this._productService.urlProtocol === link.scheme) {
|
||||
return true;
|
||||
}
|
||||
return !!webview.contentOptions.enableCommandUris && link.scheme === Schemas.command;
|
||||
}
|
||||
|
||||
private getWebview(handle: extHostProtocol.WebviewHandle): Webview {
|
||||
const webview = this._webviews.get(handle);
|
||||
if (!webview) {
|
||||
throw new Error(`Unknown webview handle:${handle}`);
|
||||
}
|
||||
return webview;
|
||||
}
|
||||
|
||||
public getWebviewResolvedFailedContent(viewType: string) {
|
||||
return `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none';">
|
||||
</head>
|
||||
<body>${localize('errorMessage', "An error occurred while loading view: {0}", escape(viewType))}</body>
|
||||
</html>`;
|
||||
}
|
||||
}
|
||||
|
||||
export function reviveWebviewExtension(extensionData: extHostProtocol.WebviewExtensionDescription): WebviewExtensionDescription {
|
||||
return { id: extensionData.id, location: URI.revive(extensionData.location) };
|
||||
}
|
||||
|
||||
export function reviveWebviewOptions(options: IWebviewOptions): WebviewInputOptions {
|
||||
return {
|
||||
...options,
|
||||
allowScripts: options.enableScripts,
|
||||
localResourceRoots: Array.isArray(options.localResourceRoots) ? options.localResourceRoots.map(r => URI.revive(r)) : undefined,
|
||||
};
|
||||
}
|
||||
@@ -473,6 +473,11 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (type === ViewType.Webview && !extension.description.enableProposedApi) {
|
||||
collector.error(localize('webviewViewsRequireProposed', "Webview views are proposed api and are only supported when running out of dev or with the following command line switch: --enable-proposed-api"));
|
||||
return null;
|
||||
}
|
||||
|
||||
const viewDescriptor = <ICustomTreeViewDescriptor>{
|
||||
type: type,
|
||||
ctorDescriptor: type === ViewType.Tree ? new SyncDescriptor(TreeViewPane) : new SyncDescriptor(WebviewViewPane),
|
||||
|
||||
@@ -16,6 +16,7 @@ import { IWorkspacesService, hasWorkspaceFileExtension, IRecent } from 'vs/platf
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IViewDescriptorService, IViewsService } from 'vs/workbench/common/views';
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// The following commands are registered on both sides separately.
|
||||
@@ -264,3 +265,42 @@ CommandsRegistry.registerCommand('_extensionTests.getLogLevel', function (access
|
||||
|
||||
return logService.getLevel();
|
||||
});
|
||||
|
||||
|
||||
CommandsRegistry.registerCommand('_workbench.action.moveViews', async function (accessor: ServicesAccessor, options: { viewIds: string[], destinationId: string }) {
|
||||
const viewDescriptorService = accessor.get(IViewDescriptorService);
|
||||
|
||||
const destination = viewDescriptorService.getViewContainerById(options.destinationId);
|
||||
if (!destination) {
|
||||
return;
|
||||
}
|
||||
|
||||
// FYI, don't use `moveViewsToContainer` in 1 shot, because it expects all views to have the same current location
|
||||
for (const viewId of options.viewIds) {
|
||||
const viewDescriptor = viewDescriptorService.getViewDescriptorById(viewId);
|
||||
if (viewDescriptor?.canMoveView) {
|
||||
viewDescriptorService.moveViewsToContainer([viewDescriptor], destination);
|
||||
}
|
||||
}
|
||||
|
||||
await accessor.get(IViewsService).openViewContainer(destination.id, true);
|
||||
});
|
||||
|
||||
export class MoveViewsAPICommand {
|
||||
public static readonly ID = 'vscode.moveViews';
|
||||
public static execute(executor: ICommandsExecutor, options: { viewIds: string[], destinationId: string }): Promise<any> {
|
||||
if (!Array.isArray(options?.viewIds) || typeof options?.destinationId !== 'string') {
|
||||
return Promise.reject('Invalid arguments');
|
||||
}
|
||||
|
||||
return executor.executeCommand('_workbench.action.moveViews', options);
|
||||
}
|
||||
}
|
||||
CommandsRegistry.registerCommand({
|
||||
id: MoveViewsAPICommand.ID,
|
||||
handler: adjustHandler(MoveViewsAPICommand.execute),
|
||||
description: {
|
||||
description: 'Move Views',
|
||||
args: []
|
||||
}
|
||||
});
|
||||
|
||||
@@ -79,7 +79,7 @@ import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePa
|
||||
import { IExtHostConsumerFileSystem } from 'vs/workbench/api/common/extHostFileSystemConsumer';
|
||||
import { ExtHostWebviewViews } from 'vs/workbench/api/common/extHostWebviewView';
|
||||
import { ExtHostCustomEditors } from 'vs/workbench/api/common/extHostCustomEditors';
|
||||
import { ExtHostWebviewSerializer } from 'vs/workbench/api/common/extHostWebviewSerializer';
|
||||
import { ExtHostWebviewPanels } from 'vs/workbench/api/common/extHostWebviewPanels';
|
||||
|
||||
export interface IExtensionApiFactory {
|
||||
(extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode;
|
||||
@@ -129,7 +129,8 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
const extHostDocuments = rpcProtocol.set(ExtHostContext.ExtHostDocuments, new ExtHostDocuments(rpcProtocol, extHostDocumentsAndEditors));
|
||||
const extHostDocumentContentProviders = rpcProtocol.set(ExtHostContext.ExtHostDocumentContentProviders, new ExtHostDocumentContentProvider(rpcProtocol, extHostDocumentsAndEditors, extHostLogService));
|
||||
const extHostDocumentSaveParticipant = rpcProtocol.set(ExtHostContext.ExtHostDocumentSaveParticipant, new ExtHostDocumentSaveParticipant(extHostLogService, extHostDocuments, rpcProtocol.getProxy(MainContext.MainThreadTextEditors)));
|
||||
const extHostEditors = rpcProtocol.set(ExtHostContext.ExtHostEditors, new ExtHostEditors(rpcProtocol, extHostDocumentsAndEditors));
|
||||
const extHostNotebook = rpcProtocol.set(ExtHostContext.ExtHostNotebook, new ExtHostNotebookController(rpcProtocol, extHostCommands, extHostDocumentsAndEditors, initData.environment, extHostLogService, extensionStoragePaths));
|
||||
const extHostEditors = rpcProtocol.set(ExtHostContext.ExtHostEditors, new ExtHostEditors(rpcProtocol, extHostDocumentsAndEditors, extHostNotebook));
|
||||
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 extHostDiagnostics = rpcProtocol.set(ExtHostContext.ExtHostDiagnostics, new ExtHostDiagnostics(rpcProtocol, extHostLogService));
|
||||
@@ -141,13 +142,12 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
const extHostComment = rpcProtocol.set(ExtHostContext.ExtHostComments, new ExtHostComments(rpcProtocol, extHostCommands, extHostDocuments));
|
||||
const extHostProgress = rpcProtocol.set(ExtHostContext.ExtHostProgress, new ExtHostProgress(rpcProtocol.getProxy(MainContext.MainThreadProgress)));
|
||||
const extHostLabelService = rpcProtocol.set(ExtHostContext.ExtHosLabelService, new ExtHostLabelService(rpcProtocol));
|
||||
const extHostNotebook = rpcProtocol.set(ExtHostContext.ExtHostNotebook, new ExtHostNotebookController(rpcProtocol, extHostCommands, extHostDocumentsAndEditors, initData.environment, extHostLogService, extensionStoragePaths));
|
||||
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 extHostWebviewSerializers = rpcProtocol.set(ExtHostContext.ExtHostWebviewSerializer, new ExtHostWebviewSerializer(rpcProtocol, extHostWebviews));
|
||||
const extHostCustomEditors = rpcProtocol.set(ExtHostContext.ExtHostCustomEditors, new ExtHostCustomEditors(rpcProtocol, extHostDocuments, extensionStoragePaths, extHostWebviews));
|
||||
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));
|
||||
|
||||
// Check that no named customers are missing
|
||||
@@ -573,7 +573,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
return extHostOutputService.createOutputChannel(name);
|
||||
},
|
||||
createWebviewPanel(viewType: string, title: string, showOptions: vscode.ViewColumn | { viewColumn: vscode.ViewColumn, preserveFocus?: boolean }, options?: vscode.WebviewPanelOptions & vscode.WebviewOptions): vscode.WebviewPanel {
|
||||
return extHostWebviews.createWebviewPanel(extension, viewType, title, showOptions, options);
|
||||
return extHostWebviewPanels.createWebviewPanel(extension, viewType, title, showOptions, options);
|
||||
},
|
||||
createWebviewTextEditorInset(editor: vscode.TextEditor, line: number, height: number, options?: vscode.WebviewOptions): vscode.WebviewEditorInset {
|
||||
checkProposedApiEnabled(extension);
|
||||
@@ -598,7 +598,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
return extHostTreeViews.createTreeView(viewId, options, extension);
|
||||
},
|
||||
registerWebviewPanelSerializer: (viewType: string, serializer: vscode.WebviewPanelSerializer) => {
|
||||
return extHostWebviewSerializers.registerWebviewPanelSerializer(extension, viewType, serializer);
|
||||
return extHostWebviewPanels.registerWebviewPanelSerializer(extension, viewType, serializer);
|
||||
},
|
||||
registerCustomEditorProvider: (viewType: string, provider: vscode.CustomTextEditorProvider | vscode.CustomReadonlyEditorProvider, options: { webviewOptions?: vscode.WebviewPanelOptions, supportsMultipleEditorsPerDocument?: boolean } = {}) => {
|
||||
return extHostCustomEditors.registerCustomEditorProvider(extension, viewType, provider, options);
|
||||
@@ -958,7 +958,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
},
|
||||
get notebookDocuments(): vscode.NotebookDocument[] {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostNotebook.notebookDocuments;
|
||||
return extHostNotebook.notebookDocuments.map(d => d.notebookDocument);
|
||||
},
|
||||
get visibleNotebookEditors() {
|
||||
checkProposedApiEnabled(extension);
|
||||
@@ -972,13 +972,12 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostNotebook.onDidChangeActiveNotebookKernel;
|
||||
},
|
||||
registerNotebookContentProvider: (viewType: string, provider: vscode.NotebookContentProvider) => {
|
||||
registerNotebookContentProvider: (viewType: string, provider: vscode.NotebookContentProvider, options?: {
|
||||
transientOutputs: boolean;
|
||||
transientMetadata: { [K in keyof vscode.NotebookCellMetadata]?: boolean }
|
||||
}) => {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostNotebook.registerNotebookContentProvider(extension, viewType, provider);
|
||||
},
|
||||
registerNotebookKernel: (id: string, selector: vscode.GlobPattern[], kernel: vscode.NotebookKernel) => {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostNotebook.registerNotebookKernel(extension, id, selector, kernel);
|
||||
return extHostNotebook.registerNotebookContentProvider(extension, viewType, provider, options);
|
||||
},
|
||||
registerNotebookKernelProvider: (selector: vscode.NotebookDocumentFilter, provider: vscode.NotebookKernelProvider) => {
|
||||
checkProposedApiEnabled(extension);
|
||||
@@ -996,6 +995,14 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostNotebook.onDidChangeNotebookCells(listener, thisArgs, disposables);
|
||||
},
|
||||
onDidChangeNotebookEditorSelection(listener, thisArgs?, disposables?) {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostNotebook.onDidChangeNotebookEditorSelection(listener, thisArgs, disposables);
|
||||
},
|
||||
onDidChangeNotebookEditorVisibleRanges(listener, thisArgs?, disposables?) {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostNotebook.onDidChangeNotebookEditorVisibleRanges(listener, thisArgs, disposables);
|
||||
},
|
||||
onDidChangeCellOutputs(listener, thisArgs?, disposables?) {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostNotebook.onDidChangeCellOutputs(listener, thisArgs, disposables);
|
||||
@@ -1011,6 +1018,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
createConcatTextDocument(notebook, selector) {
|
||||
checkProposedApiEnabled(extension);
|
||||
return new ExtHostNotebookConcatDocument(extHostNotebook, extHostDocuments, notebook, selector);
|
||||
},
|
||||
createCellStatusBarItem(cell: vscode.NotebookCell, alignment?: vscode.NotebookCellStatusBarAlignment, priority?: number): vscode.NotebookCellStatusBarItem {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostNotebook.createNotebookCellStatusBarItemInternal(cell, alignment, priority);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1114,7 +1125,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
SymbolKind: extHostTypes.SymbolKind,
|
||||
SymbolTag: extHostTypes.SymbolTag,
|
||||
Task: extHostTypes.Task,
|
||||
Task2: extHostTypes.Task,
|
||||
TaskGroup: extHostTypes.TaskGroup,
|
||||
TaskPanelKind: extHostTypes.TaskPanelKind,
|
||||
TaskRevealKind: extHostTypes.TaskRevealKind,
|
||||
@@ -1146,7 +1156,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
CellKind: extHostTypes.CellKind,
|
||||
CellOutputKind: extHostTypes.CellOutputKind,
|
||||
NotebookCellRunState: extHostTypes.NotebookCellRunState,
|
||||
NotebookRunState: extHostTypes.NotebookRunState
|
||||
NotebookRunState: extHostTypes.NotebookRunState,
|
||||
NotebookCellStatusBarAlignment: extHostTypes.NotebookCellStatusBarAlignment,
|
||||
NotebookEditorRevealType: extHostTypes.NotebookEditorRevealType
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ import { IRevealOptions, ITreeItem } from 'vs/workbench/common/views';
|
||||
import { IAdapterDescriptor, IConfig, IDebugSessionReplMode } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { ITextQueryBuilderOptions } from 'vs/workbench/contrib/search/common/queryBuilder';
|
||||
import { ITerminalDimensions, IShellLaunchConfig, ITerminalLaunchError } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { ExtensionActivationError } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ActivationKind, ExtensionActivationError } 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 { SaveReason } from 'vs/workbench/common/editor';
|
||||
@@ -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 { IProcessedOutput, INotebookDisplayOrder, NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEvent, NotebookDataDto, INotebookKernelInfoDto, IMainCellDto, INotebookDocumentFilter, INotebookKernelInfoDto2 } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { IProcessedOutput, INotebookDisplayOrder, NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEvent, NotebookDataDto, IMainCellDto, INotebookDocumentFilter, INotebookKernelInfoDto2, TransientMetadata, INotebookCellStatusBarEntry, ICellRange } 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';
|
||||
@@ -454,6 +454,7 @@ export interface MainThreadTerminalServiceShape extends IDisposable {
|
||||
$stopSendingDataEvents(): void;
|
||||
$startLinkProvider(): void;
|
||||
$stopLinkProvider(): void;
|
||||
$registerProcessSupport(isSupported: boolean): void;
|
||||
$setEnvironmentVariableCollection(extensionIdentifier: string, persistent: boolean, collection: ISerializableEnvironmentVariableCollection | undefined): void;
|
||||
|
||||
// Process
|
||||
@@ -585,7 +586,7 @@ export interface ExtHostEditorInsetsShape {
|
||||
$onDidReceiveMessage(handle: number, message: any): void;
|
||||
}
|
||||
|
||||
export type WebviewPanelHandle = string;
|
||||
export type WebviewHandle = string;
|
||||
|
||||
export interface WebviewPanelShowOptions {
|
||||
readonly viewColumn?: EditorViewColumn;
|
||||
@@ -613,31 +614,36 @@ export interface CustomTextEditorCapabilities {
|
||||
}
|
||||
|
||||
export interface MainThreadWebviewsShape extends IDisposable {
|
||||
$createWebviewPanel(extension: WebviewExtensionDescription, handle: WebviewPanelHandle, viewType: string, title: string, showOptions: WebviewPanelShowOptions, options: modes.IWebviewPanelOptions & modes.IWebviewOptions): void;
|
||||
$disposeWebview(handle: WebviewPanelHandle): void;
|
||||
$reveal(handle: WebviewPanelHandle, showOptions: WebviewPanelShowOptions): void;
|
||||
$setTitle(handle: WebviewPanelHandle, value: string): void;
|
||||
$setIconPath(handle: WebviewPanelHandle, value: { light: UriComponents, dark: UriComponents; } | undefined): void;
|
||||
$setHtml(handle: WebviewHandle, value: string): void;
|
||||
$setOptions(handle: WebviewHandle, options: modes.IWebviewOptions): void;
|
||||
$postMessage(handle: WebviewHandle, value: any): Promise<boolean>
|
||||
}
|
||||
|
||||
$setHtml(handle: WebviewPanelHandle, value: string): void;
|
||||
$setOptions(handle: WebviewPanelHandle, options: modes.IWebviewOptions): void;
|
||||
|
||||
$postMessage(handle: WebviewPanelHandle, value: any): Promise<boolean>;
|
||||
export interface MainThreadWebviewPanelsShape extends IDisposable {
|
||||
$createWebviewPanel(extension: WebviewExtensionDescription, handle: WebviewHandle, viewType: string, title: string, showOptions: WebviewPanelShowOptions, options: modes.IWebviewPanelOptions & modes.IWebviewOptions): void;
|
||||
$disposeWebview(handle: WebviewHandle): void;
|
||||
$reveal(handle: WebviewHandle, showOptions: WebviewPanelShowOptions): void;
|
||||
$setTitle(handle: WebviewHandle, value: string): void;
|
||||
$setIconPath(handle: WebviewHandle, value: { light: UriComponents, dark: UriComponents; } | undefined): void;
|
||||
|
||||
$registerSerializer(viewType: string): void;
|
||||
$unregisterSerializer(viewType: string): void;
|
||||
}
|
||||
|
||||
export interface MainThreadCustomEditorsShape extends IDisposable {
|
||||
$registerTextEditorProvider(extension: WebviewExtensionDescription, viewType: string, options: modes.IWebviewPanelOptions, capabilities: CustomTextEditorCapabilities): void;
|
||||
$registerCustomEditorProvider(extension: WebviewExtensionDescription, viewType: string, options: modes.IWebviewPanelOptions, supportsMultipleEditorsPerDocument: boolean): void;
|
||||
$unregisterEditorProvider(viewType: string): void;
|
||||
|
||||
$onDidEdit(resource: UriComponents, viewType: string, editId: number, label: string | undefined): void;
|
||||
$onContentChange(resource: UriComponents, viewType: string): void;
|
||||
}
|
||||
|
||||
export interface MainThreadWebviewViewsShape extends IDisposable {
|
||||
$registerWebviewViewProvider(viewType: string, options?: { retainContextWhenHidden?: boolean }): void;
|
||||
$unregisterWebviewViewProvider(viewType: string): void;
|
||||
|
||||
$setWebviewViewTitle(handle: WebviewPanelHandle, value: string | undefined): void;
|
||||
$setWebviewViewTitle(handle: WebviewHandle, value: string | undefined): void;
|
||||
}
|
||||
|
||||
export interface WebviewPanelViewStateData {
|
||||
@@ -649,18 +655,18 @@ export interface WebviewPanelViewStateData {
|
||||
}
|
||||
|
||||
export interface ExtHostWebviewsShape {
|
||||
$onMessage(handle: WebviewPanelHandle, message: any): void;
|
||||
$onMissingCsp(handle: WebviewPanelHandle, extensionId: string): void;
|
||||
$onDidChangeWebviewPanelViewStates(newState: WebviewPanelViewStateData): void;
|
||||
$onDidDisposeWebviewPanel(handle: WebviewPanelHandle): Promise<void>;
|
||||
$onMessage(handle: WebviewHandle, message: any): void;
|
||||
$onMissingCsp(handle: WebviewHandle, extensionId: string): void;
|
||||
}
|
||||
|
||||
export interface ExtHostWebviewSerializerShape {
|
||||
$deserializeWebviewPanel(newWebviewHandle: WebviewPanelHandle, viewType: string, title: string, state: any, position: EditorViewColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions): Promise<void>;
|
||||
export interface ExtHostWebviewPanelsShape {
|
||||
$onDidChangeWebviewPanelViewStates(newState: WebviewPanelViewStateData): void;
|
||||
$onDidDisposeWebviewPanel(handle: WebviewHandle): Promise<void>;
|
||||
$deserializeWebviewPanel(newWebviewHandle: WebviewHandle, viewType: string, title: string, state: any, position: EditorViewColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions): Promise<void>;
|
||||
}
|
||||
|
||||
export interface ExtHostCustomEditorsShape {
|
||||
$resolveWebviewEditor(resource: UriComponents, newWebviewHandle: WebviewPanelHandle, viewType: string, title: string, position: EditorViewColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions, cancellation: CancellationToken): Promise<void>;
|
||||
$resolveWebviewEditor(resource: UriComponents, newWebviewHandle: WebviewHandle, viewType: string, title: string, position: EditorViewColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions, cancellation: CancellationToken): Promise<void>;
|
||||
$createCustomDocument(resource: UriComponents, viewType: string, backupId: string | undefined, cancellation: CancellationToken): Promise<{ editable: boolean }>;
|
||||
$disposeCustomDocument(resource: UriComponents, viewType: string): Promise<void>;
|
||||
|
||||
@@ -674,15 +680,15 @@ export interface ExtHostCustomEditorsShape {
|
||||
|
||||
$backup(resource: UriComponents, viewType: string, cancellation: CancellationToken): Promise<string>;
|
||||
|
||||
$onMoveCustomEditor(handle: WebviewPanelHandle, newResource: UriComponents, viewType: string): Promise<void>;
|
||||
$onMoveCustomEditor(handle: WebviewHandle, newResource: UriComponents, viewType: string): Promise<void>;
|
||||
}
|
||||
|
||||
export interface ExtHostWebviewViewsShape {
|
||||
$resolveWebviewView(webviewHandle: WebviewPanelHandle, viewType: string, state: any, cancellation: CancellationToken): Promise<void>;
|
||||
$resolveWebviewView(webviewHandle: WebviewHandle, viewType: string, state: any, cancellation: CancellationToken): Promise<void>;
|
||||
|
||||
$onDidChangeWebviewViewVisibility(webviewHandle: WebviewPanelHandle, visible: boolean): void;
|
||||
$onDidChangeWebviewViewVisibility(webviewHandle: WebviewHandle, visible: boolean): void;
|
||||
|
||||
$disposeWebviewView(webviewHandle: WebviewPanelHandle): void;
|
||||
$disposeWebviewView(webviewHandle: WebviewHandle): void;
|
||||
}
|
||||
|
||||
export enum CellKind {
|
||||
@@ -718,22 +724,29 @@ export type NotebookCellOutputsSplice = [
|
||||
IProcessedOutput[]
|
||||
];
|
||||
|
||||
export enum NotebookEditorRevealType {
|
||||
Default = 0,
|
||||
InCenter = 1,
|
||||
InCenterIfOutsideViewport = 2,
|
||||
}
|
||||
|
||||
export type INotebookCellStatusBarEntryDto = Dto<INotebookCellStatusBarEntry>;
|
||||
|
||||
export interface MainThreadNotebookShape extends IDisposable {
|
||||
$registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, supportBackup: boolean, kernelInfoDto: INotebookKernelInfoDto | undefined): Promise<void>;
|
||||
$registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, supportBackup: boolean, options: { transientOutputs: boolean; transientMetadata: TransientMetadata }): Promise<void>;
|
||||
$onNotebookChange(viewType: string, resource: UriComponents): Promise<void>;
|
||||
$unregisterNotebookProvider(viewType: 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>;
|
||||
$onNotebookKernelChange(handle: number, uri: UriComponents | undefined): void;
|
||||
$tryApplyEdits(viewType: string, resource: UriComponents, modelVersionId: number, edits: ICellEditOperation[]): Promise<boolean>;
|
||||
$updateNotebookLanguages(viewType: string, resource: UriComponents, languages: string[]): Promise<void>;
|
||||
$updateNotebookMetadata(viewType: string, resource: UriComponents, metadata: NotebookDocumentMetadata): Promise<void>;
|
||||
$updateNotebookCellMetadata(viewType: string, resource: UriComponents, handle: number, metadata: NotebookCellMetadata | undefined): Promise<void>;
|
||||
$spliceNotebookCellOutputs(viewType: string, resource: UriComponents, cellHandle: number, splices: NotebookCellOutputsSplice[]): Promise<void>;
|
||||
$postMessage(editorId: string, forRendererId: string | undefined, value: any): Promise<boolean>;
|
||||
|
||||
$setStatusBarEntry(id: number, statusBarEntry: INotebookCellStatusBarEntryDto): Promise<void>;
|
||||
$tryRevealRange(id: string, range: ICellRange, revealType: NotebookEditorRevealType): Promise<void>;
|
||||
$onDidEdit(resource: UriComponents, viewType: string, editId: number, label: string | undefined): void;
|
||||
$onContentChange(resource: UriComponents, viewType: string): void;
|
||||
}
|
||||
@@ -1052,6 +1065,7 @@ export interface ExtHostAuthenticationShape {
|
||||
$logout(id: string, sessionId: string): Promise<void>;
|
||||
$onDidChangeAuthenticationSessions(id: string, label: string, event: modes.AuthenticationSessionsChangeEvent): Promise<void>;
|
||||
$onDidChangeAuthenticationProviders(added: modes.AuthenticationProviderInformation[], removed: modes.AuthenticationProviderInformation[]): Promise<void>;
|
||||
$setProviders(providers: modes.AuthenticationProviderInformation[]): Promise<void>;
|
||||
}
|
||||
|
||||
export interface ExtHostSearchShape {
|
||||
@@ -1079,7 +1093,7 @@ export type IResolveAuthorityResult = IResolveAuthorityErrorResult | IResolveAut
|
||||
export interface ExtHostExtensionServiceShape {
|
||||
$resolveAuthority(remoteAuthority: string, resolveAttempt: number): Promise<IResolveAuthorityResult>;
|
||||
$startExtensionHost(enabledExtensionIds: ExtensionIdentifier[]): Promise<void>;
|
||||
$activateByEvent(activationEvent: string): Promise<void>;
|
||||
$activateByEvent(activationEvent: string, activationKind: ActivationKind): Promise<void>;
|
||||
$activate(extensionId: ExtensionIdentifier, reason: ExtensionActivationReason): Promise<boolean>;
|
||||
$setRemoteEnvironment(env: { [key: string]: string | null; }): Promise<void>;
|
||||
$updateRemoteConnectionData(connectionData: IRemoteConnectionData): Promise<void>;
|
||||
@@ -1237,7 +1251,14 @@ export interface IWorkspaceEditEntryMetadataDto {
|
||||
iconPath?: { id: string } | UriComponents | { light: UriComponents, dark: UriComponents };
|
||||
}
|
||||
|
||||
export const enum WorkspaceEditType {
|
||||
File = 1,
|
||||
Text = 2,
|
||||
Cell = 3,
|
||||
}
|
||||
|
||||
export interface IWorkspaceFileEditDto {
|
||||
_type: WorkspaceEditType.File;
|
||||
oldUri?: UriComponents;
|
||||
newUri?: UriComponents;
|
||||
options?: modes.WorkspaceFileEditOptions
|
||||
@@ -1245,14 +1266,23 @@ export interface IWorkspaceFileEditDto {
|
||||
}
|
||||
|
||||
export interface IWorkspaceTextEditDto {
|
||||
_type: WorkspaceEditType.Text;
|
||||
resource: UriComponents;
|
||||
edit: modes.TextEdit;
|
||||
modelVersionId?: number;
|
||||
metadata?: IWorkspaceEditEntryMetadataDto;
|
||||
}
|
||||
|
||||
export interface IWorkspaceCellEditDto {
|
||||
_type: WorkspaceEditType.Cell;
|
||||
resource: UriComponents;
|
||||
edit: ICellEditOperation;
|
||||
modelVersionId?: number;
|
||||
metadata?: IWorkspaceEditEntryMetadataDto;
|
||||
}
|
||||
|
||||
export interface IWorkspaceEditDto {
|
||||
edits: Array<IWorkspaceFileEditDto | IWorkspaceTextEditDto>;
|
||||
edits: Array<IWorkspaceFileEditDto | IWorkspaceTextEditDto | IWorkspaceCellEditDto>;
|
||||
|
||||
// todo@joh reject should go into rename
|
||||
rejectReason?: string;
|
||||
@@ -1602,9 +1632,22 @@ export interface INotebookSelectionChangeEvent {
|
||||
selections: number[];
|
||||
}
|
||||
|
||||
export interface INotebookCellVisibleRange {
|
||||
start: number;
|
||||
end: number;
|
||||
}
|
||||
|
||||
export interface INotebookVisibleRangesEvent {
|
||||
ranges: INotebookCellVisibleRange[];
|
||||
}
|
||||
|
||||
export interface INotebookEditorPropertiesChangeData {
|
||||
selections: INotebookSelectionChangeEvent | null;
|
||||
visibleRanges: INotebookVisibleRangesEvent | null;
|
||||
}
|
||||
|
||||
export interface INotebookDocumentPropertiesChangeData {
|
||||
metadata: NotebookDocumentMetadata | null;
|
||||
selections: INotebookSelectionChangeEvent | null;
|
||||
}
|
||||
|
||||
export interface INotebookModelAddedData {
|
||||
@@ -1614,13 +1657,14 @@ export interface INotebookModelAddedData {
|
||||
cells: IMainCellDto[],
|
||||
viewType: string;
|
||||
metadata?: NotebookDocumentMetadata;
|
||||
attachedEditor?: { id: string; selections: number[]; }
|
||||
attachedEditor?: { id: string; selections: number[]; visibleRanges: ICellRange[] }
|
||||
}
|
||||
|
||||
export interface INotebookEditorAddData {
|
||||
id: string;
|
||||
documentUri: UriComponents;
|
||||
selections: number[];
|
||||
visibleRanges: ICellRange[];
|
||||
}
|
||||
|
||||
export interface INotebookDocumentsAndEditorsDelta {
|
||||
@@ -1637,8 +1681,6 @@ export interface ExtHostNotebookShape {
|
||||
$resolveNotebookEditor(viewType: string, uri: UriComponents, editorId: string): Promise<void>;
|
||||
$provideNotebookKernels(handle: number, uri: UriComponents, token: CancellationToken): Promise<INotebookKernelInfoDto2[]>;
|
||||
$resolveNotebookKernel(handle: number, editorId: string, uri: UriComponents, kernelId: string, token: CancellationToken): Promise<void>;
|
||||
$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>;
|
||||
$cancelNotebookKernelFromProvider(handle: number, uri: UriComponents, kernelId: string, cellHandle: number | undefined): Promise<void>;
|
||||
$executeNotebook2(kernelId: string, viewType: string, uri: UriComponents, cellHandle: number | undefined): Promise<void>;
|
||||
@@ -1648,9 +1690,10 @@ export interface ExtHostNotebookShape {
|
||||
$acceptDisplayOrder(displayOrder: INotebookDisplayOrder): void;
|
||||
$acceptNotebookActiveKernelChange(event: { uri: UriComponents, providerHandle: number | undefined, kernelId: string | undefined }): void;
|
||||
$onDidReceiveMessage(editorId: string, rendererId: string | undefined, message: unknown): void;
|
||||
$acceptModelChanged(uriComponents: UriComponents, event: NotebookCellsChangedEvent): void;
|
||||
$acceptModelChanged(uriComponents: UriComponents, event: NotebookCellsChangedEvent, isDirty: boolean): void;
|
||||
$acceptModelSaved(uriComponents: UriComponents): void;
|
||||
$acceptEditorPropertiesChanged(uriComponents: UriComponents, data: INotebookEditorPropertiesChangeData): void;
|
||||
$acceptEditorPropertiesChanged(id: string, data: INotebookEditorPropertiesChangeData): void;
|
||||
$acceptDocumentPropertiesChanged(uriComponents: UriComponents, data: INotebookDocumentPropertiesChangeData): void;
|
||||
$acceptDocumentAndEditorsDelta(delta: INotebookDocumentsAndEditorsDelta): void;
|
||||
$undoNotebook(viewType: string, uri: UriComponents, editId: number, isDirty: boolean): Promise<void>;
|
||||
$redoNotebook(viewType: string, uri: UriComponents, editId: number, isDirty: boolean): Promise<void>;
|
||||
@@ -1713,6 +1756,9 @@ export const MainContext = {
|
||||
MainThreadTelemetry: createMainId<MainThreadTelemetryShape>('MainThreadTelemetry'),
|
||||
MainThreadTerminalService: createMainId<MainThreadTerminalServiceShape>('MainThreadTerminalService'),
|
||||
MainThreadWebviews: createMainId<MainThreadWebviewsShape>('MainThreadWebviews'),
|
||||
MainThreadWebviewPanels: createMainId<MainThreadWebviewPanelsShape>('MainThreadWebviewPanels'),
|
||||
MainThreadWebviewViews: createMainId<MainThreadWebviewViewsShape>('MainThreadWebviewViews'),
|
||||
MainThreadCustomEditors: createMainId<MainThreadCustomEditorsShape>('MainThreadCustomEditors'),
|
||||
MainThreadUrls: createMainId<MainThreadUrlsShape>('MainThreadUrls'),
|
||||
MainThreadWorkspace: createMainId<MainThreadWorkspaceShape>('MainThreadWorkspace'),
|
||||
MainThreadFileSystem: createMainId<MainThreadFileSystemShape>('MainThreadFileSystem'),
|
||||
@@ -1753,7 +1799,7 @@ export const ExtHostContext = {
|
||||
ExtHostWorkspace: createExtId<ExtHostWorkspaceShape>('ExtHostWorkspace'),
|
||||
ExtHostWindow: createExtId<ExtHostWindowShape>('ExtHostWindow'),
|
||||
ExtHostWebviews: createExtId<ExtHostWebviewsShape>('ExtHostWebviews'),
|
||||
ExtHostWebviewSerializer: createExtId<ExtHostWebviewSerializerShape>('ExtHostWebviewSerializer'),
|
||||
ExtHostWebviewPanels: createExtId<ExtHostWebviewPanelsShape>('ExtHostWebviewPanels'),
|
||||
ExtHostCustomEditors: createExtId<ExtHostCustomEditorsShape>('ExtHostCustomEditors'),
|
||||
ExtHostWebviewViews: createExtId<ExtHostWebviewViewsShape>('ExtHostWebviewViews'),
|
||||
ExtHostEditorInsets: createExtId<ExtHostEditorInsetsShape>('ExtHostEditorInsets'),
|
||||
|
||||
@@ -28,6 +28,11 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadAuthentication);
|
||||
}
|
||||
|
||||
$setProviders(providers: vscode.AuthenticationProviderInformation[]): Promise<void> {
|
||||
this._providers = providers;
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
getProviderIds(): Promise<ReadonlyArray<string>> {
|
||||
return this._proxy.$getProviderIds();
|
||||
}
|
||||
@@ -182,9 +187,9 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
|
||||
}
|
||||
|
||||
$onDidChangeAuthenticationProviders(added: modes.AuthenticationProviderInformation[], removed: modes.AuthenticationProviderInformation[]) {
|
||||
added.forEach(id => {
|
||||
if (!this._providers.includes(id)) {
|
||||
this._providers.push(id);
|
||||
added.forEach(provider => {
|
||||
if (!this._providers.some(p => p.id === provider.id)) {
|
||||
this._providers.push(provider);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@ export class ExtHostCommands implements ExtHostCommandsShape {
|
||||
|
||||
try {
|
||||
const result = await this._proxy.$executeCommand<T>(id, toArgs, retry);
|
||||
return revive(result);
|
||||
return revive<any>(result);
|
||||
} catch (e) {
|
||||
// Rerun the command when it wasn't known, had arguments, and when retry
|
||||
// is enabled. We do this because the command might be registered inside
|
||||
|
||||
@@ -14,6 +14,7 @@ import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
|
||||
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
|
||||
import { ExtHostWebviews, toExtensionData } from 'vs/workbench/api/common/extHostWebview';
|
||||
import { ExtHostWebviewPanels } from 'vs/workbench/api/common/extHostWebviewPanels';
|
||||
import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor';
|
||||
import type * as vscode from 'vscode';
|
||||
import { Cache } from './cache';
|
||||
@@ -154,7 +155,7 @@ class EditorProviderStore {
|
||||
|
||||
export class ExtHostCustomEditors implements extHostProtocol.ExtHostCustomEditorsShape {
|
||||
|
||||
private readonly _proxy: extHostProtocol.MainThreadWebviewsShape;
|
||||
private readonly _proxy: extHostProtocol.MainThreadCustomEditorsShape;
|
||||
|
||||
private readonly _editorProviders = new EditorProviderStore();
|
||||
|
||||
@@ -165,8 +166,9 @@ export class ExtHostCustomEditors implements extHostProtocol.ExtHostCustomEditor
|
||||
private readonly _extHostDocuments: ExtHostDocuments,
|
||||
private readonly _extensionStoragePaths: IExtensionStoragePaths | undefined,
|
||||
private readonly _extHostWebview: ExtHostWebviews,
|
||||
private readonly _extHostWebviewPanels: ExtHostWebviewPanels,
|
||||
) {
|
||||
this._proxy = mainContext.getProxy(extHostProtocol.MainContext.MainThreadWebviews);
|
||||
this._proxy = mainContext.getProxy(extHostProtocol.MainContext.MainThreadCustomEditors);
|
||||
}
|
||||
|
||||
public registerCustomEditorProvider(
|
||||
@@ -247,7 +249,7 @@ export class ExtHostCustomEditors implements extHostProtocol.ExtHostCustomEditor
|
||||
|
||||
async $resolveWebviewEditor(
|
||||
resource: UriComponents,
|
||||
handle: extHostProtocol.WebviewPanelHandle,
|
||||
handle: extHostProtocol.WebviewHandle,
|
||||
viewType: string,
|
||||
title: string,
|
||||
position: EditorViewColumn,
|
||||
@@ -260,7 +262,7 @@ export class ExtHostCustomEditors implements extHostProtocol.ExtHostCustomEditor
|
||||
}
|
||||
|
||||
const webview = this._extHostWebview.createNewWebview(handle, options, entry.extension);
|
||||
const panel = this._extHostWebview.createNewWebviewPanel(handle, viewType, title, position, options, webview);
|
||||
const panel = this._extHostWebviewPanels.createNewWebviewPanel(handle, viewType, title, position, options, webview);
|
||||
|
||||
const revivedResource = URI.revive(resource);
|
||||
|
||||
@@ -297,7 +299,7 @@ export class ExtHostCustomEditors implements extHostProtocol.ExtHostCustomEditor
|
||||
throw new Error(`Provider does not implement move '${viewType}'`);
|
||||
}
|
||||
|
||||
const webview = this._extHostWebview.getWebviewPanel(handle);
|
||||
const webview = this._extHostWebviewPanels.getWebviewPanel(handle);
|
||||
if (!webview) {
|
||||
throw new Error(`No webview found`);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ interface ProviderData {
|
||||
extensionId: ExtensionIdentifier;
|
||||
}
|
||||
|
||||
export class ExtHostDecorations implements IExtHostDecorations {
|
||||
export class ExtHostDecorations implements ExtHostDecorationsShape {
|
||||
|
||||
private static _handlePool = 0;
|
||||
|
||||
@@ -85,4 +85,4 @@ export class ExtHostDecorations implements IExtHostDecorations {
|
||||
}
|
||||
|
||||
export const IExtHostDecorations = createDecorator<IExtHostDecorations>('IExtHostDecorations');
|
||||
export interface IExtHostDecorations extends ExtHostDecorations, ExtHostDecorationsShape { }
|
||||
export interface IExtHostDecorations extends ExtHostDecorations { }
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { illegalState } from 'vs/base/common/errors';
|
||||
import { ExtHostDocumentSaveParticipantShape, MainThreadTextEditorsShape, IWorkspaceEditDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostDocumentSaveParticipantShape, MainThreadTextEditorsShape, IWorkspaceEditDto, WorkspaceEditType } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { TextEdit } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { Range, TextDocumentSaveReason, EndOfLine } from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
|
||||
@@ -146,6 +146,7 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic
|
||||
if (Array.isArray(value) && (<vscode.TextEdit[]>value).every(e => e instanceof TextEdit)) {
|
||||
for (const { newText, newEol, range } of value) {
|
||||
dto.edits.push({
|
||||
_type: WorkspaceEditType.Text,
|
||||
resource: document.uri,
|
||||
edit: {
|
||||
range: range && Range.from(range),
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import * as path from 'vs/base/common/path';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { originalFSPath, joinPath } from 'vs/base/common/resources';
|
||||
import { Barrier, timeout } from 'vs/base/common/async';
|
||||
import { dispose, toDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle';
|
||||
@@ -17,7 +16,7 @@ import { ExtHostConfiguration, IExtHostConfiguration } from 'vs/workbench/api/co
|
||||
import { ActivatedExtension, EmptyExtension, ExtensionActivationReason, ExtensionActivationTimes, ExtensionActivationTimesBuilder, ExtensionsActivator, IExtensionAPI, IExtensionModule, HostExtension, ExtensionActivationTimesFragment } from 'vs/workbench/api/common/extHostExtensionActivator';
|
||||
import { ExtHostStorage, IExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
|
||||
import { ExtHostWorkspace, IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import { ExtensionActivationError, checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ExtensionActivationError, checkProposedApiEnabled, ActivationKind } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import type * as vscode from 'vscode';
|
||||
@@ -385,14 +384,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
|
||||
subscriptions: [],
|
||||
get extensionUri() { return extensionDescription.extensionLocation; },
|
||||
get extensionPath() { return extensionDescription.extensionLocation.fsPath; },
|
||||
asAbsolutePath(relativePath: string) {
|
||||
if (platform.isWeb) {
|
||||
// web worker
|
||||
return URI.joinPath(extensionDescription.extensionLocation, relativePath).toString();
|
||||
} else {
|
||||
return path.join(extensionDescription.extensionLocation.fsPath, relativePath);
|
||||
}
|
||||
},
|
||||
asAbsolutePath(relativePath: string) { return path.join(extensionDescription.extensionLocation.fsPath, relativePath); },
|
||||
get storagePath() { return that._storagePath.workspaceValue(extensionDescription)?.fsPath; },
|
||||
get globalStoragePath() { return that._storagePath.globalValue(extensionDescription).fsPath; },
|
||||
get logPath() { return path.join(that._initData.logsLocation.fsPath, extensionDescription.identifier.value); },
|
||||
@@ -686,7 +678,11 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
|
||||
return this._startExtensionHost();
|
||||
}
|
||||
|
||||
public $activateByEvent(activationEvent: string): Promise<void> {
|
||||
public $activateByEvent(activationEvent: string, activationKind: ActivationKind): Promise<void> {
|
||||
if (activationKind === ActivationKind.Immediate) {
|
||||
return this._activateByEvent(activationEvent, false);
|
||||
}
|
||||
|
||||
return (
|
||||
this._readyToRunExtensions.wait()
|
||||
.then(_ => this._activateByEvent(activationEvent, false))
|
||||
|
||||
@@ -8,12 +8,11 @@ import { IRelativePattern, parse } from 'vs/base/common/glob';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import type * as vscode from 'vscode';
|
||||
import { ExtHostFileSystemEventServiceShape, FileSystemEvents, IMainContext, MainContext, MainThreadTextEditorsShape, IWorkspaceFileEditDto, IWorkspaceTextEditDto, SourceTargetPair } from './extHost.protocol';
|
||||
import { ExtHostFileSystemEventServiceShape, FileSystemEvents, IMainContext, MainContext, MainThreadTextEditorsShape, SourceTargetPair, IWorkspaceEditDto } from './extHost.protocol';
|
||||
import * as typeConverter from './extHostTypeConverters';
|
||||
import { Disposable, WorkspaceEdit } from './extHostTypes';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { FileOperation } from 'vs/platform/files/common/files';
|
||||
import { flatten } from 'vs/base/common/arrays';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
|
||||
@@ -217,14 +216,13 @@ export class ExtHostFileSystemEventService implements ExtHostFileSystemEventServ
|
||||
}
|
||||
|
||||
if (edits.length > 0) {
|
||||
// flatten all WorkspaceEdits collected via waitUntil-call
|
||||
// and apply them in one go.
|
||||
const allEdits = new Array<Array<IWorkspaceFileEditDto | IWorkspaceTextEditDto>>();
|
||||
// concat all WorkspaceEdits collected via waitUntil-call and apply them in one go.
|
||||
const dto: IWorkspaceEditDto = { edits: [] };
|
||||
for (let edit of edits) {
|
||||
let { edits } = typeConverter.WorkspaceEdit.from(edit, this._extHostDocumentsAndEditors);
|
||||
allEdits.push(edits);
|
||||
dto.edits = dto.edits.concat(edits);
|
||||
}
|
||||
return this._mainThreadTextEditors.$tryApplyWorkspaceEdit({ edits: flatten(allEdits) });
|
||||
return this._mainThreadTextEditors.$tryApplyWorkspaceEdit(dto);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1120,7 +1120,7 @@ class ColorProviderAdapter {
|
||||
provideColors(resource: URI, token: CancellationToken): Promise<extHostProtocol.IRawColorInfo[]> {
|
||||
const doc = this._documents.getDocument(resource);
|
||||
return asPromise(() => this._provider.provideDocumentColors(doc, token)).then(colors => {
|
||||
if (!Array.isArray<vscode.ColorInformation>(colors)) {
|
||||
if (!Array.isArray(colors)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -516,6 +516,7 @@ class ExtHostSourceControl implements vscode.SourceControl {
|
||||
}
|
||||
|
||||
this._proxy.$registerGroups(this.handle, groups, splices);
|
||||
this.createdResourceGroups.clear();
|
||||
}
|
||||
|
||||
@debounce(100)
|
||||
|
||||
@@ -269,8 +269,8 @@ export namespace TaskDTO {
|
||||
presentationOptions: TaskPresentationOptionsDTO.from(value.presentationOptions),
|
||||
problemMatchers: value.problemMatchers,
|
||||
hasDefinedMatchers: (value as types.Task).hasDefinedMatchers,
|
||||
runOptions: (<vscode.Task>value).runOptions ? (<vscode.Task>value).runOptions : { reevaluateOnRerun: true },
|
||||
detail: (<vscode.Task2>value).detail
|
||||
runOptions: value.runOptions ? value.runOptions : { reevaluateOnRerun: true },
|
||||
detail: value.detail
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -339,6 +339,7 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
|
||||
public get onDidWriteTerminalData(): Event<vscode.TerminalDataWriteEvent> { return this._onDidWriteTerminalData && this._onDidWriteTerminalData.event; }
|
||||
|
||||
constructor(
|
||||
supportsProcesses: boolean,
|
||||
@IExtHostRpcService extHostRpc: IExtHostRpcService
|
||||
) {
|
||||
this._proxy = extHostRpc.getProxy(MainContext.MainThreadTerminalService);
|
||||
@@ -347,6 +348,7 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
|
||||
onFirstListenerAdd: () => this._proxy.$startSendingDataEvents(),
|
||||
onLastListenerRemove: () => this._proxy.$stopSendingDataEvents()
|
||||
});
|
||||
this._proxy.$registerProcessSupport(supportsProcesses);
|
||||
}
|
||||
|
||||
public abstract createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal;
|
||||
@@ -805,6 +807,12 @@ export class EnvironmentVariableCollection implements vscode.EnvironmentVariable
|
||||
}
|
||||
|
||||
export class WorkerExtHostTerminalService extends BaseExtHostTerminalService {
|
||||
constructor(
|
||||
@IExtHostRpcService extHostRpc: IExtHostRpcService
|
||||
) {
|
||||
super(false, extHostRpc);
|
||||
}
|
||||
|
||||
public createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal {
|
||||
throw new NotSupportedError();
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { Emitter, Event } from 'vs/base/common/event';
|
||||
import * as arrays from 'vs/base/common/arrays';
|
||||
import { ExtHostEditorsShape, IEditorPropertiesChangeData, IMainContext, ITextDocumentShowOptions, ITextEditorPositionData, MainContext, MainThreadTextEditorsShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
|
||||
import { ExtHostTextEditor, TextEditorDecorationType } from 'vs/workbench/api/common/extHostTextEditor';
|
||||
import * as TypeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { TextEditorSelectionChangeKind } from 'vs/workbench/api/common/extHostTypes';
|
||||
@@ -28,16 +29,15 @@ export class ExtHostEditors implements ExtHostEditorsShape {
|
||||
readonly onDidChangeActiveTextEditor: Event<vscode.TextEditor | undefined> = this._onDidChangeActiveTextEditor.event;
|
||||
readonly onDidChangeVisibleTextEditors: Event<vscode.TextEditor[]> = this._onDidChangeVisibleTextEditors.event;
|
||||
|
||||
|
||||
private _proxy: MainThreadTextEditorsShape;
|
||||
private _extHostDocumentsAndEditors: ExtHostDocumentsAndEditors;
|
||||
private readonly _proxy: MainThreadTextEditorsShape;
|
||||
|
||||
constructor(
|
||||
mainContext: IMainContext,
|
||||
extHostDocumentsAndEditors: ExtHostDocumentsAndEditors,
|
||||
private readonly _extHostDocumentsAndEditors: ExtHostDocumentsAndEditors,
|
||||
private readonly _extHostNotebooks: ExtHostNotebookController,
|
||||
) {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadTextEditors);
|
||||
this._extHostDocumentsAndEditors = extHostDocumentsAndEditors;
|
||||
|
||||
|
||||
this._extHostDocumentsAndEditors.onDidChangeVisibleTextEditors(e => this._onDidChangeVisibleTextEditors.fire(e));
|
||||
this._extHostDocumentsAndEditors.onDidChangeActiveTextEditor(e => this._onDidChangeActiveTextEditor.fire(e));
|
||||
@@ -93,7 +93,7 @@ export class ExtHostEditors implements ExtHostEditorsShape {
|
||||
}
|
||||
|
||||
applyWorkspaceEdit(edit: vscode.WorkspaceEdit): Promise<boolean> {
|
||||
const dto = TypeConverters.WorkspaceEdit.from(edit, this._extHostDocumentsAndEditors);
|
||||
const dto = TypeConverters.WorkspaceEdit.from(edit, this._extHostDocumentsAndEditors, this._extHostNotebooks);
|
||||
return this._proxy.$tryApplyWorkspaceEdit(dto);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ import { LogLevel as _MainLogLevel } from 'vs/platform/log/common/log';
|
||||
import { coalesce, isNonEmptyArray } from 'vs/base/common/arrays';
|
||||
import { RenderLineNumbersType } from 'vs/editor/common/config/editorOptions';
|
||||
import { CommandsConverter } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
|
||||
|
||||
export interface PositionLike {
|
||||
line: number;
|
||||
@@ -505,32 +506,42 @@ export namespace TextEdit {
|
||||
}
|
||||
|
||||
export namespace WorkspaceEdit {
|
||||
export function from(value: vscode.WorkspaceEdit, documents?: ExtHostDocumentsAndEditors): extHostProtocol.IWorkspaceEditDto {
|
||||
export function from(value: vscode.WorkspaceEdit, documents?: ExtHostDocumentsAndEditors, notebooks?: ExtHostNotebookController): extHostProtocol.IWorkspaceEditDto {
|
||||
const result: extHostProtocol.IWorkspaceEditDto = {
|
||||
edits: []
|
||||
};
|
||||
|
||||
if (value instanceof types.WorkspaceEdit) {
|
||||
for (let entry of value.allEntries()) {
|
||||
for (let entry of value._allEntries()) {
|
||||
|
||||
if (entry._type === 1) {
|
||||
if (entry._type === types.FileEditType.File) {
|
||||
// file operation
|
||||
result.edits.push(<extHostProtocol.IWorkspaceFileEditDto>{
|
||||
_type: extHostProtocol.WorkspaceEditType.File,
|
||||
oldUri: entry.from,
|
||||
newUri: entry.to,
|
||||
options: entry.options,
|
||||
metadata: entry.metadata
|
||||
});
|
||||
|
||||
} else {
|
||||
} else if (entry._type === types.FileEditType.Text) {
|
||||
// text edits
|
||||
const doc = documents?.getDocument(entry.uri);
|
||||
result.edits.push(<extHostProtocol.IWorkspaceTextEditDto>{
|
||||
_type: extHostProtocol.WorkspaceEditType.Text,
|
||||
resource: entry.uri,
|
||||
edit: TextEdit.from(entry.edit),
|
||||
modelVersionId: doc?.version,
|
||||
metadata: entry.metadata
|
||||
});
|
||||
} else if (entry._type === types.FileEditType.Cell) {
|
||||
result.edits.push(<extHostProtocol.IWorkspaceCellEditDto>{
|
||||
_type: extHostProtocol.WorkspaceEditType.Cell,
|
||||
resource: entry.uri,
|
||||
edit: entry.edit,
|
||||
metadata: entry.metadata,
|
||||
modelVersionId: notebooks?.lookupNotebookDocument(entry.uri)?.notebookDocument.version
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1281,3 +1292,58 @@ export namespace LogLevel {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export namespace NotebookExclusiveDocumentPattern {
|
||||
export function from(pattern: { include: vscode.GlobPattern | undefined, exclude: vscode.GlobPattern | undefined }): { include: string | types.RelativePattern | undefined, exclude: string | types.RelativePattern | undefined };
|
||||
export function from(pattern: vscode.GlobPattern): string | types.RelativePattern;
|
||||
export function from(pattern: undefined): undefined;
|
||||
export function from(pattern: { include: vscode.GlobPattern | undefined | null, exclude: vscode.GlobPattern | undefined } | vscode.GlobPattern | undefined): string | types.RelativePattern | { include: string | types.RelativePattern | undefined, exclude: string | types.RelativePattern | undefined } | undefined;
|
||||
export function from(pattern: { include: vscode.GlobPattern | undefined | null, exclude: vscode.GlobPattern | undefined } | vscode.GlobPattern | undefined): string | types.RelativePattern | { include: string | types.RelativePattern | undefined, exclude: string | types.RelativePattern | undefined } | undefined {
|
||||
if (pattern === null || pattern === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (pattern instanceof types.RelativePattern) {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
if (typeof pattern === 'string') {
|
||||
return pattern;
|
||||
}
|
||||
|
||||
|
||||
if (isRelativePattern(pattern)) {
|
||||
return new types.RelativePattern(pattern.base, pattern.pattern);
|
||||
}
|
||||
|
||||
if (isExclusivePattern(pattern)) {
|
||||
return {
|
||||
include: GlobPattern.from(pattern.include) || undefined,
|
||||
exclude: GlobPattern.from(pattern.exclude) || undefined
|
||||
};
|
||||
}
|
||||
|
||||
return undefined; // preserve `undefined`
|
||||
|
||||
}
|
||||
|
||||
function isExclusivePattern(obj: any): obj is { include: types.RelativePattern | undefined | null, exclude: types.RelativePattern | undefined | null } {
|
||||
const ep = obj as { include: vscode.GlobPattern, exclude: vscode.GlobPattern };
|
||||
const include = GlobPattern.from(ep.include);
|
||||
if (!(include && include instanceof types.RelativePattern || typeof include === 'string')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const exclude = GlobPattern.from(ep.exclude);
|
||||
if (!(exclude && exclude instanceof types.RelativePattern || typeof exclude === 'string')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function isRelativePattern(obj: any): obj is vscode.RelativePattern {
|
||||
const rp = obj as vscode.RelativePattern;
|
||||
return rp && typeof rp.base === 'string' && typeof rp.pattern === 'string';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,17 +3,19 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { coalesce, equals } from 'vs/base/common/arrays';
|
||||
import { coalesceInPlace, equals } from 'vs/base/common/arrays';
|
||||
import { escapeCodicons } from 'vs/base/common/codicons';
|
||||
import { illegalArgument } from 'vs/base/common/errors';
|
||||
import { IRelativePattern } from 'vs/base/common/glob';
|
||||
import { isMarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { ResourceMap } from 'vs/base/common/map';
|
||||
import { startsWith } from 'vs/base/common/strings';
|
||||
import { isStringArray } from 'vs/base/common/types';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { FileSystemProviderErrorCode, markAsFileSystemProviderError } from 'vs/platform/files/common/files';
|
||||
import { RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { addIdToOutput, CellEditType, ICellEditOperation } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import type * as vscode from 'vscode';
|
||||
|
||||
function es5ClassCompat(target: Function): any {
|
||||
@@ -575,8 +577,14 @@ export interface IFileOperationOptions {
|
||||
recursive?: boolean;
|
||||
}
|
||||
|
||||
export const enum FileEditType {
|
||||
File = 1,
|
||||
Text = 2,
|
||||
Cell = 3
|
||||
}
|
||||
|
||||
export interface IFileOperation {
|
||||
_type: 1;
|
||||
_type: FileEditType.File;
|
||||
from?: URI;
|
||||
to?: URI;
|
||||
options?: IFileOperationOptions;
|
||||
@@ -584,31 +592,61 @@ export interface IFileOperation {
|
||||
}
|
||||
|
||||
export interface IFileTextEdit {
|
||||
_type: 2;
|
||||
_type: FileEditType.Text;
|
||||
uri: URI;
|
||||
edit: TextEdit;
|
||||
metadata?: vscode.WorkspaceEditEntryMetadata;
|
||||
}
|
||||
|
||||
export interface IFileCellEdit {
|
||||
_type: FileEditType.Cell;
|
||||
uri: URI;
|
||||
edit: ICellEditOperation;
|
||||
metadata?: vscode.WorkspaceEditEntryMetadata;
|
||||
}
|
||||
|
||||
@es5ClassCompat
|
||||
export class WorkspaceEdit implements vscode.WorkspaceEdit {
|
||||
|
||||
private _edits = new Array<IFileOperation | IFileTextEdit>();
|
||||
private readonly _edits = new Array<IFileOperation | IFileTextEdit | IFileCellEdit>();
|
||||
|
||||
|
||||
_allEntries(): ReadonlyArray<IFileTextEdit | IFileOperation | IFileCellEdit> {
|
||||
return this._edits;
|
||||
}
|
||||
|
||||
// --- file
|
||||
|
||||
renameFile(from: vscode.Uri, to: vscode.Uri, options?: { overwrite?: boolean, ignoreIfExists?: boolean; }, metadata?: vscode.WorkspaceEditEntryMetadata): void {
|
||||
this._edits.push({ _type: 1, from, to, options, metadata });
|
||||
this._edits.push({ _type: FileEditType.File, from, to, options, metadata });
|
||||
}
|
||||
|
||||
createFile(uri: vscode.Uri, options?: { overwrite?: boolean, ignoreIfExists?: boolean; }, metadata?: vscode.WorkspaceEditEntryMetadata): void {
|
||||
this._edits.push({ _type: 1, from: undefined, to: uri, options, metadata });
|
||||
this._edits.push({ _type: FileEditType.File, from: undefined, to: uri, options, metadata });
|
||||
}
|
||||
|
||||
deleteFile(uri: vscode.Uri, options?: { recursive?: boolean, ignoreIfNotExists?: boolean; }, metadata?: vscode.WorkspaceEditEntryMetadata): void {
|
||||
this._edits.push({ _type: 1, from: uri, to: undefined, options, metadata });
|
||||
this._edits.push({ _type: FileEditType.File, from: uri, to: undefined, options, metadata });
|
||||
}
|
||||
|
||||
// --- cell
|
||||
|
||||
replaceCells(uri: URI, start: number, end: number, cells: vscode.NotebookCellData[], metadata?: vscode.WorkspaceEditEntryMetadata): void {
|
||||
this._edits.push({ _type: FileEditType.Cell, metadata, uri, edit: { editType: CellEditType.Replace, index: start, count: end - start, cells: cells.map(cell => ({ ...cell, outputs: cell.outputs.map(output => addIdToOutput(output)) })) } });
|
||||
}
|
||||
|
||||
replaceCellOutput(uri: URI, index: number, outputs: vscode.CellOutput[], metadata?: vscode.WorkspaceEditEntryMetadata): void {
|
||||
this._edits.push({ _type: FileEditType.Cell, metadata, uri, edit: { editType: CellEditType.Output, index, outputs: outputs.map(output => addIdToOutput(output)) } });
|
||||
}
|
||||
|
||||
replaceCellMetadata(uri: URI, index: number, cellMetadata: vscode.NotebookCellMetadata, metadata?: vscode.WorkspaceEditEntryMetadata): void {
|
||||
this._edits.push({ _type: FileEditType.Cell, metadata, uri, edit: { editType: CellEditType.Metadata, index, metadata: cellMetadata } });
|
||||
}
|
||||
|
||||
// --- text
|
||||
|
||||
replace(uri: URI, range: Range, newText: string, metadata?: vscode.WorkspaceEditEntryMetadata): void {
|
||||
this._edits.push({ _type: 2, uri, edit: new TextEdit(range, newText), metadata });
|
||||
this._edits.push({ _type: FileEditType.Text, uri, edit: new TextEdit(range, newText), metadata });
|
||||
}
|
||||
|
||||
insert(resource: URI, position: Position, newText: string, metadata?: vscode.WorkspaceEditEntryMetadata): void {
|
||||
@@ -619,8 +657,10 @@ export class WorkspaceEdit implements vscode.WorkspaceEdit {
|
||||
this.replace(resource, range, '', metadata);
|
||||
}
|
||||
|
||||
// --- text (Maplike)
|
||||
|
||||
has(uri: URI): boolean {
|
||||
return this._edits.some(edit => edit._type === 2 && edit.uri.toString() === uri.toString());
|
||||
return this._edits.some(edit => edit._type === FileEditType.Text && edit.uri.toString() === uri.toString());
|
||||
}
|
||||
|
||||
set(uri: URI, edits: TextEdit[]): void {
|
||||
@@ -628,16 +668,16 @@ export class WorkspaceEdit implements vscode.WorkspaceEdit {
|
||||
// remove all text edits for `uri`
|
||||
for (let i = 0; i < this._edits.length; i++) {
|
||||
const element = this._edits[i];
|
||||
if (element._type === 2 && element.uri.toString() === uri.toString()) {
|
||||
if (element._type === FileEditType.Text && element.uri.toString() === uri.toString()) {
|
||||
this._edits[i] = undefined!; // will be coalesced down below
|
||||
}
|
||||
}
|
||||
this._edits = coalesce(this._edits);
|
||||
coalesceInPlace(this._edits);
|
||||
} else {
|
||||
// append edit to the end
|
||||
for (const edit of edits) {
|
||||
if (edit) {
|
||||
this._edits.push({ _type: 2, uri, edit });
|
||||
this._edits.push({ _type: FileEditType.Text, uri, edit });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -646,7 +686,7 @@ export class WorkspaceEdit implements vscode.WorkspaceEdit {
|
||||
get(uri: URI): TextEdit[] {
|
||||
const res: TextEdit[] = [];
|
||||
for (let candidate of this._edits) {
|
||||
if (candidate._type === 2 && candidate.uri.toString() === uri.toString()) {
|
||||
if (candidate._type === FileEditType.Text && candidate.uri.toString() === uri.toString()) {
|
||||
res.push(candidate.edit);
|
||||
}
|
||||
}
|
||||
@@ -654,13 +694,13 @@ export class WorkspaceEdit implements vscode.WorkspaceEdit {
|
||||
}
|
||||
|
||||
entries(): [URI, TextEdit[]][] {
|
||||
const textEdits = new Map<string, [URI, TextEdit[]]>();
|
||||
const textEdits = new ResourceMap<[URI, TextEdit[]]>();
|
||||
for (let candidate of this._edits) {
|
||||
if (candidate._type === 2) {
|
||||
let textEdit = textEdits.get(candidate.uri.toString());
|
||||
if (candidate._type === FileEditType.Text) {
|
||||
let textEdit = textEdits.get(candidate.uri);
|
||||
if (!textEdit) {
|
||||
textEdit = [candidate.uri, []];
|
||||
textEdits.set(candidate.uri.toString(), textEdit);
|
||||
textEdits.set(candidate.uri, textEdit);
|
||||
}
|
||||
textEdit[1].push(candidate.edit);
|
||||
}
|
||||
@@ -668,22 +708,6 @@ export class WorkspaceEdit implements vscode.WorkspaceEdit {
|
||||
return [...textEdits.values()];
|
||||
}
|
||||
|
||||
allEntries(): ReadonlyArray<IFileTextEdit | IFileOperation> {
|
||||
return this._edits;
|
||||
}
|
||||
|
||||
// _allEntries(): ([URI, TextEdit] | [URI?, URI?, IFileOperationOptions?])[] {
|
||||
// const res: ([URI, TextEdit] | [URI?, URI?, IFileOperationOptions?])[] = [];
|
||||
// for (let edit of this._edits) {
|
||||
// if (edit._type === 1) {
|
||||
// res.push([edit.from, edit.to, edit.options]);
|
||||
// } else {
|
||||
// res.push([edit.uri, edit.edit]);
|
||||
// }
|
||||
// }
|
||||
// return res;
|
||||
// }
|
||||
|
||||
get size(): number {
|
||||
return this.entries().length;
|
||||
}
|
||||
@@ -1850,7 +1874,7 @@ export class CustomExecution implements vscode.CustomExecution {
|
||||
}
|
||||
|
||||
@es5ClassCompat
|
||||
export class Task implements vscode.Task2 {
|
||||
export class Task implements vscode.Task {
|
||||
|
||||
private static ExtensionCallbackType: string = 'customExecution';
|
||||
private static ProcessType: string = 'process';
|
||||
@@ -2756,6 +2780,18 @@ export enum NotebookRunState {
|
||||
Idle = 2
|
||||
}
|
||||
|
||||
export enum NotebookCellStatusBarAlignment {
|
||||
Left = 1,
|
||||
Right = 2
|
||||
}
|
||||
|
||||
export enum NotebookEditorRevealType {
|
||||
Default = 0,
|
||||
InCenter = 1,
|
||||
InCenterIfOutsideViewport = 2
|
||||
}
|
||||
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Timeline
|
||||
|
||||
@@ -4,14 +4,11 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IExtHostApiDeprecationService } from 'vs/workbench/api/common/extHostApiDeprecationService';
|
||||
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import { asWebviewUri, WebviewInitData } from 'vs/workbench/api/common/shared/webview';
|
||||
import type * as vscode from 'vscode';
|
||||
@@ -19,7 +16,7 @@ import * as extHostProtocol from './extHost.protocol';
|
||||
|
||||
export class ExtHostWebview implements vscode.Webview {
|
||||
|
||||
readonly #handle: extHostProtocol.WebviewPanelHandle;
|
||||
readonly #handle: extHostProtocol.WebviewHandle;
|
||||
readonly #proxy: extHostProtocol.MainThreadWebviewsShape;
|
||||
readonly #deprecationService: IExtHostApiDeprecationService;
|
||||
|
||||
@@ -33,7 +30,7 @@ export class ExtHostWebview implements vscode.Webview {
|
||||
#hasCalledAsWebviewUri = false;
|
||||
|
||||
constructor(
|
||||
handle: extHostProtocol.WebviewPanelHandle,
|
||||
handle: extHostProtocol.WebviewHandle,
|
||||
proxy: extHostProtocol.MainThreadWebviewsShape,
|
||||
options: vscode.WebviewOptions,
|
||||
initData: WebviewInitData,
|
||||
@@ -114,169 +111,11 @@ export class ExtHostWebview implements vscode.Webview {
|
||||
}
|
||||
}
|
||||
|
||||
type IconPath = URI | { light: URI, dark: URI };
|
||||
|
||||
|
||||
class ExtHostWebviewPanel extends Disposable implements vscode.WebviewPanel {
|
||||
|
||||
readonly #handle: extHostProtocol.WebviewPanelHandle;
|
||||
readonly #proxy: extHostProtocol.MainThreadWebviewsShape;
|
||||
readonly #viewType: string;
|
||||
|
||||
readonly #webview: ExtHostWebview;
|
||||
readonly #options: vscode.WebviewPanelOptions;
|
||||
|
||||
#title: string;
|
||||
#iconPath?: IconPath;
|
||||
#viewColumn: vscode.ViewColumn | undefined = undefined;
|
||||
#visible: boolean = true;
|
||||
#active: boolean = true;
|
||||
#isDisposed: boolean = false;
|
||||
|
||||
readonly #onDidDispose = this._register(new Emitter<void>());
|
||||
public readonly onDidDispose = this.#onDidDispose.event;
|
||||
|
||||
readonly #onDidChangeViewState = this._register(new Emitter<vscode.WebviewPanelOnDidChangeViewStateEvent>());
|
||||
public readonly onDidChangeViewState = this.#onDidChangeViewState.event;
|
||||
|
||||
constructor(
|
||||
handle: extHostProtocol.WebviewPanelHandle,
|
||||
proxy: extHostProtocol.MainThreadWebviewsShape,
|
||||
viewType: string,
|
||||
title: string,
|
||||
viewColumn: vscode.ViewColumn | undefined,
|
||||
editorOptions: vscode.WebviewPanelOptions,
|
||||
webview: ExtHostWebview
|
||||
) {
|
||||
super();
|
||||
this.#handle = handle;
|
||||
this.#proxy = proxy;
|
||||
this.#viewType = viewType;
|
||||
this.#options = editorOptions;
|
||||
this.#viewColumn = viewColumn;
|
||||
this.#title = title;
|
||||
this.#webview = webview;
|
||||
}
|
||||
|
||||
public dispose() {
|
||||
if (this.#isDisposed) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.#isDisposed = true;
|
||||
this.#onDidDispose.fire();
|
||||
|
||||
this.#proxy.$disposeWebview(this.#handle);
|
||||
this.#webview.dispose();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
get webview() {
|
||||
this.assertNotDisposed();
|
||||
return this.#webview;
|
||||
}
|
||||
|
||||
get viewType(): string {
|
||||
this.assertNotDisposed();
|
||||
return this.#viewType;
|
||||
}
|
||||
|
||||
get title(): string {
|
||||
this.assertNotDisposed();
|
||||
return this.#title;
|
||||
}
|
||||
|
||||
set title(value: string) {
|
||||
this.assertNotDisposed();
|
||||
if (this.#title !== value) {
|
||||
this.#title = value;
|
||||
this.#proxy.$setTitle(this.#handle, value);
|
||||
}
|
||||
}
|
||||
|
||||
get iconPath(): IconPath | undefined {
|
||||
this.assertNotDisposed();
|
||||
return this.#iconPath;
|
||||
}
|
||||
|
||||
set iconPath(value: IconPath | undefined) {
|
||||
this.assertNotDisposed();
|
||||
if (this.#iconPath !== value) {
|
||||
this.#iconPath = value;
|
||||
|
||||
this.#proxy.$setIconPath(this.#handle, URI.isUri(value) ? { light: value, dark: value } : value);
|
||||
}
|
||||
}
|
||||
|
||||
get options() {
|
||||
return this.#options;
|
||||
}
|
||||
|
||||
get viewColumn(): vscode.ViewColumn | undefined {
|
||||
this.assertNotDisposed();
|
||||
if (typeof this.#viewColumn === 'number' && this.#viewColumn < 0) {
|
||||
// We are using a symbolic view column
|
||||
// Return undefined instead to indicate that the real view column is currently unknown but will be resolved.
|
||||
return undefined;
|
||||
}
|
||||
return this.#viewColumn;
|
||||
}
|
||||
|
||||
public get active(): boolean {
|
||||
this.assertNotDisposed();
|
||||
return this.#active;
|
||||
}
|
||||
|
||||
public get visible(): boolean {
|
||||
this.assertNotDisposed();
|
||||
return this.#visible;
|
||||
}
|
||||
|
||||
_updateViewState(newState: { active: boolean; visible: boolean; viewColumn: vscode.ViewColumn; }) {
|
||||
if (this.#isDisposed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.active !== newState.active || this.visible !== newState.visible || this.viewColumn !== newState.viewColumn) {
|
||||
this.#active = newState.active;
|
||||
this.#visible = newState.visible;
|
||||
this.#viewColumn = newState.viewColumn;
|
||||
this.#onDidChangeViewState.fire({ webviewPanel: this });
|
||||
}
|
||||
}
|
||||
|
||||
public postMessage(message: any): Promise<boolean> {
|
||||
this.assertNotDisposed();
|
||||
return this.#proxy.$postMessage(this.#handle, message);
|
||||
}
|
||||
|
||||
public reveal(viewColumn?: vscode.ViewColumn, preserveFocus?: boolean): void {
|
||||
this.assertNotDisposed();
|
||||
this.#proxy.$reveal(this.#handle, {
|
||||
viewColumn: viewColumn ? typeConverters.ViewColumn.from(viewColumn) : undefined,
|
||||
preserveFocus: !!preserveFocus
|
||||
});
|
||||
}
|
||||
|
||||
private assertNotDisposed() {
|
||||
if (this.#isDisposed) {
|
||||
throw new Error('Webview is disposed');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostWebviews implements extHostProtocol.ExtHostWebviewsShape {
|
||||
|
||||
private static newHandle(): extHostProtocol.WebviewPanelHandle {
|
||||
return generateUuid();
|
||||
}
|
||||
|
||||
private readonly _proxy: extHostProtocol.MainThreadWebviewsShape;
|
||||
|
||||
private readonly _webviews = new Map<extHostProtocol.WebviewPanelHandle, ExtHostWebview>();
|
||||
private readonly _webviewPanels = new Map<extHostProtocol.WebviewPanelHandle, ExtHostWebviewPanel>();
|
||||
private readonly _webviewProxy: extHostProtocol.MainThreadWebviewsShape;
|
||||
|
||||
private readonly _webviews = new Map<extHostProtocol.WebviewHandle, ExtHostWebview>();
|
||||
|
||||
constructor(
|
||||
mainContext: extHostProtocol.IMainContext,
|
||||
@@ -285,33 +124,11 @@ export class ExtHostWebviews implements extHostProtocol.ExtHostWebviewsShape {
|
||||
private readonly _logService: ILogService,
|
||||
private readonly _deprecationService: IExtHostApiDeprecationService,
|
||||
) {
|
||||
this._proxy = mainContext.getProxy(extHostProtocol.MainContext.MainThreadWebviews);
|
||||
}
|
||||
|
||||
public createWebviewPanel(
|
||||
extension: IExtensionDescription,
|
||||
viewType: string,
|
||||
title: string,
|
||||
showOptions: vscode.ViewColumn | { viewColumn: vscode.ViewColumn, preserveFocus?: boolean },
|
||||
options: (vscode.WebviewPanelOptions & vscode.WebviewOptions) = {},
|
||||
): vscode.WebviewPanel {
|
||||
const viewColumn = typeof showOptions === 'object' ? showOptions.viewColumn : showOptions;
|
||||
const webviewShowOptions = {
|
||||
viewColumn: typeConverters.ViewColumn.from(viewColumn),
|
||||
preserveFocus: typeof showOptions === 'object' && !!showOptions.preserveFocus
|
||||
};
|
||||
|
||||
const handle = ExtHostWebviews.newHandle();
|
||||
this._proxy.$createWebviewPanel(toExtensionData(extension), handle, viewType, title, webviewShowOptions, convertWebviewOptions(extension, this.workspace, options));
|
||||
|
||||
const webview = this.createNewWebview(handle, options, extension);
|
||||
const panel = this.createNewWebviewPanel(handle, viewType, title, viewColumn, options, webview);
|
||||
|
||||
return panel;
|
||||
this._webviewProxy = mainContext.getProxy(extHostProtocol.MainContext.MainThreadWebviews);
|
||||
}
|
||||
|
||||
public $onMessage(
|
||||
handle: extHostProtocol.WebviewPanelHandle,
|
||||
handle: extHostProtocol.WebviewHandle,
|
||||
message: any
|
||||
): void {
|
||||
const webview = this.getWebview(handle);
|
||||
@@ -321,61 +138,14 @@ export class ExtHostWebviews implements extHostProtocol.ExtHostWebviewsShape {
|
||||
}
|
||||
|
||||
public $onMissingCsp(
|
||||
_handle: extHostProtocol.WebviewPanelHandle,
|
||||
_handle: extHostProtocol.WebviewHandle,
|
||||
extensionId: string
|
||||
): void {
|
||||
this._logService.warn(`${extensionId} created a webview without a content security policy: https://aka.ms/vscode-webview-missing-csp`);
|
||||
}
|
||||
|
||||
public $onDidChangeWebviewPanelViewStates(newStates: extHostProtocol.WebviewPanelViewStateData): void {
|
||||
const handles = Object.keys(newStates);
|
||||
// Notify webviews of state changes in the following order:
|
||||
// - Non-visible
|
||||
// - Visible
|
||||
// - Active
|
||||
handles.sort((a, b) => {
|
||||
const stateA = newStates[a];
|
||||
const stateB = newStates[b];
|
||||
if (stateA.active) {
|
||||
return 1;
|
||||
}
|
||||
if (stateB.active) {
|
||||
return -1;
|
||||
}
|
||||
return (+stateA.visible) - (+stateB.visible);
|
||||
});
|
||||
|
||||
for (const handle of handles) {
|
||||
const panel = this.getWebviewPanel(handle);
|
||||
if (!panel) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const newState = newStates[handle];
|
||||
panel._updateViewState({
|
||||
active: newState.active,
|
||||
visible: newState.visible,
|
||||
viewColumn: typeConverters.ViewColumn.to(newState.position),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async $onDidDisposeWebviewPanel(handle: extHostProtocol.WebviewPanelHandle): Promise<void> {
|
||||
const panel = this.getWebviewPanel(handle);
|
||||
panel?.dispose();
|
||||
|
||||
this._webviewPanels.delete(handle);
|
||||
this._webviews.delete(handle);
|
||||
}
|
||||
|
||||
public createNewWebviewPanel(webviewHandle: string, viewType: string, title: string, position: number, options: modes.IWebviewOptions & modes.IWebviewPanelOptions, webview: ExtHostWebview) {
|
||||
const panel = new ExtHostWebviewPanel(webviewHandle, this._proxy, viewType, title, typeof position === 'number' && position >= 0 ? typeConverters.ViewColumn.to(position) : undefined, options, webview);
|
||||
this._webviewPanels.set(webviewHandle, panel);
|
||||
return panel;
|
||||
}
|
||||
|
||||
public createNewWebview(handle: string, options: modes.IWebviewOptions & modes.IWebviewPanelOptions, extension: IExtensionDescription): ExtHostWebview {
|
||||
const webview = new ExtHostWebview(handle, this._proxy, reviveOptions(options), this.initData, this.workspace, extension, this._deprecationService);
|
||||
const webview = new ExtHostWebview(handle, this._webviewProxy, reviveOptions(options), this.initData, this.workspace, extension, this._deprecationService);
|
||||
this._webviews.set(handle, webview);
|
||||
|
||||
webview._onDidDispose(() => { this._webviews.delete(handle); });
|
||||
@@ -383,12 +153,12 @@ export class ExtHostWebviews implements extHostProtocol.ExtHostWebviewsShape {
|
||||
return webview;
|
||||
}
|
||||
|
||||
private getWebview(handle: extHostProtocol.WebviewPanelHandle): ExtHostWebview | undefined {
|
||||
return this._webviews.get(handle);
|
||||
public deleteWebview(handle: string) {
|
||||
this._webviews.delete(handle);
|
||||
}
|
||||
|
||||
public getWebviewPanel(handle: extHostProtocol.WebviewPanelHandle): ExtHostWebviewPanel | undefined {
|
||||
return this._webviewPanels.get(handle);
|
||||
private getWebview(handle: extHostProtocol.WebviewHandle): ExtHostWebview | undefined {
|
||||
return this._webviews.get(handle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -396,7 +166,7 @@ export function toExtensionData(extension: IExtensionDescription): extHostProtoc
|
||||
return { id: extension.identifier, location: extension.extensionLocation };
|
||||
}
|
||||
|
||||
function convertWebviewOptions(
|
||||
export function convertWebviewOptions(
|
||||
extension: IExtensionDescription,
|
||||
workspace: IExtHostWorkspace | undefined,
|
||||
options: vscode.WebviewPanelOptions & vscode.WebviewOptions,
|
||||
|
||||
299
src/vs/workbench/api/common/extHostWebviewPanels.ts
Normal file
299
src/vs/workbench/api/common/extHostWebviewPanels.ts
Normal file
@@ -0,0 +1,299 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { convertWebviewOptions, ExtHostWebview, ExtHostWebviews, toExtensionData } from 'vs/workbench/api/common/extHostWebview';
|
||||
import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor';
|
||||
import type * as vscode from 'vscode';
|
||||
import * as extHostProtocol from './extHost.protocol';
|
||||
import * as extHostTypes from './extHostTypes';
|
||||
|
||||
|
||||
type IconPath = URI | { light: URI, dark: URI };
|
||||
|
||||
class ExtHostWebviewPanel extends Disposable implements vscode.WebviewPanel {
|
||||
|
||||
readonly #handle: extHostProtocol.WebviewHandle;
|
||||
readonly #proxy: extHostProtocol.MainThreadWebviewPanelsShape;
|
||||
readonly #viewType: string;
|
||||
|
||||
readonly #webview: ExtHostWebview;
|
||||
readonly #options: vscode.WebviewPanelOptions;
|
||||
|
||||
#title: string;
|
||||
#iconPath?: IconPath;
|
||||
#viewColumn: vscode.ViewColumn | undefined = undefined;
|
||||
#visible: boolean = true;
|
||||
#active: boolean = true;
|
||||
#isDisposed: boolean = false;
|
||||
|
||||
readonly #onDidDispose = this._register(new Emitter<void>());
|
||||
public readonly onDidDispose = this.#onDidDispose.event;
|
||||
|
||||
readonly #onDidChangeViewState = this._register(new Emitter<vscode.WebviewPanelOnDidChangeViewStateEvent>());
|
||||
public readonly onDidChangeViewState = this.#onDidChangeViewState.event;
|
||||
|
||||
constructor(
|
||||
handle: extHostProtocol.WebviewHandle,
|
||||
proxy: extHostProtocol.MainThreadWebviewPanelsShape,
|
||||
viewType: string,
|
||||
title: string,
|
||||
viewColumn: vscode.ViewColumn | undefined,
|
||||
editorOptions: vscode.WebviewPanelOptions,
|
||||
webview: ExtHostWebview
|
||||
) {
|
||||
super();
|
||||
this.#handle = handle;
|
||||
this.#proxy = proxy;
|
||||
this.#viewType = viewType;
|
||||
this.#options = editorOptions;
|
||||
this.#viewColumn = viewColumn;
|
||||
this.#title = title;
|
||||
this.#webview = webview;
|
||||
}
|
||||
|
||||
public dispose() {
|
||||
if (this.#isDisposed) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.#isDisposed = true;
|
||||
this.#onDidDispose.fire();
|
||||
|
||||
this.#proxy.$disposeWebview(this.#handle);
|
||||
this.#webview.dispose();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
get webview() {
|
||||
this.assertNotDisposed();
|
||||
return this.#webview;
|
||||
}
|
||||
|
||||
get viewType(): string {
|
||||
this.assertNotDisposed();
|
||||
return this.#viewType;
|
||||
}
|
||||
|
||||
get title(): string {
|
||||
this.assertNotDisposed();
|
||||
return this.#title;
|
||||
}
|
||||
|
||||
set title(value: string) {
|
||||
this.assertNotDisposed();
|
||||
if (this.#title !== value) {
|
||||
this.#title = value;
|
||||
this.#proxy.$setTitle(this.#handle, value);
|
||||
}
|
||||
}
|
||||
|
||||
get iconPath(): IconPath | undefined {
|
||||
this.assertNotDisposed();
|
||||
return this.#iconPath;
|
||||
}
|
||||
|
||||
set iconPath(value: IconPath | undefined) {
|
||||
this.assertNotDisposed();
|
||||
if (this.#iconPath !== value) {
|
||||
this.#iconPath = value;
|
||||
|
||||
this.#proxy.$setIconPath(this.#handle, URI.isUri(value) ? { light: value, dark: value } : value);
|
||||
}
|
||||
}
|
||||
|
||||
get options() {
|
||||
return this.#options;
|
||||
}
|
||||
|
||||
get viewColumn(): vscode.ViewColumn | undefined {
|
||||
this.assertNotDisposed();
|
||||
if (typeof this.#viewColumn === 'number' && this.#viewColumn < 0) {
|
||||
// We are using a symbolic view column
|
||||
// Return undefined instead to indicate that the real view column is currently unknown but will be resolved.
|
||||
return undefined;
|
||||
}
|
||||
return this.#viewColumn;
|
||||
}
|
||||
|
||||
public get active(): boolean {
|
||||
this.assertNotDisposed();
|
||||
return this.#active;
|
||||
}
|
||||
|
||||
public get visible(): boolean {
|
||||
this.assertNotDisposed();
|
||||
return this.#visible;
|
||||
}
|
||||
|
||||
_updateViewState(newState: { active: boolean; visible: boolean; viewColumn: vscode.ViewColumn; }) {
|
||||
if (this.#isDisposed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.active !== newState.active || this.visible !== newState.visible || this.viewColumn !== newState.viewColumn) {
|
||||
this.#active = newState.active;
|
||||
this.#visible = newState.visible;
|
||||
this.#viewColumn = newState.viewColumn;
|
||||
this.#onDidChangeViewState.fire({ webviewPanel: this });
|
||||
}
|
||||
}
|
||||
|
||||
public reveal(viewColumn?: vscode.ViewColumn, preserveFocus?: boolean): void {
|
||||
this.assertNotDisposed();
|
||||
this.#proxy.$reveal(this.#handle, {
|
||||
viewColumn: viewColumn ? typeConverters.ViewColumn.from(viewColumn) : undefined,
|
||||
preserveFocus: !!preserveFocus
|
||||
});
|
||||
}
|
||||
|
||||
private assertNotDisposed() {
|
||||
if (this.#isDisposed) {
|
||||
throw new Error('Webview is disposed');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostWebviewPanels implements extHostProtocol.ExtHostWebviewPanelsShape {
|
||||
|
||||
private static newHandle(): extHostProtocol.WebviewHandle {
|
||||
return generateUuid();
|
||||
}
|
||||
|
||||
private readonly _proxy: extHostProtocol.MainThreadWebviewPanelsShape;
|
||||
|
||||
private readonly _webviewPanels = new Map<extHostProtocol.WebviewHandle, ExtHostWebviewPanel>();
|
||||
|
||||
private readonly _serializers = new Map<string, {
|
||||
readonly serializer: vscode.WebviewPanelSerializer;
|
||||
readonly extension: IExtensionDescription;
|
||||
}>();
|
||||
|
||||
constructor(
|
||||
mainContext: extHostProtocol.IMainContext,
|
||||
private readonly webviews: ExtHostWebviews,
|
||||
private readonly workspace: IExtHostWorkspace | undefined,
|
||||
) {
|
||||
this._proxy = mainContext.getProxy(extHostProtocol.MainContext.MainThreadWebviewPanels);
|
||||
}
|
||||
|
||||
public createWebviewPanel(
|
||||
extension: IExtensionDescription,
|
||||
viewType: string,
|
||||
title: string,
|
||||
showOptions: vscode.ViewColumn | { viewColumn: vscode.ViewColumn, preserveFocus?: boolean },
|
||||
options: (vscode.WebviewPanelOptions & vscode.WebviewOptions) = {},
|
||||
): vscode.WebviewPanel {
|
||||
const viewColumn = typeof showOptions === 'object' ? showOptions.viewColumn : showOptions;
|
||||
const webviewShowOptions = {
|
||||
viewColumn: typeConverters.ViewColumn.from(viewColumn),
|
||||
preserveFocus: typeof showOptions === 'object' && !!showOptions.preserveFocus
|
||||
};
|
||||
|
||||
const handle = ExtHostWebviewPanels.newHandle();
|
||||
this._proxy.$createWebviewPanel(toExtensionData(extension), handle, viewType, title, webviewShowOptions, convertWebviewOptions(extension, this.workspace, options));
|
||||
|
||||
const webview = this.webviews.createNewWebview(handle, options, extension);
|
||||
const panel = this.createNewWebviewPanel(handle, viewType, title, viewColumn, options, webview);
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
public $onDidChangeWebviewPanelViewStates(newStates: extHostProtocol.WebviewPanelViewStateData): void {
|
||||
const handles = Object.keys(newStates);
|
||||
// Notify webviews of state changes in the following order:
|
||||
// - Non-visible
|
||||
// - Visible
|
||||
// - Active
|
||||
handles.sort((a, b) => {
|
||||
const stateA = newStates[a];
|
||||
const stateB = newStates[b];
|
||||
if (stateA.active) {
|
||||
return 1;
|
||||
}
|
||||
if (stateB.active) {
|
||||
return -1;
|
||||
}
|
||||
return (+stateA.visible) - (+stateB.visible);
|
||||
});
|
||||
|
||||
for (const handle of handles) {
|
||||
const panel = this.getWebviewPanel(handle);
|
||||
if (!panel) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const newState = newStates[handle];
|
||||
panel._updateViewState({
|
||||
active: newState.active,
|
||||
visible: newState.visible,
|
||||
viewColumn: typeConverters.ViewColumn.to(newState.position),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async $onDidDisposeWebviewPanel(handle: extHostProtocol.WebviewHandle): Promise<void> {
|
||||
const panel = this.getWebviewPanel(handle);
|
||||
panel?.dispose();
|
||||
|
||||
this._webviewPanels.delete(handle);
|
||||
this.webviews.deleteWebview(handle);
|
||||
}
|
||||
|
||||
public registerWebviewPanelSerializer(
|
||||
extension: IExtensionDescription,
|
||||
viewType: string,
|
||||
serializer: vscode.WebviewPanelSerializer
|
||||
): vscode.Disposable {
|
||||
if (this._serializers.has(viewType)) {
|
||||
throw new Error(`Serializer for '${viewType}' already registered`);
|
||||
}
|
||||
|
||||
this._serializers.set(viewType, { serializer, extension });
|
||||
this._proxy.$registerSerializer(viewType);
|
||||
|
||||
return new extHostTypes.Disposable(() => {
|
||||
this._serializers.delete(viewType);
|
||||
this._proxy.$unregisterSerializer(viewType);
|
||||
});
|
||||
}
|
||||
|
||||
async $deserializeWebviewPanel(
|
||||
webviewHandle: extHostProtocol.WebviewHandle,
|
||||
viewType: string,
|
||||
title: string,
|
||||
state: any,
|
||||
position: EditorViewColumn,
|
||||
options: modes.IWebviewOptions & modes.IWebviewPanelOptions
|
||||
): Promise<void> {
|
||||
const entry = this._serializers.get(viewType);
|
||||
if (!entry) {
|
||||
throw new Error(`No serializer found for '${viewType}'`);
|
||||
}
|
||||
const { serializer, extension } = entry;
|
||||
|
||||
const webview = this.webviews.createNewWebview(webviewHandle, options, extension);
|
||||
const revivedPanel = this.createNewWebviewPanel(webviewHandle, viewType, title, position, options, webview);
|
||||
await serializer.deserializeWebviewPanel(revivedPanel, state);
|
||||
}
|
||||
|
||||
public createNewWebviewPanel(webviewHandle: string, viewType: string, title: string, position: number, options: modes.IWebviewOptions & modes.IWebviewPanelOptions, webview: ExtHostWebview) {
|
||||
const panel = new ExtHostWebviewPanel(webviewHandle, this._proxy, viewType, title, typeof position === 'number' && position >= 0 ? typeConverters.ViewColumn.to(position) : undefined, options, webview);
|
||||
this._webviewPanels.set(webviewHandle, panel);
|
||||
return panel;
|
||||
}
|
||||
|
||||
public getWebviewPanel(handle: extHostProtocol.WebviewHandle): ExtHostWebviewPanel | undefined {
|
||||
return this._webviewPanels.get(handle);
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtHostWebviews } from 'vs/workbench/api/common/extHostWebview';
|
||||
import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor';
|
||||
import type * as vscode from 'vscode';
|
||||
import * as extHostProtocol from './extHost.protocol';
|
||||
import * as extHostTypes from './extHostTypes';
|
||||
|
||||
export class ExtHostWebviewSerializer implements extHostProtocol.ExtHostWebviewSerializerShape {
|
||||
|
||||
private readonly _proxy: extHostProtocol.MainThreadWebviewsShape;
|
||||
|
||||
private readonly _serializers = new Map<string, {
|
||||
readonly serializer: vscode.WebviewPanelSerializer;
|
||||
readonly extension: IExtensionDescription;
|
||||
}>();
|
||||
|
||||
constructor(
|
||||
mainContext: extHostProtocol.IMainContext,
|
||||
private readonly _webviewService: ExtHostWebviews,
|
||||
) {
|
||||
this._proxy = mainContext.getProxy(extHostProtocol.MainContext.MainThreadWebviews);
|
||||
}
|
||||
|
||||
public registerWebviewPanelSerializer(
|
||||
extension: IExtensionDescription,
|
||||
viewType: string,
|
||||
serializer: vscode.WebviewPanelSerializer
|
||||
): vscode.Disposable {
|
||||
if (this._serializers.has(viewType)) {
|
||||
throw new Error(`Serializer for '${viewType}' already registered`);
|
||||
}
|
||||
|
||||
this._serializers.set(viewType, { serializer, extension });
|
||||
this._proxy.$registerSerializer(viewType);
|
||||
|
||||
return new extHostTypes.Disposable(() => {
|
||||
this._serializers.delete(viewType);
|
||||
this._proxy.$unregisterSerializer(viewType);
|
||||
});
|
||||
}
|
||||
|
||||
async $deserializeWebviewPanel(
|
||||
webviewHandle: extHostProtocol.WebviewPanelHandle,
|
||||
viewType: string,
|
||||
title: string,
|
||||
state: any,
|
||||
position: EditorViewColumn,
|
||||
options: modes.IWebviewOptions & modes.IWebviewPanelOptions
|
||||
): Promise<void> {
|
||||
const entry = this._serializers.get(viewType);
|
||||
if (!entry) {
|
||||
throw new Error(`No serializer found for '${viewType}'`);
|
||||
}
|
||||
const { serializer, extension } = entry;
|
||||
|
||||
const webview = this._webviewService.createNewWebview(webviewHandle, options, extension);
|
||||
const revivedPanel = this._webviewService.createNewWebviewPanel(webviewHandle, viewType, title, position, options, webview);
|
||||
await serializer.deserializeWebviewPanel(revivedPanel, state);
|
||||
}
|
||||
}
|
||||
@@ -14,8 +14,8 @@ import * as extHostTypes from './extHostTypes';
|
||||
|
||||
class ExtHostWebviewView extends Disposable implements vscode.WebviewView {
|
||||
|
||||
readonly #handle: extHostProtocol.WebviewPanelHandle;
|
||||
readonly #proxy: extHostProtocol.MainThreadWebviewsShape;
|
||||
readonly #handle: extHostProtocol.WebviewHandle;
|
||||
readonly #proxy: extHostProtocol.MainThreadWebviewViewsShape;
|
||||
|
||||
readonly #viewType: string;
|
||||
readonly #webview: ExtHostWebview;
|
||||
@@ -25,8 +25,8 @@ class ExtHostWebviewView extends Disposable implements vscode.WebviewView {
|
||||
#title: string | undefined;
|
||||
|
||||
constructor(
|
||||
handle: extHostProtocol.WebviewPanelHandle,
|
||||
proxy: extHostProtocol.MainThreadWebviewsShape,
|
||||
handle: extHostProtocol.WebviewHandle,
|
||||
proxy: extHostProtocol.MainThreadWebviewViewsShape,
|
||||
viewType: string,
|
||||
webview: ExtHostWebview,
|
||||
isVisible: boolean,
|
||||
@@ -94,20 +94,20 @@ class ExtHostWebviewView extends Disposable implements vscode.WebviewView {
|
||||
|
||||
export class ExtHostWebviewViews implements extHostProtocol.ExtHostWebviewViewsShape {
|
||||
|
||||
private readonly _proxy: extHostProtocol.MainThreadWebviewsShape;
|
||||
private readonly _proxy: extHostProtocol.MainThreadWebviewViewsShape;
|
||||
|
||||
private readonly _viewProviders = new Map<string, {
|
||||
readonly provider: vscode.WebviewViewProvider;
|
||||
readonly extension: IExtensionDescription;
|
||||
}>();
|
||||
|
||||
private readonly _webviewViews = new Map<extHostProtocol.WebviewPanelHandle, ExtHostWebviewView>();
|
||||
private readonly _webviewViews = new Map<extHostProtocol.WebviewHandle, ExtHostWebviewView>();
|
||||
|
||||
constructor(
|
||||
mainContext: extHostProtocol.IMainContext,
|
||||
private readonly _extHostWebview: ExtHostWebviews,
|
||||
) {
|
||||
this._proxy = mainContext.getProxy(extHostProtocol.MainContext.MainThreadWebviews);
|
||||
this._proxy = mainContext.getProxy(extHostProtocol.MainContext.MainThreadWebviewViews);
|
||||
}
|
||||
|
||||
public registerWebviewViewProvider(
|
||||
|
||||
@@ -12,7 +12,7 @@ import { isFalsyOrWhitespace } from 'vs/base/common/strings';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
|
||||
export class ExtHostWindow implements IExtHostWindow {
|
||||
export class ExtHostWindow implements ExtHostWindowShape {
|
||||
|
||||
private static InitialState: WindowState = {
|
||||
focused: true
|
||||
|
||||
@@ -61,7 +61,12 @@ const apiMenus: IAPIMenu[] = [
|
||||
{
|
||||
key: 'debug/callstack/context',
|
||||
id: MenuId.DebugCallStackContext,
|
||||
description: localize('menus.debugCallstackContext', "The debug callstack context menu")
|
||||
description: localize('menus.debugCallstackContext', "The debug callstack view context menu")
|
||||
},
|
||||
{
|
||||
key: 'debug/variables/context',
|
||||
id: MenuId.DebugVariablesContext,
|
||||
description: localize('menus.debugVariablesContext', "The debug variables view context menu")
|
||||
},
|
||||
{
|
||||
key: 'debug/toolBar',
|
||||
|
||||
@@ -97,7 +97,7 @@ export class ExtHostTask extends ExtHostTaskBase {
|
||||
// The ID is calculated on the main thread task side, so, let's call into it here.
|
||||
// We need the task id's pre-computed for custom task executions because when OnDidStartTask
|
||||
// is invoked, we have to be able to map it back to our data.
|
||||
taskIdPromises.push(this.addCustomExecution(taskDTO, <vscode.Task2>task, true));
|
||||
taskIdPromises.push(this.addCustomExecution(taskDTO, task, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ export class ExtHostTerminalService extends BaseExtHostTerminalService {
|
||||
@IExtHostDocumentsAndEditors private _extHostDocumentsAndEditors: ExtHostDocumentsAndEditors,
|
||||
@ILogService private _logService: ILogService
|
||||
) {
|
||||
super(extHostRpc);
|
||||
super(true, extHostRpc);
|
||||
this._updateLastActiveWorkspace();
|
||||
this._updateVariableResolver();
|
||||
this._registerListeners();
|
||||
|
||||
Reference in New Issue
Block a user