Merge from vscode fb5dc0083bfa9a0e3da7ed1f86e1ecb9836fcc8b

This commit is contained in:
ADS Merger
2020-03-13 05:35:18 +00:00
parent 7658a5df28
commit a7e56d334f
88 changed files with 1627 additions and 553 deletions

View File

@@ -596,7 +596,7 @@ export interface MainThreadWebviewsShape extends IDisposable {
$registerCustomEditorProvider(extension: WebviewExtensionDescription, viewType: string, options: modes.IWebviewPanelOptions): void;
$unregisterEditorProvider(viewType: string): void;
$onDidChangeCustomDocumentState(resource: UriComponents, viewType: string, state: { dirty: boolean }): void;
$onDidEdit(resource: UriComponents, viewType: string, editId: number, label: string | undefined): void;
}
export interface WebviewPanelViewStateData {
@@ -619,9 +619,11 @@ export interface ExtHostWebviewsShape {
$createWebviewCustomEditorDocument(resource: UriComponents, viewType: string): Promise<{ editable: boolean }>;
$disposeWebviewCustomEditorDocument(resource: UriComponents, viewType: string): Promise<void>;
$undo(resource: UriComponents, viewType: string): void;
$redo(resource: UriComponents, viewType: string): void;
$revert(resource: UriComponents, viewType: string): void;
$undo(resource: UriComponents, viewType: string, editId: number): Promise<void>;
$redo(resource: UriComponents, viewType: string, editId: number): Promise<void>;
$revert(resource: UriComponents, viewType: string, changes: { undoneEdits: number[], redoneEdits: number[] }): Promise<void>;
$disposeEdits(resourceComponents: UriComponents, viewType: string, editIds: number[]): void;
$onSave(resource: UriComponents, viewType: string, cancellation: CancellationToken): Promise<void>;
$onSaveAs(resource: UriComponents, viewType: string, targetResource: UriComponents): Promise<void>;

View File

@@ -5,7 +5,7 @@
import { CancellationToken } from 'vs/base/common/cancellation';
import { Emitter, Event } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { URI, UriComponents } from 'vs/base/common/uri';
import { generateUuid } from 'vs/base/common/uuid';
import * as modes from 'vs/editor/common/modes';
@@ -18,6 +18,7 @@ import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor';
import { asWebviewUri, WebviewInitData } from 'vs/workbench/api/common/shared/webview';
import type * as vscode from 'vscode';
import { Cache } from './cache';
import { ExtHostWebviewsShape, IMainContext, MainContext, MainThreadWebviewsShape, WebviewExtensionDescription, WebviewPanelHandle, WebviewPanelViewStateData } from './extHost.protocol';
import { Disposable as VSCodeDisposable } from './extHostTypes';
@@ -245,31 +246,33 @@ export class ExtHostWebviewEditor extends Disposable implements vscode.WebviewPa
}
}
type EditType = unknown;
class CustomDocument extends Disposable implements vscode.CustomDocument {
public static create(proxy: MainThreadWebviewsShape, viewType: string, uri: vscode.Uri) {
return Object.seal(new CustomDocument(proxy, viewType, uri));
public static create(
viewType: string,
uri: vscode.Uri,
editingDelegate: vscode.CustomEditorEditingDelegate | undefined
) {
return Object.seal(new CustomDocument(viewType, uri, editingDelegate));
}
// Explicitly initialize all properties as we seal the object after creation!
#currentEditIndex: number = -1;
#savePoint: number = -1;
readonly #edits: Array<EditType> = [];
readonly #_edits = new Cache<unknown>('edits');
readonly #proxy: MainThreadWebviewsShape;
readonly #viewType: string;
readonly #uri: vscode.Uri;
readonly #editingDelegate: vscode.CustomEditorEditingDelegate | undefined;
#capabilities: vscode.CustomEditorCapabilities | undefined = undefined;
private constructor(proxy: MainThreadWebviewsShape, viewType: string, uri: vscode.Uri) {
private constructor(
viewType: string,
uri: vscode.Uri,
editingDelegate: vscode.CustomEditorEditingDelegate | undefined,
) {
super();
this.#proxy = proxy;
this.#viewType = viewType;
this.#uri = uri;
this.#editingDelegate = editingDelegate;
}
dispose() {
@@ -292,107 +295,54 @@ class CustomDocument extends Disposable implements vscode.CustomDocument {
//#region Internal
/** @internal*/ _setCapabilities(capabilities: vscode.CustomEditorCapabilities) {
if (this.#capabilities) {
throw new Error('Capabilities already provided');
}
this.#capabilities = capabilities;
capabilities.editing?.onDidEdit(edit => {
this.pushEdit(edit);
});
/** @internal*/ async _revert(changes: { undoneEdits: number[], redoneEdits: number[] }) {
const editing = this.getEditingDelegate();
const undoneEdits = changes.undoneEdits.map(id => this.#_edits.get(id, 0));
const appliedEdits = changes.redoneEdits.map(id => this.#_edits.get(id, 0));
return editing.revert(this, { undoneEdits, appliedEdits });
}
/** @internal*/ async _revert() {
const editing = this.getEditingCapability();
if (this.#currentEditIndex === this.#savePoint) {
return true;
}
let undoneEdits: EditType[] = [];
let appliedEdits: EditType[] = [];
if (this.#currentEditIndex >= this.#savePoint) {
undoneEdits = this.#edits.slice(this.#savePoint, this.#currentEditIndex).reverse();
} else if (this.#currentEditIndex < this.#savePoint) {
appliedEdits = this.#edits.slice(this.#currentEditIndex, this.#savePoint);
}
this.#currentEditIndex = this.#savePoint;
this.spliceEdits();
await editing.revert({ undoneEdits, appliedEdits });
this.updateState();
return true;
/** @internal*/ _undo(editId: number) {
const editing = this.getEditingDelegate();
const edit = this.#_edits.get(editId, 0);
return editing.undoEdits(this, [edit]);
}
/** @internal*/ _undo() {
const editing = this.getEditingCapability();
if (this.#currentEditIndex < 0) {
// nothing to undo
return;
}
const undoneEdit = this.#edits[this.#currentEditIndex];
--this.#currentEditIndex;
editing.undoEdits([undoneEdit]);
this.updateState();
}
/** @internal*/ _redo() {
const editing = this.getEditingCapability();
if (this.#currentEditIndex >= this.#edits.length - 1) {
// nothing to redo
return;
}
++this.#currentEditIndex;
const redoneEdit = this.#edits[this.#currentEditIndex];
editing.applyEdits([redoneEdit]);
this.updateState();
/** @internal*/ _redo(editId: number) {
const editing = this.getEditingDelegate();
const edit = this.#_edits.get(editId, 0);
return editing.applyEdits(this, [edit]);
}
/** @internal*/ _save(cancellation: CancellationToken) {
return this.getEditingCapability().save(cancellation);
return this.getEditingDelegate().save(this, cancellation);
}
/** @internal*/ _saveAs(target: vscode.Uri) {
return this.getEditingCapability().saveAs(target);
return this.getEditingDelegate().saveAs(this, target);
}
/** @internal*/ _backup(cancellation: CancellationToken) {
return this.getEditingCapability().backup(cancellation);
return this.getEditingDelegate().backup(this, cancellation);
}
/** @internal*/ _disposeEdits(editIds: number[]) {
for (const editId of editIds) {
this.#_edits.delete(editId);
}
}
/** @internal*/ _pushEdit(edit: unknown): number {
return this.#_edits.add([edit]);
}
//#endregion
private pushEdit(edit: EditType) {
this.spliceEdits(edit);
this.#currentEditIndex = this.#edits.length - 1;
this.updateState();
}
private updateState() {
const dirty = this.#edits.length > 0 && this.#savePoint !== this.#currentEditIndex;
this.#proxy.$onDidChangeCustomDocumentState(this.uri, this.viewType, { dirty });
}
private spliceEdits(editToInsert?: EditType) {
const start = this.#currentEditIndex + 1;
const toRemove = this.#edits.length - this.#currentEditIndex;
editToInsert
? this.#edits.splice(start, toRemove, editToInsert)
: this.#edits.splice(start, toRemove);
}
private getEditingCapability(): vscode.CustomEditorEditingCapability {
if (!this.#capabilities?.editing) {
private getEditingDelegate(): vscode.CustomEditorEditingDelegate {
if (!this.#editingDelegate) {
throw new Error('Document is not editable');
}
return this.#capabilities.editing;
return this.#editingDelegate;
}
}
@@ -535,17 +485,24 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
provider: vscode.CustomEditorProvider | vscode.CustomTextEditorProvider,
options: vscode.WebviewPanelOptions | undefined = {}
): vscode.Disposable {
let disposable: vscode.Disposable;
const disposables = new DisposableStore();
if ('resolveCustomTextEditor' in provider) {
disposable = this._editorProviders.addTextProvider(viewType, extension, provider);
disposables.add(this._editorProviders.addTextProvider(viewType, extension, provider));
this._proxy.$registerTextEditorProvider(toExtensionData(extension), viewType, options);
} else {
disposable = this._editorProviders.addCustomProvider(viewType, extension, provider);
disposables.add(this._editorProviders.addCustomProvider(viewType, extension, provider));
this._proxy.$registerCustomEditorProvider(toExtensionData(extension), viewType, options);
if (provider.editingDelegate) {
disposables.add(provider.editingDelegate.onDidEdit(e => {
const document = e.document;
const editId = (document as CustomDocument)._pushEdit(e.edit);
this._proxy.$onDidEdit(document.uri, document.viewType, editId, e.label);
}));
}
}
return VSCodeDisposable.from(
disposable,
disposables,
new VSCodeDisposable(() => {
this._proxy.$unregisterEditorProvider(viewType);
}));
@@ -640,12 +597,11 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
}
const revivedResource = URI.revive(resource);
const document = CustomDocument.create(this._proxy, viewType, revivedResource);
const capabilities = await entry.provider.resolveCustomDocument(document);
document._setCapabilities(capabilities);
const document = CustomDocument.create(viewType, revivedResource, entry.provider.editingDelegate);
await entry.provider.resolveCustomDocument(document);
this._documents.add(document);
return {
editable: !!capabilities.editing
editable: !!entry.provider.editingDelegate,
};
}
@@ -702,24 +658,29 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
}
}
async $undo(resourceComponents: UriComponents, viewType: string): Promise<void> {
$disposeEdits(resourceComponents: UriComponents, viewType: string, editIds: number[]): void {
const document = this.getCustomDocument(viewType, resourceComponents);
document._undo();
document._disposeEdits(editIds);
}
async $redo(resourceComponents: UriComponents, viewType: string): Promise<void> {
async $undo(resourceComponents: UriComponents, viewType: string, editId: number): Promise<void> {
const document = this.getCustomDocument(viewType, resourceComponents);
document._redo();
return document._undo(editId);
}
async $revert(resourceComponents: UriComponents, viewType: string): Promise<void> {
async $redo(resourceComponents: UriComponents, viewType: string, editId: number): Promise<void> {
const document = this.getCustomDocument(viewType, resourceComponents);
document._revert();
return document._redo(editId);
}
async $revert(resourceComponents: UriComponents, viewType: string, changes: { undoneEdits: number[], redoneEdits: number[] }): Promise<void> {
const document = this.getCustomDocument(viewType, resourceComponents);
return document._revert(changes);
}
async $onSave(resourceComponents: UriComponents, viewType: string, cancellation: CancellationToken): Promise<void> {
const document = this.getCustomDocument(viewType, resourceComponents);
document._save(cancellation);
return document._save(cancellation);
}
async $onSaveAs(resourceComponents: UriComponents, viewType: string, targetResource: UriComponents): Promise<void> {