提交 56660bef 编写于 作者: R rebornix

messages channel between ext and webview for outputs

上级 a47badb3
...@@ -1656,6 +1656,19 @@ declare module 'vscode' { ...@@ -1656,6 +1656,19 @@ declare module 'vscode' {
export interface NotebookEditor { export interface NotebookEditor {
readonly document: NotebookDocument; readonly document: NotebookDocument;
viewColumn?: ViewColumn; viewColumn?: ViewColumn;
/**
* Fired when the output hosting webview posts a message.
*/
readonly onDidReceiveMessage: Event<any>;
/**
* Post a message to the output hosting webview.
*
* Messages are only delivered if the editor is live.
*
* @param message Body of the message. This must be a string or other json serilizable object.
*/
postMessage(message: any): Thenable<boolean>;
/** /**
* Create a notebook cell. The cell is not inserted into current document when created. Extensions should insert the cell into the document by [TextDocument.cells](#TextDocument.cells) * Create a notebook cell. The cell is not inserted into current document when created. Extensions should insert the cell into the document by [TextDocument.cells](#TextDocument.cells)
*/ */
......
...@@ -12,6 +12,8 @@ import { INotebookTextModel, INotebookMimeTypeSelector, NOTEBOOK_DISPLAY_ORDER, ...@@ -12,6 +12,8 @@ import { INotebookTextModel, INotebookMimeTypeSelector, NOTEBOOK_DISPLAY_ORDER,
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; 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';
export class MainThreadNotebookDocument extends Disposable { export class MainThreadNotebookDocument extends Disposable {
private _textModel: NotebookTextModel; private _textModel: NotebookTextModel;
...@@ -54,7 +56,9 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo ...@@ -54,7 +56,9 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
constructor( constructor(
extHostContext: IExtHostContext, extHostContext: IExtHostContext,
@INotebookService private _notebookService: INotebookService, @INotebookService private _notebookService: INotebookService,
@IConfigurationService private readonly configurationService: IConfigurationService @IConfigurationService private readonly configurationService: IConfigurationService,
@IEditorService private readonly editorService: IEditorService,
) { ) {
super(); super();
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostNotebook); this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostNotebook);
...@@ -141,6 +145,21 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo ...@@ -141,6 +145,21 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
async executeNotebook(viewType: string, uri: URI): Promise<void> { async executeNotebook(viewType: string, uri: URI): Promise<void> {
return this._proxy.$executeNotebook(viewType, uri, undefined); return this._proxy.$executeNotebook(viewType, uri, undefined);
} }
async $postMessage(handle: number, value: any): Promise<boolean> {
const activeEditorPane = this.editorService.activeEditorPane as any | undefined;
if (activeEditorPane?.isNotebookEditor) {
const notebookEditor = (activeEditorPane as INotebookEditor);
if (notebookEditor.viewModel?.handle === handle) {
notebookEditor.postMessage(value);
return true;
}
}
return false;
}
} }
export class MainThreadNotebookController implements IMainNotebookController { export class MainThreadNotebookController implements IMainNotebookController {
...@@ -186,6 +205,10 @@ export class MainThreadNotebookController implements IMainNotebookController { ...@@ -186,6 +205,10 @@ export class MainThreadNotebookController implements IMainNotebookController {
this._mainThreadNotebook.executeNotebook(viewType, uri); this._mainThreadNotebook.executeNotebook(viewType, uri);
} }
onDidReceiveMessage(uri: UriComponents, message: any): void {
this._proxy.$onDidReceiveMessage(uri, message);
}
// Methods for ExtHost // Methods for ExtHost
async createNotebookDocument(handle: number, viewType: string, resource: UriComponents): Promise<void> { async createNotebookDocument(handle: number, viewType: string, resource: UriComponents): Promise<void> {
let document = new MainThreadNotebookDocument(this._proxy, handle, viewType, URI.revive(resource)); let document = new MainThreadNotebookDocument(this._proxy, handle, viewType, URI.revive(resource));
......
...@@ -688,6 +688,7 @@ export interface MainThreadNotebookShape extends IDisposable { ...@@ -688,6 +688,7 @@ export interface MainThreadNotebookShape extends IDisposable {
$updateNotebookLanguages(viewType: string, resource: UriComponents, languages: string[]): Promise<void>; $updateNotebookLanguages(viewType: string, resource: UriComponents, languages: string[]): Promise<void>;
$spliceNotebookCells(viewType: string, resource: UriComponents, splices: NotebookCellsSplice[], renderers: number[]): Promise<void>; $spliceNotebookCells(viewType: string, resource: UriComponents, splices: NotebookCellsSplice[], renderers: number[]): Promise<void>;
$spliceNotebookCellOutputs(viewType: string, resource: UriComponents, cellHandle: number, splices: NotebookCellOutputsSplice[], renderers: number[]): Promise<void>; $spliceNotebookCellOutputs(viewType: string, resource: UriComponents, cellHandle: number, splices: NotebookCellOutputsSplice[], renderers: number[]): Promise<void>;
$postMessage(handle: number, value: any): Promise<boolean>;
} }
export interface MainThreadUrlsShape extends IDisposable { export interface MainThreadUrlsShape extends IDisposable {
...@@ -1527,6 +1528,7 @@ export interface ExtHostNotebookShape { ...@@ -1527,6 +1528,7 @@ export interface ExtHostNotebookShape {
$updateActiveEditor(viewType: string, uri: UriComponents): Promise<void>; $updateActiveEditor(viewType: string, uri: UriComponents): Promise<void>;
$destoryNotebookDocument(viewType: string, uri: UriComponents): Promise<boolean>; $destoryNotebookDocument(viewType: string, uri: UriComponents): Promise<boolean>;
$acceptDisplayOrder(displayOrder: INotebookDisplayOrder): void; $acceptDisplayOrder(displayOrder: INotebookDisplayOrder): void;
$onDidReceiveMessage(uri: UriComponents, message: any): void;
} }
export interface ExtHostStorageShape { export interface ExtHostStorageShape {
......
...@@ -331,11 +331,14 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo ...@@ -331,11 +331,14 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
export class ExtHostNotebookEditor extends Disposable implements vscode.NotebookEditor { export class ExtHostNotebookEditor extends Disposable implements vscode.NotebookEditor {
private _viewColumn: vscode.ViewColumn | undefined; private _viewColumn: vscode.ViewColumn | undefined;
private static _cellhandlePool: number = 0; private static _cellhandlePool: number = 0;
onDidReceiveMessage: vscode.Event<any> = this._onDidReceiveMessage.event;
constructor( constructor(
viewType: string, viewType: string,
readonly id: string, readonly id: string,
public uri: URI, public uri: URI,
private _proxy: MainThreadNotebookShape,
private _onDidReceiveMessage: Emitter<any>,
public document: ExtHostNotebookDocument, public document: ExtHostNotebookDocument,
private _documentsAndEditors: ExtHostDocumentsAndEditors private _documentsAndEditors: ExtHostDocumentsAndEditors
) { ) {
...@@ -377,6 +380,11 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook ...@@ -377,6 +380,11 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook
set viewColumn(value) { set viewColumn(value) {
throw readonly('viewColumn'); throw readonly('viewColumn');
} }
async postMessage(message: any): Promise<boolean> {
return this._proxy.$postMessage(this.document.handle, message);
}
} }
export class ExtHostNotebookOutputRenderer { export class ExtHostNotebookOutputRenderer {
...@@ -418,7 +426,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN ...@@ -418,7 +426,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
private readonly _proxy: MainThreadNotebookShape; private readonly _proxy: MainThreadNotebookShape;
private readonly _notebookProviders = new Map<string, { readonly provider: vscode.NotebookProvider, readonly extension: IExtensionDescription; }>(); private readonly _notebookProviders = new Map<string, { readonly provider: vscode.NotebookProvider, readonly extension: IExtensionDescription; }>();
private readonly _documents = new Map<string, ExtHostNotebookDocument>(); private readonly _documents = new Map<string, ExtHostNotebookDocument>();
private readonly _editors = new Map<string, ExtHostNotebookEditor>(); private readonly _editors = new Map<string, { editor: ExtHostNotebookEditor, onDidReceiveMessage: Emitter<any> }>();
private readonly _notebookOutputRenderers = new Map<number, ExtHostNotebookOutputRenderer>(); private readonly _notebookOutputRenderers = new Map<number, ExtHostNotebookOutputRenderer>();
private _outputDisplayOrder: INotebookDisplayOrder | undefined; private _outputDisplayOrder: INotebookDisplayOrder | undefined;
...@@ -442,8 +450,8 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN ...@@ -442,8 +450,8 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
const cellHandle = arg.cell.handle; const cellHandle = arg.cell.handle;
for (let value of this._editors) { for (let value of this._editors) {
if (value[1].document.handle === documentHandle) { if (value[1].editor.document.handle === documentHandle) {
const cell = value[1].document.getCell(cellHandle); const cell = value[1].editor.document.getCell(cellHandle);
if (cell) { if (cell) {
return cell; return cell;
} }
...@@ -515,15 +523,19 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN ...@@ -515,15 +523,19 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
this._documents.set(URI.revive(uri).toString(), document); this._documents.set(URI.revive(uri).toString(), document);
} }
const onDidReceiveMessage = new Emitter<any>();
let editor = new ExtHostNotebookEditor( let editor = new ExtHostNotebookEditor(
viewType, viewType,
`${ExtHostNotebookController._handlePool++}`, `${ExtHostNotebookController._handlePool++}`,
URI.revive(uri), URI.revive(uri),
this._proxy,
onDidReceiveMessage,
this._documents.get(URI.revive(uri).toString())!, this._documents.get(URI.revive(uri).toString())!,
this._documentsAndEditors this._documentsAndEditors
); );
this._editors.set(URI.revive(uri).toString(), editor); this._editors.set(URI.revive(uri).toString(), { editor, onDidReceiveMessage });
await provider.provider.resolveNotebook(editor); await provider.provider.resolveNotebook(editor);
// await editor.document.$updateCells(); // await editor.document.$updateCells();
return editor.document.handle; return editor.document.handle;
...@@ -556,7 +568,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN ...@@ -556,7 +568,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
let editor = this._editors.get(URI.revive(uri).toString()); let editor = this._editors.get(URI.revive(uri).toString());
let document = this._documents.get(URI.revive(uri).toString()); let document = this._documents.get(URI.revive(uri).toString());
let rawCell = editor?.createCell('', language, type, []) as ExtHostCell; let rawCell = editor?.editor.createCell('', language, type, []) as ExtHostCell;
document?.insertCell(index, rawCell!); document?.insertCell(index, rawCell!);
let allDocuments = this._documentsAndEditors.allDocuments(); let allDocuments = this._documentsAndEditors.allDocuments();
...@@ -629,7 +641,8 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN ...@@ -629,7 +641,8 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
let editor = this._editors.get(URI.revive(uri).toString()); let editor = this._editors.get(URI.revive(uri).toString());
if (editor) { if (editor) {
editor.dispose(); editor.editor.dispose();
editor.onDidReceiveMessage.dispose();
this._editors.delete(URI.revive(uri).toString()); this._editors.delete(URI.revive(uri).toString());
} }
...@@ -639,4 +652,12 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN ...@@ -639,4 +652,12 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
$acceptDisplayOrder(displayOrder: INotebookDisplayOrder): void { $acceptDisplayOrder(displayOrder: INotebookDisplayOrder): void {
this._outputDisplayOrder = displayOrder; this._outputDisplayOrder = displayOrder;
} }
$onDidReceiveMessage(uri: UriComponents, message: any): void {
let editor = this._editors.get(URI.revive(uri).toString());
if (editor) {
editor.onDidReceiveMessage.fire(message);
}
}
} }
...@@ -44,6 +44,8 @@ export interface INotebookEditor { ...@@ -44,6 +44,8 @@ export interface INotebookEditor {
*/ */
viewModel: NotebookViewModel | undefined; viewModel: NotebookViewModel | undefined;
isNotebookEditor: boolean;
/** /**
* Focus the notebook editor cell list * Focus the notebook editor cell list
*/ */
...@@ -121,6 +123,11 @@ export interface INotebookEditor { ...@@ -121,6 +123,11 @@ export interface INotebookEditor {
*/ */
removeInset(output: IOutput): void; removeInset(output: IOutput): void;
/**
* Send message to the webview for outputs.
*/
postMessage(message: any): void;
/** /**
* Trigger the editor to scroll from scroll event programmatically * Trigger the editor to scroll from scroll event programmatically
*/ */
......
...@@ -219,6 +219,11 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor { ...@@ -219,6 +219,11 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
this.control = new NotebookCodeEditors(this.list, this.renderedEditors); this.control = new NotebookCodeEditors(this.list, this.renderedEditors);
this.webview = new BackLayerWebView(this.webviewService, this.notebookService, this, this.environmentSerice); this.webview = new BackLayerWebView(this.webviewService, this.notebookService, this, this.environmentSerice);
this._register(this.webview.onMessage(message => {
if (this.viewModel) {
this.notebookService.onDidReceiveMessage(this.viewModel.viewType, this.viewModel.uri, message);
}
}));
this.list.rowsContainer.appendChild(this.webview.element); this.list.rowsContainer.appendChild(this.webview.element);
this._register(this.list); this._register(this.list);
} }
...@@ -697,6 +702,10 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor { ...@@ -697,6 +702,10 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
return this.outputRenderer; return this.outputRenderer;
} }
postMessage(message: any) {
this.webview?.webview.sendMessage(message);
}
//#endregion //#endregion
toJSON(): any { toJSON(): any {
......
...@@ -30,6 +30,7 @@ export interface IMainNotebookController { ...@@ -30,6 +30,7 @@ export interface IMainNotebookController {
createRawCell(uri: URI, index: number, language: string, type: CellKind): Promise<NotebookCellTextModel | undefined>; createRawCell(uri: URI, index: number, language: string, type: CellKind): Promise<NotebookCellTextModel | undefined>;
deleteCell(uri: URI, index: number): Promise<boolean> deleteCell(uri: URI, index: number): Promise<boolean>
executeNotebookActiveCell(uri: URI): void; executeNotebookActiveCell(uri: URI): void;
onDidReceiveMessage(uri: URI, message: any): void;
destoryNotebookDocument(notebook: INotebookTextModel): Promise<void>; destoryNotebookDocument(notebook: INotebookTextModel): Promise<void>;
save(uri: URI): Promise<boolean>; save(uri: URI): Promise<boolean>;
} }
...@@ -54,6 +55,7 @@ export interface INotebookService { ...@@ -54,6 +55,7 @@ export interface INotebookService {
destoryNotebookDocument(viewType: string, notebook: INotebookTextModel): void; destoryNotebookDocument(viewType: string, notebook: INotebookTextModel): void;
updateActiveNotebookDocument(viewType: string, resource: URI): void; updateActiveNotebookDocument(viewType: string, resource: URI): void;
save(viewType: string, resource: URI): Promise<boolean>; save(viewType: string, resource: URI): Promise<boolean>;
onDidReceiveMessage(viewType: string, uri: URI, message: any): void;
} }
export class NotebookProviderInfoStore { export class NotebookProviderInfoStore {
...@@ -325,6 +327,14 @@ export class NotebookService extends Disposable implements INotebookService { ...@@ -325,6 +327,14 @@ export class NotebookService extends Disposable implements INotebookService {
return false; return false;
} }
onDidReceiveMessage(viewType: string, uri: URI, message: any): void {
let provider = this._notebookProviders.get(viewType);
if (provider) {
return provider.controller.onDidReceiveMessage(uri, message);
}
}
private _onWillDispose(model: INotebookTextModel): void { private _onWillDispose(model: INotebookTextModel): void {
let modelId = MODEL_ID(model.uri); let modelId = MODEL_ID(model.uri);
let modelData = this._models[modelId]; let modelData = this._models[modelId];
......
...@@ -16,8 +16,10 @@ import { IWebviewService, WebviewElement } from 'vs/workbench/contrib/webview/br ...@@ -16,8 +16,10 @@ import { IWebviewService, WebviewElement } from 'vs/workbench/contrib/webview/br
import { WebviewResourceScheme } from 'vs/workbench/contrib/webview/common/resourceLoader'; import { WebviewResourceScheme } from 'vs/workbench/contrib/webview/common/resourceLoader';
import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookCellViewModel'; import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookCellViewModel';
import { CELL_MARGIN } from 'vs/workbench/contrib/notebook/browser/constants'; import { CELL_MARGIN } from 'vs/workbench/contrib/notebook/browser/constants';
import { Emitter, Event } from 'vs/base/common/event';
export interface IDimentionMessage { export interface IDimentionMessage {
__vscode_notebook_message: boolean;
type: 'dimension'; type: 'dimension';
id: string; id: string;
data: DOM.Dimension; data: DOM.Dimension;
...@@ -25,6 +27,7 @@ export interface IDimentionMessage { ...@@ -25,6 +27,7 @@ export interface IDimentionMessage {
export interface IScrollAckMessage { export interface IScrollAckMessage {
__vscode_notebook_message: boolean;
type: 'scroll-ack'; type: 'scroll-ack';
data: { top: number }; data: { top: number };
version: number; version: number;
...@@ -78,6 +81,9 @@ export class BackLayerWebView extends Disposable { ...@@ -78,6 +81,9 @@ export class BackLayerWebView extends Disposable {
preloadsCache: Map<string, boolean> = new Map(); preloadsCache: Map<string, boolean> = new Map();
localResourceRootsCache: URI[] | undefined = undefined; localResourceRootsCache: URI[] | undefined = undefined;
rendererRootsCache: URI[] = []; rendererRootsCache: URI[] = [];
private readonly _onMessage = this._register(new Emitter<any>());
public readonly onMessage: Event<any> = this._onMessage.event;
constructor(public webviewService: IWebviewService, public notebookService: INotebookService, public notebookEditor: INotebookEditor, public environmentSerice: IEnvironmentService) { constructor(public webviewService: IWebviewService, public notebookService: INotebookService, public notebookEditor: INotebookEditor, public environmentSerice: IEnvironmentService) {
super(); super();
...@@ -154,6 +160,7 @@ export class BackLayerWebView extends Disposable { ...@@ -154,6 +160,7 @@ export class BackLayerWebView extends Disposable {
for (let entry of entries) { for (let entry of entries) {
if (entry.target.id === id && entry.contentRect) { if (entry.target.id === id && entry.contentRect) {
vscode.postMessage({ vscode.postMessage({
__vscode_notebook_message: true,
type: 'dimension', type: 'dimension',
id: id, id: id,
data: { data: {
...@@ -198,6 +205,7 @@ export class BackLayerWebView extends Disposable { ...@@ -198,6 +205,7 @@ export class BackLayerWebView extends Disposable {
resizeObserve(outputNode, outputId); resizeObserve(outputNode, outputId);
vscode.postMessage({ vscode.postMessage({
__vscode_notebook_message: true,
type: 'dimension', type: 'dimension',
id: outputId, id: outputId,
data: { data: {
...@@ -255,27 +263,32 @@ export class BackLayerWebView extends Disposable { ...@@ -255,27 +263,32 @@ export class BackLayerWebView extends Disposable {
})); }));
this._register(this.webview.onMessage((data: IMessage) => { this._register(this.webview.onMessage((data: IMessage) => {
if (data.type === 'dimension') { if (data.__vscode_notebook_message) {
let output = this.reversedInsetMapping.get(data.id); if (data.type === 'dimension') {
let output = this.reversedInsetMapping.get(data.id);
if (!output) { if (!output) {
return; return;
} }
let cell = this.insetMapping.get(output)!.cell; let cell = this.insetMapping.get(output)!.cell;
let height = data.data.height; let height = data.data.height;
let outputHeight = height === 0 ? 0 : height + 16; let outputHeight = height === 0 ? 0 : height + 16;
if (cell) { if (cell) {
let outputIndex = cell.outputs.indexOf(output); let outputIndex = cell.outputs.indexOf(output);
cell.updateOutputHeight(outputIndex, outputHeight); cell.updateOutputHeight(outputIndex, outputHeight);
this.notebookEditor.layoutNotebookCell(cell, cell.getCellTotalHeight()); this.notebookEditor.layoutNotebookCell(cell, cell.getCellTotalHeight());
}
} else if (data.type === 'scroll-ack') {
// const date = new Date();
// const top = data.data.top;
// console.log('ack top ', top, ' version: ', data.version, ' - ', date.getMinutes() + ':' + date.getSeconds() + ':' + date.getMilliseconds());
} }
} else if (data.type === 'scroll-ack') { return;
// const date = new Date();
// const top = data.data.top;
// console.log('ack top ', top, ' version: ', data.version, ' - ', date.getMinutes() + ':' + date.getSeconds() + ':' + date.getMilliseconds());
} }
this._onMessage.fire(data);
})); }));
} }
......
...@@ -69,6 +69,12 @@ export class TestNotebookEditor implements INotebookEditor { ...@@ -69,6 +69,12 @@ export class TestNotebookEditor implements INotebookEditor {
constructor( constructor(
) { } ) { }
isNotebookEditor = true;
postMessage(message: any): void {
throw new Error('Method not implemented.');
}
setCellSelection(cell: CellViewModel, selection: Range): void { setCellSelection(cell: CellViewModel, selection: Range): void {
throw new Error('Method not implemented.'); throw new Error('Method not implemented.');
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册