Skip to content

Commit

Permalink
vscode: Request output rendering when idle in webview. (#176710)
Browse files Browse the repository at this point in the history
Commit: 711cd94734e015e48de00d1380b14e9626463b86
  • Loading branch information
Peng Lyu authored and sourcegraph-bot committed Mar 13, 2023
1 parent bd8736b commit 991036c
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -869,7 +869,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD

if (!activeWebview.insetMapping.has(output.source)) {
const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel);
await activeWebview.createOutput({ diffElement: cellDiffViewModel, cellHandle: cellViewModel.handle, cellId: cellViewModel.id, cellUri: cellViewModel.uri }, output, cellTop, getOffset(), false);
await activeWebview.createOutput({ diffElement: cellDiffViewModel, cellHandle: cellViewModel.handle, cellId: cellViewModel.id, cellUri: cellViewModel.uri }, output, cellTop, getOffset());
} else {
const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel);
const outputIndex = cellViewModel.outputsViewModels.indexOf(output.source);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2664,13 +2664,17 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
if (!existingOutput
|| (!existingOutput.renderer && output.type === RenderOutputType.Extension)
) {
this._webview.createOutput({ cellId: cell.id, cellHandle: cell.handle, cellUri: cell.uri, executionId: cell.internalMetadata.executionId }, output, cellTop, offset, createWhenIdle);
if (createWhenIdle) {
this._webview.requestCreateOutputWhenWebviewIdle({ cellId: cell.id, cellHandle: cell.handle, cellUri: cell.uri, executionId: cell.internalMetadata.executionId }, output, cellTop, offset);
} else {
this._webview.createOutput({ cellId: cell.id, cellHandle: cell.handle, cellUri: cell.uri, executionId: cell.internalMetadata.executionId }, output, cellTop, offset);
}
} else if (existingOutput.renderer
&& output.type === RenderOutputType.Extension
&& existingOutput.renderer.id !== output.renderer.id) {
// switch mimetype
this._webview.removeInsets([output.source]);
this._webview.createOutput({ cellId: cell.id, cellHandle: cell.handle, cellUri: cell.uri }, output, cellTop, offset, createWhenIdle);
this._webview.createOutput({ cellId: cell.id, cellHandle: cell.handle, cellUri: cell.uri }, output, cellTop, offset);
} else {
const outputIndex = cell.outputsViewModels.indexOf(output.source);
const outputOffset = cell.getOutputOffset(outputIndex);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import * as osPath from 'vs/base/common/path';
import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent';
import { coalesce } from 'vs/base/common/arrays';
import { DeferredPromise, runWhenIdle } from 'vs/base/common/async';
import { DeferredPromise } from 'vs/base/common/async';
import { decodeBase64 } from 'vs/base/common/buffer';
import { Emitter, Event } from 'vs/base/common/event';
import { getExtensionForMimeType } from 'vs/base/common/mime';
Expand Down Expand Up @@ -126,6 +126,9 @@ export class BackLayerWebView<T extends ICommonCellInfo> extends Themable {
element: HTMLElement;
webview: IWebviewElement | undefined = undefined;
insetMapping: Map<IDisplayOutputViewModel, ICachedInset<T>> = new Map();
pendingWebviewIdleInsetCreationRequest: Map<IDisplayOutputViewModel, ICachedInset<T>> = new Map();
private reversedPendingWebviewIdleInsetMapping: Map<string, IDisplayOutputViewModel> = new Map();

pendingInsetCreationRequest: Map<IDisplayOutputViewModel, IDisposable> = new Map();
readonly markupPreviewMapping = new Map<string, IMarkupCellInitialization>();
private hiddenInsetMapping: Set<IDisplayOutputViewModel> = new Set();
Expand Down Expand Up @@ -579,6 +582,17 @@ export class BackLayerWebView<T extends ICommonCellInfo> extends Themable {
const { cellInfo, output } = resolvedResult;
this.notebookEditor.updateOutputHeight(cellInfo, output, height, !!update.init, 'webview#dimension');
this.notebookEditor.scheduleOutputHeightAck(cellInfo, update.id, height);
} else if (update.init) {
// might be idle render request's ack
const outputRequest = this.reversedPendingWebviewIdleInsetMapping.get(update.id);
if (outputRequest) {
const inset = this.pendingWebviewIdleInsetCreationRequest.get(outputRequest)!;
const cellInfo = inset.cellInfo;
this.reversedInsetMapping.set(update.id, outputRequest);
this.insetMapping.set(outputRequest, inset);
this.notebookEditor.updateOutputHeight(cellInfo, outputRequest, height, !!update.init, 'webview#dimension');
this.notebookEditor.scheduleOutputHeightAck(cellInfo, update.id, height);
}
}
} else {
this.notebookEditor.updateMarkupCellHeight(update.id, height, !!update.init);
Expand Down Expand Up @@ -1279,13 +1293,38 @@ export class BackLayerWebView<T extends ICommonCellInfo> extends Themable {
}
}

createOutput(cellInfo: T, content: IInsetRenderOutput, cellTop: number, offset: number, createWhenIdle: boolean): void {
requestCreateOutputWhenWebviewIdle(cellInfo: T, content: IInsetRenderOutput, cellTop: number, offset: number) {
if (this._disposed) {
return;
}

if (this.insetMapping.has(content.source)) {
return;
}

if (this.pendingWebviewIdleInsetCreationRequest.has(content.source)) {
return;
}

const { message, renderer } = this._createOutputCreationMessage(cellInfo, content, cellTop, offset, true, true);
this._sendMessageToWebview(message);
this.pendingWebviewIdleInsetCreationRequest.set(content.source, { outputId: message.outputId, cellInfo: cellInfo, renderer, cachedCreation: message });
this.reversedPendingWebviewIdleInsetMapping.set(message.outputId, content.source);
}

createOutput(cellInfo: T, content: IInsetRenderOutput, cellTop: number, offset: number): void {
if (this._disposed) {
return;
}

const cachedInset = this.insetMapping.get(content.source);

// we now request to render the output immediately, so we can remove the pending request
this.pendingWebviewIdleInsetCreationRequest.delete(content.source);
if (cachedInset) {
this.reversedPendingWebviewIdleInsetMapping.delete(cachedInset.outputId);
}

if (cachedInset && this._cachedInsetEqual(cachedInset, content)) {
this.hiddenInsetMapping.delete(content.source);
this._sendMessageToWebview({
Expand All @@ -1300,70 +1339,70 @@ export class BackLayerWebView<T extends ICommonCellInfo> extends Themable {

// create new output
const createOutput = () => {
const messageBase = {
type: 'html',
executionId: cellInfo.executionId,
cellId: cellInfo.cellId,
cellTop: cellTop,
outputOffset: offset,
left: 0,
requiredPreloads: [],
} as const;

let message: ICreationRequestMessage;
let renderer: INotebookRendererInfo | undefined;
if (content.type === RenderOutputType.Extension) {
const output = content.source.model;
renderer = content.renderer;
const first = output.outputs.find(op => op.mime === content.mimeType)!;

// TODO@jrieken - the message can contain "bytes" and those are transferable
// which improves IPC performance and therefore should be used. However, it does
// means that the bytes cannot be used here anymore
message = {
...messageBase,
outputId: output.outputId,
rendererId: content.renderer.id,
content: {
type: RenderOutputType.Extension,
outputId: output.outputId,
metadata: output.metadata,
output: {
mime: first.mime,
valueBytes: first.data.buffer,
},
allOutputs: output.outputs.map(output => ({ mime: output.mime })),
},
};
} else {
message = {
...messageBase,
outputId: UUID.generateUuid(),
content: {
type: content.type,
htmlContent: content.htmlContent,
}
};
}

const { message, renderer } = this._createOutputCreationMessage(cellInfo, content, cellTop, offset, false, false);
this._sendMessageToWebview(message);
this.insetMapping.set(content.source, { outputId: message.outputId, cellInfo: cellInfo, renderer, cachedCreation: message });
this.hiddenInsetMapping.delete(content.source);
this.reversedInsetMapping.set(message.outputId, content.source);
};

if (createWhenIdle) {
this.pendingInsetCreationRequest.get(content.source)?.dispose();
this.pendingInsetCreationRequest.set(content.source, runWhenIdle(() => {
createOutput();
this.pendingInsetCreationRequest.delete(content.source);
}));
createOutput();
}

private _createOutputCreationMessage(cellInfo: T, content: IInsetRenderOutput, cellTop: number, offset: number, createOnIdle: boolean, initiallyHidden: boolean): { readonly message: ICreationRequestMessage; readonly renderer: INotebookRendererInfo | undefined } {
const messageBase = {
type: 'html',
executionId: cellInfo.executionId,
cellId: cellInfo.cellId,
cellTop: cellTop,
outputOffset: offset,
left: 0,
requiredPreloads: [],
createOnIdle: createOnIdle
} as const;

let message: ICreationRequestMessage;
let renderer: INotebookRendererInfo | undefined;
if (content.type === RenderOutputType.Extension) {
const output = content.source.model;
renderer = content.renderer;
const first = output.outputs.find(op => op.mime === content.mimeType)!;

// TODO@jrieken - the message can contain "bytes" and those are transferable
// which improves IPC performance and therefore should be used. However, it does
// means that the bytes cannot be used here anymore
message = {
...messageBase,
outputId: output.outputId,
rendererId: content.renderer.id,
content: {
type: RenderOutputType.Extension,
outputId: output.outputId,
metadata: output.metadata,
output: {
mime: first.mime,
valueBytes: first.data.buffer,
},
allOutputs: output.outputs.map(output => ({ mime: output.mime })),
},
initiallyHidden: initiallyHidden
};
} else {
this.pendingInsetCreationRequest.get(content.source)?.dispose();
this.pendingInsetCreationRequest.delete(content.source);
createOutput();
message = {
...messageBase,
outputId: UUID.generateUuid(),
content: {
type: content.type,
htmlContent: content.htmlContent,
},
initiallyHidden: initiallyHidden
};
}

return {
message,
renderer
};
}

updateOutput(cellInfo: T, content: IInsetRenderOutput, cellTop: number, offset: number): void {
Expand All @@ -1372,7 +1411,7 @@ export class BackLayerWebView<T extends ICommonCellInfo> extends Themable {
}

if (!this.insetMapping.has(content.source)) {
this.createOutput(cellInfo, content, cellTop, offset, false);
this.createOutput(cellInfo, content, cellTop, offset);
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ export interface ICreationRequestMessage {
readonly initiallyHidden?: boolean;
readonly rendererId?: string | undefined;
readonly executionId?: string | undefined;
readonly createOnIdle: boolean;
}

export interface IContentWidgetTopRequest {
Expand Down
Loading

0 comments on commit 991036c

Please sign in to comment.