Merge from vscode 7eaf220cafb9d9e901370ffce02229171cbf3ea6

This commit is contained in:
ADS Merger
2020-09-03 02:34:56 +00:00
committed by Anthony Dresser
parent 39d9eed585
commit a63578e6f7
519 changed files with 14338 additions and 6670 deletions

View File

@@ -54,7 +54,7 @@ import './mainThreadTreeViews';
import './mainThreadDownloadService';
import './mainThreadUrls';
import './mainThreadWindow';
import './mainThreadWebview';
import './mainThreadWebviewManager';
import './mainThreadWorkspace';
import './mainThreadComments';
import './mainThreadNotebook';

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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> {

View File

@@ -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 {

View File

@@ -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));
}
}
}

View File

@@ -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);
}

View 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);
}
}

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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);

View 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,
};
}

View File

@@ -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),

View File

@@ -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: []
}
});

View File

@@ -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
};
};
}

View File

@@ -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'),

View File

@@ -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);
}
});

View File

@@ -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

View File

@@ -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`);
}

View File

@@ -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 { }

View File

@@ -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),

View File

@@ -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))

View File

@@ -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);
}
}
}

View File

@@ -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

View File

@@ -516,6 +516,7 @@ class ExtHostSourceControl implements vscode.SourceControl {
}
this._proxy.$registerGroups(this.handle, groups, splices);
this.createdResourceGroups.clear();
}
@debounce(100)

View File

@@ -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;
}

View File

@@ -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();
}

View File

@@ -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);
}

View File

@@ -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';
}
}

View File

@@ -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

View File

@@ -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,

View 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);
}
}

View File

@@ -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);
}
}

View File

@@ -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(

View File

@@ -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

View File

@@ -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',

View File

@@ -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));
}
}
}

View File

@@ -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();