Hookup experimental undo for customEditors

This currently is not connected to any actual actions in the editor
This commit is contained in:
Matt Bierner
2019-11-07 17:22:21 -08:00
parent b5dbace111
commit 278b4f8cfa
7 changed files with 125 additions and 22 deletions

View File

@@ -27,6 +27,7 @@ import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { extHostNamedCustomer } from '../common/extHostCustomers';
import { CustomEditorModel } from 'vs/workbench/contrib/customEditor/browser/customEditorModel';
/**
* Bi-directional map between webview handles and inputs.
@@ -94,6 +95,7 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
private readonly _webviewInputs = new WebviewInputStore();
private readonly _revivers = new Map<string, IDisposable>();
private readonly _editorProviders = new Map<string, IDisposable>();
private readonly _models = new Map<string, CustomEditorModel>();
constructor(
context: extHostProtocol.IExtHostContext,
@@ -261,7 +263,7 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
canResolve: (webviewInput) => {
return webviewInput instanceof CustomFileEditorInput && webviewInput.viewType === viewType;
},
resolveWebview: async (webviewInput) => {
resolveWebview: async (webviewInput: CustomFileEditorInput) => {
const handle = webviewInput.id;
this._webviewInputs.add(handle, webviewInput);
this.hookupWebviewEventDelegate(handle, webviewInput);
@@ -269,6 +271,18 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
webviewInput.webview.options = options;
webviewInput.webview.extension = extension;
const model = new CustomEditorModel();
webviewInput.setModel(model);
this._models.set(handle, model);
webviewInput.onDispose(() => {
this._models.delete(handle);
});
model.onUndo(edit => {
this._proxy.$undoEdits(handle, [edit]);
});
try {
await this._proxy.$resolveWebviewEditor(
webviewInput.getResource(),
@@ -296,11 +310,18 @@ export class MainThreadWebviews extends Disposable implements extHostProtocol.Ma
this._editorProviders.delete(viewType);
}
public $onEdit(handle: extHostProtocol.WebviewPanelHandle, editJson: string): void {
public $onEdit(handle: extHostProtocol.WebviewPanelHandle, editData: string): void {
const webview = this.getWebviewInput(handle);
if (!(webview instanceof CustomFileEditorInput)) {
throw new Error(`Webview is not a webview editor`);
throw new Error('Webview is not a webview editor');
}
const model = this._models.get(handle);
if (!model) {
throw new Error('Could not find model for webview editor');
}
model.makeEdit(editData);
}
private hookupWebviewEventDelegate(handle: extHostProtocol.WebviewPanelHandle, input: WebviewInput) {

View File

@@ -589,6 +589,7 @@ export interface ExtHostWebviewsShape {
$onDidDisposeWebviewPanel(handle: WebviewPanelHandle): Promise<void>;
$deserializeWebviewPanel(newWebviewHandle: WebviewPanelHandle, viewType: string, title: string, state: any, position: EditorViewColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions): Promise<void>;
$resolveWebviewEditor(resource: UriComponents, newWebviewHandle: WebviewPanelHandle, viewType: string, title: string, position: EditorViewColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions): Promise<void>;
$undoEdits(handle: WebviewPanelHandle, edits: string[]): void;
}
export interface MainThreadUrlsShape extends IDisposable {

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { Emitter, Event } from 'vs/base/common/event';
import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
import { Disposable } 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';
@@ -93,6 +93,7 @@ export class ExtHostWebview implements vscode.Webview {
}
export class ExtHostWebviewEditor extends Disposable implements vscode.WebviewPanel {
private readonly _handle: WebviewPanelHandle;
private readonly _proxy: MainThreadWebviewsShape;
private readonly _viewType: string;
@@ -112,6 +113,7 @@ export class ExtHostWebviewEditor extends Disposable implements vscode.WebviewPa
readonly _onDidChangeViewStateEmitter = this._register(new Emitter<vscode.WebviewPanelOnDidChangeViewStateEvent>());
public readonly onDidChangeViewState: Event<vscode.WebviewPanelOnDidChangeViewStateEvent> = this._onDidChangeViewStateEmitter.event;
_capabilities: vscode.WebviewEditorCapabilities;
constructor(
handle: WebviewPanelHandle,
@@ -233,8 +235,17 @@ export class ExtHostWebviewEditor extends Disposable implements vscode.WebviewPa
});
}
_addDisposable(disposable: IDisposable) {
this._register(disposable);
_setCapabilities(capabilities: vscode.WebviewEditorCapabilities) {
this._capabilities = capabilities;
if (capabilities.editingCapability) {
this._register(capabilities.editingCapability.onEdit(edit => {
this._proxy.$onEdit(this._handle, JSON.stringify(edit));
}));
}
}
_undoEdits(edits: string[]): void {
this._capabilities.editingCapability?.undoEdits(edits);
}
private assertNotDisposed() {
@@ -402,10 +413,6 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
await serializer.deserializeWebviewPanel(revivedPanel, state);
}
private getWebviewPanel(handle: WebviewPanelHandle): ExtHostWebviewEditor | undefined {
return this._webviewPanels.get(handle);
}
async $resolveWebviewEditor(
resource: UriComponents,
handle: WebviewPanelHandle,
@@ -424,19 +431,19 @@ export class ExtHostWebviews implements ExtHostWebviewsShape {
const revivedPanel = new ExtHostWebviewEditor(handle, this._proxy, viewType, title, typeof position === 'number' && position >= 0 ? typeConverters.ViewColumn.to(position) : undefined, options, webview);
this._webviewPanels.set(handle, revivedPanel);
const capabilities = await provider.resolveWebviewEditor({ resource: URI.revive(resource) }, revivedPanel);
revivedPanel._addDisposable(this.hookupCapabilities(handle, capabilities));
revivedPanel._setCapabilities(capabilities);
}
private hookupCapabilities(handle: WebviewPanelHandle, capabilities: vscode.WebviewEditorCapabilities): IDisposable {
const disposables = new DisposableStore();
if (capabilities.editingCapability) {
disposables.add(capabilities.editingCapability.onEdit(edit => {
this._proxy.$onEdit(handle, JSON.stringify(edit));
}));
$undoEdits(handle: WebviewPanelHandle, edits: string[]): void {
const panel = this.getWebviewPanel(handle);
if (!panel) {
return;
}
panel._undoEdits(edits);
}
return disposables;
private getWebviewPanel(handle: WebviewPanelHandle): ExtHostWebviewEditor | undefined {
return this._webviewPanels.get(handle);
}
}