From 8a5f6fa5ce5d45f60a0fc49a2b29201fa1f271a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Tue, 17 Nov 2020 15:29:34 +0100 Subject: [PATCH 001/262] include remote-wsl by default --- build/gulpfile.vscode.js | 14 ++++++++++++-- build/lib/builtInExtensions.ts | 10 ++++++++++ product.json | 16 ++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 3c8bbe5b87f..1bcd653656b 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -161,7 +161,17 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op .pipe(rename(function (path) { path.dirname = path.dirname.replace(new RegExp('^' + out), 'out'); })) .pipe(util.setExecutableBit(['**/*.sh'])); - const extensions = gulp.src('.build/extensions/**', { base: '.build', dot: true }); + const platformSpecificBuiltInExtensionsFilter = product.builtInExtensions.filter(ext => { + if (!ext.platforms) { + return false; + } + + const set = new Set(ext.platforms); + return !set.has(platform); + }).map(ext => `!.build/extensions/${ext.name}/**`); + + const extensions = gulp.src('.build/extensions/**', { base: '.build', dot: true }) + .pipe(filter(['**', ...platformSpecificBuiltInExtensionsFilter])); const sources = es.merge(src, extensions) .pipe(filter(['**', '!**/*.js.map'], { dot: true })); @@ -201,7 +211,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op const telemetry = gulp.src('.build/telemetry/**', { base: '.build/telemetry', dot: true }); - const jsFilter = util.filter(data => !data.isDirectory() &&/\.js$/.test(data.path)); + const jsFilter = util.filter(data => !data.isDirectory() && /\.js$/.test(data.path)); const root = path.resolve(path.join(__dirname, '..')); const dependenciesSrc = _.flatten(productionDependencies.map(d => path.relative(root, d.path)).map(d => [`${d}/**`, `!${d}/**/{test,tests}/**`])); diff --git a/build/lib/builtInExtensions.ts b/build/lib/builtInExtensions.ts index b20913f49d1..20f2ee0aa32 100644 --- a/build/lib/builtInExtensions.ts +++ b/build/lib/builtInExtensions.ts @@ -21,6 +21,7 @@ interface IExtensionDefinition { name: string; version: string; repo: string; + platforms?: string[]; metadata: { id: string; publisherId: { @@ -82,6 +83,15 @@ function syncMarketplaceExtension(extension: IExtensionDefinition): Stream { } function syncExtension(extension: IExtensionDefinition, controlState: 'disabled' | 'marketplace'): Stream { + if (extension.platforms) { + const platforms = new Set(extension.platforms); + + if (!platforms.has(process.platform)) { + log(ansiColors.gray('[skip]'), `${extension.name}@${extension.version}: Platform '${process.platform}' not supported: [${extension.platforms}]`, ansiColors.green('✔︎')); + return es.readArray([]); + } + } + switch (controlState) { case 'disabled': log(ansiColors.blue('[disabled]'), ansiColors.gray(extension.name)); diff --git a/product.json b/product.json index 2d2bb2c605a..9fff131af79 100644 --- a/product.json +++ b/product.json @@ -119,6 +119,22 @@ }, "publisherDisplayName": "Microsoft" } + }, + { + "name": "ms-vscode-remote.remote-wsl", + "version": "0.51.3", + "repo": "https://github.com/microsoft/vscode-remote-release", + "metadata": { + "id": "f0c5397b-d357-4197-99f0-cb4202f22818", + "publisherId": { + "publisherId": "ac9410a2-0d75-40ec-90de-b59bb705801d", + "publisherName": "ms-vscode", + "displayName": "Microsoft", + "flags": "verified" + }, + "publisherDisplayName": "Microsoft" + }, + "platforms": ["win32"] } ], "webBuiltInExtensions": [ From 357fe395aefc590b95f11a9b9f0c3b0456a2283b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Wed, 18 Nov 2020 11:03:00 +0100 Subject: [PATCH 002/262] fix buil --- build/gulpfile.vscode.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 1bcd653656b..fb6ab60c3ee 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -161,7 +161,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op .pipe(rename(function (path) { path.dirname = path.dirname.replace(new RegExp('^' + out), 'out'); })) .pipe(util.setExecutableBit(['**/*.sh'])); - const platformSpecificBuiltInExtensionsFilter = product.builtInExtensions.filter(ext => { + const platformSpecificBuiltInExtensionsExclusions = product.builtInExtensions.filter(ext => { if (!ext.platforms) { return false; } @@ -170,8 +170,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op return !set.has(platform); }).map(ext => `!.build/extensions/${ext.name}/**`); - const extensions = gulp.src('.build/extensions/**', { base: '.build', dot: true }) - .pipe(filter(['**', ...platformSpecificBuiltInExtensionsFilter])); + const extensions = gulp.src(['.build/extensions/**', ...platformSpecificBuiltInExtensionsExclusions], { base: '.build', dot: true }); const sources = es.merge(src, extensions) .pipe(filter(['**', '!**/*.js.map'], { dot: true })); From 9f9c0e71ad60afb78c54dfefb185dc0aceb4b212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Wed, 18 Nov 2020 14:59:42 +0100 Subject: [PATCH 003/262] distro --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 89404b25424..fcd9d02a808 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.52.0", - "distro": "628a1cbabb4fbbcb9e751a86f240801028c96bd7", + "distro": "a3152c719226dcbded2acde438bbacf79ad260ae", "author": { "name": "Microsoft Corporation" }, @@ -195,4 +195,4 @@ "windows-mutex": "0.3.0", "windows-process-tree": "0.2.4" } -} +} \ No newline at end of file From adb24c6486a2e7e984fb5d2c51981e7fac2c6faf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Wed, 18 Nov 2020 16:36:28 +0100 Subject: [PATCH 004/262] use clientOnly for remote wsl extension --- product.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/product.json b/product.json index 9fff131af79..919a6d0fb17 100644 --- a/product.json +++ b/product.json @@ -134,7 +134,8 @@ }, "publisherDisplayName": "Microsoft" }, - "platforms": ["win32"] + "platforms": ["win32"], + "clientOnly": true } ], "webBuiltInExtensions": [ From 2e2b0d1895a9df5f2702c7984ba12ad1f94677ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Wed, 18 Nov 2020 16:36:44 +0100 Subject: [PATCH 005/262] distro --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fcd9d02a808..a2907bdca41 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.52.0", - "distro": "a3152c719226dcbded2acde438bbacf79ad260ae", + "distro": "d94402318753ba4d45684bd5d73d0f0447197b1c", "author": { "name": "Microsoft Corporation" }, From 2926b2c1f19a750d0054bbe55ba4b36d10536f8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moreno?= Date: Fri, 20 Nov 2020 09:45:03 +0100 Subject: [PATCH 006/262] use latest wsl --- product.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/product.json b/product.json index 919a6d0fb17..03dd31bd74b 100644 --- a/product.json +++ b/product.json @@ -122,7 +122,7 @@ }, { "name": "ms-vscode-remote.remote-wsl", - "version": "0.51.3", + "version": "0.51.4", "repo": "https://github.com/microsoft/vscode-remote-release", "metadata": { "id": "f0c5397b-d357-4197-99f0-cb4202f22818", From f46cb57055dcf95cc42ca23c5fd75e08a5beb913 Mon Sep 17 00:00:00 2001 From: rebornix Date: Thu, 10 Dec 2020 15:03:07 -0800 Subject: [PATCH 007/262] move picked mimetype to its view model. --- .../notebook/browser/notebookEditorWidget.ts | 2 +- .../browser/view/renderers/cellContextKeys.ts | 2 +- .../browser/view/renderers/cellOutput.ts | 110 ++++++++---------- .../browser/view/renderers/cellRenderer.ts | 4 +- .../browser/view/renderers/codeCell.ts | 2 +- .../browser/viewModel/cellOutputViewModel.ts | 50 ++++++++ .../browser/viewModel/codeCellViewModel.ts | 15 ++- 7 files changed, 117 insertions(+), 68 deletions(-) create mode 100644 src/vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel.ts diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index cc2d889c3e6..9f7cdd54c38 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -1026,7 +1026,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor return; } - if (cell.outputs.indexOf(key) < 0) { + if (cell.outputsViewModels.findIndex(viewModel => viewModel.model === key) < 0) { // output is already gone removedItems.push(key); } diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellContextKeys.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellContextKeys.ts index a9bd2c2849f..3d138d8840a 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellContextKeys.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellContextKeys.ts @@ -138,7 +138,7 @@ export class CellContextKeyManager extends Disposable { private updateForOutputs() { if (this.element instanceof CodeCellViewModel) { - this.cellHasOutputs.set(this.element.outputs.length > 0); + this.cellHasOutputs.set(this.element.outputsViewModels.length > 0); } else { this.cellHasOutputs.set(false); } diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellOutput.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellOutput.ts index a9ba33bf5bb..ecd819b2beb 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellOutput.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellOutput.ts @@ -13,7 +13,7 @@ import { IQuickPickItem, IQuickInputService } from 'vs/platform/quickinput/commo import { CodeCellRenderTemplate, INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { getResizesObserver } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellWidgets'; import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel'; -import { ITransformedDisplayOutputDto, IRenderOutput, IProcessedOutput, RENDERER_NOT_AVAILABLE, BUILTIN_RENDERER_ID, RenderOutputType, outputHasDynamicHeight, CellUri, CellOutputKind, NotebookCellOutputsSplice, IInsetRenderOutput } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { IRenderOutput, BUILTIN_RENDERER_ID, RenderOutputType, outputHasDynamicHeight, CellUri, CellOutputKind, NotebookCellOutputsSplice, IInsetRenderOutput } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { IMarkdownString } from 'vs/base/common/htmlContent'; import { renderMarkdown } from 'vs/base/browser/markdownRenderer'; @@ -23,6 +23,7 @@ import { format } from 'vs/base/common/jsonFormatter'; import { applyEdits } from 'vs/base/common/jsonEdit'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { mimetypeIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons'; +import { CellOutputViewModel, IDisplayOutputViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel'; const OUTPUT_COUNT_LIMIT = 500; @@ -31,12 +32,6 @@ interface IMimeTypeRenderer extends IQuickPickItem { } export class OutputElement extends Disposable { - - // this isn't super proper but I couldn't find a view-model equivalent for output - // and it seems as of today we use the domain model - and pragamtically enrich it - // with UX properties - private pickedMimeTypes = new WeakMap(); - readonly resizeListener = new DisposableStore(); domNode!: HTMLElement; renderResult?: IRenderOutput; @@ -47,7 +42,7 @@ export class OutputElement extends Disposable { private quickInputService: IQuickInputService, private viewCell: CodeCellViewModel, private outputContainer: HTMLElement, - readonly output: IProcessedOutput + readonly output: CellOutputViewModel ) { super(); } @@ -60,14 +55,8 @@ export class OutputElement extends Disposable { const outputItemDiv = document.createElement('div'); let result: IRenderOutput | undefined = undefined; - if (this.output.outputKind === CellOutputKind.Rich) { - const transformedDisplayOutput = this.output as ITransformedDisplayOutputDto; - - const mimeTypes = this.notebookService.getMimeTypeInfo(this.notebookEditor.textModel!, this.output); - - // there is at least one mimetype which is safe and can be rendered by the core - const pick = this.pickedMimeTypes.get(this.output) ?? Math.max(mimeTypes.findIndex(mimeType => mimeType.rendererId !== RENDERER_NOT_AVAILABLE && mimeType.isTrusted), 0); - + if (this.output.isDisplayOutput()) { + const [mimeTypes, pick] = this.output.resolveMimeTypes(this.notebookEditor.textModel!); if (mimeTypes.length > 1) { outputItemDiv.style.position = 'relative'; const mimeTypePicker = DOM.$('.multi-mimetype-output'); @@ -79,7 +68,7 @@ export class OutputElement extends Disposable { if (e.leftButton) { e.preventDefault(); e.stopPropagation(); - await this.pickActiveMimeTypeRenderer(transformedDisplayOutput); + await this.pickActiveMimeTypeRenderer(this.output as CellOutputViewModel & IDisplayOutputViewModel); } })); @@ -88,10 +77,9 @@ export class OutputElement extends Disposable { if ((event.equals(KeyCode.Enter) || event.equals(KeyCode.Space))) { e.preventDefault(); e.stopPropagation(); - await this.pickActiveMimeTypeRenderer(transformedDisplayOutput); + await this.pickActiveMimeTypeRenderer(this.output as CellOutputViewModel & IDisplayOutputViewModel); } }))); - } const pickedMimeTypeRenderer = mimeTypes[pick]; @@ -102,19 +90,19 @@ export class OutputElement extends Disposable { if (pickedMimeTypeRenderer.rendererId !== BUILTIN_RENDERER_ID) { const renderer = this.notebookService.getRendererInfo(pickedMimeTypeRenderer.rendererId); result = renderer - ? { type: RenderOutputType.Extension, renderer, source: this.output, mimeType: pickedMimeTypeRenderer.mimeType } - : this.notebookEditor.getOutputRenderer().render(this.output, innerContainer, pickedMimeTypeRenderer.mimeType, this.getNotebookUri(),); + ? { type: RenderOutputType.Extension, renderer, source: this.output.model, mimeType: pickedMimeTypeRenderer.mimeType } + : this.notebookEditor.getOutputRenderer().render(this.output.model, innerContainer, pickedMimeTypeRenderer.mimeType, this.getNotebookUri(),); } else { - result = this.notebookEditor.getOutputRenderer().render(this.output, innerContainer, pickedMimeTypeRenderer.mimeType, this.getNotebookUri(),); + result = this.notebookEditor.getOutputRenderer().render(this.output.model, innerContainer, pickedMimeTypeRenderer.mimeType, this.getNotebookUri(),); } - this.pickedMimeTypes.set(this.output, pick); + this.output.pickedMimeType = pick; } else { // for text and error, there is no mimetype const innerContainer = DOM.$('.output-inner-container'); DOM.append(outputItemDiv, innerContainer); - result = this.notebookEditor.getOutputRenderer().render(this.output, innerContainer, undefined, this.getNotebookUri(),); + result = this.notebookEditor.getOutputRenderer().render(this.output.model, innerContainer, undefined, this.getNotebookUri(),); } this.domNode = outputItemDiv; @@ -155,7 +143,7 @@ export class OutputElement extends Disposable { return; } - const currIndex = this.viewCell.outputs.indexOf(this.output); + const currIndex = this.viewCell.outputsViewModels.indexOf(this.output); if (currIndex < 0) { return; } @@ -176,12 +164,10 @@ export class OutputElement extends Disposable { } } - async pickActiveMimeTypeRenderer(output: ITransformedDisplayOutputDto) { + async pickActiveMimeTypeRenderer(viewModel: CellOutputViewModel & IDisplayOutputViewModel) { + const output = viewModel.model; + const [mimeTypes, currIndex] = viewModel.resolveMimeTypes(this.notebookEditor.textModel!); - const mimeTypes = this.notebookService.getMimeTypeInfo(this.notebookEditor.textModel!, output); - const currIndex = this.pickedMimeTypes.get(output); - - // const currIndex = output.pickedMimeTypeIndex; const items = mimeTypes.filter(mimeType => mimeType.isTrusted).map((mimeType, index): IMimeTypeRenderer => ({ label: mimeType.mimeType, id: mimeType.mimeType, @@ -212,7 +198,7 @@ export class OutputElement extends Disposable { if (pick !== currIndex) { // user chooses another mimetype - const index = this.viewCell.outputs.indexOf(output); + const index = this.viewCell.outputsViewModels.indexOf(viewModel); const nextElement = this.domNode.nextElementSibling; this.resizeListener.clear(); const element = this.domNode; @@ -221,7 +207,7 @@ export class OutputElement extends Disposable { this.notebookEditor.removeInset(output); } - this.pickedMimeTypes.set(output, pick); + viewModel.pickedMimeType = pick; this.render(index, nextElement as HTMLElement); this.relayoutCell(); } @@ -252,7 +238,7 @@ export class OutputElement extends Disposable { } export class OutputContainer extends Disposable { - private outputEntries = new Map(); + private outputEntries = new Map(); constructor( private notebookEditor: INotebookEditor, @@ -271,7 +257,7 @@ export class OutputContainer extends Disposable { this._register(viewCell.onDidChangeLayout(() => { this.outputEntries.forEach((value, key) => { - const index = viewCell.outputs.indexOf(key); + const index = viewCell.outputsViewModels.indexOf(key); if (index >= 0) { const top = this.viewCell.getOutputOffsetInContainer(index); value.domNode.style.top = `${top}px`; @@ -281,7 +267,7 @@ export class OutputContainer extends Disposable { } render(editorHeight: number) { - if (this.viewCell.outputs.length > 0) { + if (this.viewCell.outputsViewModels.length > 0) { let layoutCache = false; if (this.viewCell.layoutInfo.totalHeight !== 0 && this.viewCell.layoutInfo.editorHeight > editorHeight) { layoutCache = true; @@ -293,14 +279,14 @@ export class OutputContainer extends Disposable { // @TODO@rebornix, if there is no resizable output, we should not check their height individually, which hurts the performance const outputsToRender = this._calcuateOutputsToRender(); for (let index = 0; index < outputsToRender.length; index++) { - const currOutput = this.viewCell.outputs[index]; + const currOutput = this.viewCell.outputsViewModels[index]; // always add to the end this._renderOutput(currOutput, index, undefined); } this.viewCell.editorHeight = editorHeight; - if (this.viewCell.outputs.length > OUTPUT_COUNT_LIMIT) { + if (this.viewCell.outputsViewModels.length > OUTPUT_COUNT_LIMIT) { this.templateData.outputShowMoreContainer.style.display = 'block'; this.viewCell.updateOutputShowMoreContainerHeight(46); } @@ -321,15 +307,15 @@ export class OutputContainer extends Disposable { this.templateData.outputShowMoreContainer.appendChild(this._generateShowMoreElement()); // this.templateData.outputShowMoreContainer.style.top = `${this.viewCell.layoutInfo.outputShowMoreContainerOffset}px`; - if (this.viewCell.outputs.length < OUTPUT_COUNT_LIMIT) { + if (this.viewCell.outputsViewModels.length < OUTPUT_COUNT_LIMIT) { this.templateData.outputShowMoreContainer.style.display = 'none'; this.viewCell.updateOutputShowMoreContainerHeight(0); } } viewUpdateShowOutputs(): void { - for (let index = 0; index < this.viewCell.outputs.length; index++) { - const currOutput = this.viewCell.outputs[index]; + for (let index = 0; index < this.viewCell.outputsViewModels.length; index++) { + const currOutput = this.viewCell.outputsViewModels[index]; const renderedOutput = this.outputEntries.get(currOutput); if (renderedOutput && renderedOutput.renderResult) { @@ -350,12 +336,12 @@ export class OutputContainer extends Disposable { viewUpdateHideOuputs(): void { for (const e of this.outputEntries.keys()) { - this.notebookEditor.hideInset(e); + this.notebookEditor.hideInset(e.model); } } onCellWidthChange(): void { - this.viewCell.outputs.forEach((o, i) => { + this.viewCell.outputsViewModels.forEach((o, i) => { const renderedOutput = this.outputEntries.get(o); if (renderedOutput && renderedOutput.renderResult && renderedOutput.renderResult.type === RenderOutputType.None && !renderedOutput.renderResult.hasDynamicHeight) { this.viewCell.updateOutputHeight(i, renderedOutput.domNode.clientHeight); @@ -363,12 +349,12 @@ export class OutputContainer extends Disposable { }); } - private _calcuateOutputsToRender() { - const outputs = this.viewCell.outputs.slice(0, Math.min(OUTPUT_COUNT_LIMIT, this.viewCell.outputs.length)); + private _calcuateOutputsToRender(): CellOutputViewModel[] { + const outputs = this.viewCell.outputsViewModels.slice(0, Math.min(OUTPUT_COUNT_LIMIT, this.viewCell.outputsViewModels.length)); if (!this.notebookEditor.viewModel!.metadata.trusted) { // not trusted const secureOutput = outputs.filter(output => { - switch (output.outputKind) { + switch (output.model.outputKind) { case CellOutputKind.Text: return true; case CellOutputKind.Error: @@ -376,7 +362,7 @@ export class OutputContainer extends Disposable { case CellOutputKind.Rich: { const mimeTypes = []; - for (const property in output.data) { + for (const property in output.model.data) { mimeTypes.push(property); } @@ -407,7 +393,7 @@ export class OutputContainer extends Disposable { const previousOutputHeight = this.viewCell.layoutInfo.outputTotalHeight; - if (this.viewCell.outputs.length) { + if (this.viewCell.outputsViewModels.length) { this.templateData.outputContainer.style.display = 'block'; } else { this.templateData.outputContainer.style.display = 'none'; @@ -419,15 +405,15 @@ export class OutputContainer extends Disposable { this.viewCell.spliceOutputHeights(splice[0], splice[1], splice[2].map(_ => 0)); }); - const removedKeys: IProcessedOutput[] = []; + const removedKeys: CellOutputViewModel[] = []; this.outputEntries.forEach((value, key) => { - if (this.viewCell.outputs.indexOf(key) < 0) { + if (this.viewCell.outputsViewModels.indexOf(key) < 0) { // already removed removedKeys.push(key); // remove element from DOM this.templateData?.outputContainer?.removeChild(value.domNode); - this.notebookEditor.removeInset(key); + this.notebookEditor.removeInset(key.model); } }); @@ -447,12 +433,12 @@ export class OutputContainer extends Disposable { } // newly added element - const currIndex = this.viewCell.outputs.indexOf(output); + const currIndex = this.viewCell.outputsViewModels.indexOf(output); this._renderOutput(output, currIndex, prevElement); prevElement = this.outputEntries.get(output)?.domNode; }); - if (this.viewCell.outputs.length > OUTPUT_COUNT_LIMIT) { + if (this.viewCell.outputsViewModels.length > OUTPUT_COUNT_LIMIT) { this.templateData.outputShowMoreContainer.style.display = 'block'; this.viewCell.updateOutputShowMoreContainerHeight(46); } else { @@ -462,7 +448,7 @@ export class OutputContainer extends Disposable { const editorHeight = this.templateData.editor.getContentHeight(); this.viewCell.editorHeight = editorHeight; - if (previousOutputHeight === 0 || this.viewCell.outputs.length === 0) { + if (previousOutputHeight === 0 || this.viewCell.outputsViewModels.length === 0) { // first execution or removing all outputs this._relayoutCell(); } else { @@ -470,7 +456,7 @@ export class OutputContainer extends Disposable { } } - private _renderOutput(currOutput: IProcessedOutput, index: number, beforeElement?: HTMLElement) { + private _renderOutput(currOutput: CellOutputViewModel, index: number, beforeElement?: HTMLElement) { if (!this.outputEntries.has(currOutput)) { this.outputEntries.set(currOutput, new OutputElement(this.notebookEditor, this.notebookService, this.quickInputService, this.viewCell, this.templateData.outputContainer, currOutput)); } @@ -489,24 +475,24 @@ export class OutputContainer extends Disposable { actionHandler: { callback: (content) => { if (content === 'command:workbench.action.openLargeOutput') { - const content = JSON.stringify(this.viewCell.outputs.map(output => { - switch (output.outputKind) { + const content = JSON.stringify(this.viewCell.outputsViewModels.map(output => { + switch (output.model.outputKind) { case CellOutputKind.Text: return { outputKind: 'text', - text: output.text + text: output.model.text }; case CellOutputKind.Error: return { outputKind: 'error', - ename: output.ename, - evalue: output.evalue, - traceback: output.traceback + ename: output.model.ename, + evalue: output.model.evalue, + traceback: output.model.traceback }; case CellOutputKind.Rich: return { - data: output.data, - metadata: output.metadata + data: output.model.data, + metadata: output.model.metadata }; } })); diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts index ac81b9a601e..3d043dcdc4b 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts @@ -789,7 +789,7 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende this.dndController.registerDragHandle(templateData, rootContainer, dragHandle, () => new CodeCellDragImageRenderer().getDragImage(templateData, templateData.editor, 'code')); disposables.add(DOM.addDisposableListener(focusSinkElement, DOM.EventType.FOCUS, () => { - if (templateData.currentRenderedCell && (templateData.currentRenderedCell as CodeCellViewModel).outputs.length) { + if (templateData.currentRenderedCell && (templateData.currentRenderedCell as CodeCellViewModel).outputsViewModels.length) { this.notebookEditor.focusNotebookCell(templateData.currentRenderedCell, 'output'); } })); @@ -800,7 +800,7 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende } private updateForOutputs(element: CodeCellViewModel, templateData: CodeCellRenderTemplate): void { - if (element.outputs.length) { + if (element.outputsViewModels.length) { DOM.show(templateData.focusSinkElement); } else { DOM.hide(templateData.focusSinkElement); diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/codeCell.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/codeCell.ts index 56869eb8308..c4c74c15a1f 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/codeCell.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/codeCell.ts @@ -284,7 +284,7 @@ export class CodeCell extends Disposable { this.viewUpdateAllCollapsed(); } else if (this.viewCell.metadata?.inputCollapsed) { this.viewUpdateInputCollapsed(); - } else if (this.viewCell.metadata?.outputCollapsed && this.viewCell.outputs.length) { + } else if (this.viewCell.metadata?.outputCollapsed && this.viewCell.outputsViewModels.length) { this.viewUpdateOutputCollapsed(); } else { this.viewUpdateExpanded(); diff --git a/src/vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel.ts b/src/vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel.ts new file mode 100644 index 00000000000..2a2ec98c543 --- /dev/null +++ b/src/vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel.ts @@ -0,0 +1,50 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Disposable } from 'vs/base/common/lifecycle'; +import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; +import { CellOutputKind, IOrderedMimeType, IProcessedOutput, ITransformedDisplayOutputDto, RENDERER_NOT_AVAILABLE } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; + +export interface IDisplayOutputViewModel { + model: ITransformedDisplayOutputDto; + resolveMimeTypes(textModel: NotebookTextModel): [readonly IOrderedMimeType[], number]; +} + +export class CellOutputViewModel extends Disposable { + get model() { + return this._outputData; + } + + private _pickedMimeType: number = -1; + get pickedMimeType() { + return this._pickedMimeType; + } + + set pickedMimeType(value: number) { + this._pickedMimeType = value; + } + + constructor( + private readonly _outputData: IProcessedOutput, + private readonly _notebookService: INotebookService + ) { + super(); + } + + isDisplayOutput(): this is IDisplayOutputViewModel { + return this._outputData.outputKind === CellOutputKind.Rich; + } + + resolveMimeTypes(textModel: NotebookTextModel): [readonly IOrderedMimeType[], number] { + const mimeTypes = this._notebookService.getMimeTypeInfo(textModel, this.model as ITransformedDisplayOutputDto); + if (this._pickedMimeType === -1) { + // there is at least one mimetype which is safe and can be rendered by the core + this._pickedMimeType = Math.max(mimeTypes.findIndex(mimeType => mimeType.rendererId !== RENDERER_NOT_AVAILABLE && mimeType.isTrusted), 0); + } + + return [mimeTypes, this._pickedMimeType]; + } +} diff --git a/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts b/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts index bbc8ee2374c..bca4635e68e 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts @@ -11,9 +11,11 @@ import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer' import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { BOTTOM_CELL_TOOLBAR_GAP, BOTTOM_CELL_TOOLBAR_HEIGHT, CELL_BOTTOM_MARGIN, CELL_MARGIN, CELL_RUN_GUTTER, CELL_TOP_MARGIN, CODE_CELL_LEFT_MARGIN, COLLAPSED_INDICATOR_HEIGHT, EDITOR_BOTTOM_PADDING, EDITOR_TOOLBAR_HEIGHT } from 'vs/workbench/contrib/notebook/browser/constants'; import { CellEditState, CellFindMatch, CodeCellLayoutChangeEvent, CodeCellLayoutInfo, CodeCellLayoutState, getEditorTopPadding, ICellViewModel, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { CellOutputViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel'; import { NotebookEventDispatcher } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import { CellKind, INotebookSearchOptions, NotebookCellOutputsSplice } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { BaseCellViewModel } from './baseCellViewModel'; export class CodeCellViewModel extends BaseCellViewModel implements ICellViewModel { @@ -65,18 +67,29 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod return this._layoutInfo; } + private _outputViewModels: CellOutputViewModel[]; + + get outputsViewModels() { + return this._outputViewModels; + } + constructor( readonly viewType: string, readonly model: NotebookCellTextModel, initialNotebookLayoutInfo: NotebookLayoutInfo | null, readonly eventDispatcher: NotebookEventDispatcher, - @IConfigurationService configurationService: IConfigurationService + @IConfigurationService configurationService: IConfigurationService, + @INotebookService private _notebookService: INotebookService ) { super(viewType, model, UUID.generateUuid(), configurationService); + this._outputViewModels = this.model.outputs.map(output => new CellOutputViewModel(output, this._notebookService)); + this._register(this.model.onDidChangeOutputs((splices) => { splices.reverse().forEach(splice => { this._outputCollection.splice(splice[0], splice[1], ...splice[2].map(() => 0)); + this._outputViewModels.splice(splice[0], splice[1], ...splice[2].map(output => new CellOutputViewModel(output, this._notebookService))); }); + this._outputsTop = null; this._onDidChangeOutputs.fire(splices); })); From 4586eb012f97ed016171b4d7f0a73006fd6ce4d6 Mon Sep 17 00:00:00 2001 From: rebornix Date: Thu, 10 Dec 2020 15:53:30 -0800 Subject: [PATCH 008/262] renders all deal with output view model. --- .../notebook/browser/notebookBrowser.ts | 65 +++++++++++++++++-- .../notebook/browser/notebookEditorWidget.ts | 24 +++---- .../notebook/browser/view/notebookCellList.ts | 54 ++++++++------- .../browser/view/output/outputRenderer.ts | 13 ++-- .../view/output/transforms/errorTransform.ts | 7 +- .../view/output/transforms/richTransform.ts | 48 +++++++------- .../view/output/transforms/streamTransform.ts | 7 +- .../view/renderers/backLayerWebView.ts | 30 ++++----- .../browser/view/renderers/cellOutput.ts | 38 +++++------ .../browser/view/renderers/webviewPreloads.ts | 2 +- .../browser/viewModel/cellOutputViewModel.ts | 15 +++-- .../browser/viewModel/codeCellViewModel.ts | 4 +- .../contrib/notebook/common/notebookCommon.ts | 30 --------- .../notebook/test/testNotebookEditor.ts | 8 +-- 14 files changed, 190 insertions(+), 155 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index 1633a9f7b5d..60c9cf0f345 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -22,7 +22,7 @@ import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/outpu import { RunStateRenderer, TimerRenderer } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer'; import { CellViewModel, IModelDecorationsChangeAccessor, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; -import { CellKind, IProcessedOutput, IRenderOutput, NotebookCellMetadata, NotebookDocumentMetadata, IEditor, INotebookKernelInfo2, IInsetRenderOutput, ICellRange } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellKind, IProcessedOutput, NotebookCellMetadata, NotebookDocumentMetadata, IEditor, INotebookKernelInfo2, ICellRange, IOrderedMimeType, ITransformedDisplayOutputDto, INotebookRendererInfo, IErrorOutput, IStreamOutput } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { Webview } from 'vs/workbench/contrib/webview/browser/webview'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; import { IMenu } from 'vs/platform/actions/common/actions'; @@ -122,6 +122,59 @@ export interface MarkdownCellLayoutChangeEvent { totalHeight?: number; } +export const enum RenderOutputType { + None, + Html, + Extension +} + +export interface IRenderNoOutput { + type: RenderOutputType.None; + hasDynamicHeight: boolean; +} + +export interface IRenderPlainHtmlOutput { + type: RenderOutputType.Html; + source: IDisplayOutputViewModel; + htmlContent: string; + hasDynamicHeight: boolean; +} + +export interface IRenderOutputViaExtension { + type: RenderOutputType.Extension; + source: IDisplayOutputViewModel; + mimeType: string; + renderer: INotebookRendererInfo; +} + +export type IInsetRenderOutput = IRenderPlainHtmlOutput | IRenderOutputViaExtension; +export type IRenderOutput = IRenderNoOutput | IInsetRenderOutput; + +export const outputHasDynamicHeight = (o: IRenderOutput) => o.type !== RenderOutputType.Extension && o.hasDynamicHeight; + + +export interface ICellOutputViewModel { + model: IProcessedOutput; + isDisplayOutput(): this is IDisplayOutputViewModel; + isErrorOutput(): this is IErrorOutputViewModel; + isStreamOutput(): this is IStreamOutputViewModel; +} + +export interface IDisplayOutputViewModel extends ICellOutputViewModel { + model: ITransformedDisplayOutputDto; + resolveMimeTypes(textModel: NotebookTextModel): [readonly IOrderedMimeType[], number]; + pickedMimeType: number; + resolveMimeTypes(textModel: NotebookTextModel): [readonly IOrderedMimeType[], number]; +} + +export interface IErrorOutputViewModel extends ICellOutputViewModel { + model: IErrorOutput; +} + +export interface IStreamOutputViewModel extends ICellOutputViewModel { + model: IStreamOutput; +} + export interface ICellViewModel { readonly model: NotebookCellTextModel; readonly id: string; @@ -361,12 +414,12 @@ export interface INotebookEditor extends IEditor { /** * Remove the output from the webview layer */ - removeInset(output: IProcessedOutput): void; + removeInset(output: IDisplayOutputViewModel): void; /** * Hide the inset in the webview layer without removing it */ - hideInset(output: IProcessedOutput): void; + hideInset(output: IDisplayOutputViewModel): void; /** * Send message to the webview for outputs. @@ -494,8 +547,8 @@ export interface INotebookCellList { scrollLeft: number; length: number; rowsContainer: HTMLElement; - readonly onDidRemoveOutput: Event; - readonly onDidHideOutput: Event; + readonly onDidRemoveOutput: Event; + readonly onDidHideOutput: Event; readonly onMouseUp: Event>; readonly onMouseDown: Event>; readonly onContextMenu: Event>; @@ -594,7 +647,7 @@ export interface IOutputTransformContribution { * This call is allowed to have side effects, such as placing output * directly into the container element. */ - render(output: IProcessedOutput, container: HTMLElement, preferredMimeType: string | undefined, notebookUri: URI | undefined): IRenderOutput; + render(output: ICellOutputViewModel, container: HTMLElement, preferredMimeType: string | undefined, notebookUri: URI | undefined): IRenderOutput; } export interface CellFindMatch { diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 9f7cdd54c38..4ed86a8982a 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -42,7 +42,7 @@ import { Memento, MementoObject } from 'vs/workbench/common/memento'; import { PANEL_BORDER } from 'vs/workbench/common/theme'; import { debugIconStartForeground } from 'vs/workbench/contrib/debug/browser/debugToolBar'; import { BOTTOM_CELL_TOOLBAR_GAP, BOTTOM_CELL_TOOLBAR_HEIGHT, CELL_BOTTOM_MARGIN, CELL_MARGIN, CELL_RUN_GUTTER, CELL_TOP_MARGIN, CODE_CELL_LEFT_MARGIN, COLLAPSED_INDICATOR_HEIGHT, SCROLLABLE_ELEMENT_PADDING_TOP } from 'vs/workbench/contrib/notebook/browser/constants'; -import { CellEditState, CellFocusMode, IActiveNotebookEditor, ICellViewModel, INotebookCellList, INotebookDeltaDecoration, INotebookEditor, INotebookEditorContribution, INotebookEditorContributionDescription, INotebookEditorCreationOptions, INotebookEditorMouseEvent, NotebookEditorOptions, NotebookLayoutInfo, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_RUNNABLE, NOTEBOOK_HAS_MULTIPLE_KERNELS, NOTEBOOK_OUTPUT_FOCUSED } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { CellEditState, CellFocusMode, IActiveNotebookEditor, ICellOutputViewModel, ICellViewModel, IDisplayOutputViewModel, IInsetRenderOutput, INotebookCellList, INotebookDeltaDecoration, INotebookEditor, INotebookEditorContribution, INotebookEditorContributionDescription, INotebookEditorCreationOptions, INotebookEditorMouseEvent, NotebookEditorOptions, NotebookLayoutInfo, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_RUNNABLE, NOTEBOOK_HAS_MULTIPLE_KERNELS, NOTEBOOK_OUTPUT_FOCUSED } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { NotebookEditorExtensionsRegistry } from 'vs/workbench/contrib/notebook/browser/notebookEditorExtensions'; import { NotebookKernelProviderAssociation, NotebookKernelProviderAssociations, notebookKernelProviderAssociationsSettingId } from 'vs/workbench/contrib/notebook/browser/notebookKernelAssociation'; import { NotebookCellList } from 'vs/workbench/contrib/notebook/browser/view/notebookCellList'; @@ -55,7 +55,7 @@ import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewMod import { NotebookEventDispatcher, NotebookLayoutChangedEvent } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher'; import { CellViewModel, IModelDecorationsChangeAccessor, INotebookEditorViewState, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; -import { CellKind, CellToolbarLocKey, ICellRange, IInsetRenderOutput, INotebookDecorationRenderOptions, INotebookKernelInfo2, IProcessedOutput, isTransformedDisplayOutput, NotebookCellRunState, NotebookRunState, ShowCellStatusBarKey } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellKind, CellToolbarLocKey, ICellRange, INotebookDecorationRenderOptions, INotebookKernelInfo2, NotebookCellRunState, NotebookRunState, ShowCellStatusBarKey } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { NotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookProvider'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { editorGutterModifiedBackground } from 'vs/workbench/contrib/scm/browser/dirtydiffDecorator'; @@ -1016,8 +1016,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor this._webview!.element.style.height = `${scrollHeight}px`; if (this._webview?.insetMapping) { - const updateItems: { cell: CodeCellViewModel, output: IProcessedOutput, cellTop: number }[] = []; - const removedItems: IProcessedOutput[] = []; + const updateItems: { cell: CodeCellViewModel, output: IDisplayOutputViewModel, cellTop: number }[] = []; + const removedItems: IDisplayOutputViewModel[] = []; this._webview?.insetMapping.forEach((value, key) => { const cell = value.cell; const viewIndex = this._list.getViewIndex(cell); @@ -1026,7 +1026,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor return; } - if (cell.outputsViewModels.findIndex(viewModel => viewModel.model === key) < 0) { + if (cell.outputsViewModels.indexOf(key) < 0) { // output is already gone removedItems.push(key); } @@ -1847,7 +1847,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor } async createInset(cell: CodeCellViewModel, output: IInsetRenderOutput, offset: number): Promise { - this._insetModifyQueueByOutputId.queue(output.source.outputId, async () => { + this._insetModifyQueueByOutputId.queue(output.source.model.outputId, async () => { if (!this._webview) { return; } @@ -1866,12 +1866,12 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor }); } - removeInset(output: IProcessedOutput) { - if (!isTransformedDisplayOutput(output)) { + removeInset(output: ICellOutputViewModel) { + if (!output.isDisplayOutput()) { return; } - this._insetModifyQueueByOutputId.queue(output.outputId, async () => { + this._insetModifyQueueByOutputId.queue(output.model.outputId, async () => { if (!this._webview || !this._webviewResolved) { return; } @@ -1879,16 +1879,16 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor }); } - hideInset(output: IProcessedOutput) { + hideInset(output: ICellOutputViewModel) { if (!this._webview || !this._webviewResolved) { return; } - if (!isTransformedDisplayOutput(output)) { + if (!output.isDisplayOutput()) { return; } - this._insetModifyQueueByOutputId.queue(output.outputId, async () => { + this._insetModifyQueueByOutputId.queue(output.model.outputId, async () => { this._webview!.hideInset(output); }); } diff --git a/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts b/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts index d6d8ed7c046..8de660ff484 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts @@ -19,9 +19,9 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IListService, IWorkbenchListOptions, WorkbenchList } from 'vs/platform/list/browser/listService'; import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { CellRevealPosition, CellRevealType, CursorAtBoundary, getVisibleCells, ICellViewModel, INotebookCellList, reduceCellRanges, CellEditState, CellFocusMode, BaseCellRenderTemplate, NOTEBOOK_CELL_LIST_FOCUSED, cellRangesEqual } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { CellRevealPosition, CellRevealType, CursorAtBoundary, getVisibleCells, ICellViewModel, INotebookCellList, reduceCellRanges, CellEditState, CellFocusMode, BaseCellRenderTemplate, NOTEBOOK_CELL_LIST_FOCUSED, cellRangesEqual, ICellOutputViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellViewModel, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; -import { diff, IProcessedOutput, NOTEBOOK_EDITOR_CURSOR_BOUNDARY, CellKind, ICellRange, NOTEBOOK_EDITOR_CURSOR_BEGIN_END } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { diff, NOTEBOOK_EDITOR_CURSOR_BOUNDARY, CellKind, ICellRange, NOTEBOOK_EDITOR_CURSOR_BEGIN_END } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { clamp } from 'vs/base/common/numbers'; import { SCROLLABLE_ELEMENT_PADDING_TOP } from 'vs/workbench/contrib/notebook/browser/constants'; @@ -45,10 +45,10 @@ export class NotebookCellList extends WorkbenchList implements ID private _viewModelStore = new DisposableStore(); private styleElement?: HTMLStyleElement; - private readonly _onDidRemoveOutput = new Emitter(); - readonly onDidRemoveOutput: Event = this._onDidRemoveOutput.event; - private readonly _onDidHideOutput = new Emitter(); - readonly onDidHideOutput: Event = this._onDidHideOutput.event; + private readonly _onDidRemoveOutput = new Emitter(); + readonly onDidRemoveOutput: Event = this._onDidRemoveOutput.event; + private readonly _onDidHideOutput = new Emitter(); + readonly onDidHideOutput: Event = this._onDidHideOutput.event; private _viewModel: NotebookViewModel | null = null; private _hiddenRangeIds: string[] = []; @@ -314,15 +314,17 @@ export class NotebookCellList extends WorkbenchList implements ID if (e.synchronous) { viewDiffs.reverse().forEach((diff) => { // remove output in the webview - const hideOutputs: IProcessedOutput[] = []; - const deletedOutputs: IProcessedOutput[] = []; + const hideOutputs: ICellOutputViewModel[] = []; + const deletedOutputs: ICellOutputViewModel[] = []; for (let i = diff.start; i < diff.start + diff.deleteCount; i++) { const cell = this.element(i); - if (this._viewModel!.hasCell(cell.handle)) { - hideOutputs.push(...cell?.model.outputs); - } else { - deletedOutputs.push(...cell?.model.outputs); + if (cell.cellKind === CellKind.Code) { + if (this._viewModel!.hasCell(cell.handle)) { + hideOutputs.push(...cell?.outputsViewModels); + } else { + deletedOutputs.push(...cell?.outputsViewModels); + } } } @@ -338,15 +340,17 @@ export class NotebookCellList extends WorkbenchList implements ID } viewDiffs.reverse().forEach((diff) => { - const hideOutputs: IProcessedOutput[] = []; - const deletedOutputs: IProcessedOutput[] = []; + const hideOutputs: ICellOutputViewModel[] = []; + const deletedOutputs: ICellOutputViewModel[] = []; for (let i = diff.start; i < diff.start + diff.deleteCount; i++) { const cell = this.element(i); - if (this._viewModel!.hasCell(cell.handle)) { - hideOutputs.push(...cell?.model.outputs); - } else { - deletedOutputs.push(...cell?.model.outputs); + if (cell.cellKind === CellKind.Code) { + if (this._viewModel!.hasCell(cell.handle)) { + hideOutputs.push(...cell?.outputsViewModels); + } else { + deletedOutputs.push(...cell?.outputsViewModels); + } } } @@ -460,15 +464,17 @@ export class NotebookCellList extends WorkbenchList implements ID viewDiffs.reverse().forEach((diff) => { // remove output in the webview - const hideOutputs: IProcessedOutput[] = []; - const deletedOutputs: IProcessedOutput[] = []; + const hideOutputs: ICellOutputViewModel[] = []; + const deletedOutputs: ICellOutputViewModel[] = []; for (let i = diff.start; i < diff.start + diff.deleteCount; i++) { const cell = this.element(i); - if (this._viewModel!.hasCell(cell.handle)) { - hideOutputs.push(...cell?.model.outputs); - } else { - deletedOutputs.push(...cell?.model.outputs); + if (cell.cellKind === CellKind.Code) { + if (this._viewModel!.hasCell(cell.handle)) { + hideOutputs.push(...cell?.outputsViewModels); + } else { + deletedOutputs.push(...cell?.outputsViewModels); + } } } diff --git a/src/vs/workbench/contrib/notebook/browser/view/output/outputRenderer.ts b/src/vs/workbench/contrib/notebook/browser/view/output/outputRenderer.ts index 41a457e3dc6..5d21b1cc3c2 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/output/outputRenderer.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/output/outputRenderer.ts @@ -4,10 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IProcessedOutput, IRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { NotebookRegistry } from 'vs/workbench/contrib/notebook/browser/notebookRegistry'; import { onUnexpectedError } from 'vs/base/common/errors'; -import { INotebookEditor, IOutputTransformContribution } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { ICellOutputViewModel, INotebookEditor, IOutputTransformContribution, IRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { URI } from 'vs/base/common/uri'; export class OutputRenderer { @@ -34,7 +33,8 @@ export class OutputRenderer { } } - renderNoop(output: IProcessedOutput, container: HTMLElement): IRenderOutput { + renderNoop(viewModel: ICellOutputViewModel, container: HTMLElement): IRenderOutput { + const output = viewModel.model; const contentNode = document.createElement('p'); contentNode.innerText = `No renderer could be found for output. It has the following output type: ${output.outputKind}`; @@ -42,13 +42,14 @@ export class OutputRenderer { return { type: RenderOutputType.None, hasDynamicHeight: false }; } - render(output: IProcessedOutput, container: HTMLElement, preferredMimeType: string | undefined, notebookUri: URI | undefined): IRenderOutput { + render(viewModel: ICellOutputViewModel, container: HTMLElement, preferredMimeType: string | undefined, notebookUri: URI | undefined): IRenderOutput { + const output = viewModel.model; const transform = this._mimeTypeMapping[output.outputKind]; if (transform) { - return transform.render(output, container, preferredMimeType, notebookUri); + return transform.render(viewModel, container, preferredMimeType, notebookUri); } else { - return this.renderNoop(output, container); + return this.renderNoop(viewModel, container); } } } diff --git a/src/vs/workbench/contrib/notebook/browser/view/output/transforms/errorTransform.ts b/src/vs/workbench/contrib/notebook/browser/view/output/transforms/errorTransform.ts index 10a4839b4ba..43586d0d998 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/output/transforms/errorTransform.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/output/transforms/errorTransform.ts @@ -3,12 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IRenderOutput, CellOutputKind, IErrorOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellOutputKind } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { NotebookRegistry } from 'vs/workbench/contrib/notebook/browser/notebookRegistry'; import { RGBA, Color } from 'vs/base/common/color'; import { ansiColorIdentifiers } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { INotebookEditor, IOutputTransformContribution } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { IErrorOutputViewModel, INotebookEditor, IOutputTransformContribution, IRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; class ErrorTransform implements IOutputTransformContribution { constructor( @@ -17,7 +17,8 @@ class ErrorTransform implements IOutputTransformContribution { ) { } - render(output: IErrorOutput, container: HTMLElement): IRenderOutput { + render(viewModel: IErrorOutputViewModel, container: HTMLElement): IRenderOutput { + const output = viewModel.model; const header = document.createElement('div'); const headerMessage = output.ename && output.evalue ? `${output.ename}: ${output.evalue}` diff --git a/src/vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform.ts b/src/vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform.ts index b2cec39953d..eb29fc42dd1 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform.ts @@ -3,10 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IRenderOutput, CellOutputKind, ITransformedDisplayOutputDto, RenderOutputType } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellOutputKind } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { NotebookRegistry } from 'vs/workbench/contrib/notebook/browser/notebookRegistry'; import * as DOM from 'vs/base/browser/dom'; -import { INotebookEditor, IOutputTransformContribution } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { IDisplayOutputViewModel, INotebookEditor, IOutputTransformContribution, IRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { isArray } from 'vs/base/common/types'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; @@ -22,7 +22,7 @@ import { IOpenerService } from 'vs/platform/opener/common/opener'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; class RichRenderer implements IOutputTransformContribution { - private _richMimeTypeRenderers = new Map IRenderOutput>(); + private _richMimeTypeRenderers = new Map IRenderOutput>(); constructor( public notebookEditor: INotebookEditor, @@ -44,8 +44,8 @@ class RichRenderer implements IOutputTransformContribution { this._richMimeTypeRenderers.set('text/x-javascript', this.renderCode.bind(this)); } - render(output: ITransformedDisplayOutputDto, container: HTMLElement, preferredMimeType: string | undefined, notebookUri: URI): IRenderOutput { - if (!output.data) { + render(output: IDisplayOutputViewModel, container: HTMLElement, preferredMimeType: string | undefined, notebookUri: URI): IRenderOutput { + if (!output.model.data) { const contentNode = document.createElement('p'); contentNode.innerText = `No data could be found for output.`; container.appendChild(contentNode); @@ -55,7 +55,7 @@ class RichRenderer implements IOutputTransformContribution { if (!preferredMimeType || !this._richMimeTypeRenderers.has(preferredMimeType)) { const contentNode = document.createElement('p'); const mimeTypes = []; - for (const property in output.data) { + for (const property in output.model.data) { mimeTypes.push(property); } @@ -75,8 +75,8 @@ class RichRenderer implements IOutputTransformContribution { return renderer!(output, notebookUri, container); } - renderJSON(output: ITransformedDisplayOutputDto, notebookUri: URI, container: HTMLElement): IRenderOutput { - const data = output.data['application/json']; + renderJSON(output: IDisplayOutputViewModel, notebookUri: URI, container: HTMLElement): IRenderOutput { + const data = output.model.data['application/json']; const str = JSON.stringify(data, null, '\t'); const editor = this.instantiationService.createInstance(CodeEditorWidget, container, { @@ -108,8 +108,8 @@ class RichRenderer implements IOutputTransformContribution { return { type: RenderOutputType.None, hasDynamicHeight: true }; } - renderCode(output: ITransformedDisplayOutputDto, notebookUri: URI, container: HTMLElement): IRenderOutput { - const data = output.data['text/x-javascript']; + renderCode(output: IDisplayOutputViewModel, notebookUri: URI, container: HTMLElement): IRenderOutput { + const data = output.model.data['text/x-javascript']; const str = (isArray(data) ? data.join('') : data) as string; const editor = this.instantiationService.createInstance(CodeEditorWidget, container, { @@ -141,8 +141,8 @@ class RichRenderer implements IOutputTransformContribution { return { type: RenderOutputType.None, hasDynamicHeight: true }; } - renderJavaScript(output: ITransformedDisplayOutputDto, notebookUri: URI, container: HTMLElement): IRenderOutput { - const data = output.data['application/javascript']; + renderJavaScript(output: IDisplayOutputViewModel, notebookUri: URI, container: HTMLElement): IRenderOutput { + const data = output.model.data['application/javascript']; const str = isArray(data) ? data.join('') : data; const scriptVal = ``; return { @@ -153,8 +153,8 @@ class RichRenderer implements IOutputTransformContribution { }; } - renderHTML(output: ITransformedDisplayOutputDto, notebookUri: URI, container: HTMLElement): IRenderOutput { - const data = output.data['text/html']; + renderHTML(output: IDisplayOutputViewModel, notebookUri: URI, container: HTMLElement): IRenderOutput { + const data = output.model.data['text/html']; const str = (isArray(data) ? data.join('') : data) as string; return { type: RenderOutputType.Html, @@ -164,8 +164,8 @@ class RichRenderer implements IOutputTransformContribution { }; } - renderSVG(output: ITransformedDisplayOutputDto, notebookUri: URI, container: HTMLElement): IRenderOutput { - const data = output.data['image/svg+xml']; + renderSVG(output: IDisplayOutputViewModel, notebookUri: URI, container: HTMLElement): IRenderOutput { + const data = output.model.data['image/svg+xml']; const str = (isArray(data) ? data.join('') : data) as string; return { type: RenderOutputType.Html, @@ -175,8 +175,8 @@ class RichRenderer implements IOutputTransformContribution { }; } - renderMarkdown(output: ITransformedDisplayOutputDto, notebookUri: URI, container: HTMLElement): IRenderOutput { - const data = output.data['text/markdown']; + renderMarkdown(output: IDisplayOutputViewModel, notebookUri: URI, container: HTMLElement): IRenderOutput { + const data = output.model.data['text/markdown']; const str = (isArray(data) ? data.join('') : data) as string; const mdOutput = document.createElement('div'); const mdRenderer = this.instantiationService.createInstance(MarkdownRenderer, { baseUrl: dirname(notebookUri) }); @@ -186,9 +186,9 @@ class RichRenderer implements IOutputTransformContribution { return { type: RenderOutputType.None, hasDynamicHeight: true }; } - renderPNG(output: ITransformedDisplayOutputDto, notebookUri: URI, container: HTMLElement): IRenderOutput { + renderPNG(output: IDisplayOutputViewModel, notebookUri: URI, container: HTMLElement): IRenderOutput { const image = document.createElement('img'); - image.src = `data:image/png;base64,${output.data['image/png']}`; + image.src = `data:image/png;base64,${output.model.data['image/png']}`; const display = document.createElement('div'); display.classList.add('display'); display.appendChild(image); @@ -196,9 +196,9 @@ class RichRenderer implements IOutputTransformContribution { return { type: RenderOutputType.None, hasDynamicHeight: true }; } - renderJPEG(output: ITransformedDisplayOutputDto, notebookUri: URI, container: HTMLElement): IRenderOutput { + renderJPEG(output: IDisplayOutputViewModel, notebookUri: URI, container: HTMLElement): IRenderOutput { const image = document.createElement('img'); - image.src = `data:image/jpeg;base64,${output.data['image/jpeg']}`; + image.src = `data:image/jpeg;base64,${output.model.data['image/jpeg']}`; const display = document.createElement('div'); display.classList.add('display'); display.appendChild(image); @@ -206,8 +206,8 @@ class RichRenderer implements IOutputTransformContribution { return { type: RenderOutputType.None, hasDynamicHeight: true }; } - renderPlainText(output: ITransformedDisplayOutputDto, notebookUri: URI, container: HTMLElement): IRenderOutput { - const data = output.data['text/plain']; + renderPlainText(output: IDisplayOutputViewModel, notebookUri: URI, container: HTMLElement): IRenderOutput { + const data = output.model.data['text/plain']; const contentNode = DOM.$('.output-plaintext'); truncatedArrayOfString(contentNode, isArray(data) ? data : [data], this.openerService, this.textFileService, this.themeService, true); container.appendChild(contentNode); diff --git a/src/vs/workbench/contrib/notebook/browser/view/output/transforms/streamTransform.ts b/src/vs/workbench/contrib/notebook/browser/view/output/transforms/streamTransform.ts index b05a25d3b33..446c169057b 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/output/transforms/streamTransform.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/output/transforms/streamTransform.ts @@ -4,9 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import * as DOM from 'vs/base/browser/dom'; -import { IRenderOutput, CellOutputKind, IStreamOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellOutputKind } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { NotebookRegistry } from 'vs/workbench/contrib/notebook/browser/notebookRegistry'; -import { INotebookEditor, IOutputTransformContribution } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { INotebookEditor, IOutputTransformContribution, IRenderOutput, IStreamOutputViewModel, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { truncatedArrayOfString } from 'vs/workbench/contrib/notebook/browser/view/output/transforms/textHelper'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; @@ -21,7 +21,8 @@ class StreamRenderer implements IOutputTransformContribution { ) { } - render(output: IStreamOutput, container: HTMLElement): IRenderOutput { + render(viewModel: IStreamOutputViewModel, container: HTMLElement): IRenderOutput { + const output = viewModel.model; const contentNode = DOM.$('.output-stream'); truncatedArrayOfString(contentNode, [output.text], this.openerService, this.textFileService, this.themeService, false); container.appendChild(contentNode); diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index 31fc6590e1f..7f81379160c 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -11,13 +11,12 @@ import { URI } from 'vs/base/common/uri'; import * as UUID from 'vs/base/common/uuid'; import { IOpenerService, matchesScheme } from 'vs/platform/opener/common/opener'; import { CELL_MARGIN, CELL_RUN_GUTTER, CODE_CELL_LEFT_MARGIN, CELL_OUTPUT_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; -import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { IDisplayOutputViewModel, IInsetRenderOutput, INotebookEditor, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel'; -import { CellOutputKind, IDisplayOutput, IInsetRenderOutput, INotebookRendererInfo, IProcessedOutput, ITransformedDisplayOutputDto, RenderOutputType } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellOutputKind, IDisplayOutput, INotebookRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { IWebviewService, WebviewElement, WebviewContentPurpose } from 'vs/workbench/contrib/webview/browser/webview'; import { asWebviewUri } from 'vs/workbench/contrib/webview/common/webviewUri'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { dirname, joinPath } from 'vs/base/common/resources'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { preloadsScriptStr } from 'vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads'; @@ -26,6 +25,7 @@ import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IFileService } from 'vs/platform/files/common/files'; import { VSBuffer } from 'vs/base/common/buffer'; import { getExtensionForMimeType } from 'vs/base/common/mime'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; export interface WebviewIntialized { __vscode_notebook_message: boolean; @@ -220,9 +220,9 @@ let version = 0; export class BackLayerWebView extends Disposable { element: HTMLElement; webview: WebviewElement | undefined = undefined; - insetMapping: Map = new Map(); - hiddenInsetMapping: Set = new Set(); - reversedInsetMapping: Map = new Map(); + insetMapping: Map = new Map(); + hiddenInsetMapping: Set = new Set(); + reversedInsetMapping: Map = new Map(); localResourceRootsCache: URI[] | undefined = undefined; rendererRootsCache: URI[] = []; kernelRootsCache: URI[] = []; @@ -336,7 +336,7 @@ export class BackLayerWebView extends Disposable { }); } - private resolveOutputId(id: string): { cell: CodeCellViewModel, output: IProcessedOutput } | undefined { + private resolveOutputId(id: string): { cell: CodeCellViewModel, output: IDisplayOutputViewModel } | undefined { const output = this.reversedInsetMapping.get(id); if (!output) { return; @@ -461,7 +461,7 @@ var requirejs = (function() { const info = this.resolveOutputId(data.id); if (info) { const { cell, output } = info; - const outputIndex = cell.outputs.indexOf(output); + const outputIndex = cell.outputsViewModels.indexOf(output); cell.updateOutputHeight(outputIndex, outputHeight); this.notebookEditor.layoutNotebookCell(cell, cell.layoutInfo.totalHeight); } @@ -585,7 +585,7 @@ var requirejs = (function() { return webview; } - shouldUpdateInset(cell: CodeCellViewModel, output: IProcessedOutput, cellTop: number) { + shouldUpdateInset(cell: CodeCellViewModel, output: IDisplayOutputViewModel, cellTop: number) { if (this._disposed) { return; } @@ -595,7 +595,7 @@ var requirejs = (function() { } const outputCache = this.insetMapping.get(output)!; - const outputIndex = cell.outputs.indexOf(output); + const outputIndex = cell.outputsViewModels.indexOf(output); const outputOffset = cellTop + cell.getOutputOffset(outputIndex); if (this.hiddenInsetMapping.has(output)) { @@ -609,7 +609,7 @@ var requirejs = (function() { return true; } - updateViewScrollTop(top: number, forceDisplay: boolean, items: { cell: CodeCellViewModel, output: IProcessedOutput, cellTop: number }[]) { + updateViewScrollTop(top: number, forceDisplay: boolean, items: { cell: CodeCellViewModel, output: IDisplayOutputViewModel, cellTop: number }[]) { if (this._disposed) { return; } @@ -617,7 +617,7 @@ var requirejs = (function() { const widgets: IContentWidgetTopRequest[] = items.map(item => { const outputCache = this.insetMapping.get(item.output)!; const id = outputCache.outputId; - const outputIndex = item.cell.outputs.indexOf(item.output); + const outputIndex = item.cell.outputsViewModels.indexOf(item.output); const outputOffset = item.cellTop + item.cell.getOutputOffset(outputIndex); outputCache.cachedCreation.top = outputOffset; @@ -672,7 +672,7 @@ var requirejs = (function() { let message: ICreationRequestMessage; let renderer: INotebookRendererInfo | undefined; if (content.type === RenderOutputType.Extension) { - const output = content.source as ITransformedDisplayOutputDto; + const output = content.source.model; renderer = content.renderer; message = { ...messageBase, @@ -706,7 +706,7 @@ var requirejs = (function() { this.reversedInsetMapping.set(message.outputId, content.source); } - removeInset(output: IProcessedOutput) { + removeInset(output: IDisplayOutputViewModel) { if (this._disposed) { return; } @@ -729,7 +729,7 @@ var requirejs = (function() { this.reversedInsetMapping.delete(id); } - hideInset(output: IProcessedOutput) { + hideInset(output: IDisplayOutputViewModel) { if (this._disposed) { return; } diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellOutput.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellOutput.ts index ecd819b2beb..8c6a4129bc0 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellOutput.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellOutput.ts @@ -10,10 +10,10 @@ import { KeyCode } from 'vs/base/common/keyCodes'; import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { IQuickPickItem, IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; -import { CodeCellRenderTemplate, INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { CodeCellRenderTemplate, ICellOutputViewModel, IDisplayOutputViewModel, IInsetRenderOutput, INotebookEditor, IRenderOutput, outputHasDynamicHeight, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { getResizesObserver } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellWidgets'; import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel'; -import { IRenderOutput, BUILTIN_RENDERER_ID, RenderOutputType, outputHasDynamicHeight, CellUri, CellOutputKind, NotebookCellOutputsSplice, IInsetRenderOutput } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { BUILTIN_RENDERER_ID, CellUri, CellOutputKind, NotebookCellOutputsSplice } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { IMarkdownString } from 'vs/base/common/htmlContent'; import { renderMarkdown } from 'vs/base/browser/markdownRenderer'; @@ -23,7 +23,6 @@ import { format } from 'vs/base/common/jsonFormatter'; import { applyEdits } from 'vs/base/common/jsonEdit'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { mimetypeIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons'; -import { CellOutputViewModel, IDisplayOutputViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel'; const OUTPUT_COUNT_LIMIT = 500; @@ -42,7 +41,7 @@ export class OutputElement extends Disposable { private quickInputService: IQuickInputService, private viewCell: CodeCellViewModel, private outputContainer: HTMLElement, - readonly output: CellOutputViewModel + readonly output: ICellOutputViewModel ) { super(); } @@ -68,7 +67,7 @@ export class OutputElement extends Disposable { if (e.leftButton) { e.preventDefault(); e.stopPropagation(); - await this.pickActiveMimeTypeRenderer(this.output as CellOutputViewModel & IDisplayOutputViewModel); + await this.pickActiveMimeTypeRenderer(this.output as IDisplayOutputViewModel); } })); @@ -77,7 +76,7 @@ export class OutputElement extends Disposable { if ((event.equals(KeyCode.Enter) || event.equals(KeyCode.Space))) { e.preventDefault(); e.stopPropagation(); - await this.pickActiveMimeTypeRenderer(this.output as CellOutputViewModel & IDisplayOutputViewModel); + await this.pickActiveMimeTypeRenderer(this.output as IDisplayOutputViewModel); } }))); } @@ -90,10 +89,10 @@ export class OutputElement extends Disposable { if (pickedMimeTypeRenderer.rendererId !== BUILTIN_RENDERER_ID) { const renderer = this.notebookService.getRendererInfo(pickedMimeTypeRenderer.rendererId); result = renderer - ? { type: RenderOutputType.Extension, renderer, source: this.output.model, mimeType: pickedMimeTypeRenderer.mimeType } - : this.notebookEditor.getOutputRenderer().render(this.output.model, innerContainer, pickedMimeTypeRenderer.mimeType, this.getNotebookUri(),); + ? { type: RenderOutputType.Extension, renderer, source: this.output, mimeType: pickedMimeTypeRenderer.mimeType } + : this.notebookEditor.getOutputRenderer().render(this.output, innerContainer, pickedMimeTypeRenderer.mimeType, this.getNotebookUri(),); } else { - result = this.notebookEditor.getOutputRenderer().render(this.output.model, innerContainer, pickedMimeTypeRenderer.mimeType, this.getNotebookUri(),); + result = this.notebookEditor.getOutputRenderer().render(this.output, innerContainer, pickedMimeTypeRenderer.mimeType, this.getNotebookUri(),); } this.output.pickedMimeType = pick; @@ -102,7 +101,7 @@ export class OutputElement extends Disposable { const innerContainer = DOM.$('.output-inner-container'); DOM.append(outputItemDiv, innerContainer); - result = this.notebookEditor.getOutputRenderer().render(this.output.model, innerContainer, undefined, this.getNotebookUri(),); + result = this.notebookEditor.getOutputRenderer().render(this.output, innerContainer, undefined, this.getNotebookUri(),); } this.domNode = outputItemDiv; @@ -164,8 +163,7 @@ export class OutputElement extends Disposable { } } - async pickActiveMimeTypeRenderer(viewModel: CellOutputViewModel & IDisplayOutputViewModel) { - const output = viewModel.model; + async pickActiveMimeTypeRenderer(viewModel: IDisplayOutputViewModel) { const [mimeTypes, currIndex] = viewModel.resolveMimeTypes(this.notebookEditor.textModel!); const items = mimeTypes.filter(mimeType => mimeType.isTrusted).map((mimeType, index): IMimeTypeRenderer => ({ @@ -204,7 +202,7 @@ export class OutputElement extends Disposable { const element = this.domNode; if (element) { element.parentElement?.removeChild(element); - this.notebookEditor.removeInset(output); + this.notebookEditor.removeInset(viewModel); } viewModel.pickedMimeType = pick; @@ -238,7 +236,7 @@ export class OutputElement extends Disposable { } export class OutputContainer extends Disposable { - private outputEntries = new Map(); + private outputEntries = new Map(); constructor( private notebookEditor: INotebookEditor, @@ -336,7 +334,7 @@ export class OutputContainer extends Disposable { viewUpdateHideOuputs(): void { for (const e of this.outputEntries.keys()) { - this.notebookEditor.hideInset(e.model); + this.notebookEditor.hideInset(e as IDisplayOutputViewModel); } } @@ -349,7 +347,7 @@ export class OutputContainer extends Disposable { }); } - private _calcuateOutputsToRender(): CellOutputViewModel[] { + private _calcuateOutputsToRender(): ICellOutputViewModel[] { const outputs = this.viewCell.outputsViewModels.slice(0, Math.min(OUTPUT_COUNT_LIMIT, this.viewCell.outputsViewModels.length)); if (!this.notebookEditor.viewModel!.metadata.trusted) { // not trusted @@ -405,7 +403,7 @@ export class OutputContainer extends Disposable { this.viewCell.spliceOutputHeights(splice[0], splice[1], splice[2].map(_ => 0)); }); - const removedKeys: CellOutputViewModel[] = []; + const removedKeys: ICellOutputViewModel[] = []; this.outputEntries.forEach((value, key) => { if (this.viewCell.outputsViewModels.indexOf(key) < 0) { @@ -413,7 +411,9 @@ export class OutputContainer extends Disposable { removedKeys.push(key); // remove element from DOM this.templateData?.outputContainer?.removeChild(value.domNode); - this.notebookEditor.removeInset(key.model); + if (key.isDisplayOutput()) { + this.notebookEditor.removeInset(key); + } } }); @@ -456,7 +456,7 @@ export class OutputContainer extends Disposable { } } - private _renderOutput(currOutput: CellOutputViewModel, index: number, beforeElement?: HTMLElement) { + private _renderOutput(currOutput: ICellOutputViewModel, index: number, beforeElement?: HTMLElement) { if (!this.outputEntries.has(currOutput)) { this.outputEntries.set(currOutput, new OutputElement(this.notebookEditor, this.notebookService, this.quickInputService, this.viewCell, this.templateData.outputContainer, currOutput)); } diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts index 0de4cdaa717..4ef35e2bdad 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts @@ -5,8 +5,8 @@ import type { Event } from 'vs/base/common/event'; import type { IDisposable } from 'vs/base/common/lifecycle'; +import { RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { ToWebviewMessage } from 'vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView'; -import { RenderOutputType } from 'vs/workbench/contrib/notebook/common/notebookCommon'; // !! IMPORTANT !! everything must be in-line within the webviewPreloads // function. Imports are not allowed. This is stringifies and injected into diff --git a/src/vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel.ts b/src/vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel.ts index 2a2ec98c543..6f3b8bdd43b 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel.ts @@ -4,16 +4,12 @@ *--------------------------------------------------------------------------------------------*/ import { Disposable } from 'vs/base/common/lifecycle'; +import { ICellOutputViewModel, IDisplayOutputViewModel, IErrorOutputViewModel, IStreamOutputViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; import { CellOutputKind, IOrderedMimeType, IProcessedOutput, ITransformedDisplayOutputDto, RENDERER_NOT_AVAILABLE } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; -export interface IDisplayOutputViewModel { - model: ITransformedDisplayOutputDto; - resolveMimeTypes(textModel: NotebookTextModel): [readonly IOrderedMimeType[], number]; -} - -export class CellOutputViewModel extends Disposable { +export class CellOutputViewModel extends Disposable implements ICellOutputViewModel { get model() { return this._outputData; } @@ -33,6 +29,13 @@ export class CellOutputViewModel extends Disposable { ) { super(); } + isStreamOutput(): this is IStreamOutputViewModel { + return this._outputData.outputKind === CellOutputKind.Text; + } + + isErrorOutput(): this is IErrorOutputViewModel { + return this._outputData.outputKind === CellOutputKind.Error; + } isDisplayOutput(): this is IDisplayOutputViewModel { return this._outputData.outputKind === CellOutputKind.Rich; diff --git a/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts b/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts index bca4635e68e..0d104847236 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts @@ -10,7 +10,7 @@ import * as model from 'vs/editor/common/model'; import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { BOTTOM_CELL_TOOLBAR_GAP, BOTTOM_CELL_TOOLBAR_HEIGHT, CELL_BOTTOM_MARGIN, CELL_MARGIN, CELL_RUN_GUTTER, CELL_TOP_MARGIN, CODE_CELL_LEFT_MARGIN, COLLAPSED_INDICATOR_HEIGHT, EDITOR_BOTTOM_PADDING, EDITOR_TOOLBAR_HEIGHT } from 'vs/workbench/contrib/notebook/browser/constants'; -import { CellEditState, CellFindMatch, CodeCellLayoutChangeEvent, CodeCellLayoutInfo, CodeCellLayoutState, getEditorTopPadding, ICellViewModel, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { CellEditState, CellFindMatch, CodeCellLayoutChangeEvent, CodeCellLayoutInfo, CodeCellLayoutState, getEditorTopPadding, ICellOutputViewModel, ICellViewModel, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellOutputViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel'; import { NotebookEventDispatcher } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; @@ -67,7 +67,7 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod return this._layoutInfo; } - private _outputViewModels: CellOutputViewModel[]; + private _outputViewModels: ICellOutputViewModel[]; get outputsViewModels() { return this._outputViewModels; diff --git a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts index 941f4a479c4..d59dd7a95a3 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts @@ -271,36 +271,6 @@ export interface INotebookTextModel { onWillDispose(listener: () => void): IDisposable; } -export const enum RenderOutputType { - None, - Html, - Extension -} - -export interface IRenderNoOutput { - type: RenderOutputType.None; - hasDynamicHeight: boolean; -} - -export interface IRenderPlainHtmlOutput { - type: RenderOutputType.Html; - source: ITransformedDisplayOutputDto; - htmlContent: string; - hasDynamicHeight: boolean; -} - -export interface IRenderOutputViaExtension { - type: RenderOutputType.Extension; - source: ITransformedDisplayOutputDto; - mimeType: string; - renderer: INotebookRendererInfo; -} - -export type IInsetRenderOutput = IRenderPlainHtmlOutput | IRenderOutputViaExtension; -export type IRenderOutput = IRenderNoOutput | IInsetRenderOutput; - -export const outputHasDynamicHeight = (o: IRenderOutput) => o.type !== RenderOutputType.Extension && o.hasDynamicHeight; - export type NotebookCellTextModelSplice = [ number /* start */, number, diff --git a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts index 855ffe9fc61..ea7c4180a81 100644 --- a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts @@ -12,13 +12,13 @@ import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; import { Range } from 'vs/editor/common/core/range'; import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo'; import { EditorModel } from 'vs/workbench/common/editor'; -import { ICellViewModel, INotebookEditor, INotebookEditorContribution, INotebookEditorMouseEvent, NotebookLayoutInfo, INotebookDeltaDecoration, INotebookEditorCreationOptions, NotebookEditorOptions } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { ICellViewModel, INotebookEditor, INotebookEditorContribution, INotebookEditorMouseEvent, NotebookLayoutInfo, INotebookDeltaDecoration, INotebookEditorCreationOptions, NotebookEditorOptions, ICellOutputViewModel, IInsetRenderOutput } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer'; import { NotebookEventDispatcher } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher'; import { CellViewModel, IModelDecorationsChangeAccessor, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; -import { CellKind, CellUri, INotebookEditorModel, IProcessedOutput, NotebookCellMetadata, IInsetRenderOutput, ICellRange, INotebookKernelInfo2, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellKind, CellUri, INotebookEditorModel, IProcessedOutput, NotebookCellMetadata, ICellRange, INotebookKernelInfo2, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { Webview } from 'vs/workbench/contrib/webview/browser/webview'; import { ICompositeCodeEditor, IEditor } from 'vs/editor/common/editorCommon'; import { NotImplementedError } from 'vs/base/common/errors'; @@ -84,7 +84,7 @@ export class TestNotebookEditor implements INotebookEditor { throw new Error('Method not implemented.'); } - hideInset(output: IProcessedOutput): void { + hideInset(output: ICellOutputViewModel): void { throw new Error('Method not implemented.'); } @@ -282,7 +282,7 @@ export class TestNotebookEditor implements INotebookEditor { createInset(cell: CellViewModel, output: IInsetRenderOutput, offset: number): Promise { return Promise.resolve(); } - removeInset(output: IProcessedOutput): void { + removeInset(output: ICellOutputViewModel): void { // throw new Error('Method not implemented.'); } triggerScroll(event: IMouseWheelEvent): void { From ed0634933e24cd0701bd0c1901aea86349fd3d6f Mon Sep 17 00:00:00 2001 From: rebornix Date: Thu, 10 Dec 2020 16:03:45 -0800 Subject: [PATCH 009/262] :lipstick: --- .../contrib/notebook/browser/viewModel/codeCellViewModel.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts b/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts index 0d104847236..74f6cf9385a 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts @@ -33,9 +33,6 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod } private _outputsTop: PrefixSumComputer | null = null; - get outputs() { - return this.model.outputs; - } protected readonly _onDidChangeLayout = new Emitter(); readonly onDidChangeLayout = this._onDidChangeLayout.event; From 618bf22ca5ea100cc9a714a148e74a4e9664ac7b Mon Sep 17 00:00:00 2001 From: rebornix Date: Thu, 10 Dec 2020 16:11:42 -0800 Subject: [PATCH 010/262] remove !. --- .../browser/view/renderers/cellOutput.ts | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellOutput.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellOutput.ts index 8c6a4129bc0..6f17a156f95 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellOutput.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellOutput.ts @@ -23,6 +23,7 @@ import { format } from 'vs/base/common/jsonFormatter'; import { applyEdits } from 'vs/base/common/jsonEdit'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { mimetypeIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons'; +import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; const OUTPUT_COUNT_LIMIT = 500; @@ -51,11 +52,17 @@ export class OutputElement extends Disposable { return; } + if (!this.notebookEditor.hasModel()) { + return; + } + + const notebookTextModel = this.notebookEditor.viewModel.notebookDocument; + const outputItemDiv = document.createElement('div'); let result: IRenderOutput | undefined = undefined; if (this.output.isDisplayOutput()) { - const [mimeTypes, pick] = this.output.resolveMimeTypes(this.notebookEditor.textModel!); + const [mimeTypes, pick] = this.output.resolveMimeTypes(notebookTextModel); if (mimeTypes.length > 1) { outputItemDiv.style.position = 'relative'; const mimeTypePicker = DOM.$('.multi-mimetype-output'); @@ -67,7 +74,7 @@ export class OutputElement extends Disposable { if (e.leftButton) { e.preventDefault(); e.stopPropagation(); - await this.pickActiveMimeTypeRenderer(this.output as IDisplayOutputViewModel); + await this.pickActiveMimeTypeRenderer(notebookTextModel, this.output as IDisplayOutputViewModel); } })); @@ -76,7 +83,7 @@ export class OutputElement extends Disposable { if ((event.equals(KeyCode.Enter) || event.equals(KeyCode.Space))) { e.preventDefault(); e.stopPropagation(); - await this.pickActiveMimeTypeRenderer(this.output as IDisplayOutputViewModel); + await this.pickActiveMimeTypeRenderer(notebookTextModel, this.output as IDisplayOutputViewModel); } }))); } @@ -135,7 +142,7 @@ export class OutputElement extends Disposable { height: clientHeight }; const elementSizeObserver = getResizesObserver(outputItemDiv, dimension, () => { - if (this.outputContainer && document.body.contains(this.outputContainer!)) { + if (this.outputContainer && document.body.contains(this.outputContainer)) { const height = Math.ceil(elementSizeObserver.getHeight()); if (clientHeight === height) { @@ -163,8 +170,8 @@ export class OutputElement extends Disposable { } } - async pickActiveMimeTypeRenderer(viewModel: IDisplayOutputViewModel) { - const [mimeTypes, currIndex] = viewModel.resolveMimeTypes(this.notebookEditor.textModel!); + private async pickActiveMimeTypeRenderer(notebookTextModel: NotebookTextModel, viewModel: IDisplayOutputViewModel) { + const [mimeTypes, currIndex] = viewModel.resolveMimeTypes(notebookTextModel); const items = mimeTypes.filter(mimeType => mimeType.isTrusted).map((mimeType, index): IMimeTypeRenderer => ({ label: mimeType.mimeType, @@ -215,7 +222,7 @@ export class OutputElement extends Disposable { return CellUri.parse(this.viewCell.uri)?.notebook; } - generateRendererInfo(renderId: string | undefined): string { + private generateRendererInfo(renderId: string | undefined): string { if (renderId === undefined || renderId === BUILTIN_RENDERER_ID) { return nls.localize('builtinRenderInfo', "built-in"); } @@ -230,7 +237,7 @@ export class OutputElement extends Disposable { return nls.localize('builtinRenderInfo', "built-in"); } - relayoutCell() { + private relayoutCell() { this.notebookEditor.layoutNotebookCell(this.viewCell, this.viewCell.layoutInfo.totalHeight); } } From 7ae944e4b043e5c84a687c401654b3e06b86182d Mon Sep 17 00:00:00 2001 From: rebornix Date: Fri, 11 Dec 2020 14:19:23 -0800 Subject: [PATCH 011/262] load static renderers --- .../notebook/browser/diff/cellComponents.ts | 94 ++++++++-- .../notebook/browser/diff/cellOutputs.ts | 165 ++++++++++++++++++ .../contrib/notebook/browser/diff/common.ts | 2 + .../notebook/browser/diff/notebookDiff.css | 69 +++++++- .../browser/diff/notebookTextDiffEditor.ts | 23 ++- .../notebook/browser/notebookBrowser.ts | 1 - 6 files changed, 333 insertions(+), 21 deletions(-) create mode 100644 src/vs/workbench/contrib/notebook/browser/diff/cellOutputs.ts diff --git a/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts index a6c71a531c6..eebd011d88a 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts @@ -32,6 +32,9 @@ import { getEditorTopPadding } from 'vs/workbench/contrib/notebook/browser/noteb import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { collapsedIcon, expandedIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons'; import { renderCodicons } from 'vs/base/browser/codicons'; +import { OutputContainer } from 'vs/workbench/contrib/notebook/browser/diff/cellOutputs'; + +const RENDER_RICH_OUTPUT = true; const fixedEditorOptions: IEditorOptions = { padding: { @@ -82,7 +85,7 @@ class PropertyHeader extends Disposable { constructor( readonly cell: CellDiffViewModel, - readonly metadataHeaderContainer: HTMLElement, + readonly propertyHeaderContainer: HTMLElement, readonly notebookEditor: INotebookTextDiffEditor, readonly accessor: { updateInfoRendering: () => void; @@ -105,21 +108,21 @@ class PropertyHeader extends Disposable { buildHeader(): void { let metadataChanged = this.accessor.checkIfModified(this.cell); - this._foldingIndicator = DOM.append(this.metadataHeaderContainer, DOM.$('.property-folding-indicator')); + this._foldingIndicator = DOM.append(this.propertyHeaderContainer, DOM.$('.property-folding-indicator')); this._foldingIndicator.classList.add(this.accessor.prefix); this._updateFoldingIcon(); - const metadataStatus = DOM.append(this.metadataHeaderContainer, DOM.$('div.property-status')); + const metadataStatus = DOM.append(this.propertyHeaderContainer, DOM.$('div.property-status')); this._statusSpan = DOM.append(metadataStatus, DOM.$('span')); if (metadataChanged) { this._statusSpan.textContent = this.accessor.changedLabel; this._statusSpan.style.fontWeight = 'bold'; - this.metadataHeaderContainer.classList.add('modified'); + this.propertyHeaderContainer.classList.add('modified'); } else { this._statusSpan.textContent = this.accessor.unChangedLabel; } - const cellToolbarContainer = DOM.append(this.metadataHeaderContainer, DOM.$('div.property-toolbar')); + const cellToolbarContainer = DOM.append(this.propertyHeaderContainer, DOM.$('div.property-toolbar')); this._toolbar = new ToolBar(cellToolbarContainer, this.contextMenuService, { actionViewItemProvider: action => { if (action instanceof MenuItemAction) { @@ -190,7 +193,7 @@ class PropertyHeader extends Disposable { if (metadataChanged) { this._statusSpan.textContent = this.accessor.changedLabel; this._statusSpan.style.fontWeight = 'bold'; - this.metadataHeaderContainer.classList.add('modified'); + this.propertyHeaderContainer.classList.add('modified'); const actions: IAction[] = []; createAndFillInActionBarActions(this._menu, undefined, actions); this._toolbar.setActions(actions); @@ -222,6 +225,11 @@ abstract class AbstractCellRenderer extends Disposable { protected _outputHeader!: PropertyHeader; protected _outputInfoContainer!: HTMLElement; protected _outputEditorContainer?: HTMLElement; + protected _outputViewContainer?: HTMLElement; + protected _outputLeftContainer?: HTMLElement; + protected _outputRightContainer?: HTMLElement; + protected _outputLeftView?: OutputContainer; + protected _outputRightView?: OutputContainer; protected _outputEditorDisposeStore!: DisposableStore; protected _outputEditor?: CodeEditorWidget | DiffEditorWidget; @@ -300,15 +308,26 @@ abstract class AbstractCellRenderer extends Disposable { updateOutputRendering() { if (this.cell.outputFoldingState === PropertyFoldingState.Expanded) { - this._outputInfoContainer.style.display = 'block'; + if (RENDER_RICH_OUTPUT) { + this._outputInfoContainer.style.display = 'block'; - if (!this._outputEditorContainer || !this._outputEditor) { - // create editor - this._outputEditorContainer = DOM.append(this._outputInfoContainer, DOM.$('.output-editor-container')); - this._buildOutputEditor(); + if (!this._outputViewContainer) { + this._outputViewContainer = DOM.append(this._outputInfoContainer, DOM.$('.output-view-container')); + this._buildOutputContainer(); + } else { + this.layout({ outputView: true }); + } } else { - this._layoutInfo.outputHeight = this._outputEditor.getContentHeight(); - this.layout({ outputEditor: true }); + this._outputInfoContainer.style.display = 'block'; + + if (!this._outputEditorContainer || !this._outputEditor) { + // create editor + this._outputEditorContainer = DOM.append(this._outputInfoContainer, DOM.$('.output-editor-container')); + this._buildOutputEditor(); + } else { + this._layoutInfo.outputHeight = this._outputEditor.getContentHeight(); + this.layout({ outputEditor: true }); + } } } else { this._outputInfoContainer.style.display = 'none'; @@ -318,6 +337,8 @@ abstract class AbstractCellRenderer extends Disposable { } } + abstract _buildOutputContainer(): void; + protected _getFormatedMetadataJSON(metadata: NotebookCellMetadata, language?: string) { let filteredMetadata: { [key: string]: any } = {}; @@ -638,7 +659,7 @@ abstract class AbstractCellRenderer extends Disposable { abstract styleContainer(container: HTMLElement): void; abstract updateSourceEditor(): void; abstract onDidLayoutChange(event: CellDiffViewModelLayoutChangeEvent): void; - abstract layout(state: { outerWidth?: boolean, editorHeight?: boolean, metadataEditor?: boolean, outputEditor?: boolean }): void; + abstract layout(state: { outerWidth?: boolean, editorHeight?: boolean, metadataEditor?: boolean, outputEditor?: boolean, outputView?: boolean }): void; } abstract class SingleSideCell extends AbstractCellRenderer { @@ -779,7 +800,6 @@ abstract class SingleSideCell extends AbstractCellRenderer { this._register(this._outputHeader); this._outputHeader.buildHeader(); } - } export class DeletedCell extends SingleSideCell { private _editor!: CodeEditorWidget; @@ -872,6 +892,12 @@ export class DeletedCell extends SingleSideCell { this.layoutNotebookCell(); }); } + + _buildOutputContainer() { + // this._outputView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell.modified!, this._outputViewContainer!); + // this._outputView.render(); + // this.layout({ outputView: true }); + } } export class InsertCell extends SingleSideCell { @@ -939,7 +965,13 @@ export class InsertCell extends SingleSideCell { } } - layout(state: { outerWidth?: boolean, editorHeight?: boolean, metadataEditor?: boolean, outputEditor?: boolean }) { + _buildOutputContainer() { + this._outputLeftView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell.modified!, this._outputViewContainer!); + this._outputLeftView.render(); + this.layout({ outputView: true }); + } + + layout(state: { outerWidth?: boolean, editorHeight?: boolean, metadataEditor?: boolean, outputEditor?: boolean, outputView?: boolean }) { DOM.scheduleAtNextAnimationFrame(() => { if (state.editorHeight || state.outerWidth) { this._editor.layout({ @@ -962,7 +994,15 @@ export class InsertCell extends SingleSideCell { }); } + if (state.outputView) { + this._layoutInfo.outputHeight = (this._outputViewContainer!.childNodes[0] as HTMLElement).clientHeight; + } + this.layoutNotebookCell(); + + if (this._diagonalFill) { + this._diagonalFill.style.height = `${this._layoutInfo.editorHeight + this._layoutInfo.editorMargin + this._layoutInfo.metadataStatusHeight + this._layoutInfo.metadataHeight + this._layoutInfo.outputHeight + this._layoutInfo.outputStatusHeight}px`; + } }); } } @@ -1068,6 +1108,10 @@ export class ModifiedCell extends AbstractCellRenderer { return cell.type !== 'delete' && cell.type !== 'insert' && !this.notebookEditor.textModel!.transientOptions.transientOutputs && cell.type === 'modified' && hash(cell.original?.outputs ?? []) !== hash(cell.modified?.outputs ?? []); }; + if (checkIfOutputsModified(this.cell)) { + this._outputInfoContainer.classList.add('modified'); + } + if (checkIfOutputsModified(this.cell)) { this.cell.outputFoldingState = PropertyFoldingState.Expanded; } @@ -1098,6 +1142,17 @@ export class ModifiedCell extends AbstractCellRenderer { this._outputHeader.buildHeader(); } + _buildOutputContainer() { + this._outputLeftContainer = DOM.append(this._outputViewContainer!, DOM.$('.output-view-container-left')); + this._outputRightContainer = DOM.append(this._outputViewContainer!, DOM.$('.output-view-container-right')); + // We should use the original text model here + this._outputLeftView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell.original!, this._outputLeftContainer!); + this._outputLeftView.render(); + this._outputRightView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell.modified!, this._outputRightContainer!); + this._outputRightView.render(); + + this.layout({ outputView: true }); + } updateSourceEditor(): void { const modifiedCell = this.cell.modified!; @@ -1202,7 +1257,7 @@ export class ModifiedCell extends AbstractCellRenderer { } } - layout(state: { outerWidth?: boolean, editorHeight?: boolean, metadataEditor?: boolean, outputEditor?: boolean }) { + layout(state: { outerWidth?: boolean, editorHeight?: boolean, metadataEditor?: boolean, outputEditor?: boolean, outputView?: boolean }) { DOM.scheduleAtNextAnimationFrame(() => { if (state.editorHeight) { this._editorContainer.style.height = `${this._layoutInfo.editorHeight}px`; @@ -1231,6 +1286,11 @@ export class ModifiedCell extends AbstractCellRenderer { } } + if (state.outputView) { + this._layoutInfo.outputHeight = Math.max((this._outputLeftContainer!.childNodes[0] as HTMLElement).clientHeight, (this._outputRightContainer!.childNodes[0] as HTMLElement).clientHeight); + } + + this.layoutNotebookCell(); }); } diff --git a/src/vs/workbench/contrib/notebook/browser/diff/cellOutputs.ts b/src/vs/workbench/contrib/notebook/browser/diff/cellOutputs.ts new file mode 100644 index 00000000000..6ba1e204d3a --- /dev/null +++ b/src/vs/workbench/contrib/notebook/browser/diff/cellOutputs.ts @@ -0,0 +1,165 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as DOM from 'vs/base/browser/dom'; +import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { IOpenerService } from 'vs/platform/opener/common/opener'; +import { INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common'; +import { ICellOutputViewModel, IRenderOutput, outputHasDynamicHeight, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { CellOutputViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel'; +import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; +import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; +import { BUILTIN_RENDERER_ID } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; +import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; + +export class OutputElement extends Disposable { + readonly resizeListener = new DisposableStore(); + domNode!: HTMLElement; + renderResult?: IRenderOutput; + + constructor( + private notebookEditor: INotebookTextDiffEditor, + private notebookTextModel: NotebookTextModel, + private notebookService: INotebookService, + // private viewCell: CodeCellViewModel, + private outputContainer: HTMLElement, + readonly output: ICellOutputViewModel + ) { + super(); + } + + render(beforeElement?: HTMLElement) { + const outputItemDiv = document.createElement('div'); + let result: IRenderOutput | undefined = undefined; + + if (this.output.isDisplayOutput()) { + const [mimeTypes, pick] = this.output.resolveMimeTypes(this.notebookTextModel); + const pickedMimeTypeRenderer = mimeTypes[pick]; + const innerContainer = DOM.$('.output-inner-container'); + DOM.append(outputItemDiv, innerContainer); + + + if (pickedMimeTypeRenderer.rendererId !== BUILTIN_RENDERER_ID) { + const renderer = this.notebookService.getRendererInfo(pickedMimeTypeRenderer.rendererId); + result = renderer + ? { type: RenderOutputType.Extension, renderer, source: this.output, mimeType: pickedMimeTypeRenderer.mimeType } + : this.notebookEditor.getOutputRenderer().render(this.output, innerContainer, pickedMimeTypeRenderer.mimeType, this.notebookTextModel.uri,); + } else { + result = this.notebookEditor.getOutputRenderer().render(this.output, innerContainer, pickedMimeTypeRenderer.mimeType, this.notebookTextModel.uri); + } + + this.output.pickedMimeType = pick; + } else { + // for text and error, there is no mimetype + const innerContainer = DOM.$('.output-inner-container'); + DOM.append(outputItemDiv, innerContainer); + + result = this.notebookEditor.getOutputRenderer().render(this.output, innerContainer, undefined, this.notebookTextModel.uri); + } + + this.domNode = outputItemDiv; + this.renderResult = result; + + if (!result) { + // this.viewCell.updateOutputHeight(index, 0); + return; + } + + if (beforeElement) { + this.outputContainer.insertBefore(outputItemDiv, beforeElement); + } else { + this.outputContainer.appendChild(outputItemDiv); + } + + if (result.type !== RenderOutputType.None) { + // this.viewCell.selfSizeMonitoring = true; + // this.notebookEditor.createInset(this.viewCell, result as any, this.viewCell.getOutputOffset(index)); + } else { + outputItemDiv.classList.add('foreground', 'output-element'); + outputItemDiv.style.position = 'absolute'; + } + + if (outputHasDynamicHeight(result)) { + // this.viewCell.selfSizeMonitoring = true; + + // const clientHeight = outputItemDiv.clientHeight; + // const dimension = { + // width: this.viewCell.layoutInfo.editorWidth, + // height: clientHeight + // }; + // const elementSizeObserver = getResizesObserver(outputItemDiv, dimension, () => { + // if (this.outputContainer && document.body.contains(this.outputContainer)) { + // const height = Math.ceil(elementSizeObserver.getHeight()); + + // if (clientHeight === height) { + // return; + // } + + // const currIndex = this.viewCell.outputsViewModels.indexOf(this.output); + // if (currIndex < 0) { + // return; + // } + + // this.viewCell.updateOutputHeight(currIndex, height); + // this.relayoutCell(); + // } + // }); + // elementSizeObserver.startObserving(); + // this.resizeListener.add(elementSizeObserver); + // this.viewCell.updateOutputHeight(index, clientHeight); + } else if (result.type === RenderOutputType.None) { // no-op if it's a webview + // const clientHeight = Math.ceil(outputItemDiv.clientHeight); + // this.viewCell.updateOutputHeight(index, clientHeight); + + // const top = this.viewCell.getOutputOffsetInContainer(index); + // outputItemDiv.style.top = `${top}px`; + } + } + +} + +export class OutputContainer extends Disposable { + private _outputViewModels: ICellOutputViewModel[]; + private outputEntries = new Map(); + constructor( + private _editor: INotebookTextDiffEditor, + private notebookTextModel: NotebookTextModel, + cell: NotebookCellTextModel, + private outputContainer: HTMLElement, + @INotebookService private notebookService: INotebookService, + // @IQuickInputService private readonly quickInputService: IQuickInputService, + @IOpenerService readonly openerService: IOpenerService, + @ITextFileService readonly textFileService: ITextFileService, + + ) { + super(); + this._outputViewModels = cell.outputs.map(output => new CellOutputViewModel(output, notebookService)); + + // TODO, onDidChangeOutputs + + // viewCell.onDidChangeLayout + // say the height of the cell editor changes + } + + render() { + // TODO, outputs to render (should have a limit) + for (let index = 0; index < this._outputViewModels.length; index++) { + const currOutput = this._outputViewModels[index]; + + // always add to the end + this._renderOutput(currOutput, index, undefined); + } + } + + private _renderOutput(currOutput: ICellOutputViewModel, index: number, beforeElement?: HTMLElement) { + if (!this.outputEntries.has(currOutput)) { + this.outputEntries.set(currOutput, new OutputElement(this._editor, this.notebookTextModel, this.notebookService, this.outputContainer, currOutput)); + } + + this.outputEntries.get(currOutput)!.render(beforeElement); + + } +} diff --git a/src/vs/workbench/contrib/notebook/browser/diff/common.ts b/src/vs/workbench/contrib/notebook/browser/diff/common.ts index 8fa33af9dbe..115173f8bac 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/common.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/common.ts @@ -12,6 +12,7 @@ import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/no import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; +import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer'; export interface INotebookTextDiffEditor { readonly textModel?: NotebookTextModel; @@ -19,6 +20,7 @@ export interface INotebookTextDiffEditor { getOverflowContainerDomNode(): HTMLElement; getLayoutInfo(): NotebookLayoutInfo; layoutNotebookCell(cell: CellDiffViewModel, height: number): void; + getOutputRenderer(): OutputRenderer; } export interface CellDiffSingleSideRenderTemplate { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css index 950cbce2f43..5866ea2c558 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css @@ -32,7 +32,8 @@ .notebook-text-diff-editor .cell-body .cell-diff-editor-container { width: 100%; - overflow: hidden; + /* why we overflow hidden at the beginning?*/ + /* overflow: hidden; */ } .notebook-text-diff-editor .cell-body .cell-diff-editor-container .metadata-editor-container.diff, @@ -106,6 +107,10 @@ overflow: hidden; } +.monaco-workbench .notebook-text-diff-editor > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row { + overflow: visible !important; +} + .monaco-workbench .notebook-text-diff-editor > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row, .monaco-workbench .notebook-text-diff-editor > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row:hover, .monaco-workbench .notebook-text-diff-editor > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.focused { @@ -118,3 +123,65 @@ top: 16px; margin: 4px 2px; } + + + +.monaco-workbench .notebook-text-diff-editor .cell-body .output-view-container .output-inner-container { + /* overflow-x: scroll; */ + white-space: initial; +} + +.monaco-workbench .notebook-text-diff-editor .cell-body.left .output-view-container .output-inner-container, +.monaco-workbench .notebook-text-diff-editor .cell-body.right .output-view-container .output-inner-container { + width: calc(50% - 16px); + padding: 4px 8px; + box-sizing: border-box; +} +.monaco-workbench .notebook-text-diff-editor .cell-body.full .output-view-container .output-inner-container { + width: calc(100% - 16px); + padding: 4px 8px; + box-sizing: border-box; +} + +.monaco-workbench .notebook-text-diff-editor .cell-body.full .output-info-container.modified .output-view-container .output-view-container-left, +.monaco-workbench .notebook-text-diff-editor .cell-body.full .output-info-container.modified .output-view-container .output-view-container-right { + width: 50%; + display: inline-block; +} + +.monaco-workbench .notebook-text-diff-editor .cell-body.full .output-info-container.modified .output-view-container .output-view-container-left, +.monaco-workbench .notebook-text-diff-editor .cell-body.full .output-info-container.modified .output-view-container .output-view-container-right { + width: 50%; + position: relative; +} + +.monaco-workbench .notebook-text-diff-editor .cell-body.full .output-info-container.modified .output-view-container .output-view-container-left div.foreground, +.monaco-workbench .notebook-text-diff-editor .cell-body.full .output-info-container.modified .output-view-container .output-view-container-right div.foreground { + width: 100%; +} + +.monaco-workbench .notebook-text-diff-editor .output-view-container > div.foreground { + width: 100%; + min-height: 24px; + box-sizing: border-box; +} + +.monaco-workbench .notebook-text-diff-editor .output-view-container .error_message { + color: red; +} + +.monaco-workbench .notebook-text-diff-editor .output-view-container .error > div { + white-space: normal; +} + +.monaco-workbench .notebook-text-diff-editor .output-view-container .error pre.traceback { + margin: 8px 0; +} + +.monaco-workbench .notebook-text-diff-editor .output-view-container .error .traceback > span { + display: block; +} + +.monaco-workbench .notebook-text-diff-editor .output-view-container .display img { + max-width: 100%; +} diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 5c715b6d923..473e3cea78d 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -24,7 +24,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; import { getZoomLevel } from 'vs/base/browser/browser'; -import { NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { INotebookEditor, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { DIFF_CELL_MARGIN, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common'; import { Emitter } from 'vs/base/common/event'; import { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; @@ -37,6 +37,7 @@ import { URI } from 'vs/base/common/uri'; import { Schemas } from 'vs/base/common/network'; import { IDiffChange } from 'vs/base/common/diff/diff'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; +import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer'; export const IN_NOTEBOOK_TEXT_DIFF_EDITOR = new RawContextKey('isInNotebookTextDiffEditor', false); @@ -55,6 +56,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD protected _scopeContextKeyService!: IContextKeyService; private _model: INotebookDiffEditorModel | null = null; private _modifiedResourceDisposableStore = new DisposableStore(); + private _outputRenderer: OutputRenderer; get textModel() { return this._model?.modified.notebook; @@ -79,6 +81,8 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD this._revealFirst = true; this._register(this._modifiedResourceDisposableStore); + // TODO + this._outputRenderer = new OutputRenderer(this as unknown as INotebookEditor, this.instantiationService); } protected createEditor(parent: HTMLElement): void { @@ -381,6 +385,10 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD this._list?.splice(0, this._list?.length || 0); } + getOutputRenderer(): OutputRenderer { + return this._outputRenderer; + } + getLayoutInfo(): NotebookLayoutInfo { if (!this._list) { throw new Error('Editor is not initalized successfully'); @@ -430,6 +438,11 @@ registerThemingParticipant((theme, collector) => { const added = theme.getColor(diffInserted); if (added) { + collector.addRule( + ` + .monaco-workbench .notebook-text-diff-editor .cell-body.full .output-info-container.modified .output-view-container .output-view-container-right div.foreground { background-color: ${added}; } + ` + ); collector.addRule(` .notebook-text-diff-editor .cell-body .cell-diff-editor-container.inserted .source-container { background-color: ${added}; } .notebook-text-diff-editor .cell-body .cell-diff-editor-container.inserted .source-container .monaco-editor .margin, @@ -448,6 +461,7 @@ registerThemingParticipant((theme, collector) => { ); collector.addRule(` .notebook-text-diff-editor .cell-body .cell-diff-editor-container.inserted .output-editor-container { background-color: ${added}; } + .notebook-text-diff-editor .cell-body .cell-diff-editor-container.inserted .output-inner-container { background-color: ${added}; } .notebook-text-diff-editor .cell-body .cell-diff-editor-container.inserted .output-editor-container .monaco-editor .margin, .notebook-text-diff-editor .cell-body .cell-diff-editor-container.inserted .output-editor-container .monaco-editor .monaco-editor-background { background-color: ${added}; @@ -461,7 +475,12 @@ registerThemingParticipant((theme, collector) => { ); } const removed = theme.getColor(diffRemoved); - if (added) { + if (removed) { + collector.addRule( + ` + .monaco-workbench .notebook-text-diff-editor .cell-body.full .output-info-container.modified .output-view-container .output-view-container-left div.foreground { background-color: ${removed}; } + ` + ); collector.addRule(` .notebook-text-diff-editor .cell-body .cell-diff-editor-container.removed .source-container { background-color: ${removed}; } .notebook-text-diff-editor .cell-body .cell-diff-editor-container.removed .source-container .monaco-editor .margin, diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index 60c9cf0f345..5c8a46f1063 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -164,7 +164,6 @@ export interface IDisplayOutputViewModel extends ICellOutputViewModel { model: ITransformedDisplayOutputDto; resolveMimeTypes(textModel: NotebookTextModel): [readonly IOrderedMimeType[], number]; pickedMimeType: number; - resolveMimeTypes(textModel: NotebookTextModel): [readonly IOrderedMimeType[], number]; } export interface IErrorOutputViewModel extends ICellOutputViewModel { From 75dd72eeff5aad66989973cfbf352ebb699c5d0c Mon Sep 17 00:00:00 2001 From: rebornix Date: Fri, 11 Dec 2020 15:17:15 -0800 Subject: [PATCH 012/262] move layout info into diff cell view model. --- .../notebook/browser/diff/cellComponents.ts | 160 +++++------------- .../browser/diff/celllDiffViewModel.ts | 86 +++++++++- .../contrib/notebook/browser/diff/common.ts | 6 +- 3 files changed, 134 insertions(+), 118 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts index eebd011d88a..0fa9531f4a5 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts @@ -8,7 +8,7 @@ import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IDiffEditorOptions, IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { CellDiffViewModel, PropertyFoldingState } from 'vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel'; -import { CellDiffSideBySideRenderTemplate, CellDiffSingleSideRenderTemplate, CellDiffViewModelLayoutChangeEvent, DIFF_CELL_MARGIN, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common'; +import { CellDiffSideBySideRenderTemplate, CellDiffSingleSideRenderTemplate, DIFF_CELL_MARGIN, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common'; import { EDITOR_BOTTOM_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; @@ -236,15 +236,6 @@ abstract class AbstractCellRenderer extends Disposable { protected _diffEditorContainer!: HTMLElement; protected _diagonalFill?: HTMLElement; - protected _layoutInfo!: { - editorHeight: number; - editorMargin: number; - metadataStatusHeight: number; - metadataHeight: number; - outputStatusHeight: number; - outputHeight: number; - bodyMargin: number; - }; protected _isDisposed: boolean; constructor( @@ -266,20 +257,11 @@ abstract class AbstractCellRenderer extends Disposable { super(); // init this._isDisposed = false; - this._layoutInfo = { - editorHeight: 0, - editorMargin: 0, - metadataHeight: 0, - metadataStatusHeight: 25, - outputHeight: 0, - outputStatusHeight: 25, - bodyMargin: 32 - }; this._metadataEditorDisposeStore = new DisposableStore(); this._outputEditorDisposeStore = new DisposableStore(); this._register(this._metadataEditorDisposeStore); + this._register(cell.onDidLayoutChange(e => this.layout(e))); this.buildBody(); - this._register(cell.onDidLayoutChange(e => this.onDidLayoutChange(e))); } abstract buildBody(): void; @@ -294,15 +276,13 @@ abstract class AbstractCellRenderer extends Disposable { this._metadataEditorContainer = DOM.append(this._metadataInfoContainer, DOM.$('.metadata-editor-container')); this._buildMetadataEditor(); } else { - this._layoutInfo.metadataHeight = this._metadataEditor.getContentHeight(); - this.layout({ metadataEditor: true }); + this.cell.metadataHeight = this._metadataEditor.getContentHeight(); } } else { // we should collapse the metadata editor this._metadataInfoContainer.style.display = 'none'; this._metadataEditorDisposeStore.clear(); - this._layoutInfo.metadataHeight = 0; - this.layout({}); + this.cell.metadataHeight = 0; } } @@ -315,6 +295,7 @@ abstract class AbstractCellRenderer extends Disposable { this._outputViewContainer = DOM.append(this._outputInfoContainer, DOM.$('.output-view-container')); this._buildOutputContainer(); } else { + // TODO, should we check its height? this.layout({ outputView: true }); } } else { @@ -325,15 +306,13 @@ abstract class AbstractCellRenderer extends Disposable { this._outputEditorContainer = DOM.append(this._outputInfoContainer, DOM.$('.output-editor-container')); this._buildOutputEditor(); } else { - this._layoutInfo.outputHeight = this._outputEditor.getContentHeight(); - this.layout({ outputEditor: true }); + this.cell.outputHeight = this._outputEditor.getContentHeight(); } } } else { this._outputInfoContainer.style.display = 'none'; this._outputEditorDisposeStore.clear(); - this._layoutInfo.outputHeight = 0; - this.layout({}); + this.cell.outputHeight = 0; } } @@ -479,13 +458,11 @@ abstract class AbstractCellRenderer extends Disposable { this._register(originalMetadataModel); this._register(modifiedMetadataModel); - this._layoutInfo.metadataHeight = this._metadataEditor.getContentHeight(); - this.layout({ metadataEditor: true }); + this.cell.metadataHeight = this._metadataEditor.getContentHeight(); this._register(this._metadataEditor.onDidContentSizeChange((e) => { if (e.contentHeightChanged && this.cell.metadataFoldingState === PropertyFoldingState.Expanded) { - this._layoutInfo.metadataHeight = e.contentHeight; - this.layout({ metadataEditor: true }); + this.cell.metadataHeight = e.contentHeight; } })); @@ -539,13 +516,11 @@ abstract class AbstractCellRenderer extends Disposable { this._metadataEditor.setModel(metadataModel); this._register(metadataModel); - this._layoutInfo.metadataHeight = this._metadataEditor.getContentHeight(); - this.layout({ metadataEditor: true }); + this.cell.metadataHeight = this._metadataEditor.getContentHeight(); this._register(this._metadataEditor.onDidContentSizeChange((e) => { if (e.contentHeightChanged && this.cell.metadataFoldingState === PropertyFoldingState.Expanded) { - this._layoutInfo.metadataHeight = e.contentHeight; - this.layout({ metadataEditor: true }); + this.cell.metadataHeight = e.contentHeight; } })); } @@ -587,13 +562,11 @@ abstract class AbstractCellRenderer extends Disposable { modified: modifiedModel }); - this._layoutInfo.outputHeight = this._outputEditor.getContentHeight(); - this.layout({ outputEditor: true }); + this.cell.outputHeight = this._outputEditor.getContentHeight(); this._register(this._outputEditor.onDidContentSizeChange((e) => { if (e.contentHeightChanged && this.cell.outputFoldingState === PropertyFoldingState.Expanded) { - this._layoutInfo.outputHeight = e.contentHeight; - this.layout({ outputEditor: true }); + this.cell.outputHeight = e.contentHeight; } })); @@ -627,13 +600,11 @@ abstract class AbstractCellRenderer extends Disposable { const outputModel = this.modelService.createModel(originaloutputSource, mode, undefined, true); this._outputEditor.setModel(outputModel); - this._layoutInfo.outputHeight = this._outputEditor.getContentHeight(); - this.layout({ outputEditor: true }); + this.cell.outputHeight = this._outputEditor.getContentHeight(); this._register(this._outputEditor.onDidContentSizeChange((e) => { if (e.contentHeightChanged && this.cell.outputFoldingState === PropertyFoldingState.Expanded) { - this._layoutInfo.outputHeight = e.contentHeight; - this.layout({ outputEditor: true }); + this.cell.outputHeight = e.contentHeight; } })); } @@ -641,13 +612,7 @@ abstract class AbstractCellRenderer extends Disposable { protected layoutNotebookCell() { this.notebookEditor.layoutNotebookCell( this.cell, - this._layoutInfo.editorHeight - + this._layoutInfo.editorMargin - + this._layoutInfo.metadataHeight - + this._layoutInfo.metadataStatusHeight - + this._layoutInfo.outputHeight - + this._layoutInfo.outputStatusHeight - + this._layoutInfo.bodyMargin + this.cell.totalHeight ); } @@ -658,7 +623,6 @@ abstract class AbstractCellRenderer extends Disposable { abstract styleContainer(container: HTMLElement): void; abstract updateSourceEditor(): void; - abstract onDidLayoutChange(event: CellDiffViewModelLayoutChangeEvent): void; abstract layout(state: { outerWidth?: boolean, editorHeight?: boolean, metadataEditor?: boolean, outputEditor?: boolean, outputView?: boolean }): void; } @@ -753,9 +717,8 @@ abstract class SingleSideCell extends AbstractCellRenderer { this._metadataHeader.buildHeader(); if (this.notebookEditor.textModel?.transientOptions.transientOutputs) { - this._layoutInfo.outputHeight = 0; - this._layoutInfo.outputStatusHeight = 0; - this.layout({}); + this.cell.outputHeight = 0; + this.cell.outputStatusHeight = 0; this.templateData.outputHeaderContainer.style.display = 'none'; this.templateData.outputInfoContainer.style.display = 'none'; return; @@ -837,12 +800,11 @@ export class DeletedCell extends SingleSideCell { height: editorHeight }); - this._layoutInfo.editorHeight = editorHeight; + this.cell.editorHeight = editorHeight; this._register(this._editor.onDidContentSizeChange((e) => { - if (e.contentHeightChanged && this._layoutInfo.editorHeight !== e.contentHeight) { - this._layoutInfo.editorHeight = e.contentHeight; - this.layout({ editorHeight: true }); + if (e.contentHeightChanged && this.cell.editorHeight !== e.contentHeight) { + this.cell.editorHeight = e.contentHeight; } })); @@ -855,37 +817,30 @@ export class DeletedCell extends SingleSideCell { const textModel = ref.object.textEditorModel; this._editor.setModel(textModel); - this._layoutInfo.editorHeight = this._editor.getContentHeight(); - this.layout({ editorHeight: true }); + this.cell.editorHeight = this._editor.getContentHeight(); }); - } - onDidLayoutChange(e: CellDiffViewModelLayoutChangeEvent) { - if (e.outerWidth !== undefined) { - this.layout({ outerWidth: true }); - } - } layout(state: { outerWidth?: boolean, editorHeight?: boolean, metadataEditor?: boolean, outputEditor?: boolean }) { DOM.scheduleAtNextAnimationFrame(() => { if (state.editorHeight || state.outerWidth) { this._editor.layout({ width: this.cell.getComputedCellContainerWidth(this.notebookEditor.getLayoutInfo(), false, false), - height: this._layoutInfo.editorHeight + height: this.cell.editorHeight }); } if (state.metadataEditor || state.outerWidth) { this._metadataEditor?.layout({ width: this.cell.getComputedCellContainerWidth(this.notebookEditor.getLayoutInfo(), false, false), - height: this._layoutInfo.metadataHeight + height: this.cell.metadataHeight }); } if (state.outputEditor || state.outerWidth) { this._outputEditor?.layout({ width: this.cell.getComputedCellContainerWidth(this.notebookEditor.getLayoutInfo(), false, false), - height: this._layoutInfo.outputHeight + height: this.cell.outputHeight }); } @@ -936,12 +891,11 @@ export class InsertCell extends SingleSideCell { } ); this._editor.updateOptions({ readOnly: false }); - this._layoutInfo.editorHeight = editorHeight; + this.cell.editorHeight = editorHeight; this._register(this._editor.onDidContentSizeChange((e) => { - if (e.contentHeightChanged && this._layoutInfo.editorHeight !== e.contentHeight) { - this._layoutInfo.editorHeight = e.contentHeight; - this.layout({ editorHeight: true }); + if (e.contentHeightChanged && this.cell.editorHeight !== e.contentHeight) { + this.cell.editorHeight = e.contentHeight; } })); @@ -954,21 +908,14 @@ export class InsertCell extends SingleSideCell { const textModel = ref.object.textEditorModel; this._editor.setModel(textModel); - this._layoutInfo.editorHeight = this._editor.getContentHeight(); - this.layout({ editorHeight: true }); + this.cell.editorHeight = this._editor.getContentHeight(); }); } - onDidLayoutChange(e: CellDiffViewModelLayoutChangeEvent) { - if (e.outerWidth !== undefined) { - this.layout({ outerWidth: true }); - } - } - _buildOutputContainer() { this._outputLeftView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell.modified!, this._outputViewContainer!); this._outputLeftView.render(); - this.layout({ outputView: true }); + this.cell.outputHeight = (this._outputViewContainer!.childNodes[0] as HTMLElement).clientHeight; } layout(state: { outerWidth?: boolean, editorHeight?: boolean, metadataEditor?: boolean, outputEditor?: boolean, outputView?: boolean }) { @@ -976,32 +923,29 @@ export class InsertCell extends SingleSideCell { if (state.editorHeight || state.outerWidth) { this._editor.layout({ width: this.cell.getComputedCellContainerWidth(this.notebookEditor.getLayoutInfo(), false, false), - height: this._layoutInfo.editorHeight + height: this.cell.editorHeight }); } if (state.metadataEditor || state.outerWidth) { this._metadataEditor?.layout({ width: this.cell.getComputedCellContainerWidth(this.notebookEditor.getLayoutInfo(), false, true), - height: this._layoutInfo.metadataHeight + height: this.cell.metadataHeight }); } if (state.outputEditor || state.outerWidth) { this._outputEditor?.layout({ width: this.cell.getComputedCellContainerWidth(this.notebookEditor.getLayoutInfo(), false, true), - height: this._layoutInfo.outputHeight + height: this.cell.outputHeight }); } - if (state.outputView) { - this._layoutInfo.outputHeight = (this._outputViewContainer!.childNodes[0] as HTMLElement).clientHeight; - } this.layoutNotebookCell(); if (this._diagonalFill) { - this._diagonalFill.style.height = `${this._layoutInfo.editorHeight + this._layoutInfo.editorMargin + this._layoutInfo.metadataStatusHeight + this._layoutInfo.metadataHeight + this._layoutInfo.outputHeight + this._layoutInfo.outputStatusHeight}px`; + this._diagonalFill.style.height = `${this.cell.editorHeight + this.cell.editorMargin + this.cell.metadataStatusHeight + this.cell.metadataHeight + this.cell.outputHeight + this.cell.outputStatusHeight}px`; } }); } @@ -1091,9 +1035,8 @@ export class ModifiedCell extends AbstractCellRenderer { this._metadataHeader.buildHeader(); if (this.notebookEditor.textModel?.transientOptions.transientOutputs) { - this._layoutInfo.outputHeight = 0; - this._layoutInfo.outputStatusHeight = 0; - this.layout({}); + this.cell.outputHeight = 0; + this.cell.outputStatusHeight = 0; this.templateData.outputHeaderContainer.style.display = 'none'; this.templateData.outputInfoContainer.style.display = 'none'; return; @@ -1151,7 +1094,7 @@ export class ModifiedCell extends AbstractCellRenderer { this._outputRightView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell.modified!, this._outputRightContainer!); this._outputRightView.render(); - this.layout({ outputView: true }); + this.cell.outputHeight = Math.max((this._outputLeftContainer!.childNodes[0] as HTMLElement).clientHeight, (this._outputRightContainer!.childNodes[0] as HTMLElement).clientHeight); } updateSourceEditor(): void { @@ -1172,9 +1115,8 @@ export class ModifiedCell extends AbstractCellRenderer { this._editorContainer.style.height = `${editorHeight}px`; this._register(this._editor.onDidContentSizeChange((e) => { - if (e.contentHeightChanged && this._layoutInfo.editorHeight !== e.contentHeight) { - this._layoutInfo.editorHeight = e.contentHeight; - this.layout({ editorHeight: true }); + if (e.contentHeightChanged && this.cell.editorHeight !== e.contentHeight) { + this.cell.editorHeight = e.contentHeight; } })); @@ -1246,50 +1188,38 @@ export class ModifiedCell extends AbstractCellRenderer { }); const contentHeight = this._editor!.getContentHeight(); - this._layoutInfo.editorHeight = contentHeight; - this.layout({ editorHeight: true }); - - } - - onDidLayoutChange(e: CellDiffViewModelLayoutChangeEvent) { - if (e.outerWidth !== undefined) { - this.layout({ outerWidth: true }); - } + this.cell.editorHeight = contentHeight; } layout(state: { outerWidth?: boolean, editorHeight?: boolean, metadataEditor?: boolean, outputEditor?: boolean, outputView?: boolean }) { DOM.scheduleAtNextAnimationFrame(() => { if (state.editorHeight) { - this._editorContainer.style.height = `${this._layoutInfo.editorHeight}px`; + this._editorContainer.style.height = `${this.cell.editorHeight}px`; this._editor!.layout({ width: this._editor!.getViewWidth(), - height: this._layoutInfo.editorHeight + height: this.cell.editorHeight }); } if (state.outerWidth) { - this._editorContainer.style.height = `${this._layoutInfo.editorHeight}px`; + this._editorContainer.style.height = `${this.cell.editorHeight}px`; this._editor!.layout(); } if (state.metadataEditor || state.outerWidth) { if (this._metadataEditorContainer) { - this._metadataEditorContainer.style.height = `${this._layoutInfo.metadataHeight}px`; + this._metadataEditorContainer.style.height = `${this.cell.metadataHeight}px`; this._metadataEditor?.layout(); } } if (state.outputEditor || state.outerWidth) { if (this._outputEditorContainer) { - this._outputEditorContainer.style.height = `${this._layoutInfo.outputHeight}px`; + this._outputEditorContainer.style.height = `${this.cell.outputHeight}px`; this._outputEditor?.layout(); } } - if (state.outputView) { - this._layoutInfo.outputHeight = Math.max((this._outputLeftContainer!.childNodes[0] as HTMLElement).clientHeight, (this._outputRightContainer!.childNodes[0] as HTMLElement).clientHeight); - } - this.layoutNotebookCell(); }); diff --git a/src/vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel.ts b/src/vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel.ts index 55e25cee313..bda3804f7df 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel.ts @@ -20,9 +20,77 @@ export class CellDiffViewModel extends Disposable { public metadataFoldingState: PropertyFoldingState; public outputFoldingState: PropertyFoldingState; private _layoutInfoEmitter = new Emitter(); - onDidLayoutChange = this._layoutInfoEmitter.event; + protected _layoutInfo!: { + editorHeight: number; + editorMargin: number; + metadataStatusHeight: number; + metadataHeight: number; + outputStatusHeight: number; + outputHeight: number; + bodyMargin: number; + }; + + set outputHeight(height: number) { + this._layoutInfo.outputHeight = height; + this._fireLayoutChangeEvent({ outputEditor: true, outputView: true }); + } + + get outputHeight() { + return this._layoutInfo.outputHeight; + } + + set outputStatusHeight(height: number) { + this._layoutInfo.outputStatusHeight = height; + this._fireLayoutChangeEvent({}); + } + + get outputStatusHeight() { + return this._layoutInfo.outputStatusHeight; + } + + set editorHeight(height: number) { + this._layoutInfo.editorHeight = height; + this._fireLayoutChangeEvent({ editorHeight: true }); + } + + get editorHeight() { + return this._layoutInfo.editorHeight; + } + + set editorMargin(height: number) { + this._layoutInfo.editorMargin = height; + this._fireLayoutChangeEvent({}); + } + + get editorMargin() { + return this._layoutInfo.editorMargin; + } + + get metadataStatusHeight() { + return this._layoutInfo.metadataStatusHeight; + } + + set metadataHeight(height: number) { + this._layoutInfo.metadataHeight = height; + this._fireLayoutChangeEvent({ metadataEditor: true }); + } + + get metadataHeight() { + return this._layoutInfo.metadataHeight; + } + + get totalHeight() { + return this._layoutInfo.editorHeight + + this._layoutInfo.editorMargin + + this._layoutInfo.metadataHeight + + this._layoutInfo.metadataStatusHeight + + this._layoutInfo.outputHeight + + this._layoutInfo.outputStatusHeight + + this._layoutInfo.bodyMargin; + } + constructor( readonly original: NotebookCellTextModel | undefined, readonly modified: NotebookCellTextModel | undefined, @@ -30,14 +98,28 @@ export class CellDiffViewModel extends Disposable { readonly editorEventDispatcher: NotebookDiffEditorEventDispatcher ) { super(); + this._layoutInfo = { + editorHeight: 0, + editorMargin: 0, + metadataHeight: 0, + metadataStatusHeight: 25, + outputHeight: 0, + outputStatusHeight: 25, + bodyMargin: 32 + }; + this.metadataFoldingState = PropertyFoldingState.Collapsed; this.outputFoldingState = PropertyFoldingState.Collapsed; this._register(this.editorEventDispatcher.onDidChangeLayout(e => { - this._layoutInfoEmitter.fire({ outerWidth: e.value.width }); + this._layoutInfoEmitter.fire({ outerWidth: true }); })); } + private _fireLayoutChangeEvent(state: { outerWidth?: boolean, editorHeight?: boolean, metadataEditor?: boolean, outputEditor?: boolean, outputView?: boolean }) { + this._layoutInfoEmitter.fire(state); + } + getComputedCellContainerWidth(layoutInfo: NotebookLayoutInfo, diffEditor: boolean, fullWidth: boolean) { if (fullWidth) { return layoutInfo.width - 2 * DIFF_CELL_MARGIN + (diffEditor ? DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH : 0) - 2; diff --git a/src/vs/workbench/contrib/notebook/browser/diff/common.ts b/src/vs/workbench/contrib/notebook/browser/diff/common.ts index 115173f8bac..a08dce346a1 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/common.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/common.ts @@ -54,7 +54,11 @@ export interface CellDiffSideBySideRenderTemplate { export interface CellDiffViewModelLayoutChangeEvent { font?: BareFontInfo; - outerWidth?: number; + outerWidth?: boolean; + editorHeight?: boolean; + metadataEditor?: boolean; + outputEditor?: boolean; + outputView?: boolean; } export const DIFF_CELL_MARGIN = 16; From ced21a0abcc77cd1c54c84bebd11cf8c70e84a78 Mon Sep 17 00:00:00 2001 From: rebornix Date: Fri, 11 Dec 2020 16:06:48 -0800 Subject: [PATCH 013/262] :lipstick: --- .../notebook/browser/diff/cellComponents.ts | 99 +++++-------------- .../browser/diff/celllDiffViewModel.ts | 50 ++++++++++ .../browser/diff/notebookTextDiffEditor.ts | 6 ++ .../view/output/transforms/textHelper.ts | 1 - 4 files changed, 82 insertions(+), 74 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts index 0fa9531f4a5..6a5be0bdd4d 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts @@ -7,7 +7,7 @@ import * as DOM from 'vs/base/browser/dom'; import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IDiffEditorOptions, IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { CellDiffViewModel, PropertyFoldingState } from 'vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel'; +import { CellDiffViewModel, getFormatedMetadataJSON, PropertyFoldingState } from 'vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel'; import { CellDiffSideBySideRenderTemplate, CellDiffSingleSideRenderTemplate, DIFF_CELL_MARGIN, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common'; import { EDITOR_BOTTOM_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; @@ -17,7 +17,6 @@ import { IModeService } from 'vs/editor/common/services/modeService'; import { format } from 'vs/base/common/jsonFormatter'; import { applyEdits } from 'vs/base/common/jsonEdit'; import { CellEditType, CellUri, NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; -import { hash } from 'vs/base/common/hash'; import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IMenu, IMenuService, MenuId, MenuItemAction } from 'vs/platform/actions/common/actions'; @@ -295,8 +294,7 @@ abstract class AbstractCellRenderer extends Disposable { this._outputViewContainer = DOM.append(this._outputInfoContainer, DOM.$('.output-view-container')); this._buildOutputContainer(); } else { - // TODO, should we check its height? - this.layout({ outputView: true }); + this._updateOutputContainerHeight(); } } else { this._outputInfoContainer.style.display = 'block'; @@ -317,34 +315,7 @@ abstract class AbstractCellRenderer extends Disposable { } abstract _buildOutputContainer(): void; - - protected _getFormatedMetadataJSON(metadata: NotebookCellMetadata, language?: string) { - let filteredMetadata: { [key: string]: any } = {}; - - if (this.notebookEditor.textModel) { - const transientMetadata = this.notebookEditor.textModel!.transientOptions.transientMetadata; - - const keys = new Set([...Object.keys(metadata)]); - for (let key of keys) { - if (!(transientMetadata[key as keyof NotebookCellMetadata]) - ) { - filteredMetadata[key] = metadata[key as keyof NotebookCellMetadata]; - } - } - } else { - filteredMetadata = metadata; - } - - const content = JSON.stringify({ - language, - ...filteredMetadata - }); - - const edits = format(content, undefined, {}); - const metadataSource = applyEdits(content, edits); - - return metadataSource; - } + abstract _updateOutputContainerHeight(): void; private _applySanitizedMetadataChanges(currentMetadata: NotebookCellMetadata, newMetadata: any) { let result: { [key: string]: any } = {}; @@ -429,8 +400,8 @@ abstract class AbstractCellRenderer extends Disposable { private _buildMetadataEditor() { if (this.cell.type === 'modified' || this.cell.type === 'unchanged') { - const originalMetadataSource = this._getFormatedMetadataJSON(this.cell.original?.metadata || {}, this.cell.original?.language); - const modifiedMetadataSource = this._getFormatedMetadataJSON(this.cell.modified?.metadata || {}, this.cell.modified?.language); + const originalMetadataSource = getFormatedMetadataJSON(this.notebookEditor.textModel!, this.cell.original?.metadata || {}, this.cell.original?.language); + const modifiedMetadataSource = getFormatedMetadataJSON(this.notebookEditor.textModel!, this.cell.modified?.metadata || {}, this.cell.modified?.language); this._metadataEditor = this.instantiationService.createInstance(DiffEditorWidget, this._metadataEditorContainer!, { ...fixedDiffEditorOptions, overflowWidgetsDomNode: this.notebookEditor.getOverflowContainerDomNode(), @@ -481,7 +452,7 @@ abstract class AbstractCellRenderer extends Disposable { return; } - const modifiedMetadataSource = this._getFormatedMetadataJSON(this.cell.modified?.metadata || {}, this.cell.modified?.language); + const modifiedMetadataSource = getFormatedMetadataJSON(this.notebookEditor.textModel!, this.cell.modified?.metadata || {}, this.cell.modified?.language); modifiedMetadataModel.setValue(modifiedMetadataSource); })); @@ -500,7 +471,7 @@ abstract class AbstractCellRenderer extends Disposable { this._register(this._metadataEditor); const mode = this.modeService.create('jsonc'); - const originalMetadataSource = this._getFormatedMetadataJSON( + const originalMetadataSource = getFormatedMetadataJSON(this.notebookEditor.textModel!, this.cell.type === 'insert' ? this.cell.modified!.metadata || {} : this.cell.original!.metadata || {}); @@ -683,14 +654,6 @@ abstract class SingleSideCell extends AbstractCellRenderer { this._metadataHeaderContainer.innerText = ''; this._metadataInfoContainer.innerText = ''; - const checkIfModified = (cell: CellDiffViewModel) => { - return cell.type !== 'delete' && cell.type !== 'insert' && hash(this._getFormatedMetadataJSON(cell.original?.metadata || {}, cell.original?.language)) !== hash(this._getFormatedMetadataJSON(cell.modified?.metadata ?? {}, cell.modified?.language)); - }; - - if (checkIfModified(this.cell)) { - this.cell.metadataFoldingState = PropertyFoldingState.Expanded; - } - this._metadataHeader = this.instantiationService.createInstance( PropertyHeader, this.cell, @@ -699,7 +662,7 @@ abstract class SingleSideCell extends AbstractCellRenderer { { updateInfoRendering: this.updateMetadataRendering.bind(this), checkIfModified: (cell) => { - return checkIfModified(cell); + return cell.checkMetadataIfModified(); }, getFoldingState: (cell) => { return cell.metadataFoldingState; @@ -730,14 +693,6 @@ abstract class SingleSideCell extends AbstractCellRenderer { this._outputHeaderContainer.innerText = ''; this._outputInfoContainer.innerText = ''; - const checkIfOutputsModified = (cell: CellDiffViewModel) => { - return cell.type !== 'delete' && cell.type !== 'insert' && !this.notebookEditor.textModel!.transientOptions.transientOutputs && cell.type === 'modified' && hash(cell.original?.outputs ?? []) !== hash(cell.modified?.outputs ?? []); - }; - - if (checkIfOutputsModified(this.cell)) { - this.cell.outputFoldingState = PropertyFoldingState.Expanded; - } - this._outputHeader = this.instantiationService.createInstance( PropertyHeader, this.cell, @@ -746,7 +701,7 @@ abstract class SingleSideCell extends AbstractCellRenderer { { updateInfoRendering: this.updateOutputRendering.bind(this), checkIfModified: (cell) => { - return checkIfOutputsModified(cell); + return cell.checkIfOutputsModified(); }, getFoldingState: (cell) => { return cell.outputFoldingState; @@ -853,6 +808,10 @@ export class DeletedCell extends SingleSideCell { // this._outputView.render(); // this.layout({ outputView: true }); } + + _updateOutputContainerHeight(): void { + // throw new Error('Method not implemented.'); + } } export class InsertCell extends SingleSideCell { @@ -918,6 +877,11 @@ export class InsertCell extends SingleSideCell { this.cell.outputHeight = (this._outputViewContainer!.childNodes[0] as HTMLElement).clientHeight; } + _updateOutputContainerHeight(): void { + // throw new Error('Method not implemented.'); + this.cell.outputHeight = (this._outputViewContainer!.childNodes[0] as HTMLElement).clientHeight; + } + layout(state: { outerWidth?: boolean, editorHeight?: boolean, metadataEditor?: boolean, outputEditor?: boolean, outputView?: boolean }) { DOM.scheduleAtNextAnimationFrame(() => { if (state.editorHeight || state.outerWidth) { @@ -1001,14 +965,6 @@ export class ModifiedCell extends AbstractCellRenderer { this._metadataHeaderContainer.innerText = ''; this._metadataInfoContainer.innerText = ''; - const checkIfModified = (cell: CellDiffViewModel) => { - return cell.type !== 'delete' && cell.type !== 'insert' && hash(this._getFormatedMetadataJSON(cell.original?.metadata || {}, cell.original?.language)) !== hash(this._getFormatedMetadataJSON(cell.modified?.metadata ?? {}, cell.modified?.language)); - }; - - if (checkIfModified(this.cell)) { - this.cell.metadataFoldingState = PropertyFoldingState.Expanded; - } - this._metadataHeader = this.instantiationService.createInstance( PropertyHeader, this.cell, @@ -1017,7 +973,7 @@ export class ModifiedCell extends AbstractCellRenderer { { updateInfoRendering: this.updateMetadataRendering.bind(this), checkIfModified: (cell) => { - return checkIfModified(cell); + return cell.checkMetadataIfModified(); }, getFoldingState: (cell) => { return cell.metadataFoldingState; @@ -1047,18 +1003,10 @@ export class ModifiedCell extends AbstractCellRenderer { this._outputHeaderContainer.innerText = ''; this._outputInfoContainer.innerText = ''; - const checkIfOutputsModified = (cell: CellDiffViewModel) => { - return cell.type !== 'delete' && cell.type !== 'insert' && !this.notebookEditor.textModel!.transientOptions.transientOutputs && cell.type === 'modified' && hash(cell.original?.outputs ?? []) !== hash(cell.modified?.outputs ?? []); - }; - - if (checkIfOutputsModified(this.cell)) { + if (this.cell.checkIfOutputsModified()) { this._outputInfoContainer.classList.add('modified'); } - if (checkIfOutputsModified(this.cell)) { - this.cell.outputFoldingState = PropertyFoldingState.Expanded; - } - this._outputHeader = this.instantiationService.createInstance( PropertyHeader, this.cell, @@ -1067,7 +1015,7 @@ export class ModifiedCell extends AbstractCellRenderer { { updateInfoRendering: this.updateOutputRendering.bind(this), checkIfModified: (cell) => { - return checkIfOutputsModified(cell); + return cell.checkIfOutputsModified(); }, getFoldingState: (cell) => { return cell.outputFoldingState; @@ -1097,6 +1045,11 @@ export class ModifiedCell extends AbstractCellRenderer { this.cell.outputHeight = Math.max((this._outputLeftContainer!.childNodes[0] as HTMLElement).clientHeight, (this._outputRightContainer!.childNodes[0] as HTMLElement).clientHeight); } + + _updateOutputContainerHeight(): void { + this.cell.outputHeight = Math.max((this._outputLeftContainer!.childNodes[0] as HTMLElement).clientHeight, (this._outputRightContainer!.childNodes[0] as HTMLElement).clientHeight); + } + updateSourceEditor(): void { const modifiedCell = this.cell.modified!; const lineCount = modifiedCell.textBuffer.getLineCount(); diff --git a/src/vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel.ts b/src/vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel.ts index bda3804f7df..8eed8eff932 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel.ts @@ -10,6 +10,11 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { CellDiffViewModelLayoutChangeEvent, DIFF_CELL_MARGIN } from 'vs/workbench/contrib/notebook/browser/diff/common'; import { NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; +import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; +import { hash } from 'vs/base/common/hash'; +import { format } from 'vs/base/common/jsonFormatter'; +import { applyEdits } from 'vs/base/common/jsonEdit'; +import { NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; export enum PropertyFoldingState { Expanded, @@ -92,6 +97,7 @@ export class CellDiffViewModel extends Disposable { } constructor( + readonly documentTextModel: NotebookTextModel, readonly original: NotebookCellTextModel | undefined, readonly modified: NotebookCellTextModel | undefined, readonly type: 'unchanged' | 'insert' | 'delete' | 'modified', @@ -111,6 +117,14 @@ export class CellDiffViewModel extends Disposable { this.metadataFoldingState = PropertyFoldingState.Collapsed; this.outputFoldingState = PropertyFoldingState.Collapsed; + if (this.checkMetadataIfModified()) { + this.metadataFoldingState = PropertyFoldingState.Expanded; + } + + if (this.checkIfOutputsModified()) { + this.outputFoldingState = PropertyFoldingState.Expanded; + } + this._register(this.editorEventDispatcher.onDidChangeLayout(e => { this._layoutInfoEmitter.fire({ outerWidth: true }); })); @@ -120,6 +134,14 @@ export class CellDiffViewModel extends Disposable { this._layoutInfoEmitter.fire(state); } + checkIfOutputsModified() { + return this.type !== 'delete' && this.type !== 'insert' && !this.documentTextModel.transientOptions.transientOutputs && this.type === 'modified' && hash(this.original?.outputs ?? []) !== hash(this.modified?.outputs ?? []); + } + + checkMetadataIfModified() { + return this.type !== 'delete' && this.type !== 'insert' && hash(getFormatedMetadataJSON(this.documentTextModel, this.original?.metadata || {}, this.original?.language)) !== hash(getFormatedMetadataJSON(this.documentTextModel, this.modified?.metadata ?? {}, this.modified?.language)); + } + getComputedCellContainerWidth(layoutInfo: NotebookLayoutInfo, diffEditor: boolean, fullWidth: boolean) { if (fullWidth) { return layoutInfo.width - 2 * DIFF_CELL_MARGIN + (diffEditor ? DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH : 0) - 2; @@ -128,3 +150,31 @@ export class CellDiffViewModel extends Disposable { return (layoutInfo.width - 2 * DIFF_CELL_MARGIN + (diffEditor ? DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH : 0)) / 2 - 18 - 2; } } + +export function getFormatedMetadataJSON(documentTextModel: NotebookTextModel, metadata: NotebookCellMetadata, language?: string) { + let filteredMetadata: { [key: string]: any } = {}; + + if (documentTextModel) { + const transientMetadata = documentTextModel.transientOptions.transientMetadata; + + const keys = new Set([...Object.keys(metadata)]); + for (let key of keys) { + if (!(transientMetadata[key as keyof NotebookCellMetadata]) + ) { + filteredMetadata[key] = metadata[key as keyof NotebookCellMetadata]; + } + } + } else { + filteredMetadata = metadata; + } + + const content = JSON.stringify({ + language, + ...filteredMetadata + }); + + const edits = format(content, undefined, {}); + const metadataSource = applyEdits(content, edits); + + return metadataSource; +} diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 473e3cea78d..1f838eecf76 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -244,6 +244,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD const modifiedCell = modifiedModel.cells[modifiedCellIndex + j]; if (originalCell.getHashValue() === modifiedCell.getHashValue()) { cellDiffViewModels.push(new CellDiffViewModel( + this._model.modified.notebook, originalCell, modifiedCell, 'unchanged', @@ -255,6 +256,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD } cellDiffViewModels.push(new CellDiffViewModel( + this._model.modified.notebook, originalCell, modifiedCell, 'modified', @@ -275,6 +277,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD for (let i = originalCellIndex; i < originalModel.cells.length; i++) { cellDiffViewModels.push(new CellDiffViewModel( + this._model.modified.notebook, originalModel.cells[i], modifiedModel.cells[i - originalCellIndex + modifiedCellIndex], 'unchanged', @@ -298,6 +301,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD for (let j = 0; j < modifiedLen; j++) { result.push(new CellDiffViewModel( + modifiedModel, originalModel.cells[change.originalStart + j], modifiedModel.cells[change.modifiedStart + j], 'modified', @@ -308,6 +312,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD for (let j = modifiedLen; j < change.originalLength; j++) { // deletion result.push(new CellDiffViewModel( + originalModel, originalModel.cells[change.originalStart + j], undefined, 'delete', @@ -318,6 +323,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD for (let j = modifiedLen; j < change.modifiedLength; j++) { // insertion result.push(new CellDiffViewModel( + modifiedModel, undefined, modifiedModel.cells[change.modifiedStart + j], 'insert', diff --git a/src/vs/workbench/contrib/notebook/browser/view/output/transforms/textHelper.ts b/src/vs/workbench/contrib/notebook/browser/view/output/transforms/textHelper.ts index 1a4fbe7bfcc..08e8abf93ae 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/output/transforms/textHelper.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/output/transforms/textHelper.ts @@ -90,7 +90,6 @@ export function truncatedArrayOfString(container: HTMLElement, outputs: string[] const lineCount = buffer.getLineCount(); const fullRange = new Range(1, 1, lineCount, Math.max(1, buffer.getLineLastNonWhitespaceColumn(lineCount))); - container.innerText = buffer.getValueInRange(fullRange, EndOfLinePreference.TextDefined); if (renderANSI) { container.appendChild(handleANSIOutput(buffer.getValueInRange(fullRange, EndOfLinePreference.TextDefined), themeService)); } else { From 42e31e92e293616e8b87748c858610a54c663fad Mon Sep 17 00:00:00 2001 From: rebornix Date: Mon, 14 Dec 2020 10:27:24 -0800 Subject: [PATCH 014/262] cursor and user select update for output --- .../contrib/notebook/browser/diff/notebookDiff.css | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css index 5866ea2c558..95afc16af1f 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css @@ -126,9 +126,12 @@ -.monaco-workbench .notebook-text-diff-editor .cell-body .output-view-container .output-inner-container { - /* overflow-x: scroll; */ +.monaco-workbench .notebook-text-diff-editor .cell-body .output-view-container { + user-select: text; + -webkit-user-select: text; + -ms-user-select: text; white-space: initial; + cursor: auto; } .monaco-workbench .notebook-text-diff-editor .cell-body.left .output-view-container .output-inner-container, From 7989b98326e7234ce88fca09d22f8eb8d5b1aa50 Mon Sep 17 00:00:00 2001 From: rebornix Date: Mon, 14 Dec 2020 11:55:20 -0800 Subject: [PATCH 015/262] separate side by side and single side viewmodel --- .../notebook/browser/diff/cellComponents.ts | 94 +++++++++---------- .../browser/diff/celllDiffViewModel.ts | 81 ++++++++++++---- .../contrib/notebook/browser/diff/common.ts | 6 +- .../browser/diff/notebookDiffActions.ts | 8 +- .../browser/diff/notebookTextDiffEditor.ts | 28 +++--- .../browser/diff/notebookTextDiffList.ts | 30 +++--- 6 files changed, 148 insertions(+), 99 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts index 6a5be0bdd4d..29e062d6156 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts @@ -7,7 +7,7 @@ import * as DOM from 'vs/base/browser/dom'; import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IDiffEditorOptions, IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { CellDiffViewModel, getFormatedMetadataJSON, PropertyFoldingState } from 'vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel'; +import { CellDiffViewModelBase, getFormatedMetadataJSON, PropertyFoldingState, SideBySideCellDiffViewModel, SingleSideCellDiffViewModel } from 'vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel'; import { CellDiffSideBySideRenderTemplate, CellDiffSingleSideRenderTemplate, DIFF_CELL_MARGIN, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common'; import { EDITOR_BOTTOM_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; @@ -83,14 +83,14 @@ class PropertyHeader extends Disposable { protected _menu!: IMenu; constructor( - readonly cell: CellDiffViewModel, + readonly cell: CellDiffViewModelBase, readonly propertyHeaderContainer: HTMLElement, readonly notebookEditor: INotebookTextDiffEditor, readonly accessor: { updateInfoRendering: () => void; - checkIfModified: (cell: CellDiffViewModel) => boolean; - getFoldingState: (cell: CellDiffViewModel) => PropertyFoldingState; - updateFoldingState: (cell: CellDiffViewModel, newState: PropertyFoldingState) => void; + checkIfModified: (cell: CellDiffViewModelBase) => boolean; + getFoldingState: (cell: CellDiffViewModelBase) => PropertyFoldingState; + updateFoldingState: (cell: CellDiffViewModelBase, newState: PropertyFoldingState) => void; unChangedLabel: string; changedLabel: string; prefix: string; @@ -239,7 +239,7 @@ abstract class AbstractCellRenderer extends Disposable { constructor( readonly notebookEditor: INotebookTextDiffEditor, - readonly cell: CellDiffViewModel, + readonly cell: CellDiffViewModelBase, readonly templateData: CellDiffSingleSideRenderTemplate | CellDiffSideBySideRenderTemplate, readonly style: 'left' | 'right' | 'full', protected readonly instantiationService: IInstantiationService, @@ -399,7 +399,7 @@ abstract class AbstractCellRenderer extends Disposable { } private _buildMetadataEditor() { - if (this.cell.type === 'modified' || this.cell.type === 'unchanged') { + if (this.cell instanceof SideBySideCellDiffViewModel) { const originalMetadataSource = getFormatedMetadataJSON(this.notebookEditor.textModel!, this.cell.original?.metadata || {}, this.cell.original?.language); const modifiedMetadataSource = getFormatedMetadataJSON(this.notebookEditor.textModel!, this.cell.modified?.metadata || {}, this.cell.modified?.language); this._metadataEditor = this.instantiationService.createInstance(DiffEditorWidget, this._metadataEditorContainer!, { @@ -457,43 +457,43 @@ abstract class AbstractCellRenderer extends Disposable { })); return; + } else { + this._metadataEditor = this.instantiationService.createInstance(CodeEditorWidget, this._metadataEditorContainer!, { + ...fixedEditorOptions, + dimension: { + width: this.cell.getComputedCellContainerWidth(this.notebookEditor.getLayoutInfo(), false, true), + height: 0 + }, + overflowWidgetsDomNode: this.notebookEditor.getOverflowContainerDomNode(), + readOnly: false + }, {}); + this._register(this._metadataEditor); + + const mode = this.modeService.create('jsonc'); + const originalMetadataSource = getFormatedMetadataJSON(this.notebookEditor.textModel!, + this.cell.type === 'insert' + ? this.cell.modified!.metadata || {} + : this.cell.original!.metadata || {}); + const uri = this.cell.type === 'insert' + ? this.cell.modified!.uri + : this.cell.original!.uri; + const handle = this.cell.type === 'insert' + ? this.cell.modified!.handle + : this.cell.original!.handle; + + const modelUri = CellUri.generateCellMetadataUri(uri, handle); + const metadataModel = this.modelService.createModel(originalMetadataSource, mode, modelUri, false); + this._metadataEditor.setModel(metadataModel); + this._register(metadataModel); + + this.cell.metadataHeight = this._metadataEditor.getContentHeight(); + + this._register(this._metadataEditor.onDidContentSizeChange((e) => { + if (e.contentHeightChanged && this.cell.metadataFoldingState === PropertyFoldingState.Expanded) { + this.cell.metadataHeight = e.contentHeight; + } + })); } - - this._metadataEditor = this.instantiationService.createInstance(CodeEditorWidget, this._metadataEditorContainer!, { - ...fixedEditorOptions, - dimension: { - width: this.cell.getComputedCellContainerWidth(this.notebookEditor.getLayoutInfo(), false, true), - height: 0 - }, - overflowWidgetsDomNode: this.notebookEditor.getOverflowContainerDomNode(), - readOnly: false - }, {}); - this._register(this._metadataEditor); - - const mode = this.modeService.create('jsonc'); - const originalMetadataSource = getFormatedMetadataJSON(this.notebookEditor.textModel!, - this.cell.type === 'insert' - ? this.cell.modified!.metadata || {} - : this.cell.original!.metadata || {}); - const uri = this.cell.type === 'insert' - ? this.cell.modified!.uri - : this.cell.original!.uri; - const handle = this.cell.type === 'insert' - ? this.cell.modified!.handle - : this.cell.original!.handle; - - const modelUri = CellUri.generateCellMetadataUri(uri, handle); - const metadataModel = this.modelService.createModel(originalMetadataSource, mode, modelUri, false); - this._metadataEditor.setModel(metadataModel); - this._register(metadataModel); - - this.cell.metadataHeight = this._metadataEditor.getContentHeight(); - - this._register(this._metadataEditor.onDidContentSizeChange((e) => { - if (e.contentHeightChanged && this.cell.metadataFoldingState === PropertyFoldingState.Expanded) { - this.cell.metadataHeight = e.contentHeight; - } - })); } private _getFormatedOutputJSON(outputs: any[]) { @@ -600,7 +600,7 @@ abstract class AbstractCellRenderer extends Disposable { abstract class SingleSideCell extends AbstractCellRenderer { constructor( readonly notebookEditor: INotebookTextDiffEditor, - readonly cell: CellDiffViewModel, + readonly cell: SingleSideCellDiffViewModel, readonly templateData: CellDiffSingleSideRenderTemplate, readonly style: 'left' | 'right' | 'full', protected readonly instantiationService: IInstantiationService, @@ -723,7 +723,7 @@ export class DeletedCell extends SingleSideCell { private _editor!: CodeEditorWidget; constructor( readonly notebookEditor: INotebookTextDiffEditor, - readonly cell: CellDiffViewModel, + readonly cell: SingleSideCellDiffViewModel, readonly templateData: CellDiffSingleSideRenderTemplate, @IModeService readonly modeService: IModeService, @IModelService readonly modelService: IModelService, @@ -818,7 +818,7 @@ export class InsertCell extends SingleSideCell { private _editor!: CodeEditorWidget; constructor( readonly notebookEditor: INotebookTextDiffEditor, - readonly cell: CellDiffViewModel, + readonly cell: SingleSideCellDiffViewModel, readonly templateData: CellDiffSingleSideRenderTemplate, @IInstantiationService protected readonly instantiationService: IInstantiationService, @IModeService readonly modeService: IModeService, @@ -924,7 +924,7 @@ export class ModifiedCell extends AbstractCellRenderer { constructor( readonly notebookEditor: INotebookTextDiffEditor, - readonly cell: CellDiffViewModel, + readonly cell: SideBySideCellDiffViewModel, readonly templateData: CellDiffSideBySideRenderTemplate, @IInstantiationService protected readonly instantiationService: IInstantiationService, @IModeService readonly modeService: IModeService, diff --git a/src/vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel.ts b/src/vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel.ts index 8eed8eff932..a6df242c3fc 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel.ts @@ -15,16 +15,17 @@ import { hash } from 'vs/base/common/hash'; import { format } from 'vs/base/common/jsonFormatter'; import { applyEdits } from 'vs/base/common/jsonEdit'; import { NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer'; export enum PropertyFoldingState { Expanded, Collapsed } -export class CellDiffViewModel extends Disposable { +export abstract class CellDiffViewModelBase extends Disposable { public metadataFoldingState: PropertyFoldingState; public outputFoldingState: PropertyFoldingState; - private _layoutInfoEmitter = new Emitter(); + protected _layoutInfoEmitter = new Emitter(); onDidLayoutChange = this._layoutInfoEmitter.event; protected _layoutInfo!: { @@ -37,6 +38,9 @@ export class CellDiffViewModel extends Disposable { bodyMargin: number; }; + protected _outputCollection: number[] = []; + protected _outputsTop: PrefixSumComputer | null = null; + set outputHeight(height: number) { this._layoutInfo.outputHeight = height; this._fireLayoutChangeEvent({ outputEditor: true, outputView: true }); @@ -114,17 +118,10 @@ export class CellDiffViewModel extends Disposable { bodyMargin: 32 }; + this.metadataFoldingState = PropertyFoldingState.Collapsed; this.outputFoldingState = PropertyFoldingState.Collapsed; - if (this.checkMetadataIfModified()) { - this.metadataFoldingState = PropertyFoldingState.Expanded; - } - - if (this.checkIfOutputsModified()) { - this.outputFoldingState = PropertyFoldingState.Expanded; - } - this._register(this.editorEventDispatcher.onDidChangeLayout(e => { this._layoutInfoEmitter.fire({ outerWidth: true }); })); @@ -134,13 +131,9 @@ export class CellDiffViewModel extends Disposable { this._layoutInfoEmitter.fire(state); } - checkIfOutputsModified() { - return this.type !== 'delete' && this.type !== 'insert' && !this.documentTextModel.transientOptions.transientOutputs && this.type === 'modified' && hash(this.original?.outputs ?? []) !== hash(this.modified?.outputs ?? []); - } + abstract checkIfOutputsModified(): boolean; + abstract checkMetadataIfModified(): boolean; - checkMetadataIfModified() { - return this.type !== 'delete' && this.type !== 'insert' && hash(getFormatedMetadataJSON(this.documentTextModel, this.original?.metadata || {}, this.original?.language)) !== hash(getFormatedMetadataJSON(this.documentTextModel, this.modified?.metadata ?? {}, this.modified?.language)); - } getComputedCellContainerWidth(layoutInfo: NotebookLayoutInfo, diffEditor: boolean, fullWidth: boolean) { if (fullWidth) { @@ -151,6 +144,62 @@ export class CellDiffViewModel extends Disposable { } } +export class SideBySideCellDiffViewModel extends CellDiffViewModelBase { + constructor( + readonly documentTextModel: NotebookTextModel, + readonly original: NotebookCellTextModel | undefined, + readonly modified: NotebookCellTextModel | undefined, + readonly type: 'unchanged' | 'modified', + readonly editorEventDispatcher: NotebookDiffEditorEventDispatcher + ) { + super( + documentTextModel, + original, + modified, + type, + editorEventDispatcher); + + this.metadataFoldingState = PropertyFoldingState.Collapsed; + this.outputFoldingState = PropertyFoldingState.Collapsed; + + if (this.checkMetadataIfModified()) { + this.metadataFoldingState = PropertyFoldingState.Expanded; + } + + if (this.checkIfOutputsModified()) { + this.outputFoldingState = PropertyFoldingState.Expanded; + } + } + + checkIfOutputsModified() { + return !this.documentTextModel.transientOptions.transientOutputs && this.type === 'modified' && hash(this.original?.outputs ?? []) !== hash(this.modified?.outputs ?? []); + } + + checkMetadataIfModified(): boolean { + return hash(getFormatedMetadataJSON(this.documentTextModel, this.original?.metadata || {}, this.original?.language)) !== hash(getFormatedMetadataJSON(this.documentTextModel, this.modified?.metadata ?? {}, this.modified?.language)); + } +} + +export class SingleSideCellDiffViewModel extends CellDiffViewModelBase { + constructor( + readonly documentTextModel: NotebookTextModel, + readonly original: NotebookCellTextModel | undefined, + readonly modified: NotebookCellTextModel | undefined, + readonly type: 'insert' | 'delete', + readonly editorEventDispatcher: NotebookDiffEditorEventDispatcher + ) { + super(documentTextModel, original, modified, type, editorEventDispatcher); + } + + checkIfOutputsModified(): boolean { + return false; + } + + checkMetadataIfModified(): boolean { + return false; + } +} + export function getFormatedMetadataJSON(documentTextModel: NotebookTextModel, metadata: NotebookCellMetadata, language?: string) { let filteredMetadata: { [key: string]: any } = {}; diff --git a/src/vs/workbench/contrib/notebook/browser/diff/common.ts b/src/vs/workbench/contrib/notebook/browser/diff/common.ts index a08dce346a1..40fe1571f42 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/common.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/common.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; -import { CellDiffViewModel } from 'vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel'; +import { CellDiffViewModelBase } from 'vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel'; import { Event } from 'vs/base/common/event'; import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; import { DisposableStore } from 'vs/base/common/lifecycle'; @@ -16,10 +16,10 @@ import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/outpu export interface INotebookTextDiffEditor { readonly textModel?: NotebookTextModel; - onMouseUp: Event<{ readonly event: MouseEvent; readonly target: CellDiffViewModel; }>; + onMouseUp: Event<{ readonly event: MouseEvent; readonly target: CellDiffViewModelBase; }>; getOverflowContainerDomNode(): HTMLElement; getLayoutInfo(): NotebookLayoutInfo; - layoutNotebookCell(cell: CellDiffViewModel, height: number): void; + layoutNotebookCell(cell: CellDiffViewModelBase, height: number): void; getOutputRenderer(): OutputRenderer; } diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts index cb8709d167d..3983cfcc4bb 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts @@ -8,7 +8,7 @@ import { localize } from 'vs/nls'; import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ActiveEditorContext, viewColumnToEditorGroup } from 'vs/workbench/common/editor'; -import { CellDiffViewModel } from 'vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel'; +import { CellDiffViewModelBase } from 'vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel'; import { NotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor'; import { NotebookDiffEditorInput } from 'vs/workbench/contrib/notebook/browser/notebookDiffEditorInput'; import { openAsTextIcon, revertIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons'; @@ -65,7 +65,7 @@ registerAction2(class extends Action2 { } ); } - run(accessor: ServicesAccessor, context?: { cell: CellDiffViewModel }) { + run(accessor: ServicesAccessor, context?: { cell: CellDiffViewModelBase }) { if (!context) { return; } @@ -95,7 +95,7 @@ registerAction2(class extends Action2 { } ); } - run(accessor: ServicesAccessor, context?: { cell: CellDiffViewModel }) { + run(accessor: ServicesAccessor, context?: { cell: CellDiffViewModelBase }) { if (!context) { return; } @@ -125,7 +125,7 @@ registerAction2(class extends Action2 { } ); } - run(accessor: ServicesAccessor, context?: { cell: CellDiffViewModel }) { + run(accessor: ServicesAccessor, context?: { cell: CellDiffViewModelBase }) { if (!context) { return; } diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 1f838eecf76..dd1a285d7e3 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -14,7 +14,7 @@ import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsSe import { NotebookDiffEditorInput } from '../notebookDiffEditorInput'; import { CancellationToken } from 'vs/base/common/cancellation'; import { WorkbenchList } from 'vs/platform/list/browser/listService'; -import { CellDiffViewModel } from 'vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel'; +import { CellDiffViewModelBase, SideBySideCellDiffViewModel, SingleSideCellDiffViewModel } from 'vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { CellDiffSideBySideRenderer, CellDiffSingleSideRenderer, NotebookCellTextDiffListDelegate, NotebookTextDiffList } from 'vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList'; import { IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; @@ -47,10 +47,10 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD private _rootElement!: HTMLElement; private _overflowContainer!: HTMLElement; private _dimension: DOM.Dimension | null = null; - private _list!: WorkbenchList; + private _list!: WorkbenchList; private _fontInfo: BareFontInfo | undefined; - private readonly _onMouseUp = this._register(new Emitter<{ readonly event: MouseEvent; readonly target: CellDiffViewModel; }>()); + private readonly _onMouseUp = this._register(new Emitter<{ readonly event: MouseEvent; readonly target: CellDiffViewModelBase; }>()); public readonly onMouseUp = this._onMouseUp.event; private _eventDispatcher: NotebookDiffEditorEventDispatcher | undefined; protected _scopeContextKeyService!: IContextKeyService; @@ -227,7 +227,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD const diffResult = await this.notebookEditorWorkerService.computeDiff(this._model.original.resource, this._model.modified.resource); const cellChanges = diffResult.cellsDiff.changes; - const cellDiffViewModels: CellDiffViewModel[] = []; + const cellDiffViewModels: CellDiffViewModelBase[] = []; const originalModel = this._model.original.notebook; const modifiedModel = this._model.modified.notebook; let originalCellIndex = 0; @@ -243,7 +243,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD const originalCell = originalModel.cells[originalCellIndex + j]; const modifiedCell = modifiedModel.cells[modifiedCellIndex + j]; if (originalCell.getHashValue() === modifiedCell.getHashValue()) { - cellDiffViewModels.push(new CellDiffViewModel( + cellDiffViewModels.push(new SideBySideCellDiffViewModel( this._model.modified.notebook, originalCell, modifiedCell, @@ -255,7 +255,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD firstChangeIndex = cellDiffViewModels.length; } - cellDiffViewModels.push(new CellDiffViewModel( + cellDiffViewModels.push(new SideBySideCellDiffViewModel( this._model.modified.notebook, originalCell, modifiedCell, @@ -276,7 +276,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD } for (let i = originalCellIndex; i < originalModel.cells.length; i++) { - cellDiffViewModels.push(new CellDiffViewModel( + cellDiffViewModels.push(new SideBySideCellDiffViewModel( this._model.modified.notebook, originalModel.cells[i], modifiedModel.cells[i - originalCellIndex + modifiedCellIndex], @@ -295,12 +295,12 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD } private _computeModifiedLCS(change: IDiffChange, originalModel: NotebookTextModel, modifiedModel: NotebookTextModel) { - const result: CellDiffViewModel[] = []; + const result: CellDiffViewModelBase[] = []; // modified cells const modifiedLen = Math.min(change.originalLength, change.modifiedLength); for (let j = 0; j < modifiedLen; j++) { - result.push(new CellDiffViewModel( + result.push(new SideBySideCellDiffViewModel( modifiedModel, originalModel.cells[change.originalStart + j], modifiedModel.cells[change.modifiedStart + j], @@ -311,7 +311,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD for (let j = modifiedLen; j < change.originalLength; j++) { // deletion - result.push(new CellDiffViewModel( + result.push(new SingleSideCellDiffViewModel( originalModel, originalModel.cells[change.originalStart + j], undefined, @@ -322,7 +322,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD for (let j = modifiedLen; j < change.modifiedLength; j++) { // insertion - result.push(new CellDiffViewModel( + result.push(new SingleSideCellDiffViewModel( modifiedModel, undefined, modifiedModel.cells[change.modifiedStart + j], @@ -334,11 +334,11 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD return result; } - private pendingLayouts = new WeakMap(); + private pendingLayouts = new WeakMap(); - layoutNotebookCell(cell: CellDiffViewModel, height: number) { - const relayout = (cell: CellDiffViewModel, height: number) => { + layoutNotebookCell(cell: CellDiffViewModelBase, height: number) { + const relayout = (cell: CellDiffViewModelBase, height: number) => { const viewIndex = this._list.indexOf(cell); this._list?.updateElementHeight(viewIndex, height); diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts index f4bc58255c3..beacd76156e 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts @@ -14,7 +14,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IListService, IWorkbenchListOptions, WorkbenchList } from 'vs/platform/list/browser/listService'; import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { CellDiffViewModel } from 'vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel'; +import { CellDiffViewModelBase, SideBySideCellDiffViewModel, SingleSideCellDiffViewModel } from 'vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel'; import { CellDiffSideBySideRenderTemplate, CellDiffSingleSideRenderTemplate, DIFF_CELL_MARGIN, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common'; import { isMacintosh } from 'vs/base/common/platform'; import { DeletedCell, InsertCell, ModifiedCell } from 'vs/workbench/contrib/notebook/browser/diff/cellComponents'; @@ -88,7 +88,7 @@ export function getOptimizedNestedCodeEditorWidgetOptions(): ICodeEditorWidgetOp }; } -export class NotebookCellTextDiffListDelegate implements IListVirtualDelegate { +export class NotebookCellTextDiffListDelegate implements IListVirtualDelegate { // private readonly lineHeight: number; constructor( @@ -98,15 +98,15 @@ export class NotebookCellTextDiffListDelegate implements IListVirtualDelegate { +export class CellDiffSingleSideRenderer implements IListRenderer { static readonly TEMPLATE_ID = 'cell_diff_single'; constructor( @@ -177,7 +177,7 @@ export class CellDiffSingleSideRenderer implements IListRenderer { +export class CellDiffSideBySideRenderer implements IListRenderer { static readonly TEMPLATE_ID = 'cell_diff_side_by_side'; constructor( @@ -286,7 +286,7 @@ export class CellDiffSideBySideRenderer implements IListRenderer implements IDisposable, IStyleController { +export class NotebookTextDiffList extends WorkbenchList implements IDisposable, IStyleController { private styleElement?: HTMLStyleElement; constructor( listUser: string, container: HTMLElement, - delegate: IListVirtualDelegate, - renderers: IListRenderer[], + delegate: IListVirtualDelegate, + renderers: IListRenderer[], contextKeyService: IContextKeyService, - options: IWorkbenchListOptions, + options: IWorkbenchListOptions, @IListService listService: IListService, @IThemeService themeService: IThemeService, @IConfigurationService configurationService: IConfigurationService, From 239c211326d5ff9d0ca2ee0070489e915059316d Mon Sep 17 00:00:00 2001 From: rebornix Date: Mon, 14 Dec 2020 14:10:32 -0800 Subject: [PATCH 016/262] positioning for dynamic height output --- .../notebook/browser/diff/cellComponents.ts | 15 +- .../notebook/browser/diff/cellOutputs.ts | 104 +++++++++---- .../browser/diff/celllDiffViewModel.ts | 145 +++++++++++++++++- .../notebook/browser/diff/notebookDiff.css | 4 +- .../browser/viewModel/codeCellViewModel.ts | 2 +- 5 files changed, 226 insertions(+), 44 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts index 29e062d6156..f4e30a7c966 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts @@ -872,14 +872,13 @@ export class InsertCell extends SingleSideCell { } _buildOutputContainer() { - this._outputLeftView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell.modified!, this._outputViewContainer!); + this._outputLeftView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell, this.cell.modified!, true, this._outputViewContainer!); this._outputLeftView.render(); - this.cell.outputHeight = (this._outputViewContainer!.childNodes[0] as HTMLElement).clientHeight; + this.cell.outputHeight = this.cell.getOutputTotalHeight(); } _updateOutputContainerHeight(): void { - // throw new Error('Method not implemented.'); - this.cell.outputHeight = (this._outputViewContainer!.childNodes[0] as HTMLElement).clientHeight; + this.cell.outputHeight = this.cell.getOutputTotalHeight(); } layout(state: { outerWidth?: boolean, editorHeight?: boolean, metadataEditor?: boolean, outputEditor?: boolean, outputView?: boolean }) { @@ -1037,17 +1036,17 @@ export class ModifiedCell extends AbstractCellRenderer { this._outputLeftContainer = DOM.append(this._outputViewContainer!, DOM.$('.output-view-container-left')); this._outputRightContainer = DOM.append(this._outputViewContainer!, DOM.$('.output-view-container-right')); // We should use the original text model here - this._outputLeftView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell.original!, this._outputLeftContainer!); + this._outputLeftView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell, this.cell.original!, false, this._outputLeftContainer!); this._outputLeftView.render(); - this._outputRightView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell.modified!, this._outputRightContainer!); + this._outputRightView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell, this.cell.modified!, true, this._outputRightContainer!); this._outputRightView.render(); - this.cell.outputHeight = Math.max((this._outputLeftContainer!.childNodes[0] as HTMLElement).clientHeight, (this._outputRightContainer!.childNodes[0] as HTMLElement).clientHeight); + this.cell.outputHeight = this.cell.getOutputTotalHeight(); } _updateOutputContainerHeight(): void { - this.cell.outputHeight = Math.max((this._outputLeftContainer!.childNodes[0] as HTMLElement).clientHeight, (this._outputRightContainer!.childNodes[0] as HTMLElement).clientHeight); + this.cell.outputHeight = this.cell.getOutputTotalHeight(); } updateSourceEditor(): void { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/cellOutputs.ts b/src/vs/workbench/contrib/notebook/browser/diff/cellOutputs.ts index 6ba1e204d3a..6bf10590626 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/cellOutputs.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/cellOutputs.ts @@ -6,8 +6,10 @@ import * as DOM from 'vs/base/browser/dom'; import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IOpenerService } from 'vs/platform/opener/common/opener'; +import { CellDiffViewModelBase, SideBySideCellDiffViewModel, SingleSideCellDiffViewModel } from 'vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel'; import { INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common'; import { ICellOutputViewModel, IRenderOutput, outputHasDynamicHeight, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { getResizesObserver } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellWidgets'; import { CellOutputViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; @@ -24,6 +26,9 @@ export class OutputElement extends Disposable { private notebookEditor: INotebookTextDiffEditor, private notebookTextModel: NotebookTextModel, private notebookService: INotebookService, + private cellViewModel: CellDiffViewModelBase, + private modified: boolean, + // private viewCell: CodeCellViewModel, private outputContainer: HTMLElement, readonly output: ICellOutputViewModel @@ -31,7 +36,7 @@ export class OutputElement extends Disposable { super(); } - render(beforeElement?: HTMLElement) { + render(index: number, beforeElement?: HTMLElement) { const outputItemDiv = document.createElement('div'); let result: IRenderOutput | undefined = undefined; @@ -84,41 +89,69 @@ export class OutputElement extends Disposable { if (outputHasDynamicHeight(result)) { // this.viewCell.selfSizeMonitoring = true; - - // const clientHeight = outputItemDiv.clientHeight; + const clientHeight = outputItemDiv.clientHeight; + // TODO, set an inital dimension to avoid force reflow // const dimension = { - // width: this.viewCell.layoutInfo.editorWidth, + // width: this.cellViewModel., // height: clientHeight // }; - // const elementSizeObserver = getResizesObserver(outputItemDiv, dimension, () => { - // if (this.outputContainer && document.body.contains(this.outputContainer)) { - // const height = Math.ceil(elementSizeObserver.getHeight()); - // if (clientHeight === height) { - // return; - // } + const elementSizeObserver = getResizesObserver(outputItemDiv, undefined, () => { + if (this.outputContainer && document.body.contains(this.outputContainer)) { + const height = Math.ceil(elementSizeObserver.getHeight()); - // const currIndex = this.viewCell.outputsViewModels.indexOf(this.output); - // if (currIndex < 0) { - // return; - // } + if (clientHeight === height) { + return; + } - // this.viewCell.updateOutputHeight(currIndex, height); - // this.relayoutCell(); - // } - // }); - // elementSizeObserver.startObserving(); - // this.resizeListener.add(elementSizeObserver); + const currIndex = this.getCellOutputCurrentIndex(); + if (currIndex < 0) { + return; + } + + this.updateHeight(currIndex, height); + } + }); + elementSizeObserver.startObserving(); + this.resizeListener.add(elementSizeObserver); // this.viewCell.updateOutputHeight(index, clientHeight); + this.updateHeight(index, clientHeight); } else if (result.type === RenderOutputType.None) { // no-op if it's a webview - // const clientHeight = Math.ceil(outputItemDiv.clientHeight); - // this.viewCell.updateOutputHeight(index, clientHeight); + const clientHeight = Math.ceil(outputItemDiv.clientHeight); + this.updateHeight(index, clientHeight); - // const top = this.viewCell.getOutputOffsetInContainer(index); - // outputItemDiv.style.top = `${top}px`; + const top = this.getOffset(index); + outputItemDiv.style.top = `${top}px`; } } + getCellOutputCurrentIndex() { + if (this.cellViewModel instanceof SideBySideCellDiffViewModel) { + if (this.modified) { + return this.cellViewModel.modified.outputs.indexOf(this.output.model); + } else { + return this.cellViewModel.original.outputs.indexOf(this.output.model); + } + } else { + return (this.cellViewModel as SingleSideCellDiffViewModel).cellTextModel!.outputs.indexOf(this.output.model); + } + } + + updateHeight(index: number, height: number) { + if (this.cellViewModel instanceof SideBySideCellDiffViewModel) { + this.cellViewModel.updateOutputHeight(!this.modified, index, height); + } else { + (this.cellViewModel as SingleSideCellDiffViewModel).updateOutputHeight(index, height); + } + } + + getOffset(index: number) { + if (this.cellViewModel instanceof SideBySideCellDiffViewModel) { + return this.cellViewModel.getOutputOffsetInContainer(!this.modified, index); + } else { + return (this.cellViewModel as SingleSideCellDiffViewModel).getOutputOffsetInContainer(index); + } + } } export class OutputContainer extends Disposable { @@ -127,7 +160,9 @@ export class OutputContainer extends Disposable { constructor( private _editor: INotebookTextDiffEditor, private notebookTextModel: NotebookTextModel, + private cellViewModel: CellDiffViewModelBase, cell: NotebookCellTextModel, + private modified: boolean, private outputContainer: HTMLElement, @INotebookService private notebookService: INotebookService, // @IQuickInputService private readonly quickInputService: IQuickInputService, @@ -142,6 +177,21 @@ export class OutputContainer extends Disposable { // viewCell.onDidChangeLayout // say the height of the cell editor changes + + this._register(this.cellViewModel.onDidLayoutChange(() => { + this.outputEntries.forEach((value, key) => { + const index = cell.outputs.indexOf(key.model); + if (index >= 0) { + if (this.cellViewModel instanceof SideBySideCellDiffViewModel) { + const top = this.cellViewModel.getOutputOffsetInContainer(!this.modified, index); + value.domNode.style.top = `${top}px`; + } else { + const top = (this.cellViewModel as SingleSideCellDiffViewModel).getOutputOffsetInContainer(index); + value.domNode.style.top = `${top}px`; + } + } + }); + })); } render() { @@ -156,10 +206,10 @@ export class OutputContainer extends Disposable { private _renderOutput(currOutput: ICellOutputViewModel, index: number, beforeElement?: HTMLElement) { if (!this.outputEntries.has(currOutput)) { - this.outputEntries.set(currOutput, new OutputElement(this._editor, this.notebookTextModel, this.notebookService, this.outputContainer, currOutput)); + this.outputEntries.set(currOutput, new OutputElement(this._editor, this.notebookTextModel, this.notebookService, this.cellViewModel, this.modified, this.outputContainer, currOutput)); } - this.outputEntries.get(currOutput)!.render(beforeElement); - + const renderElement = this.outputEntries.get(currOutput)!; + renderElement.render(index, beforeElement); } } diff --git a/src/vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel.ts b/src/vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel.ts index a6df242c3fc..59774828baf 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel.ts @@ -29,6 +29,7 @@ export abstract class CellDiffViewModelBase extends Disposable { onDidLayoutChange = this._layoutInfoEmitter.event; protected _layoutInfo!: { + width: number; editorHeight: number; editorMargin: number; metadataStatusHeight: number; @@ -38,9 +39,6 @@ export abstract class CellDiffViewModelBase extends Disposable { bodyMargin: number; }; - protected _outputCollection: number[] = []; - protected _outputsTop: PrefixSumComputer | null = null; - set outputHeight(height: number) { this._layoutInfo.outputHeight = height; this._fireLayoutChangeEvent({ outputEditor: true, outputView: true }); @@ -109,6 +107,7 @@ export abstract class CellDiffViewModelBase extends Disposable { ) { super(); this._layoutInfo = { + width: 0, editorHeight: 0, editorMargin: 0, metadataHeight: 0, @@ -133,7 +132,7 @@ export abstract class CellDiffViewModelBase extends Disposable { abstract checkIfOutputsModified(): boolean; abstract checkMetadataIfModified(): boolean; - + abstract ensureOutputsTop(): void; getComputedCellContainerWidth(layoutInfo: NotebookLayoutInfo, diffEditor: boolean, fullWidth: boolean) { if (fullWidth) { @@ -145,10 +144,15 @@ export abstract class CellDiffViewModelBase extends Disposable { } export class SideBySideCellDiffViewModel extends CellDiffViewModelBase { + protected _originalOutputCollection: number[] = []; + protected _originalOutputsTop: PrefixSumComputer | null = null; + protected _modifiedOutputCollection: number[] = []; + protected _modifiedOutputsTop: PrefixSumComputer | null = null; + constructor( readonly documentTextModel: NotebookTextModel, - readonly original: NotebookCellTextModel | undefined, - readonly modified: NotebookCellTextModel | undefined, + readonly original: NotebookCellTextModel, + readonly modified: NotebookCellTextModel, readonly type: 'unchanged' | 'modified', readonly editorEventDispatcher: NotebookDiffEditorEventDispatcher ) { @@ -169,6 +173,9 @@ export class SideBySideCellDiffViewModel extends CellDiffViewModelBase { if (this.checkIfOutputsModified()) { this.outputFoldingState = PropertyFoldingState.Expanded; } + + this._originalOutputCollection = new Array(this.original.outputs.length); + this._modifiedOutputCollection = new Array(this.modified.outputs.length); } checkIfOutputsModified() { @@ -178,9 +185,95 @@ export class SideBySideCellDiffViewModel extends CellDiffViewModelBase { checkMetadataIfModified(): boolean { return hash(getFormatedMetadataJSON(this.documentTextModel, this.original?.metadata || {}, this.original?.language)) !== hash(getFormatedMetadataJSON(this.documentTextModel, this.modified?.metadata ?? {}, this.modified?.language)); } + + updateOutputHeight(original: boolean, index: number, height: number) { + if (original) { + if (index >= this._originalOutputCollection.length) { + throw new Error('Output index out of range!'); + } + + this.ensureOriginalOutputsTop(); + this.ensureModifiedOutputsTop(); + this._originalOutputCollection[index] = height; + + if (this._originalOutputsTop!.changeValue(index, height)) { + this.outputHeight = Math.max(this._originalOutputsTop!.getTotalValue(), this._modifiedOutputsTop!.getTotalValue()); + } + } else { + if (index >= this._modifiedOutputCollection.length) { + throw new Error('Output index out of range!'); + } + + this.ensureOriginalOutputsTop(); + this.ensureModifiedOutputsTop(); + this._modifiedOutputCollection[index] = height; + + if (this._modifiedOutputsTop!.changeValue(index, height)) { + this.outputHeight = Math.max(this._originalOutputsTop!.getTotalValue(), this._modifiedOutputsTop!.getTotalValue()); + } + } + } + + ensureOriginalOutputsTop() { + if (!this._originalOutputsTop) { + const values = new Uint32Array(this._originalOutputCollection.length); + for (let i = 0; i < this._originalOutputCollection.length; i++) { + values[i] = this._originalOutputCollection[i]; + } + + this._originalOutputsTop = new PrefixSumComputer(values); + } + } + + ensureModifiedOutputsTop() { + if (!this._modifiedOutputsTop) { + const values = new Uint32Array(this._modifiedOutputCollection.length); + for (let i = 0; i < this._modifiedOutputCollection.length; i++) { + values[i] = this._modifiedOutputCollection[i]; + } + + this._modifiedOutputsTop = new PrefixSumComputer(values); + } + } + + getOutputOffsetInContainer(original: boolean, index: number) { + this.ensureOutputsTop(); + + if (original) { + if (index >= this._originalOutputCollection.length) { + throw new Error('Output index out of range!'); + } + + return this._originalOutputsTop!.getAccumulatedValue(index - 1); + } else { + if (index >= this._modifiedOutputCollection.length) { + throw new Error('Output index out of range!'); + } + + return this._modifiedOutputsTop!.getAccumulatedValue(index - 1); + } + } + + getOutputTotalHeight() { + this.ensureOutputsTop(); + + return Math.max(this._originalOutputsTop?.getTotalValue() ?? 0, this._modifiedOutputsTop?.getTotalValue() ?? 0); + } + + ensureOutputsTop() { + this.ensureOriginalOutputsTop(); + this.ensureModifiedOutputsTop(); + } } export class SingleSideCellDiffViewModel extends CellDiffViewModelBase { + protected _outputCollection: number[] = []; + protected _outputsTop: PrefixSumComputer | null = null; + + get cellTextModel() { + return this.type === 'insert' ? this.modified : this.original; + } + constructor( readonly documentTextModel: NotebookTextModel, readonly original: NotebookCellTextModel | undefined, @@ -189,6 +282,7 @@ export class SingleSideCellDiffViewModel extends CellDiffViewModelBase { readonly editorEventDispatcher: NotebookDiffEditorEventDispatcher ) { super(documentTextModel, original, modified, type, editorEventDispatcher); + this._outputCollection = new Array(this.original ? this.original.outputs.length : this.modified!.outputs.length); } checkIfOutputsModified(): boolean { @@ -198,6 +292,45 @@ export class SingleSideCellDiffViewModel extends CellDiffViewModelBase { checkMetadataIfModified(): boolean { return false; } + + updateOutputHeight(index: number, height: number) { + if (index >= this._outputCollection.length) { + throw new Error('Output index out of range!'); + } + + this.ensureOutputsTop(); + this._outputCollection[index] = height; + if (this._outputsTop!.changeValue(index, height)) { + this.outputHeight = this._outputsTop!.getTotalValue(); + } + } + + ensureOutputsTop() { + if (!this._outputsTop) { + const values = new Uint32Array(this._outputCollection.length); + for (let i = 0; i < this._outputCollection.length; i++) { + values[i] = this._outputCollection[i]; + } + + this._outputsTop = new PrefixSumComputer(values); + } + } + + getOutputOffsetInContainer(index: number) { + this.ensureOutputsTop(); + + if (index >= this._outputCollection.length) { + throw new Error('Output index out of range!'); + } + + return this._outputsTop!.getAccumulatedValue(index - 1); + } + + getOutputTotalHeight() { + this.ensureOutputsTop(); + + return this._outputsTop?.getTotalValue() ?? 0; + } } export function getFormatedMetadataJSON(documentTextModel: NotebookTextModel, metadata: NotebookCellMetadata, language?: string) { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css index 95afc16af1f..22266135923 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css @@ -125,18 +125,18 @@ } - .monaco-workbench .notebook-text-diff-editor .cell-body .output-view-container { user-select: text; -webkit-user-select: text; -ms-user-select: text; white-space: initial; cursor: auto; + position: relative; } .monaco-workbench .notebook-text-diff-editor .cell-body.left .output-view-container .output-inner-container, .monaco-workbench .notebook-text-diff-editor .cell-body.right .output-view-container .output-inner-container { - width: calc(50% - 16px); + width: 100%; padding: 4px 8px; box-sizing: border-box; } diff --git a/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts b/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts index 74f6cf9385a..497b93760da 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts @@ -270,8 +270,8 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod throw new Error('Output index out of range!'); } - this._outputCollection[index] = height; this._ensureOutputsTop(); + this._outputCollection[index] = height; if (this._outputsTop!.changeValue(index, height)) { this.layoutChange({ outputHeight: true }); } From dcda9032e78bdd7f7dfaa194932153a8257b5bff Mon Sep 17 00:00:00 2001 From: rebornix Date: Mon, 14 Dec 2020 14:18:47 -0800 Subject: [PATCH 017/262] output height calculation in view model by reading folding state. --- .../notebook/browser/diff/cellComponents.ts | 2 +- .../browser/diff/celllDiffViewModel.ts | 45 +++++++++++++++++-- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts index f4e30a7c966..48f13b6a406 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts @@ -310,7 +310,7 @@ abstract class AbstractCellRenderer extends Disposable { } else { this._outputInfoContainer.style.display = 'none'; this._outputEditorDisposeStore.clear(); - this.cell.outputHeight = 0; + this.cell.layoutChange(); } } diff --git a/src/vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel.ts b/src/vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel.ts index 59774828baf..d7c30ce18d1 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel.ts @@ -125,7 +125,6 @@ export abstract class CellDiffViewModelBase extends Disposable { this._layoutInfoEmitter.fire({ outerWidth: true }); })); } - private _fireLayoutChangeEvent(state: { outerWidth?: boolean, editorHeight?: boolean, metadataEditor?: boolean, outputEditor?: boolean, outputView?: boolean }) { this._layoutInfoEmitter.fire(state); } @@ -133,6 +132,7 @@ export abstract class CellDiffViewModelBase extends Disposable { abstract checkIfOutputsModified(): boolean; abstract checkMetadataIfModified(): boolean; abstract ensureOutputsTop(): void; + abstract layoutChange(): void; getComputedCellContainerWidth(layoutInfo: NotebookLayoutInfo, diffEditor: boolean, fullWidth: boolean) { if (fullWidth) { @@ -178,6 +178,24 @@ export class SideBySideCellDiffViewModel extends CellDiffViewModelBase { this._modifiedOutputCollection = new Array(this.modified.outputs.length); } + layoutChange() { + this.ensureOutputsTop(); + + let outputHeight = this.outputFoldingState === PropertyFoldingState.Collapsed ? 0 : this.getOutputTotalHeight(); + this._layoutInfo = { + width: this._layoutInfo.width, + editorHeight: this._layoutInfo.editorHeight, + editorMargin: this._layoutInfo.editorMargin, + metadataHeight: this._layoutInfo.metadataHeight, + metadataStatusHeight: this._layoutInfo.metadataStatusHeight, + outputHeight: outputHeight, + outputStatusHeight: this._layoutInfo.outputStatusHeight, + bodyMargin: this._layoutInfo.bodyMargin + }; + + this._layoutInfoEmitter.fire({}); + } + checkIfOutputsModified() { return !this.documentTextModel.transientOptions.transientOutputs && this.type === 'modified' && hash(this.original?.outputs ?? []) !== hash(this.modified?.outputs ?? []); } @@ -197,7 +215,7 @@ export class SideBySideCellDiffViewModel extends CellDiffViewModelBase { this._originalOutputCollection[index] = height; if (this._originalOutputsTop!.changeValue(index, height)) { - this.outputHeight = Math.max(this._originalOutputsTop!.getTotalValue(), this._modifiedOutputsTop!.getTotalValue()); + this.layoutChange(); } } else { if (index >= this._modifiedOutputCollection.length) { @@ -209,7 +227,7 @@ export class SideBySideCellDiffViewModel extends CellDiffViewModelBase { this._modifiedOutputCollection[index] = height; if (this._modifiedOutputsTop!.changeValue(index, height)) { - this.outputHeight = Math.max(this._originalOutputsTop!.getTotalValue(), this._modifiedOutputsTop!.getTotalValue()); + this.layoutChange(); } } } @@ -285,6 +303,25 @@ export class SingleSideCellDiffViewModel extends CellDiffViewModelBase { this._outputCollection = new Array(this.original ? this.original.outputs.length : this.modified!.outputs.length); } + layoutChange() { + this.ensureOutputsTop(); + + let outputHeight = this.outputFoldingState === PropertyFoldingState.Collapsed ? 0 : this.getOutputTotalHeight(); + this._layoutInfo = { + width: this._layoutInfo.width, + editorHeight: this._layoutInfo.editorHeight, + editorMargin: this._layoutInfo.editorMargin, + metadataHeight: this._layoutInfo.metadataHeight, + metadataStatusHeight: this._layoutInfo.metadataStatusHeight, + outputHeight: outputHeight, + outputStatusHeight: this._layoutInfo.outputStatusHeight, + bodyMargin: this._layoutInfo.bodyMargin + }; + + this._layoutInfoEmitter.fire({}); + } + + checkIfOutputsModified(): boolean { return false; } @@ -301,7 +338,7 @@ export class SingleSideCellDiffViewModel extends CellDiffViewModelBase { this.ensureOutputsTop(); this._outputCollection[index] = height; if (this._outputsTop!.changeValue(index, height)) { - this.outputHeight = this._outputsTop!.getTotalValue(); + this.layoutChange(); } } From f656636cc387422959bc1fef8acf95d51a131dfc Mon Sep 17 00:00:00 2001 From: rebornix Date: Mon, 14 Dec 2020 18:29:30 -0800 Subject: [PATCH 018/262] :lipstick: --- .../notebook/browser/diff/cellComponents.ts | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts index 48f13b6a406..854e2d2ad80 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts @@ -294,7 +294,7 @@ abstract class AbstractCellRenderer extends Disposable { this._outputViewContainer = DOM.append(this._outputInfoContainer, DOM.$('.output-view-container')); this._buildOutputContainer(); } else { - this._updateOutputContainerHeight(); + this.cell.layoutChange(); } } else { this._outputInfoContainer.style.display = 'block'; @@ -315,7 +315,6 @@ abstract class AbstractCellRenderer extends Disposable { } abstract _buildOutputContainer(): void; - abstract _updateOutputContainerHeight(): void; private _applySanitizedMetadataChanges(currentMetadata: NotebookCellMetadata, newMetadata: any) { let result: { [key: string]: any } = {}; @@ -808,10 +807,6 @@ export class DeletedCell extends SingleSideCell { // this._outputView.render(); // this.layout({ outputView: true }); } - - _updateOutputContainerHeight(): void { - // throw new Error('Method not implemented.'); - } } export class InsertCell extends SingleSideCell { @@ -874,11 +869,7 @@ export class InsertCell extends SingleSideCell { _buildOutputContainer() { this._outputLeftView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell, this.cell.modified!, true, this._outputViewContainer!); this._outputLeftView.render(); - this.cell.outputHeight = this.cell.getOutputTotalHeight(); - } - - _updateOutputContainerHeight(): void { - this.cell.outputHeight = this.cell.getOutputTotalHeight(); + this.cell.layoutChange(); } layout(state: { outerWidth?: boolean, editorHeight?: boolean, metadataEditor?: boolean, outputEditor?: boolean, outputView?: boolean }) { @@ -1041,14 +1032,10 @@ export class ModifiedCell extends AbstractCellRenderer { this._outputRightView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell, this.cell.modified!, true, this._outputRightContainer!); this._outputRightView.render(); - this.cell.outputHeight = this.cell.getOutputTotalHeight(); + this.cell.layoutChange(); } - _updateOutputContainerHeight(): void { - this.cell.outputHeight = this.cell.getOutputTotalHeight(); - } - updateSourceEditor(): void { const modifiedCell = this.cell.modified!; const lineCount = modifiedCell.textBuffer.getLineCount(); From ca4601deba4fbb522b6572619a6d263c8482ad4d Mon Sep 17 00:00:00 2001 From: rebornix Date: Mon, 14 Dec 2020 18:52:05 -0800 Subject: [PATCH 019/262] no unnecessary as any --- .../contrib/notebook/browser/view/renderers/cellOutput.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellOutput.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellOutput.ts index 6f17a156f95..b0b486cf541 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellOutput.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellOutput.ts @@ -127,7 +127,7 @@ export class OutputElement extends Disposable { if (result.type !== RenderOutputType.None) { this.viewCell.selfSizeMonitoring = true; - this.notebookEditor.createInset(this.viewCell, result as any, this.viewCell.getOutputOffset(index)); + this.notebookEditor.createInset(this.viewCell, result, this.viewCell.getOutputOffset(index)); } else { outputItemDiv.classList.add('foreground', 'output-element'); outputItemDiv.style.position = 'absolute'; From cf242ccaa83c564bee910bf1423d33960480ba46 Mon Sep 17 00:00:00 2001 From: rebornix Date: Mon, 14 Dec 2020 18:57:59 -0800 Subject: [PATCH 020/262] prep for webview renderers --- .../notebook/browser/diff/cellOutputs.ts | 29 ++++++++++++++----- .../browser/diff/celllDiffViewModel.ts | 24 +++++++++++++++ .../contrib/notebook/browser/diff/common.ts | 4 ++- .../browser/diff/notebookTextDiffEditor.ts | 17 ++++++++++- 4 files changed, 65 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/cellOutputs.ts b/src/vs/workbench/contrib/notebook/browser/diff/cellOutputs.ts index 6bf10590626..2641b731f03 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/cellOutputs.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/cellOutputs.ts @@ -29,7 +29,7 @@ export class OutputElement extends Disposable { private cellViewModel: CellDiffViewModelBase, private modified: boolean, - // private viewCell: CodeCellViewModel, + private cell: NotebookCellTextModel, private outputContainer: HTMLElement, readonly output: ICellOutputViewModel ) { @@ -81,7 +81,15 @@ export class OutputElement extends Disposable { if (result.type !== RenderOutputType.None) { // this.viewCell.selfSizeMonitoring = true; - // this.notebookEditor.createInset(this.viewCell, result as any, this.viewCell.getOutputOffset(index)); + this.notebookEditor.createInset( + this.cellViewModel, + this.cell, + result, + this.getOutputOffsetInContainer(index), + this.cellViewModel instanceof SideBySideCellDiffViewModel + ? this.modified + : this.cellViewModel.type === 'insert' + ); } else { outputItemDiv.classList.add('foreground', 'output-element'); outputItemDiv.style.position = 'absolute'; @@ -114,13 +122,12 @@ export class OutputElement extends Disposable { }); elementSizeObserver.startObserving(); this.resizeListener.add(elementSizeObserver); - // this.viewCell.updateOutputHeight(index, clientHeight); this.updateHeight(index, clientHeight); } else if (result.type === RenderOutputType.None) { // no-op if it's a webview const clientHeight = Math.ceil(outputItemDiv.clientHeight); this.updateHeight(index, clientHeight); - const top = this.getOffset(index); + const top = this.getOutputOffsetInContainer(index); outputItemDiv.style.top = `${top}px`; } } @@ -145,13 +152,21 @@ export class OutputElement extends Disposable { } } - getOffset(index: number) { + getOutputOffsetInContainer(index: number) { if (this.cellViewModel instanceof SideBySideCellDiffViewModel) { return this.cellViewModel.getOutputOffsetInContainer(!this.modified, index); } else { return (this.cellViewModel as SingleSideCellDiffViewModel).getOutputOffsetInContainer(index); } } + + getOutputOffsetInCell(index: number) { + if (this.cellViewModel instanceof SideBySideCellDiffViewModel) { + return this.cellViewModel.getOutputOffsetInCell(!this.modified, index); + } else { + return (this.cellViewModel as SingleSideCellDiffViewModel).getOutputOffsetInCell(index); + } + } } export class OutputContainer extends Disposable { @@ -161,7 +176,7 @@ export class OutputContainer extends Disposable { private _editor: INotebookTextDiffEditor, private notebookTextModel: NotebookTextModel, private cellViewModel: CellDiffViewModelBase, - cell: NotebookCellTextModel, + private cell: NotebookCellTextModel, private modified: boolean, private outputContainer: HTMLElement, @INotebookService private notebookService: INotebookService, @@ -206,7 +221,7 @@ export class OutputContainer extends Disposable { private _renderOutput(currOutput: ICellOutputViewModel, index: number, beforeElement?: HTMLElement) { if (!this.outputEntries.has(currOutput)) { - this.outputEntries.set(currOutput, new OutputElement(this._editor, this.notebookTextModel, this.notebookService, this.cellViewModel, this.modified, this.outputContainer, currOutput)); + this.outputEntries.set(currOutput, new OutputElement(this._editor, this.notebookTextModel, this.notebookService, this.cellViewModel, this.modified, this.cell, this.outputContainer, currOutput)); } const renderElement = this.outputEntries.get(currOutput)!; diff --git a/src/vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel.ts b/src/vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel.ts index d7c30ce18d1..09eba7ca261 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel.ts @@ -272,6 +272,18 @@ export class SideBySideCellDiffViewModel extends CellDiffViewModelBase { } } + getOutputOffsetInCell(original: boolean, index: number) { + const offsetInOutputsContainer = this.getOutputOffsetInContainer(original, index); + + return this._layoutInfo.editorHeight + + this._layoutInfo.editorMargin + + this._layoutInfo.metadataHeight + + this._layoutInfo.metadataStatusHeight + + this._layoutInfo.outputStatusHeight + + this._layoutInfo.bodyMargin / 2 + + offsetInOutputsContainer; + } + getOutputTotalHeight() { this.ensureOutputsTop(); @@ -363,6 +375,18 @@ export class SingleSideCellDiffViewModel extends CellDiffViewModelBase { return this._outputsTop!.getAccumulatedValue(index - 1); } + getOutputOffsetInCell(index: number) { + const offsetInOutputsContainer = this.getOutputOffsetInContainer(index); + + return this._layoutInfo.editorHeight + + this._layoutInfo.editorMargin + + this._layoutInfo.metadataHeight + + this._layoutInfo.metadataStatusHeight + + this._layoutInfo.outputStatusHeight + + this._layoutInfo.bodyMargin / 2 + + offsetInOutputsContainer; + } + getOutputTotalHeight() { this.ensureOutputsTop(); diff --git a/src/vs/workbench/contrib/notebook/browser/diff/common.ts b/src/vs/workbench/contrib/notebook/browser/diff/common.ts index 40fe1571f42..8db7afd6bcb 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/common.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/common.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { IInsetRenderOutput, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellDiffViewModelBase } from 'vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel'; import { Event } from 'vs/base/common/event'; import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; @@ -13,6 +13,7 @@ import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer'; +import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; export interface INotebookTextDiffEditor { readonly textModel?: NotebookTextModel; @@ -21,6 +22,7 @@ export interface INotebookTextDiffEditor { getLayoutInfo(): NotebookLayoutInfo; layoutNotebookCell(cell: CellDiffViewModelBase, height: number): void; getOutputRenderer(): OutputRenderer; + createInset(cellDiffViewModel: CellDiffViewModelBase, cellTextModel: NotebookCellTextModel, output: IInsetRenderOutput, offset: number, rightEditor: boolean): void; } export interface CellDiffSingleSideRenderTemplate { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index dd1a285d7e3..a040aa520b6 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -24,7 +24,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; import { getZoomLevel } from 'vs/base/browser/browser'; -import { INotebookEditor, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { IInsetRenderOutput, INotebookEditor, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { DIFF_CELL_MARGIN, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common'; import { Emitter } from 'vs/base/common/event'; import { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; @@ -38,6 +38,8 @@ import { Schemas } from 'vs/base/common/network'; import { IDiffChange } from 'vs/base/common/diff/diff'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer'; +import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; +import { SequencerByKey } from 'vs/base/common/async'; export const IN_NOTEBOOK_TEXT_DIFF_EDITOR = new RawContextKey('isInNotebookTextDiffEditor', false); @@ -63,6 +65,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD } private _revealFirst: boolean; + private readonly _insetModifyQueueByOutputId = new SequencerByKey(); constructor( @IInstantiationService readonly instantiationService: IInstantiationService, @@ -364,6 +367,18 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD return new Promise(resolve => { r = resolve; }); } + + createInset(cellDiffViewModel: CellDiffViewModelBase, cellTextModel: NotebookCellTextModel, output: IInsetRenderOutput, offset: number, rightEditor: boolean): void { + this._insetModifyQueueByOutputId.queue(output.source.model.outputId, async () => { + }); + } + + // private async _resolveWebview(rightEditor: boolean): Promise { + // if (rightEditor) { + + // } + // } + getDomNode() { return this._rootElement; } From b2c0291c254b4bb279ed4dde73c37e84881f9d7c Mon Sep 17 00:00:00 2001 From: rebornix Date: Mon, 14 Dec 2020 19:00:08 -0800 Subject: [PATCH 021/262] expose notebook text diff editor list row container --- .../contrib/notebook/browser/diff/notebookTextDiffList.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts index beacd76156e..da0ad650d44 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts @@ -313,6 +313,10 @@ export class CellDiffSideBySideRenderer implements IListRenderer implements IDisposable, IStyleController { private styleElement?: HTMLStyleElement; + get rowsContainer(): HTMLElement { + return this.view.containerDomNode; + } + constructor( listUser: string, container: HTMLElement, From cbf9234d4fde1a73ff8479477bf08f69dc0924bc Mon Sep 17 00:00:00 2001 From: rebornix Date: Mon, 14 Dec 2020 20:23:29 -0800 Subject: [PATCH 022/262] hook modified webview --- .../browser/diff/backLayerWebview2.ts | 890 ++++++++++++++++++ .../browser/diff/notebookTextDiffEditor.ts | 52 +- .../browser/diff/notebookTextDiffList.ts | 10 + 3 files changed, 950 insertions(+), 2 deletions(-) create mode 100644 src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts diff --git a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts new file mode 100644 index 00000000000..0af765801a5 --- /dev/null +++ b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts @@ -0,0 +1,890 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as DOM from 'vs/base/browser/dom'; +import { Emitter, Event } from 'vs/base/common/event'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { isWeb } from 'vs/base/common/platform'; +import { URI } from 'vs/base/common/uri'; +import * as UUID from 'vs/base/common/uuid'; +import { IOpenerService, matchesScheme } from 'vs/platform/opener/common/opener'; +import { CELL_MARGIN, CELL_RUN_GUTTER, CODE_CELL_LEFT_MARGIN, CELL_OUTPUT_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; +import { IDisplayOutputViewModel, IInsetRenderOutput, INotebookEditor, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel'; +import { CellOutputKind, IDisplayOutput, INotebookRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; +import { IWebviewService, WebviewElement, WebviewContentPurpose } from 'vs/workbench/contrib/webview/browser/webview'; +import { asWebviewUri } from 'vs/workbench/contrib/webview/common/webviewUri'; +import { dirname, joinPath } from 'vs/base/common/resources'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { preloadsScriptStr } from 'vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads'; +import { FileAccess, Schemas } from 'vs/base/common/network'; +import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { IFileService } from 'vs/platform/files/common/files'; +import { VSBuffer } from 'vs/base/common/buffer'; +import { getExtensionForMimeType } from 'vs/base/common/mime'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common'; +import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; + +export interface WebviewIntialized { + __vscode_notebook_message: boolean; + type: 'initialized' +} + +export interface IDimensionMessage { + __vscode_notebook_message: boolean; + type: 'dimension'; + id: string; + data: DOM.Dimension; +} + +export interface IMouseEnterMessage { + __vscode_notebook_message: boolean; + type: 'mouseenter'; + id: string; +} + +export interface IMouseLeaveMessage { + __vscode_notebook_message: boolean; + type: 'mouseleave'; + id: string; +} + +export interface IWheelMessage { + __vscode_notebook_message: boolean; + type: 'did-scroll-wheel'; + payload: any; +} + + +export interface IScrollAckMessage { + __vscode_notebook_message: boolean; + type: 'scroll-ack'; + data: { top: number }; + version: number; +} + +export interface IBlurOutputMessage { + __vscode_notebook_message: boolean; + type: 'focus-editor'; + id: string; + focusNext?: boolean; +} + +export interface IClickedDataUrlMessage { + __vscode_notebook_message: boolean; + type: 'clicked-data-url'; + data: string; + downloadName?: string; +} + +export interface IClearMessage { + type: 'clear'; +} + +export interface ICreationRequestMessage { + type: 'html'; + content: + | { type: RenderOutputType.Html; htmlContent: string } + | { type: RenderOutputType.Extension; output: IDisplayOutput; mimeType: string }; + cellId: string; + outputId: string; + top: number; + left: number; + requiredPreloads: ReadonlyArray; + initiallyHidden?: boolean; + apiNamespace?: string | undefined; +} + +export interface IContentWidgetTopRequest { + id: string; + top: number; + left: number; +} + +export interface IViewScrollTopRequestMessage { + type: 'view-scroll'; + top?: number; + forceDisplay: boolean; + widgets: IContentWidgetTopRequest[]; + version: number; +} + +export interface IScrollRequestMessage { + type: 'scroll'; + id: string; + top: number; + widgetTop?: number; + version: number; +} + +export interface IClearOutputRequestMessage { + type: 'clearOutput'; + cellId: string; + outputId: string; + cellUri: string; + apiNamespace: string | undefined; +} + +export interface IHideOutputMessage { + type: 'hideOutput'; + outputId: string; + cellId: string; +} + +export interface IShowOutputMessage { + type: 'showOutput'; + cellId: string; + outputId: string; + top: number; +} + +export interface IFocusOutputMessage { + type: 'focus-output'; + cellId: string; +} + +export interface IPreloadResource { + originalUri: string; + uri: string; +} + +export interface IUpdatePreloadResourceMessage { + type: 'preload'; + resources: IPreloadResource[]; + source: 'renderer' | 'kernel'; +} + +export interface IUpdateDecorationsMessage { + type: 'decorations'; + cellId: string; + addedClassNames: string[]; + removedClassNames: string[]; +} + +export interface ICustomRendererMessage { + __vscode_notebook_message: boolean; + type: 'customRendererMessage'; + rendererId: string; + message: unknown; +} + +export type FromWebviewMessage = + | WebviewIntialized + | IDimensionMessage + | IMouseEnterMessage + | IMouseLeaveMessage + | IWheelMessage + | IScrollAckMessage + | IBlurOutputMessage + | ICustomRendererMessage + | IClickedDataUrlMessage; + +export type ToWebviewMessage = + | IClearMessage + | IFocusOutputMessage + | ICreationRequestMessage + | IViewScrollTopRequestMessage + | IScrollRequestMessage + | IClearOutputRequestMessage + | IHideOutputMessage + | IShowOutputMessage + | IUpdatePreloadResourceMessage + | IUpdateDecorationsMessage + | ICustomRendererMessage; + +export type AnyMessage = FromWebviewMessage | ToWebviewMessage; + +interface ICachedInset { + outputId: string; + cell: CodeCellViewModel; + renderer?: INotebookRendererInfo; + cachedCreation: ICreationRequestMessage; +} + +function html(strings: TemplateStringsArray, ...values: any[]): string { + let str = ''; + strings.forEach((string, i) => { + str += string + (values[i] || ''); + }); + return str; +} + +export interface INotebookWebviewMessage { + message: unknown; + forRenderer?: string; +} + +let version = 0; +export class BackLayerWebView extends Disposable { + element: HTMLElement; + webview: WebviewElement | undefined = undefined; + insetMapping: Map = new Map(); + hiddenInsetMapping: Set = new Set(); + reversedInsetMapping: Map = new Map(); + localResourceRootsCache: URI[] | undefined = undefined; + rendererRootsCache: URI[] = []; + kernelRootsCache: URI[] = []; + private readonly _onMessage = this._register(new Emitter()); + private readonly _preloadsCache = new Set(); + public readonly onMessage: Event = this._onMessage.event; + private _loaded!: Promise; + private _initalized?: Promise; + private _disposed = false; + + constructor( + public notebookEditor: INotebookTextDiffEditor, + public id: string, + public documentUri: URI, + @IWebviewService readonly webviewService: IWebviewService, + @IOpenerService readonly openerService: IOpenerService, + @INotebookService private readonly notebookService: INotebookService, + @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, + @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, + @IFileDialogService private readonly fileDialogService: IFileDialogService, + @IFileService private readonly fileService: IFileService, + ) { + super(); + + this.element = document.createElement('div'); + + this.element.style.width = `calc(100% - ${CODE_CELL_LEFT_MARGIN + (CELL_MARGIN * 2) + CELL_RUN_GUTTER}px)`; + this.element.style.height = '1400px'; + this.element.style.position = 'absolute'; + // this.element.style.margin = `0px 0 0px ${CODE_CELL_LEFT_MARGIN + CELL_RUN_GUTTER}px`; + } + generateContent(outputNodePadding: number, coreDependencies: string, baseUrl: string) { + return html` + + + + + + + + + ${coreDependencies} +
+ + + `; + } + + postRendererMessage(rendererId: string, message: any) { + this._sendMessageToWebview({ + __vscode_notebook_message: true, + type: 'customRendererMessage', + message, + rendererId + }); + } + + private resolveOutputId(id: string): { cell: CodeCellViewModel, output: IDisplayOutputViewModel } | undefined { + const output = this.reversedInsetMapping.get(id); + if (!output) { + return; + } + + const cell = this.insetMapping.get(output)!.cell; + + // const currCell = this.notebookEditor.viewModel?.viewCells.find(vc => vc.handle === cell.handle); + // if (currCell !== cell && currCell !== undefined) { + // this.insetMapping.get(output)!.cell = currCell as CodeCellViewModel; + // } + + return { cell: this.insetMapping.get(output)!.cell, output }; + } + + async createWebview(): Promise { + let coreDependencies = ''; + let resolveFunc: () => void; + + this._initalized = new Promise((resolve, reject) => { + resolveFunc = resolve; + }); + + const baseUrl = asWebviewUri(this.environmentService, this.id, dirname(this.documentUri)); + + if (!isWeb) { + const loaderUri = FileAccess.asFileUri('vs/loader.js', require); + const loader = asWebviewUri(this.environmentService, this.id, loaderUri); + + coreDependencies = ``; + const htmlContent = this.generateContent(CELL_OUTPUT_PADDING, coreDependencies, baseUrl.toString()); + this._initialize(htmlContent); + resolveFunc!(); + } else { + const loaderUri = FileAccess.asBrowserUri('vs/loader.js', require); + + fetch(loaderUri.toString(true)).then(async response => { + if (response.status !== 200) { + throw new Error(response.statusText); + } + + const loaderJs = await response.text(); + + coreDependencies = ` + + +`; + + const htmlContent = this.generateContent(CELL_OUTPUT_PADDING, coreDependencies, baseUrl.toString()); + this._initialize(htmlContent); + resolveFunc!(); + }); + } + + await this._initalized; + } + + private async _initialize(content: string) { + if (!document.body.contains(this.element)) { + throw new Error('Element is already detached from the DOM tree'); + } + + this.webview = this._createInset(this.webviewService, content); + this.webview.mountTo(this.element); + this._register(this.webview); + + this._register(this.webview.onDidClickLink(link => { + if (this._disposed) { + return; + } + + if (!link) { + return; + } + + if (matchesScheme(link, Schemas.http) || matchesScheme(link, Schemas.https) || matchesScheme(link, Schemas.mailto) + || matchesScheme(link, Schemas.command)) { + this.openerService.open(link, { fromUserGesture: true }); + } + })); + + this._register(this.webview.onDidReload(() => { + if (this._disposed) { + return; + } + + let renderers = new Set(); + for (const inset of this.insetMapping.values()) { + if (inset.renderer) { + renderers.add(inset.renderer); + } + } + + this._preloadsCache.clear(); + this.updateRendererPreloads(renderers); + + for (const [output, inset] of this.insetMapping.entries()) { + this._sendMessageToWebview({ ...inset.cachedCreation, initiallyHidden: this.hiddenInsetMapping.has(output) }); + } + })); + + this._register(this.webview.onMessage((data: FromWebviewMessage) => { + if (this._disposed) { + return; + } + + // if (data.__vscode_notebook_message) { + // if (data.type === 'dimension') { + // const height = data.data.height; + // const outputHeight = height; + + // const info = this.resolveOutputId(data.id); + // if (info) { + // const { cell, output } = info; + // const outputIndex = cell.outputsViewModels.indexOf(output); + // cell.updateOutputHeight(outputIndex, outputHeight); + // this.notebookEditor.layoutNotebookCell(cell, cell.layoutInfo.totalHeight); + // } + // } else if (data.type === 'mouseenter') { + // const info = this.resolveOutputId(data.id); + // if (info) { + // const { cell } = info; + // cell.outputIsHovered = true; + // } + // } else if (data.type === 'mouseleave') { + // const info = this.resolveOutputId(data.id); + // if (info) { + // const { cell } = info; + // cell.outputIsHovered = false; + // } + // } 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 === 'did-scroll-wheel') { + // this.notebookEditor.triggerScroll({ + // ...data.payload, + // preventDefault: () => { }, + // stopPropagation: () => { } + // }); + // } else if (data.type === 'focus-editor') { + // const info = this.resolveOutputId(data.id); + // if (info) { + // if (data.focusNext) { + // const idx = this.notebookEditor.viewModel?.getCellIndex(info.cell); + // if (typeof idx !== 'number') { + // return; + // } + + // const newCell = this.notebookEditor.viewModel?.viewCells[idx + 1]; + // if (!newCell) { + // return; + // } + + // this.notebookEditor.focusNotebookCell(newCell, 'editor'); + // } else { + // this.notebookEditor.focusNotebookCell(info.cell, 'editor'); + // } + // } + // } else if (data.type === 'clicked-data-url') { + // this._onDidClickDataLink(data); + // } else if (data.type === 'customRendererMessage') { + // this._onMessage.fire({ message: data.message, forRenderer: data.rendererId }); + // } + // return; + // } + + this._onMessage.fire({ message: data }); + })); + } + + private async _onDidClickDataLink(event: IClickedDataUrlMessage): Promise { + const [splitStart, splitData] = event.data.split(';base64,'); + if (!splitData || !splitStart) { + return; + } + + const defaultDir = dirname(this.documentUri); + let defaultName: string; + if (event.downloadName) { + defaultName = event.downloadName; + } else { + const mimeType = splitStart.replace(/^data:/, ''); + const candidateExtension = mimeType && getExtensionForMimeType(mimeType); + defaultName = candidateExtension ? `download${candidateExtension}` : 'download'; + } + + const defaultUri = joinPath(defaultDir, defaultName); + const newFileUri = await this.fileDialogService.showSaveDialog({ + defaultUri + }); + if (!newFileUri) { + return; + } + + const decoded = atob(splitData); + const typedArray = new Uint8Array(decoded.length); + for (let i = 0; i < decoded.length; i++) { + typedArray[i] = decoded.charCodeAt(i); + } + + const buff = VSBuffer.wrap(typedArray); + await this.fileService.writeFile(newFileUri, buff); + await this.openerService.open(newFileUri); + } + + private _createInset(webviewService: IWebviewService, content: string) { + const rootPath = isWeb ? FileAccess.asBrowserUri('', require) : FileAccess.asFileUri('', require); + + const workspaceFolders = this.contextService.getWorkspace().folders.map(x => x.uri); + + this.localResourceRootsCache = [...this.notebookService.getNotebookProviderResourceRoots(), ...workspaceFolders, rootPath]; + + const webview = webviewService.createWebviewElement(this.id, { + purpose: WebviewContentPurpose.NotebookRenderer, + enableFindWidget: false, + }, { + allowMultipleAPIAcquire: true, + allowScripts: true, + localResourceRoots: this.localResourceRootsCache + }, undefined); + + let resolveFunc: () => void; + this._loaded = new Promise((resolve, reject) => { + resolveFunc = resolve; + }); + + const dispose = webview.onMessage((data: FromWebviewMessage) => { + if (data.__vscode_notebook_message && data.type === 'initialized') { + resolveFunc(); + dispose.dispose(); + } + }); + + webview.html = content; + return webview; + } + + shouldUpdateInset(cell: CodeCellViewModel, output: IDisplayOutputViewModel, cellTop: number) { + if (this._disposed) { + return; + } + + if (cell.metadata?.outputCollapsed) { + return false; + } + + const outputCache = this.insetMapping.get(output)!; + const outputIndex = cell.outputsViewModels.indexOf(output); + const outputOffset = cellTop + cell.getOutputOffset(outputIndex); + + if (this.hiddenInsetMapping.has(output)) { + return true; + } + + if (outputOffset === outputCache.cachedCreation.top) { + return false; + } + + return true; + } + + updateViewScrollTop(top: number, forceDisplay: boolean, items: { cell: CodeCellViewModel, output: IDisplayOutputViewModel, cellTop: number }[]) { + if (this._disposed) { + return; + } + + const widgets: IContentWidgetTopRequest[] = items.map(item => { + const outputCache = this.insetMapping.get(item.output)!; + const id = outputCache.outputId; + const outputIndex = item.cell.outputsViewModels.indexOf(item.output); + + const outputOffset = item.cellTop + item.cell.getOutputOffset(outputIndex); + outputCache.cachedCreation.top = outputOffset; + this.hiddenInsetMapping.delete(item.output); + + return { + id: id, + top: outputOffset, + left: 0 + }; + }); + + this._sendMessageToWebview({ + top, + type: 'view-scroll', + version: version++, + forceDisplay, + widgets: widgets + }); + } + + async createInset(cell: NotebookCellTextModel, content: IInsetRenderOutput, cellTop: number, offset: number) { + if (this._disposed) { + return; + } + + const initialTop = cellTop + offset; + + if (this.insetMapping.has(content.source)) { + const outputCache = this.insetMapping.get(content.source); + + if (outputCache) { + this.hiddenInsetMapping.delete(content.source); + this._sendMessageToWebview({ + type: 'showOutput', + cellId: outputCache.cell.id, + outputId: outputCache.outputId, + top: initialTop + }); + return; + } + } + + const messageBase = { + type: 'html', + cellId: cell.id, + top: initialTop, + 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; + message = { + ...messageBase, + outputId: output.outputId, + apiNamespace: content.renderer.id, + requiredPreloads: await this.updateRendererPreloads([content.renderer]), + content: { + type: RenderOutputType.Extension, + mimeType: content.mimeType, + output: { + outputKind: CellOutputKind.Rich, + metadata: output.metadata, + data: output.data, + }, + }, + }; + } else { + message = { + ...messageBase, + outputId: UUID.generateUuid(), + content: { + type: content.type, + htmlContent: content.htmlContent, + } + }; + } + + this._sendMessageToWebview(message); + this.insetMapping.set(content.source, { outputId: message.outputId, cell, renderer, cachedCreation: message }); + this.hiddenInsetMapping.delete(content.source); + this.reversedInsetMapping.set(message.outputId, content.source); + } + + removeInset(output: IDisplayOutputViewModel) { + if (this._disposed) { + return; + } + + const outputCache = this.insetMapping.get(output); + if (!outputCache) { + return; + } + + const id = outputCache.outputId; + + this._sendMessageToWebview({ + type: 'clearOutput', + apiNamespace: outputCache.cachedCreation.apiNamespace, + cellUri: outputCache.cell.uri.toString(), + outputId: id, + cellId: outputCache.cell.id + }); + this.insetMapping.delete(output); + this.reversedInsetMapping.delete(id); + } + + hideInset(output: IDisplayOutputViewModel) { + if (this._disposed) { + return; + } + + const outputCache = this.insetMapping.get(output); + if (!outputCache) { + return; + } + + this.hiddenInsetMapping.add(output); + + this._sendMessageToWebview({ + type: 'hideOutput', + outputId: outputCache.outputId, + cellId: outputCache.cell.id, + }); + } + + clearInsets() { + if (this._disposed) { + return; + } + + this._sendMessageToWebview({ + type: 'clear' + }); + + this.insetMapping = new Map(); + this.reversedInsetMapping = new Map(); + } + + focusWebview() { + if (this._disposed) { + return; + } + + this.webview?.focus(); + } + + focusOutput(cellId: string) { + if (this._disposed) { + return; + } + + this.webview?.focus(); + setTimeout(() => { // Need this, or focus decoration is not shown. No clue. + this._sendMessageToWebview({ + type: 'focus-output', + cellId, + }); + }, 50); + } + + deltaCellOutputContainerClassNames(cellId: string, added: string[], removed: string[]) { + this._sendMessageToWebview({ + type: 'decorations', + cellId, + addedClassNames: added, + removedClassNames: removed + }); + + } + + async updateKernelPreloads(extensionLocations: URI[], preloads: URI[]) { + if (this._disposed) { + return; + } + + await this._loaded; + + const resources: IPreloadResource[] = []; + for (const preload of preloads) { + const uri = this.environmentService.isExtensionDevelopment && (preload.scheme === 'http' || preload.scheme === 'https') + ? preload : asWebviewUri(this.environmentService, this.id, preload); + + if (!this._preloadsCache.has(uri.toString())) { + resources.push({ uri: uri.toString(), originalUri: preload.toString() }); + this._preloadsCache.add(uri.toString()); + } + } + + if (!resources.length) { + return; + } + + this.kernelRootsCache = [...extensionLocations, ...this.kernelRootsCache]; + this._updatePreloads(resources, 'kernel'); + } + + async updateRendererPreloads(renderers: Iterable) { + if (this._disposed) { + return []; + } + + await this._loaded; + + const requiredPreloads: IPreloadResource[] = []; + const resources: IPreloadResource[] = []; + const extensionLocations: URI[] = []; + for (const rendererInfo of renderers) { + extensionLocations.push(rendererInfo.extensionLocation); + for (const preload of [rendererInfo.entrypoint, ...rendererInfo.preloads]) { + const uri = asWebviewUri(this.environmentService, this.id, preload); + const resource: IPreloadResource = { uri: uri.toString(), originalUri: preload.toString() }; + requiredPreloads.push(resource); + + if (!this._preloadsCache.has(uri.toString())) { + resources.push(resource); + this._preloadsCache.add(uri.toString()); + } + } + } + + if (!resources.length) { + return requiredPreloads; + } + + this.rendererRootsCache = extensionLocations; + this._updatePreloads(resources, 'renderer'); + return requiredPreloads; + } + + private _updatePreloads(resources: IPreloadResource[], source: 'renderer' | 'kernel') { + if (!this.webview) { + return; + } + + const mixedResourceRoots = [...(this.localResourceRootsCache || []), ...this.rendererRootsCache, ...this.kernelRootsCache]; + + this.webview.localResourcesRoot = mixedResourceRoots; + + this._sendMessageToWebview({ + type: 'preload', + resources: resources, + source: source + }); + } + + private _sendMessageToWebview(message: ToWebviewMessage) { + if (this._disposed) { + return; + } + + this.webview?.postMessage(message); + } + + clearPreloadsCache() { + this._preloadsCache.clear(); + } + + dispose() { + this._disposed = true; + this.webview?.dispose(); + super.dispose(); + } +} diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index a040aa520b6..e06081697ec 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -13,7 +13,6 @@ import { notebookCellBorder, NotebookEditorWidget } from 'vs/workbench/contrib/n import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; import { NotebookDiffEditorInput } from '../notebookDiffEditorInput'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { WorkbenchList } from 'vs/platform/list/browser/listService'; import { CellDiffViewModelBase, SideBySideCellDiffViewModel, SingleSideCellDiffViewModel } from 'vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { CellDiffSideBySideRenderer, CellDiffSingleSideRenderer, NotebookCellTextDiffListDelegate, NotebookTextDiffList } from 'vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList'; @@ -40,6 +39,11 @@ import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/no import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import { SequencerByKey } from 'vs/base/common/async'; +import { BackLayerWebView } from 'vs/workbench/contrib/notebook/browser/diff/backLayerWebview2'; +import { generateUuid } from 'vs/base/common/uuid'; +import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; + +const $ = DOM.$; export const IN_NOTEBOOK_TEXT_DIFF_EDITOR = new RawContextKey('isInNotebookTextDiffEditor', false); @@ -49,7 +53,9 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD private _rootElement!: HTMLElement; private _overflowContainer!: HTMLElement; private _dimension: DOM.Dimension | null = null; - private _list!: WorkbenchList; + private _list!: NotebookTextDiffList; + private _modifiedWebview: BackLayerWebView | null = null; + private _webviewTransparentCover: HTMLElement | null = null; private _fontInfo: BareFontInfo | undefined; private readonly _onMouseUp = this._register(new Emitter<{ readonly event: MouseEvent; readonly target: CellDiffViewModelBase; }>()); @@ -148,11 +154,30 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD } ); + this._register(this._list); + this._register(this._list.onMouseUp(e => { if (e.element) { this._onMouseUp.fire({ event: e.browserEvent, target: e.element }); } })); + + // transparent cover + this._webviewTransparentCover = DOM.append(this._list.rowsContainer, $('.webview-cover')); + this._webviewTransparentCover.style.display = 'none'; + + this._register(DOM.addStandardDisposableGenericMouseDownListner(this._overflowContainer, (e: StandardMouseEvent) => { + if (e.target.classList.contains('slider') && this._webviewTransparentCover) { + this._webviewTransparentCover.style.display = 'block'; + } + })); + + this._register(DOM.addStandardDisposableGenericMouseUpListner(this._overflowContainer, () => { + if (this._webviewTransparentCover) { + // no matter when + this._webviewTransparentCover.style.display = 'none'; + } + })); } async setInput(input: NotebookDiffEditorInput, options: EditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { @@ -204,11 +229,20 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD } })); + await this._createModifiedWebview(generateUuid(), this._model.modified.resource); this._eventDispatcher = new NotebookDiffEditorEventDispatcher(); await this.updateLayout(); } + private async _createModifiedWebview(id: string, resource: URI): Promise { + this._modifiedWebview = this.instantiationService.createInstance(BackLayerWebView, this, id, resource); + // attach the webview container to the DOM tree first + this._list.rowsContainer.insertAdjacentElement('afterbegin', this._modifiedWebview.element); + await this._modifiedWebview.createWebview(); + this._modifiedWebview.element.style.left = `calc(50%)`; + } + private async _resolveStats(resource: URI) { if (resource.scheme === Schemas.untitled) { return undefined; @@ -370,6 +404,13 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD createInset(cellDiffViewModel: CellDiffViewModelBase, cellTextModel: NotebookCellTextModel, output: IInsetRenderOutput, offset: number, rightEditor: boolean): void { this._insetModifyQueueByOutputId.queue(output.source.model.outputId, async () => { + if (rightEditor) { + if (!this._modifiedWebview!.insetMapping.has(output.source)) { + const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel); + await this._modifiedWebview?.createInset(cellTextModel, output, cellTop, offset); + + } + } }); } @@ -429,6 +470,13 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD this._rootElement.style.height = `${dimension.height}px`; this._list?.layout(this._dimension.height, this._dimension.width); + + + if (this._modifiedWebview) { + this._modifiedWebview.element.style.width = `${this._dimension.width / 2}px`; + this._modifiedWebview.element.style.left = `calc(50%)`; + } + this._eventDispatcher?.emit([new NotebookLayoutChangedEvent({ width: true, fontInfo: true }, this.getLayoutInfo())]); } } diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts index da0ad650d44..cd4ac5ef433 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts @@ -331,6 +331,16 @@ export class NotebookTextDiffList extends WorkbenchList i super(listUser, container, delegate, renderers, options, contextKeyService, listService, themeService, configurationService, keybindingService); } + getAbsoluteTopOfElement(element: CellDiffViewModelBase): number { + const index = this.indexOf(element); + // if (index === undefined || index < 0 || index >= this.length) { + // this._getViewIndexUpperBound(element); + // throw new ListError(this.listUser, `Invalid index ${index}`); + // } + + return this.view.elementTop(index); + } + style(styles: IListStyles) { const selectorSuffix = this.view.domId; if (!this.styleElement) { From 9ca7b4ed4df3d0c2110b4a27e3db95c22baaf73e Mon Sep 17 00:00:00 2001 From: rebornix Date: Mon, 14 Dec 2020 20:27:13 -0800 Subject: [PATCH 023/262] DiffElement --- .../contrib/notebook/browser/diff/common.ts | 8 ++-- .../{cellComponents.ts => diffComponents.ts} | 36 ++++++++-------- .../{cellOutputs.ts => diffElementOutputs.ts} | 28 ++++++------- ...ffViewModel.ts => diffElementViewModel.ts} | 6 +-- .../browser/diff/notebookDiffActions.ts | 8 ++-- .../browser/diff/notebookTextDiffEditor.ts | 36 ++++++++-------- .../browser/diff/notebookTextDiffList.ts | 42 +++++++++---------- 7 files changed, 81 insertions(+), 83 deletions(-) rename src/vs/workbench/contrib/notebook/browser/diff/{cellComponents.ts => diffComponents.ts} (97%) rename src/vs/workbench/contrib/notebook/browser/diff/{cellOutputs.ts => diffElementOutputs.ts} (86%) rename src/vs/workbench/contrib/notebook/browser/diff/{celllDiffViewModel.ts => diffElementViewModel.ts} (98%) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/common.ts b/src/vs/workbench/contrib/notebook/browser/diff/common.ts index 8db7afd6bcb..46abd5d8d2f 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/common.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/common.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IInsetRenderOutput, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; -import { CellDiffViewModelBase } from 'vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel'; +import { DiffElementViewModelBase } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; import { Event } from 'vs/base/common/event'; import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; import { DisposableStore } from 'vs/base/common/lifecycle'; @@ -17,12 +17,12 @@ import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/mode export interface INotebookTextDiffEditor { readonly textModel?: NotebookTextModel; - onMouseUp: Event<{ readonly event: MouseEvent; readonly target: CellDiffViewModelBase; }>; + onMouseUp: Event<{ readonly event: MouseEvent; readonly target: DiffElementViewModelBase; }>; getOverflowContainerDomNode(): HTMLElement; getLayoutInfo(): NotebookLayoutInfo; - layoutNotebookCell(cell: CellDiffViewModelBase, height: number): void; + layoutNotebookCell(cell: DiffElementViewModelBase, height: number): void; getOutputRenderer(): OutputRenderer; - createInset(cellDiffViewModel: CellDiffViewModelBase, cellTextModel: NotebookCellTextModel, output: IInsetRenderOutput, offset: number, rightEditor: boolean): void; + createInset(cellDiffViewModel: DiffElementViewModelBase, cellTextModel: NotebookCellTextModel, output: IInsetRenderOutput, offset: number, rightEditor: boolean): void; } export interface CellDiffSingleSideRenderTemplate { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts similarity index 97% rename from src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts rename to src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts index 854e2d2ad80..2bf42f22011 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/cellComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts @@ -7,7 +7,7 @@ import * as DOM from 'vs/base/browser/dom'; import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IDiffEditorOptions, IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { CellDiffViewModelBase, getFormatedMetadataJSON, PropertyFoldingState, SideBySideCellDiffViewModel, SingleSideCellDiffViewModel } from 'vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel'; +import { DiffElementViewModelBase, getFormatedMetadataJSON, PropertyFoldingState, SideBySideDiffElementViewModel, SingleSideDiffElementViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; import { CellDiffSideBySideRenderTemplate, CellDiffSingleSideRenderTemplate, DIFF_CELL_MARGIN, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common'; import { EDITOR_BOTTOM_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; @@ -31,7 +31,7 @@ import { getEditorTopPadding } from 'vs/workbench/contrib/notebook/browser/noteb import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { collapsedIcon, expandedIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons'; import { renderCodicons } from 'vs/base/browser/codicons'; -import { OutputContainer } from 'vs/workbench/contrib/notebook/browser/diff/cellOutputs'; +import { OutputContainer } from 'vs/workbench/contrib/notebook/browser/diff/diffElementOutputs'; const RENDER_RICH_OUTPUT = true; @@ -74,8 +74,6 @@ const fixedDiffEditorOptions: IDiffEditorOptions = { isInEmbeddedEditor: true, }; - - class PropertyHeader extends Disposable { protected _foldingIndicator!: HTMLElement; protected _statusSpan!: HTMLElement; @@ -83,14 +81,14 @@ class PropertyHeader extends Disposable { protected _menu!: IMenu; constructor( - readonly cell: CellDiffViewModelBase, + readonly cell: DiffElementViewModelBase, readonly propertyHeaderContainer: HTMLElement, readonly notebookEditor: INotebookTextDiffEditor, readonly accessor: { updateInfoRendering: () => void; - checkIfModified: (cell: CellDiffViewModelBase) => boolean; - getFoldingState: (cell: CellDiffViewModelBase) => PropertyFoldingState; - updateFoldingState: (cell: CellDiffViewModelBase, newState: PropertyFoldingState) => void; + checkIfModified: (cell: DiffElementViewModelBase) => boolean; + getFoldingState: (cell: DiffElementViewModelBase) => PropertyFoldingState; + updateFoldingState: (cell: DiffElementViewModelBase, newState: PropertyFoldingState) => void; unChangedLabel: string; changedLabel: string; prefix: string; @@ -212,7 +210,7 @@ class PropertyHeader extends Disposable { } } -abstract class AbstractCellRenderer extends Disposable { +abstract class AbstractElementRenderer extends Disposable { protected _metadataHeaderContainer!: HTMLElement; protected _metadataHeader!: PropertyHeader; protected _metadataInfoContainer!: HTMLElement; @@ -239,7 +237,7 @@ abstract class AbstractCellRenderer extends Disposable { constructor( readonly notebookEditor: INotebookTextDiffEditor, - readonly cell: CellDiffViewModelBase, + readonly cell: DiffElementViewModelBase, readonly templateData: CellDiffSingleSideRenderTemplate | CellDiffSideBySideRenderTemplate, readonly style: 'left' | 'right' | 'full', protected readonly instantiationService: IInstantiationService, @@ -398,7 +396,7 @@ abstract class AbstractCellRenderer extends Disposable { } private _buildMetadataEditor() { - if (this.cell instanceof SideBySideCellDiffViewModel) { + if (this.cell instanceof SideBySideDiffElementViewModel) { const originalMetadataSource = getFormatedMetadataJSON(this.notebookEditor.textModel!, this.cell.original?.metadata || {}, this.cell.original?.language); const modifiedMetadataSource = getFormatedMetadataJSON(this.notebookEditor.textModel!, this.cell.modified?.metadata || {}, this.cell.modified?.language); this._metadataEditor = this.instantiationService.createInstance(DiffEditorWidget, this._metadataEditorContainer!, { @@ -596,10 +594,10 @@ abstract class AbstractCellRenderer extends Disposable { abstract layout(state: { outerWidth?: boolean, editorHeight?: boolean, metadataEditor?: boolean, outputEditor?: boolean, outputView?: boolean }): void; } -abstract class SingleSideCell extends AbstractCellRenderer { +abstract class SingleSideDiffElement extends AbstractElementRenderer { constructor( readonly notebookEditor: INotebookTextDiffEditor, - readonly cell: SingleSideCellDiffViewModel, + readonly cell: SingleSideDiffElementViewModel, readonly templateData: CellDiffSingleSideRenderTemplate, readonly style: 'left' | 'right' | 'full', protected readonly instantiationService: IInstantiationService, @@ -718,11 +716,11 @@ abstract class SingleSideCell extends AbstractCellRenderer { this._outputHeader.buildHeader(); } } -export class DeletedCell extends SingleSideCell { +export class DeletedElement extends SingleSideDiffElement { private _editor!: CodeEditorWidget; constructor( readonly notebookEditor: INotebookTextDiffEditor, - readonly cell: SingleSideCellDiffViewModel, + readonly cell: SingleSideDiffElementViewModel, readonly templateData: CellDiffSingleSideRenderTemplate, @IModeService readonly modeService: IModeService, @IModelService readonly modelService: IModelService, @@ -809,11 +807,11 @@ export class DeletedCell extends SingleSideCell { } } -export class InsertCell extends SingleSideCell { +export class InsertElement extends SingleSideDiffElement { private _editor!: CodeEditorWidget; constructor( readonly notebookEditor: INotebookTextDiffEditor, - readonly cell: SingleSideCellDiffViewModel, + readonly cell: SingleSideDiffElementViewModel, readonly templateData: CellDiffSingleSideRenderTemplate, @IInstantiationService protected readonly instantiationService: IInstantiationService, @IModeService readonly modeService: IModeService, @@ -905,7 +903,7 @@ export class InsertCell extends SingleSideCell { } } -export class ModifiedCell extends AbstractCellRenderer { +export class ModifiedElement extends AbstractElementRenderer { private _editor?: DiffEditorWidget; private _editorContainer!: HTMLElement; private _inputToolbarContainer!: HTMLElement; @@ -914,7 +912,7 @@ export class ModifiedCell extends AbstractCellRenderer { constructor( readonly notebookEditor: INotebookTextDiffEditor, - readonly cell: SideBySideCellDiffViewModel, + readonly cell: SideBySideDiffElementViewModel, readonly templateData: CellDiffSideBySideRenderTemplate, @IInstantiationService protected readonly instantiationService: IInstantiationService, @IModeService readonly modeService: IModeService, diff --git a/src/vs/workbench/contrib/notebook/browser/diff/cellOutputs.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts similarity index 86% rename from src/vs/workbench/contrib/notebook/browser/diff/cellOutputs.ts rename to src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts index 2641b731f03..7a90e32bdae 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/cellOutputs.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts @@ -6,7 +6,7 @@ import * as DOM from 'vs/base/browser/dom'; import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { CellDiffViewModelBase, SideBySideCellDiffViewModel, SingleSideCellDiffViewModel } from 'vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel'; +import { DiffElementViewModelBase, SideBySideDiffElementViewModel, SingleSideDiffElementViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; import { INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common'; import { ICellOutputViewModel, IRenderOutput, outputHasDynamicHeight, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { getResizesObserver } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellWidgets'; @@ -26,7 +26,7 @@ export class OutputElement extends Disposable { private notebookEditor: INotebookTextDiffEditor, private notebookTextModel: NotebookTextModel, private notebookService: INotebookService, - private cellViewModel: CellDiffViewModelBase, + private cellViewModel: DiffElementViewModelBase, private modified: boolean, private cell: NotebookCellTextModel, @@ -86,7 +86,7 @@ export class OutputElement extends Disposable { this.cell, result, this.getOutputOffsetInContainer(index), - this.cellViewModel instanceof SideBySideCellDiffViewModel + this.cellViewModel instanceof SideBySideDiffElementViewModel ? this.modified : this.cellViewModel.type === 'insert' ); @@ -133,38 +133,38 @@ export class OutputElement extends Disposable { } getCellOutputCurrentIndex() { - if (this.cellViewModel instanceof SideBySideCellDiffViewModel) { + if (this.cellViewModel instanceof SideBySideDiffElementViewModel) { if (this.modified) { return this.cellViewModel.modified.outputs.indexOf(this.output.model); } else { return this.cellViewModel.original.outputs.indexOf(this.output.model); } } else { - return (this.cellViewModel as SingleSideCellDiffViewModel).cellTextModel!.outputs.indexOf(this.output.model); + return (this.cellViewModel as SingleSideDiffElementViewModel).cellTextModel!.outputs.indexOf(this.output.model); } } updateHeight(index: number, height: number) { - if (this.cellViewModel instanceof SideBySideCellDiffViewModel) { + if (this.cellViewModel instanceof SideBySideDiffElementViewModel) { this.cellViewModel.updateOutputHeight(!this.modified, index, height); } else { - (this.cellViewModel as SingleSideCellDiffViewModel).updateOutputHeight(index, height); + (this.cellViewModel as SingleSideDiffElementViewModel).updateOutputHeight(index, height); } } getOutputOffsetInContainer(index: number) { - if (this.cellViewModel instanceof SideBySideCellDiffViewModel) { + if (this.cellViewModel instanceof SideBySideDiffElementViewModel) { return this.cellViewModel.getOutputOffsetInContainer(!this.modified, index); } else { - return (this.cellViewModel as SingleSideCellDiffViewModel).getOutputOffsetInContainer(index); + return (this.cellViewModel as SingleSideDiffElementViewModel).getOutputOffsetInContainer(index); } } getOutputOffsetInCell(index: number) { - if (this.cellViewModel instanceof SideBySideCellDiffViewModel) { + if (this.cellViewModel instanceof SideBySideDiffElementViewModel) { return this.cellViewModel.getOutputOffsetInCell(!this.modified, index); } else { - return (this.cellViewModel as SingleSideCellDiffViewModel).getOutputOffsetInCell(index); + return (this.cellViewModel as SingleSideDiffElementViewModel).getOutputOffsetInCell(index); } } } @@ -175,7 +175,7 @@ export class OutputContainer extends Disposable { constructor( private _editor: INotebookTextDiffEditor, private notebookTextModel: NotebookTextModel, - private cellViewModel: CellDiffViewModelBase, + private cellViewModel: DiffElementViewModelBase, private cell: NotebookCellTextModel, private modified: boolean, private outputContainer: HTMLElement, @@ -197,11 +197,11 @@ export class OutputContainer extends Disposable { this.outputEntries.forEach((value, key) => { const index = cell.outputs.indexOf(key.model); if (index >= 0) { - if (this.cellViewModel instanceof SideBySideCellDiffViewModel) { + if (this.cellViewModel instanceof SideBySideDiffElementViewModel) { const top = this.cellViewModel.getOutputOffsetInContainer(!this.modified, index); value.domNode.style.top = `${top}px`; } else { - const top = (this.cellViewModel as SingleSideCellDiffViewModel).getOutputOffsetInContainer(index); + const top = (this.cellViewModel as SingleSideDiffElementViewModel).getOutputOffsetInContainer(index); value.domNode.style.top = `${top}px`; } } diff --git a/src/vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts similarity index 98% rename from src/vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel.ts rename to src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts index 09eba7ca261..ed66e8523ae 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts @@ -22,7 +22,7 @@ export enum PropertyFoldingState { Collapsed } -export abstract class CellDiffViewModelBase extends Disposable { +export abstract class DiffElementViewModelBase extends Disposable { public metadataFoldingState: PropertyFoldingState; public outputFoldingState: PropertyFoldingState; protected _layoutInfoEmitter = new Emitter(); @@ -143,7 +143,7 @@ export abstract class CellDiffViewModelBase extends Disposable { } } -export class SideBySideCellDiffViewModel extends CellDiffViewModelBase { +export class SideBySideDiffElementViewModel extends DiffElementViewModelBase { protected _originalOutputCollection: number[] = []; protected _originalOutputsTop: PrefixSumComputer | null = null; protected _modifiedOutputCollection: number[] = []; @@ -296,7 +296,7 @@ export class SideBySideCellDiffViewModel extends CellDiffViewModelBase { } } -export class SingleSideCellDiffViewModel extends CellDiffViewModelBase { +export class SingleSideDiffElementViewModel extends DiffElementViewModelBase { protected _outputCollection: number[] = []; protected _outputsTop: PrefixSumComputer | null = null; diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts index 3983cfcc4bb..1f2dcffe0e3 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts @@ -8,7 +8,7 @@ import { localize } from 'vs/nls'; import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ActiveEditorContext, viewColumnToEditorGroup } from 'vs/workbench/common/editor'; -import { CellDiffViewModelBase } from 'vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel'; +import { DiffElementViewModelBase } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; import { NotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor'; import { NotebookDiffEditorInput } from 'vs/workbench/contrib/notebook/browser/notebookDiffEditorInput'; import { openAsTextIcon, revertIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons'; @@ -65,7 +65,7 @@ registerAction2(class extends Action2 { } ); } - run(accessor: ServicesAccessor, context?: { cell: CellDiffViewModelBase }) { + run(accessor: ServicesAccessor, context?: { cell: DiffElementViewModelBase }) { if (!context) { return; } @@ -95,7 +95,7 @@ registerAction2(class extends Action2 { } ); } - run(accessor: ServicesAccessor, context?: { cell: CellDiffViewModelBase }) { + run(accessor: ServicesAccessor, context?: { cell: DiffElementViewModelBase }) { if (!context) { return; } @@ -125,7 +125,7 @@ registerAction2(class extends Action2 { } ); } - run(accessor: ServicesAccessor, context?: { cell: CellDiffViewModelBase }) { + run(accessor: ServicesAccessor, context?: { cell: DiffElementViewModelBase }) { if (!context) { return; } diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index e06081697ec..07861ff1596 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -13,7 +13,7 @@ import { notebookCellBorder, NotebookEditorWidget } from 'vs/workbench/contrib/n import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; import { NotebookDiffEditorInput } from '../notebookDiffEditorInput'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { CellDiffViewModelBase, SideBySideCellDiffViewModel, SingleSideCellDiffViewModel } from 'vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel'; +import { DiffElementViewModelBase, SideBySideDiffElementViewModel, SingleSideDiffElementViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { CellDiffSideBySideRenderer, CellDiffSingleSideRenderer, NotebookCellTextDiffListDelegate, NotebookTextDiffList } from 'vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList'; import { IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; @@ -58,7 +58,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD private _webviewTransparentCover: HTMLElement | null = null; private _fontInfo: BareFontInfo | undefined; - private readonly _onMouseUp = this._register(new Emitter<{ readonly event: MouseEvent; readonly target: CellDiffViewModelBase; }>()); + private readonly _onMouseUp = this._register(new Emitter<{ readonly event: MouseEvent; readonly target: DiffElementViewModelBase; }>()); public readonly onMouseUp = this._onMouseUp.event; private _eventDispatcher: NotebookDiffEditorEventDispatcher | undefined; protected _scopeContextKeyService!: IContextKeyService; @@ -264,7 +264,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD const diffResult = await this.notebookEditorWorkerService.computeDiff(this._model.original.resource, this._model.modified.resource); const cellChanges = diffResult.cellsDiff.changes; - const cellDiffViewModels: CellDiffViewModelBase[] = []; + const diffElementViewModels: DiffElementViewModelBase[] = []; const originalModel = this._model.original.notebook; const modifiedModel = this._model.modified.notebook; let originalCellIndex = 0; @@ -280,7 +280,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD const originalCell = originalModel.cells[originalCellIndex + j]; const modifiedCell = modifiedModel.cells[modifiedCellIndex + j]; if (originalCell.getHashValue() === modifiedCell.getHashValue()) { - cellDiffViewModels.push(new SideBySideCellDiffViewModel( + diffElementViewModels.push(new SideBySideDiffElementViewModel( this._model.modified.notebook, originalCell, modifiedCell, @@ -289,10 +289,10 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD )); } else { if (firstChangeIndex === -1) { - firstChangeIndex = cellDiffViewModels.length; + firstChangeIndex = diffElementViewModels.length; } - cellDiffViewModels.push(new SideBySideCellDiffViewModel( + diffElementViewModels.push(new SideBySideDiffElementViewModel( this._model.modified.notebook, originalCell, modifiedCell, @@ -304,16 +304,16 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD const modifiedLCS = this._computeModifiedLCS(change, originalModel, modifiedModel); if (modifiedLCS.length && firstChangeIndex === -1) { - firstChangeIndex = cellDiffViewModels.length; + firstChangeIndex = diffElementViewModels.length; } - cellDiffViewModels.push(...modifiedLCS); + diffElementViewModels.push(...modifiedLCS); originalCellIndex = change.originalStart + change.originalLength; modifiedCellIndex = change.modifiedStart + change.modifiedLength; } for (let i = originalCellIndex; i < originalModel.cells.length; i++) { - cellDiffViewModels.push(new SideBySideCellDiffViewModel( + diffElementViewModels.push(new SideBySideDiffElementViewModel( this._model.modified.notebook, originalModel.cells[i], modifiedModel.cells[i - originalCellIndex + modifiedCellIndex], @@ -322,7 +322,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD )); } - this._list.splice(0, this._list.length, cellDiffViewModels); + this._list.splice(0, this._list.length, diffElementViewModels); if (this._revealFirst && firstChangeIndex !== -1) { this._revealFirst = false; @@ -332,12 +332,12 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD } private _computeModifiedLCS(change: IDiffChange, originalModel: NotebookTextModel, modifiedModel: NotebookTextModel) { - const result: CellDiffViewModelBase[] = []; + const result: DiffElementViewModelBase[] = []; // modified cells const modifiedLen = Math.min(change.originalLength, change.modifiedLength); for (let j = 0; j < modifiedLen; j++) { - result.push(new SideBySideCellDiffViewModel( + result.push(new SideBySideDiffElementViewModel( modifiedModel, originalModel.cells[change.originalStart + j], modifiedModel.cells[change.modifiedStart + j], @@ -348,7 +348,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD for (let j = modifiedLen; j < change.originalLength; j++) { // deletion - result.push(new SingleSideCellDiffViewModel( + result.push(new SingleSideDiffElementViewModel( originalModel, originalModel.cells[change.originalStart + j], undefined, @@ -359,7 +359,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD for (let j = modifiedLen; j < change.modifiedLength; j++) { // insertion - result.push(new SingleSideCellDiffViewModel( + result.push(new SingleSideDiffElementViewModel( modifiedModel, undefined, modifiedModel.cells[change.modifiedStart + j], @@ -371,11 +371,11 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD return result; } - private pendingLayouts = new WeakMap(); + private pendingLayouts = new WeakMap(); - layoutNotebookCell(cell: CellDiffViewModelBase, height: number) { - const relayout = (cell: CellDiffViewModelBase, height: number) => { + layoutNotebookCell(cell: DiffElementViewModelBase, height: number) { + const relayout = (cell: DiffElementViewModelBase, height: number) => { const viewIndex = this._list.indexOf(cell); this._list?.updateElementHeight(viewIndex, height); @@ -402,7 +402,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD } - createInset(cellDiffViewModel: CellDiffViewModelBase, cellTextModel: NotebookCellTextModel, output: IInsetRenderOutput, offset: number, rightEditor: boolean): void { + createInset(cellDiffViewModel: DiffElementViewModelBase, cellTextModel: NotebookCellTextModel, output: IInsetRenderOutput, offset: number, rightEditor: boolean): void { this._insetModifyQueueByOutputId.queue(output.source.model.outputId, async () => { if (rightEditor) { if (!this._modifiedWebview!.insetMapping.has(output.source)) { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts index cd4ac5ef433..2c3c565a7d4 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts @@ -14,10 +14,10 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IListService, IWorkbenchListOptions, WorkbenchList } from 'vs/platform/list/browser/listService'; import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { CellDiffViewModelBase, SideBySideCellDiffViewModel, SingleSideCellDiffViewModel } from 'vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel'; +import { DiffElementViewModelBase, SideBySideDiffElementViewModel, SingleSideDiffElementViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; import { CellDiffSideBySideRenderTemplate, CellDiffSingleSideRenderTemplate, DIFF_CELL_MARGIN, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common'; import { isMacintosh } from 'vs/base/common/platform'; -import { DeletedCell, InsertCell, ModifiedCell } from 'vs/workbench/contrib/notebook/browser/diff/cellComponents'; +import { DeletedElement, InsertElement, ModifiedElement } from 'vs/workbench/contrib/notebook/browser/diff/diffComponents'; import { CodeEditorWidget, ICodeEditorWidgetOptions } from 'vs/editor/browser/widget/codeEditorWidget'; import { IDiffEditorOptions, IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; @@ -88,7 +88,7 @@ export function getOptimizedNestedCodeEditorWidgetOptions(): ICodeEditorWidgetOp }; } -export class NotebookCellTextDiffListDelegate implements IListVirtualDelegate { +export class NotebookCellTextDiffListDelegate implements IListVirtualDelegate { // private readonly lineHeight: number; constructor( @@ -98,15 +98,15 @@ export class NotebookCellTextDiffListDelegate implements IListVirtualDelegate { +export class CellDiffSingleSideRenderer implements IListRenderer { static readonly TEMPLATE_ID = 'cell_diff_single'; constructor( @@ -177,13 +177,13 @@ export class CellDiffSingleSideRenderer implements IListRenderer { +export class CellDiffSideBySideRenderer implements IListRenderer { static readonly TEMPLATE_ID = 'cell_diff_side_by_side'; constructor( @@ -286,13 +286,13 @@ export class CellDiffSideBySideRenderer implements IListRenderer implements IDisposable, IStyleController { +export class NotebookTextDiffList extends WorkbenchList implements IDisposable, IStyleController { private styleElement?: HTMLStyleElement; get rowsContainer(): HTMLElement { @@ -320,10 +320,10 @@ export class NotebookTextDiffList extends WorkbenchList i constructor( listUser: string, container: HTMLElement, - delegate: IListVirtualDelegate, - renderers: IListRenderer[], + delegate: IListVirtualDelegate, + renderers: IListRenderer[], contextKeyService: IContextKeyService, - options: IWorkbenchListOptions, + options: IWorkbenchListOptions, @IListService listService: IListService, @IThemeService themeService: IThemeService, @IConfigurationService configurationService: IConfigurationService, @@ -331,7 +331,7 @@ export class NotebookTextDiffList extends WorkbenchList i super(listUser, container, delegate, renderers, options, contextKeyService, listService, themeService, configurationService, keybindingService); } - getAbsoluteTopOfElement(element: CellDiffViewModelBase): number { + getAbsoluteTopOfElement(element: DiffElementViewModelBase): number { const index = this.indexOf(element); // if (index === undefined || index < 0 || index >= this.length) { // this._getViewIndexUpperBound(element); From 89fd7be7fbd58cc1e54dc8fcdba6ae665a2b9f19 Mon Sep 17 00:00:00 2001 From: rebornix Date: Mon, 14 Dec 2020 21:03:22 -0800 Subject: [PATCH 024/262] test --- .../browser/diff/backLayerWebview2.ts | 105 +++++++----------- .../contrib/notebook/browser/diff/common.ts | 7 +- .../notebook/browser/diff/diffComponents.ts | 28 ++--- .../browser/diff/diffElementOutputs.ts | 6 +- .../browser/diff/diffElementViewModel.ts | 14 +-- .../browser/diff/diffNestedCellViewModel.ts | 64 +++++++++++ .../browser/diff/notebookDiffActions.ts | 6 +- .../browser/diff/notebookTextDiffEditor.ts | 30 ++--- .../browser/view/renderers/webviewPreloads.ts | 1 + 9 files changed, 154 insertions(+), 107 deletions(-) create mode 100644 src/vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel.ts diff --git a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts index 0af765801a5..0168d38a14a 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts @@ -11,23 +11,20 @@ import { URI } from 'vs/base/common/uri'; import * as UUID from 'vs/base/common/uuid'; import { IOpenerService, matchesScheme } from 'vs/platform/opener/common/opener'; import { CELL_MARGIN, CELL_RUN_GUTTER, CODE_CELL_LEFT_MARGIN, CELL_OUTPUT_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; -import { IDisplayOutputViewModel, IInsetRenderOutput, INotebookEditor, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { IDisplayOutputViewModel, IInsetRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel'; import { CellOutputKind, IDisplayOutput, INotebookRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { IWebviewService, WebviewElement, WebviewContentPurpose } from 'vs/workbench/contrib/webview/browser/webview'; import { asWebviewUri } from 'vs/workbench/contrib/webview/common/webviewUri'; -import { dirname, joinPath } from 'vs/base/common/resources'; +import { dirname } from 'vs/base/common/resources'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { preloadsScriptStr } from 'vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads'; import { FileAccess, Schemas } from 'vs/base/common/network'; -import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { IFileService } from 'vs/platform/files/common/files'; -import { VSBuffer } from 'vs/base/common/buffer'; -import { getExtensionForMimeType } from 'vs/base/common/mime'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common'; -import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; +import { DiffNestedCellViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel'; +import { DiffElementViewModelBase, SideBySideDiffElementViewModel, SingleSideDiffElementViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; export interface WebviewIntialized { __vscode_notebook_message: boolean; @@ -200,7 +197,8 @@ export type AnyMessage = FromWebviewMessage | ToWebviewMessage; interface ICachedInset { outputId: string; - cell: CodeCellViewModel; + diffElement: DiffElementViewModelBase; + cell: DiffNestedCellViewModel; renderer?: INotebookRendererInfo; cachedCreation: ICreationRequestMessage; } @@ -244,8 +242,6 @@ export class BackLayerWebView extends Disposable { @INotebookService private readonly notebookService: INotebookService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, - @IFileDialogService private readonly fileDialogService: IFileDialogService, - @IFileService private readonly fileService: IFileService, ) { super(); @@ -338,27 +334,27 @@ export class BackLayerWebView extends Disposable { }); } - private resolveOutputId(id: string): { cell: CodeCellViewModel, output: IDisplayOutputViewModel } | undefined { + private resolveOutputId(id: string): { cell: DiffNestedCellViewModel, diffElement: DiffElementViewModelBase, output: IDisplayOutputViewModel } | undefined { const output = this.reversedInsetMapping.get(id); if (!output) { return; } - const cell = this.insetMapping.get(output)!.cell; + const info = this.insetMapping.get(output)!; // const currCell = this.notebookEditor.viewModel?.viewCells.find(vc => vc.handle === cell.handle); // if (currCell !== cell && currCell !== undefined) { // this.insetMapping.get(output)!.cell = currCell as CodeCellViewModel; // } - return { cell: this.insetMapping.get(output)!.cell, output }; + return { cell: info.cell, diffElement: info.diffElement, output }; } async createWebview(): Promise { let coreDependencies = ''; let resolveFunc: () => void; - this._initalized = new Promise((resolve, reject) => { + this._initalized = new Promise((resolve) => { resolveFunc = resolve; }); @@ -455,18 +451,25 @@ var requirejs = (function() { return; } - // if (data.__vscode_notebook_message) { - // if (data.type === 'dimension') { - // const height = data.data.height; - // const outputHeight = height; + if (data.__vscode_notebook_message) { + if (data.type === 'dimension') { + const height = data.data.height; + const outputHeight = height; - // const info = this.resolveOutputId(data.id); - // if (info) { - // const { cell, output } = info; - // const outputIndex = cell.outputsViewModels.indexOf(output); - // cell.updateOutputHeight(outputIndex, outputHeight); - // this.notebookEditor.layoutNotebookCell(cell, cell.layoutInfo.totalHeight); - // } + const info = this.resolveOutputId(data.id); + if (info) { + const { diffElement, cell, output } = info; + const outputIndex = cell.outputsViewModels.indexOf(output); + + if (diffElement instanceof SideBySideDiffElementViewModel) { + diffElement.updateOutputHeight(false, outputIndex, outputHeight); + } else { + (diffElement as SingleSideDiffElementViewModel).updateOutputHeight(outputIndex, outputHeight); + } + // cell.updateOutputHeight(outputIndex, outputHeight); + // this.notebookEditor.layoutNotebookCell(cell, cell.layoutInfo.totalHeight); + } + } // } else if (data.type === 'mouseenter') { // const info = this.resolveOutputId(data.id); // if (info) { @@ -514,46 +517,12 @@ var requirejs = (function() { // this._onMessage.fire({ message: data.message, forRenderer: data.rendererId }); // } // return; - // } + } this._onMessage.fire({ message: data }); })); } - private async _onDidClickDataLink(event: IClickedDataUrlMessage): Promise { - const [splitStart, splitData] = event.data.split(';base64,'); - if (!splitData || !splitStart) { - return; - } - - const defaultDir = dirname(this.documentUri); - let defaultName: string; - if (event.downloadName) { - defaultName = event.downloadName; - } else { - const mimeType = splitStart.replace(/^data:/, ''); - const candidateExtension = mimeType && getExtensionForMimeType(mimeType); - defaultName = candidateExtension ? `download${candidateExtension}` : 'download'; - } - - const defaultUri = joinPath(defaultDir, defaultName); - const newFileUri = await this.fileDialogService.showSaveDialog({ - defaultUri - }); - if (!newFileUri) { - return; - } - - const decoded = atob(splitData); - const typedArray = new Uint8Array(decoded.length); - for (let i = 0; i < decoded.length; i++) { - typedArray[i] = decoded.charCodeAt(i); - } - - const buff = VSBuffer.wrap(typedArray); - await this.fileService.writeFile(newFileUri, buff); - await this.openerService.open(newFileUri); - } private _createInset(webviewService: IWebviewService, content: string) { const rootPath = isWeb ? FileAccess.asBrowserUri('', require) : FileAccess.asFileUri('', require); @@ -572,7 +541,7 @@ var requirejs = (function() { }, undefined); let resolveFunc: () => void; - this._loaded = new Promise((resolve, reject) => { + this._loaded = new Promise((resolve) => { resolveFunc = resolve; }); @@ -611,7 +580,7 @@ var requirejs = (function() { return true; } - updateViewScrollTop(top: number, forceDisplay: boolean, items: { cell: CodeCellViewModel, output: IDisplayOutputViewModel, cellTop: number }[]) { + updateViewScrollTop(top: number, forceDisplay: boolean, items: { diffElement: DiffElementViewModelBase, cell: DiffNestedCellViewModel, output: IDisplayOutputViewModel, cellTop: number }[]) { if (this._disposed) { return; } @@ -620,8 +589,14 @@ var requirejs = (function() { const outputCache = this.insetMapping.get(item.output)!; const id = outputCache.outputId; const outputIndex = item.cell.outputsViewModels.indexOf(item.output); + let outputOffset = 0; + if (item.diffElement instanceof SideBySideDiffElementViewModel) { + outputOffset = item.diffElement.getOutputOffsetInCell(false, outputIndex); + } else { + outputOffset = (item.diffElement as SingleSideDiffElementViewModel).getOutputOffsetInCell(outputIndex); + } - const outputOffset = item.cellTop + item.cell.getOutputOffset(outputIndex); + // const outputOffset = item.cellTop + item.cell.getOutputOffset(outputIndex); outputCache.cachedCreation.top = outputOffset; this.hiddenInsetMapping.delete(item.output); @@ -641,7 +616,7 @@ var requirejs = (function() { }); } - async createInset(cell: NotebookCellTextModel, content: IInsetRenderOutput, cellTop: number, offset: number) { + async createInset(cellDiffViewModel: DiffElementViewModelBase, cell: DiffNestedCellViewModel, content: IInsetRenderOutput, cellTop: number, offset: number) { if (this._disposed) { return; } @@ -703,7 +678,7 @@ var requirejs = (function() { } this._sendMessageToWebview(message); - this.insetMapping.set(content.source, { outputId: message.outputId, cell, renderer, cachedCreation: message }); + this.insetMapping.set(content.source, { outputId: message.outputId, diffElement: cellDiffViewModel, cell, renderer, cachedCreation: message }); this.hiddenInsetMapping.delete(content.source); this.reversedInsetMapping.set(message.outputId, content.source); } diff --git a/src/vs/workbench/contrib/notebook/browser/diff/common.ts b/src/vs/workbench/contrib/notebook/browser/diff/common.ts index 46abd5d8d2f..521e0b053bf 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/common.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/common.ts @@ -13,7 +13,6 @@ import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer'; -import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; export interface INotebookTextDiffEditor { readonly textModel?: NotebookTextModel; @@ -22,7 +21,11 @@ export interface INotebookTextDiffEditor { getLayoutInfo(): NotebookLayoutInfo; layoutNotebookCell(cell: DiffElementViewModelBase, height: number): void; getOutputRenderer(): OutputRenderer; - createInset(cellDiffViewModel: DiffElementViewModelBase, cellTextModel: NotebookCellTextModel, output: IInsetRenderOutput, offset: number, rightEditor: boolean): void; + createInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: IDiffNestedCellViewModel, output: IInsetRenderOutput, offset: number, rightEditor: boolean): void; +} + +export interface IDiffNestedCellViewModel { + } export interface CellDiffSingleSideRenderTemplate { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts index 2bf42f22011..45357266a99 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts @@ -371,7 +371,7 @@ abstract class AbstractElementRenderer extends Disposable { } if (newLangauge !== undefined && newLangauge !== this.cell.modified!.language) { - const index = this.notebookEditor.textModel!.cells.indexOf(this.cell.modified!); + const index = this.notebookEditor.textModel!.cells.indexOf(this.cell.modified!.textModel); this.notebookEditor.textModel!.applyEdits( this.notebookEditor.textModel!.versionId, [{ editType: CellEditType.CellLanguage, index, language: newLangauge }], @@ -382,7 +382,7 @@ abstract class AbstractElementRenderer extends Disposable { ); } - const index = this.notebookEditor.textModel!.cells.indexOf(this.cell.modified!); + const index = this.notebookEditor.textModel!.cells.indexOf(this.cell.modified!.textModel); if (index < 0) { return; @@ -444,7 +444,7 @@ abstract class AbstractElementRenderer extends Disposable { respondingToContentChange = false; })); - this._register(this.cell.modified!.onDidChangeMetadata(() => { + this._register(this.cell.modified!.textModel.onDidChangeMetadata(() => { if (respondingToContentChange) { return; } @@ -538,7 +538,7 @@ abstract class AbstractElementRenderer extends Disposable { } })); - this._register(this.cell.modified!.onDidChangeOutputs(() => { + this._register(this.cell.modified!.textModel.onDidChangeOutputs(() => { const modifiedOutputsSource = this._getFormatedOutputJSON(this.cell.modified?.outputs || []); modifiedModel.setValue(modifiedOutputsSource); this._outputHeader.refresh(); @@ -742,7 +742,7 @@ export class DeletedElement extends SingleSideDiffElement { updateSourceEditor(): void { const originalCell = this.cell.original!; - const lineCount = originalCell.textBuffer.getLineCount(); + const lineCount = originalCell.textModel.textBuffer.getLineCount(); const lineHeight = this.notebookEditor.getLayoutInfo().fontInfo.lineHeight || 17; const editorHeight = lineCount * lineHeight + getEditorTopPadding() + EDITOR_BOTTOM_PADDING; @@ -760,7 +760,7 @@ export class DeletedElement extends SingleSideDiffElement { } })); - originalCell.resolveTextModelRef().then(ref => { + originalCell.textModel.resolveTextModelRef().then(ref => { if (this._isDisposed) { return; } @@ -831,7 +831,7 @@ export class InsertElement extends SingleSideDiffElement { updateSourceEditor(): void { const modifiedCell = this.cell.modified!; - const lineCount = modifiedCell.textBuffer.getLineCount(); + const lineCount = modifiedCell.textModel.textBuffer.getLineCount(); const lineHeight = this.notebookEditor.getLayoutInfo().fontInfo.lineHeight || 17; const editorHeight = lineCount * lineHeight + getEditorTopPadding() + EDITOR_BOTTOM_PADDING; @@ -851,7 +851,7 @@ export class InsertElement extends SingleSideDiffElement { } })); - modifiedCell.resolveTextModelRef().then(ref => { + modifiedCell.textModel.resolveTextModelRef().then(ref => { if (this._isDisposed) { return; } @@ -1036,7 +1036,7 @@ export class ModifiedElement extends AbstractElementRenderer { updateSourceEditor(): void { const modifiedCell = this.cell.modified!; - const lineCount = modifiedCell.textBuffer.getLineCount(); + const lineCount = modifiedCell.textModel.textBuffer.getLineCount(); const lineHeight = this.notebookEditor.getLayoutInfo().fontInfo.lineHeight || 17; const editorHeight = lineCount * lineHeight + getEditorTopPadding() + EDITOR_BOTTOM_PADDING; this._editorContainer = this.templateData.editorContainer; @@ -1072,14 +1072,14 @@ export class ModifiedElement extends AbstractElementRenderer { createAndFillInActionBarActions(this._menu, { shouldForwardArgs: true }, actions); this._toolbar.setActions(actions); - if (this.cell.modified!.getValue() !== this.cell.original!.getValue()) { + if (this.cell.modified!.textModel.getValue() !== this.cell.original!.textModel.getValue()) { this._inputToolbarContainer.style.display = 'block'; } else { this._inputToolbarContainer.style.display = 'none'; } - this._register(this.cell.modified!.onDidChangeContent(() => { - if (this.cell.modified!.getValue() !== this.cell.original!.getValue()) { + this._register(this.cell.modified!.textModel.onDidChangeContent(() => { + if (this.cell.modified!.textModel.getValue() !== this.cell.original!.textModel.getValue()) { this._inputToolbarContainer.style.display = 'block'; } else { this._inputToolbarContainer.style.display = 'none'; @@ -1091,8 +1091,8 @@ export class ModifiedElement extends AbstractElementRenderer { const originalCell = this.cell.original!; const modifiedCell = this.cell.modified!; - const originalRef = await originalCell.resolveTextModelRef(); - const modifiedRef = await modifiedCell.resolveTextModelRef(); + const originalRef = await originalCell.textModel.resolveTextModelRef(); + const modifiedRef = await modifiedCell.textModel.resolveTextModelRef(); if (this._isDisposed) { return; diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts index 7a90e32bdae..91cfe7de933 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts @@ -11,11 +11,11 @@ import { INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/d import { ICellOutputViewModel, IRenderOutput, outputHasDynamicHeight, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { getResizesObserver } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellWidgets'; import { CellOutputViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel'; -import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; import { BUILTIN_RENDERER_ID } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; +import { DiffNestedCellViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel'; export class OutputElement extends Disposable { readonly resizeListener = new DisposableStore(); @@ -29,7 +29,7 @@ export class OutputElement extends Disposable { private cellViewModel: DiffElementViewModelBase, private modified: boolean, - private cell: NotebookCellTextModel, + private cell: DiffNestedCellViewModel, private outputContainer: HTMLElement, readonly output: ICellOutputViewModel ) { @@ -176,7 +176,7 @@ export class OutputContainer extends Disposable { private _editor: INotebookTextDiffEditor, private notebookTextModel: NotebookTextModel, private cellViewModel: DiffElementViewModelBase, - private cell: NotebookCellTextModel, + private cell: DiffNestedCellViewModel, private modified: boolean, private outputContainer: HTMLElement, @INotebookService private notebookService: INotebookService, diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts index ed66e8523ae..33442495fb1 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import { NotebookDiffEditorEventDispatcher } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher'; import { Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; @@ -16,6 +15,7 @@ import { format } from 'vs/base/common/jsonFormatter'; import { applyEdits } from 'vs/base/common/jsonEdit'; import { NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer'; +import { DiffNestedCellViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel'; export enum PropertyFoldingState { Expanded, @@ -100,8 +100,8 @@ export abstract class DiffElementViewModelBase extends Disposable { constructor( readonly documentTextModel: NotebookTextModel, - readonly original: NotebookCellTextModel | undefined, - readonly modified: NotebookCellTextModel | undefined, + readonly original: DiffNestedCellViewModel | undefined, + readonly modified: DiffNestedCellViewModel | undefined, readonly type: 'unchanged' | 'insert' | 'delete' | 'modified', readonly editorEventDispatcher: NotebookDiffEditorEventDispatcher ) { @@ -151,8 +151,8 @@ export class SideBySideDiffElementViewModel extends DiffElementViewModelBase { constructor( readonly documentTextModel: NotebookTextModel, - readonly original: NotebookCellTextModel, - readonly modified: NotebookCellTextModel, + readonly original: DiffNestedCellViewModel, + readonly modified: DiffNestedCellViewModel, readonly type: 'unchanged' | 'modified', readonly editorEventDispatcher: NotebookDiffEditorEventDispatcher ) { @@ -306,8 +306,8 @@ export class SingleSideDiffElementViewModel extends DiffElementViewModelBase { constructor( readonly documentTextModel: NotebookTextModel, - readonly original: NotebookCellTextModel | undefined, - readonly modified: NotebookCellTextModel | undefined, + readonly original: DiffNestedCellViewModel | undefined, + readonly modified: DiffNestedCellViewModel | undefined, readonly type: 'insert' | 'delete', readonly editorEventDispatcher: NotebookDiffEditorEventDispatcher ) { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel.ts new file mode 100644 index 00000000000..ed4e2c14c63 --- /dev/null +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel.ts @@ -0,0 +1,64 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Disposable } from 'vs/base/common/lifecycle'; +import { generateUuid } from 'vs/base/common/uuid'; +import { IDiffNestedCellViewModel } from 'vs/workbench/contrib/notebook/browser/diff/common'; +import { ICellOutputViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { CellOutputViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel'; +import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; +import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; + +export class DiffNestedCellViewModel extends Disposable implements IDiffNestedCellViewModel { + private _id: string; + get id() { + return this._id; + } + + get outputs() { + return this.textModel.outputs; + } + + get language() { + return this.textModel.language; + } + + get metadata() { + return this.textModel.metadata; + } + + get uri() { + return this.textModel.uri; + } + + get handle() { + return this.textModel.handle; + } + + private _outputViewModels: ICellOutputViewModel[]; + + get outputsViewModels() { + return this._outputViewModels; + } + + constructor( + readonly textModel: NotebookCellTextModel, + @INotebookService private _notebookService: INotebookService + ) { + super(); + this._id = generateUuid(); + + this._outputViewModels = this.textModel.outputs.map(output => new CellOutputViewModel(output, this._notebookService)); + // this._register(this.textModel.onDidChangeOutputs((splices) => { + // splices.reverse().forEach(splice => { + // this._outputCollection.splice(splice[0], splice[1], ...splice[2].map(() => 0)); + // this._outputViewModels.splice(splice[0], splice[1], ...splice[2].map(output => new CellOutputViewModel(output, this._notebookService))); + // }); + + // this._outputsTop = null; + // this._onDidChangeOutputs.fire(splices); + // })); + } +} diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts index 1f2dcffe0e3..b88069d4fc4 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts @@ -77,7 +77,7 @@ registerAction2(class extends Action2 { return; } - modified.metadata = original.metadata; + modified.textModel.metadata = original.metadata; } }); @@ -107,7 +107,7 @@ registerAction2(class extends Action2 { return; } - modified.spliceNotebookCellOutputs([[0, modified.outputs.length, original.outputs]]); + modified.textModel.spliceNotebookCellOutputs([[0, modified.outputs.length, original.outputs]]); } }); @@ -139,7 +139,7 @@ registerAction2(class extends Action2 { const bulkEditService = accessor.get(IBulkEditService); return bulkEditService.apply([ - new ResourceTextEdit(modified.uri, { range: modified.getFullModelRange(), text: original.getValue() }), + new ResourceTextEdit(modified.uri, { range: modified.textModel.getFullModelRange(), text: original.textModel.getValue() }), ], { quotableLabel: 'Split Notebook Cell' }); } }); diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 07861ff1596..74d56b87b92 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -37,11 +37,11 @@ import { Schemas } from 'vs/base/common/network'; import { IDiffChange } from 'vs/base/common/diff/diff'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer'; -import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import { SequencerByKey } from 'vs/base/common/async'; import { BackLayerWebView } from 'vs/workbench/contrib/notebook/browser/diff/backLayerWebview2'; import { generateUuid } from 'vs/base/common/uuid'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; +import { DiffNestedCellViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel'; const $ = DOM.$; @@ -282,8 +282,8 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD if (originalCell.getHashValue() === modifiedCell.getHashValue()) { diffElementViewModels.push(new SideBySideDiffElementViewModel( this._model.modified.notebook, - originalCell, - modifiedCell, + this.instantiationService.createInstance(DiffNestedCellViewModel, originalCell), + this.instantiationService.createInstance(DiffNestedCellViewModel, modifiedCell), 'unchanged', this._eventDispatcher! )); @@ -294,8 +294,8 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD diffElementViewModels.push(new SideBySideDiffElementViewModel( this._model.modified.notebook, - originalCell, - modifiedCell, + this.instantiationService.createInstance(DiffNestedCellViewModel, originalCell), + this.instantiationService.createInstance(DiffNestedCellViewModel, modifiedCell), 'modified', this._eventDispatcher! )); @@ -315,8 +315,8 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD for (let i = originalCellIndex; i < originalModel.cells.length; i++) { diffElementViewModels.push(new SideBySideDiffElementViewModel( this._model.modified.notebook, - originalModel.cells[i], - modifiedModel.cells[i - originalCellIndex + modifiedCellIndex], + this.instantiationService.createInstance(DiffNestedCellViewModel, originalModel.cells[i]), + this.instantiationService.createInstance(DiffNestedCellViewModel, modifiedModel.cells[i - originalCellIndex + modifiedCellIndex]), 'unchanged', this._eventDispatcher! )); @@ -339,8 +339,8 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD for (let j = 0; j < modifiedLen; j++) { result.push(new SideBySideDiffElementViewModel( modifiedModel, - originalModel.cells[change.originalStart + j], - modifiedModel.cells[change.modifiedStart + j], + this.instantiationService.createInstance(DiffNestedCellViewModel, originalModel.cells[change.originalStart + j]), + this.instantiationService.createInstance(DiffNestedCellViewModel, modifiedModel.cells[change.modifiedStart + j]), 'modified', this._eventDispatcher! )); @@ -350,7 +350,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD // deletion result.push(new SingleSideDiffElementViewModel( originalModel, - originalModel.cells[change.originalStart + j], + this.instantiationService.createInstance(DiffNestedCellViewModel, originalModel.cells[change.originalStart + j]), undefined, 'delete', this._eventDispatcher! @@ -362,7 +362,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD result.push(new SingleSideDiffElementViewModel( modifiedModel, undefined, - modifiedModel.cells[change.modifiedStart + j], + this.instantiationService.createInstance(DiffNestedCellViewModel, modifiedModel.cells[change.modifiedStart + j]), 'insert', this._eventDispatcher! )); @@ -402,13 +402,17 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD } - createInset(cellDiffViewModel: DiffElementViewModelBase, cellTextModel: NotebookCellTextModel, output: IInsetRenderOutput, offset: number, rightEditor: boolean): void { + createInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: DiffNestedCellViewModel, output: IInsetRenderOutput, offset: number, rightEditor: boolean): void { this._insetModifyQueueByOutputId.queue(output.source.model.outputId, async () => { if (rightEditor) { if (!this._modifiedWebview!.insetMapping.has(output.source)) { const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel); - await this._modifiedWebview?.createInset(cellTextModel, output, cellTop, offset); + await this._modifiedWebview?.createInset(cellDiffViewModel, cellViewModel, output, cellTop, offset); + } else { + const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel); + const scrollTop = this._list.scrollTop; + this._modifiedWebview!.updateViewScrollTop(-scrollTop, true, [{ diffElement: cellDiffViewModel, cell: cellViewModel, output: output.source, cellTop }]); } } }); diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts index 4ef35e2bdad..6a8de1fac10 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts @@ -397,6 +397,7 @@ function webviewPreloads() { window.addEventListener('message', rawEvent => { const event = rawEvent as ({ data: ToWebviewMessage; }); + console.log(event); switch (event.data.type) { case 'html': From 3080c3e88c4dd7e703daf04dbd64e87dfda94fa2 Mon Sep 17 00:00:00 2001 From: rebornix Date: Tue, 15 Dec 2020 09:24:49 -0800 Subject: [PATCH 025/262] webview output first load --- .../browser/diff/backLayerWebview2.ts | 10 ++--- .../contrib/notebook/browser/diff/common.ts | 3 +- .../notebook/browser/diff/diffComponents.ts | 45 +++++++++++++++++-- .../browser/diff/diffElementOutputs.ts | 28 +++++++----- .../notebook/browser/diff/notebookDiff.css | 3 +- .../browser/diff/notebookTextDiffEditor.ts | 10 ++++- .../browser/view/renderers/webviewPreloads.ts | 9 +++- 7 files changed, 84 insertions(+), 24 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts index 0168d38a14a..79cdd189693 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts @@ -13,7 +13,7 @@ import { IOpenerService, matchesScheme } from 'vs/platform/opener/common/opener' import { CELL_MARGIN, CELL_RUN_GUTTER, CODE_CELL_LEFT_MARGIN, CELL_OUTPUT_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; import { IDisplayOutputViewModel, IInsetRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel'; -import { CellOutputKind, IDisplayOutput, INotebookRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellOutputKind, IDisplayOutput, INotebookRendererInfo, ITransformedDisplayOutputDto } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { IWebviewService, WebviewElement, WebviewContentPurpose } from 'vs/workbench/contrib/webview/browser/webview'; import { asWebviewUri } from 'vs/workbench/contrib/webview/common/webviewUri'; @@ -588,15 +588,15 @@ var requirejs = (function() { const widgets: IContentWidgetTopRequest[] = items.map(item => { const outputCache = this.insetMapping.get(item.output)!; const id = outputCache.outputId; - const outputIndex = item.cell.outputsViewModels.indexOf(item.output); + // why? does it mean, we create new output view model every time? + const outputIndex = item.cell.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (item.output.model as ITransformedDisplayOutputDto).outputId); let outputOffset = 0; if (item.diffElement instanceof SideBySideDiffElementViewModel) { - outputOffset = item.diffElement.getOutputOffsetInCell(false, outputIndex); + outputOffset = item.cellTop + item.diffElement.getOutputOffsetInCell(false, outputIndex); } else { - outputOffset = (item.diffElement as SingleSideDiffElementViewModel).getOutputOffsetInCell(outputIndex); + outputOffset = item.cellTop + (item.diffElement as SingleSideDiffElementViewModel).getOutputOffsetInCell(outputIndex); } - // const outputOffset = item.cellTop + item.cell.getOutputOffset(outputIndex); outputCache.cachedCreation.top = outputOffset; this.hiddenInsetMapping.delete(item.output); diff --git a/src/vs/workbench/contrib/notebook/browser/diff/common.ts b/src/vs/workbench/contrib/notebook/browser/diff/common.ts index 521e0b053bf..0365d2ae16f 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/common.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/common.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IInsetRenderOutput, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { IDisplayOutputViewModel, IInsetRenderOutput, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { DiffElementViewModelBase } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; import { Event } from 'vs/base/common/event'; import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; @@ -22,6 +22,7 @@ export interface INotebookTextDiffEditor { layoutNotebookCell(cell: DiffElementViewModelBase, height: number): void; getOutputRenderer(): OutputRenderer; createInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: IDiffNestedCellViewModel, output: IInsetRenderOutput, offset: number, rightEditor: boolean): void; + hideInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: IDiffNestedCellViewModel, output: IDisplayOutputViewModel): void; } export interface IDiffNestedCellViewModel { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts index 45357266a99..6b6b4cf83ed 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts @@ -292,7 +292,9 @@ abstract class AbstractElementRenderer extends Disposable { this._outputViewContainer = DOM.append(this._outputInfoContainer, DOM.$('.output-view-container')); this._buildOutputContainer(); } else { - this.cell.layoutChange(); + // todo, show insets + this._showOutputs(); + // this.cell.layoutChange(); } } else { this._outputInfoContainer.style.display = 'block'; @@ -306,13 +308,20 @@ abstract class AbstractElementRenderer extends Disposable { } } } else { - this._outputInfoContainer.style.display = 'none'; - this._outputEditorDisposeStore.clear(); - this.cell.layoutChange(); + if (RENDER_RICH_OUTPUT) { + this._hideOutputs(); + this.cell.layoutChange(); + } else { + this._outputInfoContainer.style.display = 'none'; + this._outputEditorDisposeStore.clear(); + this.cell.layoutChange(); + } } } abstract _buildOutputContainer(): void; + abstract _hideOutputs(): void; + abstract _showOutputs(): void; private _applySanitizedMetadataChanges(currentMetadata: NotebookCellMetadata, newMetadata: any) { let result: { [key: string]: any } = {}; @@ -805,6 +814,14 @@ export class DeletedElement extends SingleSideDiffElement { // this._outputView.render(); // this.layout({ outputView: true }); } + + _showOutputs() { + + } + + _hideOutputs() { + + } } export class InsertElement extends SingleSideDiffElement { @@ -870,6 +887,15 @@ export class InsertElement extends SingleSideDiffElement { this.cell.layoutChange(); } + _showOutputs() { + this._outputLeftView?.render(); + this.cell.layoutChange(); + } + + _hideOutputs() { + this._outputLeftView?.hideOutputs(); + } + layout(state: { outerWidth?: boolean, editorHeight?: boolean, metadataEditor?: boolean, outputEditor?: boolean, outputView?: boolean }) { DOM.scheduleAtNextAnimationFrame(() => { if (state.editorHeight || state.outerWidth) { @@ -1033,6 +1059,15 @@ export class ModifiedElement extends AbstractElementRenderer { this.cell.layoutChange(); } + _showOutputs() { + this._outputLeftView?.render(); + this._outputRightView?.render(); + this.cell.layoutChange(); + } + + _hideOutputs() { + + } updateSourceEditor(): void { const modifiedCell = this.cell.modified!; @@ -1128,6 +1163,8 @@ export class ModifiedElement extends AbstractElementRenderer { this.cell.editorHeight = contentHeight; } + + layout(state: { outerWidth?: boolean, editorHeight?: boolean, metadataEditor?: boolean, outputEditor?: boolean, outputView?: boolean }) { DOM.scheduleAtNextAnimationFrame(() => { if (state.editorHeight) { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts index 91cfe7de933..425be86467d 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts @@ -85,7 +85,7 @@ export class OutputElement extends Disposable { this.cellViewModel, this.cell, result, - this.getOutputOffsetInContainer(index), + this.getOutputOffsetInCell(index), this.cellViewModel instanceof SideBySideDiffElementViewModel ? this.modified : this.cellViewModel.type === 'insert' @@ -175,8 +175,8 @@ export class OutputContainer extends Disposable { constructor( private _editor: INotebookTextDiffEditor, private notebookTextModel: NotebookTextModel, - private cellViewModel: DiffElementViewModelBase, - private cell: DiffNestedCellViewModel, + private diffElementViewModel: DiffElementViewModelBase, + private cellViewModel: DiffNestedCellViewModel, private modified: boolean, private outputContainer: HTMLElement, @INotebookService private notebookService: INotebookService, @@ -186,22 +186,22 @@ export class OutputContainer extends Disposable { ) { super(); - this._outputViewModels = cell.outputs.map(output => new CellOutputViewModel(output, notebookService)); + this._outputViewModels = cellViewModel.outputs.map(output => new CellOutputViewModel(output, notebookService)); // TODO, onDidChangeOutputs // viewCell.onDidChangeLayout // say the height of the cell editor changes - this._register(this.cellViewModel.onDidLayoutChange(() => { + this._register(this.diffElementViewModel.onDidLayoutChange(() => { this.outputEntries.forEach((value, key) => { - const index = cell.outputs.indexOf(key.model); + const index = cellViewModel.outputs.indexOf(key.model); if (index >= 0) { - if (this.cellViewModel instanceof SideBySideDiffElementViewModel) { - const top = this.cellViewModel.getOutputOffsetInContainer(!this.modified, index); + if (this.diffElementViewModel instanceof SideBySideDiffElementViewModel) { + const top = this.diffElementViewModel.getOutputOffsetInContainer(!this.modified, index); value.domNode.style.top = `${top}px`; } else { - const top = (this.cellViewModel as SingleSideDiffElementViewModel).getOutputOffsetInContainer(index); + const top = (this.diffElementViewModel as SingleSideDiffElementViewModel).getOutputOffsetInContainer(index); value.domNode.style.top = `${top}px`; } } @@ -219,9 +219,17 @@ export class OutputContainer extends Disposable { } } + hideOutputs() { + this.outputEntries.forEach((outputElement, cellOutputViewModel) => { + if (cellOutputViewModel.isDisplayOutput()) { + this._editor.hideInset(this.diffElementViewModel, this.cellViewModel, cellOutputViewModel); + } + }); + } + private _renderOutput(currOutput: ICellOutputViewModel, index: number, beforeElement?: HTMLElement) { if (!this.outputEntries.has(currOutput)) { - this.outputEntries.set(currOutput, new OutputElement(this._editor, this.notebookTextModel, this.notebookService, this.cellViewModel, this.modified, this.cell, this.outputContainer, currOutput)); + this.outputEntries.set(currOutput, new OutputElement(this._editor, this.notebookTextModel, this.notebookService, this.diffElementViewModel, this.modified, this.cellViewModel, this.outputContainer, currOutput)); } const renderElement = this.outputEntries.get(currOutput)!; diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css index 22266135923..e1cb48d1588 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css @@ -115,6 +115,7 @@ .monaco-workbench .notebook-text-diff-editor > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row:hover, .monaco-workbench .notebook-text-diff-editor > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.focused { outline: none !important; + background-color: transparent !important; } .notebook-text-diff-editor .cell-diff-editor-container .editor-input-toolbar-container { @@ -137,7 +138,7 @@ .monaco-workbench .notebook-text-diff-editor .cell-body.left .output-view-container .output-inner-container, .monaco-workbench .notebook-text-diff-editor .cell-body.right .output-view-container .output-inner-container { width: 100%; - padding: 4px 8px; + padding: 0px 8px; box-sizing: border-box; } .monaco-workbench .notebook-text-diff-editor .cell-body.full .output-view-container .output-inner-container { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 74d56b87b92..d9e0fece457 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -23,7 +23,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; import { getZoomLevel } from 'vs/base/browser/browser'; -import { IInsetRenderOutput, INotebookEditor, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { IDisplayOutputViewModel, IInsetRenderOutput, INotebookEditor, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { DIFF_CELL_MARGIN, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common'; import { Emitter } from 'vs/base/common/event'; import { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; @@ -418,6 +418,14 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD }); } + removeInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: DiffNestedCellViewModel, output: IInsetRenderOutput) { + + } + + hideInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: DiffNestedCellViewModel, output: IDisplayOutputViewModel) { + this._modifiedWebview?.hideInset(output); + } + // private async _resolveWebview(rightEditor: boolean): Promise { // if (rightEditor) { diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts index 6a8de1fac10..6565898f513 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts @@ -20,6 +20,12 @@ declare module globalThis { }); } +declare var acquireVsCodeApi: () => ({ + getState(): { [key: string]: unknown; }; + setState(data: { [key: string]: unknown; }): void; + postMessage: (msg: unknown) => void; +}); + declare class ResizeObserver { constructor(onChange: (entries: { target: HTMLElement, contentRect?: ClientRect; }[]) => void); observe(element: Element): void; @@ -36,7 +42,7 @@ interface EmitterLike { } function webviewPreloads() { - const acquireVsCodeApi = globalThis.acquireVsCodeApi; + // const acquireVsCodeApi = acquireVsCodeApi; const vscode = acquireVsCodeApi(); delete (globalThis as any).acquireVsCodeApi; @@ -397,7 +403,6 @@ function webviewPreloads() { window.addEventListener('message', rawEvent => { const event = rawEvent as ({ data: ToWebviewMessage; }); - console.log(event); switch (event.data.type) { case 'html': From caa595fc06613b7f05e72665cc435e3c21388424 Mon Sep 17 00:00:00 2001 From: rebornix Date: Tue, 15 Dec 2020 10:22:38 -0800 Subject: [PATCH 026/262] absolute position of mixed static and dynamic webview --- .../browser/diff/backLayerWebview2.ts | 93 +++++++++---------- 1 file changed, 46 insertions(+), 47 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts index 79cdd189693..2d53fc60926 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts @@ -459,8 +459,7 @@ var requirejs = (function() { const info = this.resolveOutputId(data.id); if (info) { const { diffElement, cell, output } = info; - const outputIndex = cell.outputsViewModels.indexOf(output); - + const outputIndex = cell.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (output.model as ITransformedDisplayOutputDto).outputId); if (diffElement instanceof SideBySideDiffElementViewModel) { diffElement.updateOutputHeight(false, outputIndex, outputHeight); } else { @@ -470,53 +469,53 @@ var requirejs = (function() { // this.notebookEditor.layoutNotebookCell(cell, cell.layoutInfo.totalHeight); } } - // } else if (data.type === 'mouseenter') { - // const info = this.resolveOutputId(data.id); - // if (info) { - // const { cell } = info; - // cell.outputIsHovered = true; - // } - // } else if (data.type === 'mouseleave') { - // const info = this.resolveOutputId(data.id); - // if (info) { - // const { cell } = info; - // cell.outputIsHovered = false; - // } - // } 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 === 'did-scroll-wheel') { - // this.notebookEditor.triggerScroll({ - // ...data.payload, - // preventDefault: () => { }, - // stopPropagation: () => { } - // }); - // } else if (data.type === 'focus-editor') { - // const info = this.resolveOutputId(data.id); - // if (info) { - // if (data.focusNext) { - // const idx = this.notebookEditor.viewModel?.getCellIndex(info.cell); - // if (typeof idx !== 'number') { - // return; - // } + // } else if (data.type === 'mouseenter') { + // const info = this.resolveOutputId(data.id); + // if (info) { + // const { cell } = info; + // cell.outputIsHovered = true; + // } + // } else if (data.type === 'mouseleave') { + // const info = this.resolveOutputId(data.id); + // if (info) { + // const { cell } = info; + // cell.outputIsHovered = false; + // } + // } 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 === 'did-scroll-wheel') { + // this.notebookEditor.triggerScroll({ + // ...data.payload, + // preventDefault: () => { }, + // stopPropagation: () => { } + // }); + // } else if (data.type === 'focus-editor') { + // const info = this.resolveOutputId(data.id); + // if (info) { + // if (data.focusNext) { + // const idx = this.notebookEditor.viewModel?.getCellIndex(info.cell); + // if (typeof idx !== 'number') { + // return; + // } - // const newCell = this.notebookEditor.viewModel?.viewCells[idx + 1]; - // if (!newCell) { - // return; - // } + // const newCell = this.notebookEditor.viewModel?.viewCells[idx + 1]; + // if (!newCell) { + // return; + // } - // this.notebookEditor.focusNotebookCell(newCell, 'editor'); - // } else { - // this.notebookEditor.focusNotebookCell(info.cell, 'editor'); - // } - // } - // } else if (data.type === 'clicked-data-url') { - // this._onDidClickDataLink(data); - // } else if (data.type === 'customRendererMessage') { - // this._onMessage.fire({ message: data.message, forRenderer: data.rendererId }); - // } - // return; + // this.notebookEditor.focusNotebookCell(newCell, 'editor'); + // } else { + // this.notebookEditor.focusNotebookCell(info.cell, 'editor'); + // } + // } + // } else if (data.type === 'clicked-data-url') { + // this._onDidClickDataLink(data); + // } else if (data.type === 'customRendererMessage') { + // this._onMessage.fire({ message: data.message, forRenderer: data.rendererId }); + // } + // return; } this._onMessage.fire({ message: data }); From bbb797d3e4d1f897120401c03fd9bc6119ee583a Mon Sep 17 00:00:00 2001 From: rebornix Date: Tue, 15 Dec 2020 10:23:38 -0800 Subject: [PATCH 027/262] clear static outputs when collapse outputs panel --- .../workbench/contrib/notebook/browser/diff/diffComponents.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts index 6b6b4cf83ed..2771f8b135b 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts @@ -310,6 +310,8 @@ abstract class AbstractElementRenderer extends Disposable { } else { if (RENDER_RICH_OUTPUT) { this._hideOutputs(); + this._outputInfoContainer.style.display = 'none'; + this._outputEditorDisposeStore.clear(); this.cell.layoutChange(); } else { this._outputInfoContainer.style.display = 'none'; From ff02224c1bcb4d2998133d74de99093b38919e65 Mon Sep 17 00:00:00 2001 From: rebornix Date: Tue, 15 Dec 2020 11:03:12 -0800 Subject: [PATCH 028/262] move output layout info into genericCellViewModel shared by notebook and diff. --- .../browser/diff/backLayerWebview2.ts | 10 +- .../browser/diff/diffElementOutputs.ts | 2 +- .../browser/diff/diffElementViewModel.ts | 132 +++--------------- .../browser/diff/diffNestedCellViewModel.ts | 67 +++++++-- .../contrib/notebook/browser/genericTypes.ts | 18 +++ 5 files changed, 102 insertions(+), 127 deletions(-) create mode 100644 src/vs/workbench/contrib/notebook/browser/genericTypes.ts diff --git a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts index 2d53fc60926..c3c95e2355e 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts @@ -12,7 +12,6 @@ import * as UUID from 'vs/base/common/uuid'; import { IOpenerService, matchesScheme } from 'vs/platform/opener/common/opener'; import { CELL_MARGIN, CELL_RUN_GUTTER, CODE_CELL_LEFT_MARGIN, CELL_OUTPUT_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; import { IDisplayOutputViewModel, IInsetRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; -import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel'; import { CellOutputKind, IDisplayOutput, INotebookRendererInfo, ITransformedDisplayOutputDto } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { IWebviewService, WebviewElement, WebviewContentPurpose } from 'vs/workbench/contrib/webview/browser/webview'; @@ -25,6 +24,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common'; import { DiffNestedCellViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel'; import { DiffElementViewModelBase, SideBySideDiffElementViewModel, SingleSideDiffElementViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; +import { IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; export interface WebviewIntialized { __vscode_notebook_message: boolean; @@ -198,7 +198,7 @@ export type AnyMessage = FromWebviewMessage | ToWebviewMessage; interface ICachedInset { outputId: string; diffElement: DiffElementViewModelBase; - cell: DiffNestedCellViewModel; + cell: IGenericCellViewModel; renderer?: INotebookRendererInfo; cachedCreation: ICreationRequestMessage; } @@ -334,7 +334,7 @@ export class BackLayerWebView extends Disposable { }); } - private resolveOutputId(id: string): { cell: DiffNestedCellViewModel, diffElement: DiffElementViewModelBase, output: IDisplayOutputViewModel } | undefined { + private resolveOutputId(id: string): { cell: IGenericCellViewModel, diffElement: DiffElementViewModelBase, output: IDisplayOutputViewModel } | undefined { const output = this.reversedInsetMapping.get(id); if (!output) { return; @@ -555,7 +555,7 @@ var requirejs = (function() { return webview; } - shouldUpdateInset(cell: CodeCellViewModel, output: IDisplayOutputViewModel, cellTop: number) { + shouldUpdateInset(cell: IGenericCellViewModel, output: IDisplayOutputViewModel, cellTop: number) { if (this._disposed) { return; } @@ -615,7 +615,7 @@ var requirejs = (function() { }); } - async createInset(cellDiffViewModel: DiffElementViewModelBase, cell: DiffNestedCellViewModel, content: IInsetRenderOutput, cellTop: number, offset: number) { + async createInset(cellDiffViewModel: DiffElementViewModelBase, cell: IGenericCellViewModel, content: IInsetRenderOutput, cellTop: number, offset: number) { if (this._disposed) { return; } diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts index 425be86467d..0361db6bed1 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts @@ -140,7 +140,7 @@ export class OutputElement extends Disposable { return this.cellViewModel.original.outputs.indexOf(this.output.model); } } else { - return (this.cellViewModel as SingleSideDiffElementViewModel).cellTextModel!.outputs.indexOf(this.output.model); + return (this.cellViewModel as SingleSideDiffElementViewModel).cellViewModel!.outputs.indexOf(this.output.model); } } diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts index 33442495fb1..181d4557e2b 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts @@ -131,7 +131,6 @@ export abstract class DiffElementViewModelBase extends Disposable { abstract checkIfOutputsModified(): boolean; abstract checkMetadataIfModified(): boolean; - abstract ensureOutputsTop(): void; abstract layoutChange(): void; getComputedCellContainerWidth(layoutInfo: NotebookLayoutInfo, diffEditor: boolean, fullWidth: boolean) { @@ -144,11 +143,6 @@ export abstract class DiffElementViewModelBase extends Disposable { } export class SideBySideDiffElementViewModel extends DiffElementViewModelBase { - protected _originalOutputCollection: number[] = []; - protected _originalOutputsTop: PrefixSumComputer | null = null; - protected _modifiedOutputCollection: number[] = []; - protected _modifiedOutputsTop: PrefixSumComputer | null = null; - constructor( readonly documentTextModel: NotebookTextModel, readonly original: DiffNestedCellViewModel, @@ -174,13 +168,16 @@ export class SideBySideDiffElementViewModel extends DiffElementViewModelBase { this.outputFoldingState = PropertyFoldingState.Expanded; } - this._originalOutputCollection = new Array(this.original.outputs.length); - this._modifiedOutputCollection = new Array(this.modified.outputs.length); + this._register(this.original.onDidChangeOutputLayout(() => { + this.layoutChange(); + })); + + this._register(this.modified.onDidChangeOutputLayout(() => { + this.layoutChange(); + })); } layoutChange() { - this.ensureOutputsTop(); - let outputHeight = this.outputFoldingState === PropertyFoldingState.Collapsed ? 0 : this.getOutputTotalHeight(); this._layoutInfo = { width: this._layoutInfo.width, @@ -206,69 +203,17 @@ export class SideBySideDiffElementViewModel extends DiffElementViewModelBase { updateOutputHeight(original: boolean, index: number, height: number) { if (original) { - if (index >= this._originalOutputCollection.length) { - throw new Error('Output index out of range!'); - } - - this.ensureOriginalOutputsTop(); - this.ensureModifiedOutputsTop(); - this._originalOutputCollection[index] = height; - - if (this._originalOutputsTop!.changeValue(index, height)) { - this.layoutChange(); - } + this.original.updateOutputHeight(index, height); } else { - if (index >= this._modifiedOutputCollection.length) { - throw new Error('Output index out of range!'); - } - - this.ensureOriginalOutputsTop(); - this.ensureModifiedOutputsTop(); - this._modifiedOutputCollection[index] = height; - - if (this._modifiedOutputsTop!.changeValue(index, height)) { - this.layoutChange(); - } - } - } - - ensureOriginalOutputsTop() { - if (!this._originalOutputsTop) { - const values = new Uint32Array(this._originalOutputCollection.length); - for (let i = 0; i < this._originalOutputCollection.length; i++) { - values[i] = this._originalOutputCollection[i]; - } - - this._originalOutputsTop = new PrefixSumComputer(values); - } - } - - ensureModifiedOutputsTop() { - if (!this._modifiedOutputsTop) { - const values = new Uint32Array(this._modifiedOutputCollection.length); - for (let i = 0; i < this._modifiedOutputCollection.length; i++) { - values[i] = this._modifiedOutputCollection[i]; - } - - this._modifiedOutputsTop = new PrefixSumComputer(values); + this.modified.updateOutputHeight(index, height); } } getOutputOffsetInContainer(original: boolean, index: number) { - this.ensureOutputsTop(); - if (original) { - if (index >= this._originalOutputCollection.length) { - throw new Error('Output index out of range!'); - } - - return this._originalOutputsTop!.getAccumulatedValue(index - 1); + return this.original.getOutputOffset(index); } else { - if (index >= this._modifiedOutputCollection.length) { - throw new Error('Output index out of range!'); - } - - return this._modifiedOutputsTop!.getAccumulatedValue(index - 1); + return this.modified.getOutputOffset(index); } } @@ -285,22 +230,12 @@ export class SideBySideDiffElementViewModel extends DiffElementViewModelBase { } getOutputTotalHeight() { - this.ensureOutputsTop(); - - return Math.max(this._originalOutputsTop?.getTotalValue() ?? 0, this._modifiedOutputsTop?.getTotalValue() ?? 0); - } - - ensureOutputsTop() { - this.ensureOriginalOutputsTop(); - this.ensureModifiedOutputsTop(); + return Math.max(this.original.getOutputTotalHeight(), this.modified.getOutputTotalHeight()); } } export class SingleSideDiffElementViewModel extends DiffElementViewModelBase { - protected _outputCollection: number[] = []; - protected _outputsTop: PrefixSumComputer | null = null; - - get cellTextModel() { + get cellViewModel() { return this.type === 'insert' ? this.modified : this.original; } @@ -312,12 +247,12 @@ export class SingleSideDiffElementViewModel extends DiffElementViewModelBase { readonly editorEventDispatcher: NotebookDiffEditorEventDispatcher ) { super(documentTextModel, original, modified, type, editorEventDispatcher); - this._outputCollection = new Array(this.original ? this.original.outputs.length : this.modified!.outputs.length); + this._register(this.cellViewModel!.onDidChangeOutputLayout(() => { + this.layoutChange(); + })); } layoutChange() { - this.ensureOutputsTop(); - let outputHeight = this.outputFoldingState === PropertyFoldingState.Collapsed ? 0 : this.getOutputTotalHeight(); this._layoutInfo = { width: this._layoutInfo.width, @@ -343,40 +278,15 @@ export class SingleSideDiffElementViewModel extends DiffElementViewModelBase { } updateOutputHeight(index: number, height: number) { - if (index >= this._outputCollection.length) { - throw new Error('Output index out of range!'); - } - - this.ensureOutputsTop(); - this._outputCollection[index] = height; - if (this._outputsTop!.changeValue(index, height)) { - this.layoutChange(); - } - } - - ensureOutputsTop() { - if (!this._outputsTop) { - const values = new Uint32Array(this._outputCollection.length); - for (let i = 0; i < this._outputCollection.length; i++) { - values[i] = this._outputCollection[i]; - } - - this._outputsTop = new PrefixSumComputer(values); - } + this.cellViewModel?.updateOutputHeight(index, height); } getOutputOffsetInContainer(index: number) { - this.ensureOutputsTop(); - - if (index >= this._outputCollection.length) { - throw new Error('Output index out of range!'); - } - - return this._outputsTop!.getAccumulatedValue(index - 1); + return this.cellViewModel!.getOutputOffset(index); } getOutputOffsetInCell(index: number) { - const offsetInOutputsContainer = this.getOutputOffsetInContainer(index); + const offsetInOutputsContainer = this.cellViewModel!.getOutputOffset(index); return this._layoutInfo.editorHeight + this._layoutInfo.editorMargin @@ -388,9 +298,7 @@ export class SingleSideDiffElementViewModel extends DiffElementViewModelBase { } getOutputTotalHeight() { - this.ensureOutputsTop(); - - return this._outputsTop?.getTotalValue() ?? 0; + return this.cellViewModel?.getOutputTotalHeight() ?? 0; } } diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel.ts index ed4e2c14c63..e0817b93cbc 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel.ts @@ -3,15 +3,18 @@ * Licensed under the MIT License. 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 { generateUuid } from 'vs/base/common/uuid'; +import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer'; import { IDiffNestedCellViewModel } from 'vs/workbench/contrib/notebook/browser/diff/common'; +import { IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; import { ICellOutputViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellOutputViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; -export class DiffNestedCellViewModel extends Disposable implements IDiffNestedCellViewModel { +export class DiffNestedCellViewModel extends Disposable implements IDiffNestedCellViewModel, IGenericCellViewModel { private _id: string; get id() { return this._id; @@ -43,6 +46,12 @@ export class DiffNestedCellViewModel extends Disposable implements IDiffNestedCe return this._outputViewModels; } + protected _outputCollection: number[] = []; + protected _outputsTop: PrefixSumComputer | null = null; + protected readonly _onDidChangeOutputLayout = new Emitter(); + readonly onDidChangeOutputLayout = this._onDidChangeOutputLayout.event; + + constructor( readonly textModel: NotebookCellTextModel, @INotebookService private _notebookService: INotebookService @@ -51,14 +60,54 @@ export class DiffNestedCellViewModel extends Disposable implements IDiffNestedCe this._id = generateUuid(); this._outputViewModels = this.textModel.outputs.map(output => new CellOutputViewModel(output, this._notebookService)); - // this._register(this.textModel.onDidChangeOutputs((splices) => { - // splices.reverse().forEach(splice => { - // this._outputCollection.splice(splice[0], splice[1], ...splice[2].map(() => 0)); - // this._outputViewModels.splice(splice[0], splice[1], ...splice[2].map(output => new CellOutputViewModel(output, this._notebookService))); - // }); + this._register(this.textModel.onDidChangeOutputs((splices) => { + splices.reverse().forEach(splice => { + this._outputCollection.splice(splice[0], splice[1], ...splice[2].map(() => 0)); + this._outputViewModels.splice(splice[0], splice[1], ...splice[2].map(output => new CellOutputViewModel(output, this._notebookService))); + }); - // this._outputsTop = null; - // this._onDidChangeOutputs.fire(splices); - // })); + this._outputsTop = null; + this._onDidChangeOutputLayout.fire(); + })); + this._outputCollection = new Array(this.textModel.outputs.length); + } + + private _ensureOutputsTop() { + if (!this._outputsTop) { + const values = new Uint32Array(this._outputCollection.length); + for (let i = 0; i < this._outputCollection.length; i++) { + values[i] = this._outputCollection[i]; + } + + this._outputsTop = new PrefixSumComputer(values); + } + } + + getOutputOffset(index: number): number { + this._ensureOutputsTop(); + + if (index >= this._outputCollection.length) { + throw new Error('Output index out of range!'); + } + + return this._outputsTop!.getAccumulatedValue(index - 1); + } + + updateOutputHeight(index: number, height: number): void { + if (index >= this._outputCollection.length) { + throw new Error('Output index out of range!'); + } + + this._ensureOutputsTop(); + this._outputCollection[index] = height; + if (this._outputsTop!.changeValue(index, height)) { + this._onDidChangeOutputLayout.fire(); + } + } + + getOutputTotalHeight() { + this._ensureOutputsTop(); + + return this._outputsTop?.getTotalValue() ?? 0; } } diff --git a/src/vs/workbench/contrib/notebook/browser/genericTypes.ts b/src/vs/workbench/contrib/notebook/browser/genericTypes.ts new file mode 100644 index 00000000000..dc531714626 --- /dev/null +++ b/src/vs/workbench/contrib/notebook/browser/genericTypes.ts @@ -0,0 +1,18 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { URI } from 'vs/base/common/uri'; +import { ICellOutputViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; + +export interface IGenericCellViewModel { + id: string; + handle: number; + uri: URI; + metadata: NotebookCellMetadata; + outputsViewModels: ICellOutputViewModel[]; + getOutputOffset(index: number): number; + updateOutputHeight(index: number, height: number): void; +} From bd67f0d0cabb9d1c11e2b50bbf0ee1851033de11 Mon Sep 17 00:00:00 2001 From: rebornix Date: Tue, 15 Dec 2020 11:03:34 -0800 Subject: [PATCH 029/262] :lipstick: --- .../contrib/notebook/browser/diff/diffElementViewModel.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts index 181d4557e2b..e5a1415708f 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts @@ -14,7 +14,6 @@ import { hash } from 'vs/base/common/hash'; import { format } from 'vs/base/common/jsonFormatter'; import { applyEdits } from 'vs/base/common/jsonEdit'; import { NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; -import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer'; import { DiffNestedCellViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel'; export enum PropertyFoldingState { From c782b708b18dca14bb195c92b1366a090d4072e7 Mon Sep 17 00:00:00 2001 From: rebornix Date: Tue, 15 Dec 2020 11:22:24 -0800 Subject: [PATCH 030/262] cell body height to 0 so I can click into the webview --- .../workbench/contrib/notebook/browser/diff/notebookDiff.css | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css index e1cb48d1588..ba600aa00c7 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css @@ -125,6 +125,9 @@ margin: 4px 2px; } +.monaco-workbench .notebook-text-diff-editor .cell-body { + height: 0; +} .monaco-workbench .notebook-text-diff-editor .cell-body .output-view-container { user-select: text; From 0ff71d3213829113ce3a7dbc549c774614fc14d4 Mon Sep 17 00:00:00 2001 From: rebornix Date: Tue, 15 Dec 2020 11:49:51 -0800 Subject: [PATCH 031/262] update output in webview position when list view layout change. --- .../browser/diff/backLayerWebview2.ts | 2 +- .../browser/diff/notebookTextDiffEditor.ts | 51 ++++++++++++++++++- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts index c3c95e2355e..b41c94fde88 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts @@ -579,7 +579,7 @@ var requirejs = (function() { return true; } - updateViewScrollTop(top: number, forceDisplay: boolean, items: { diffElement: DiffElementViewModelBase, cell: DiffNestedCellViewModel, output: IDisplayOutputViewModel, cellTop: number }[]) { + updateViewScrollTop(top: number, forceDisplay: boolean, items: { diffElement: DiffElementViewModelBase, cell: IGenericCellViewModel, output: IDisplayOutputViewModel, cellTop: number }[]) { if (this._disposed) { return; } diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index d9e0fece457..96affc78bc6 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -29,7 +29,7 @@ import { Emitter } from 'vs/base/common/event'; import { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { NotebookDiffEditorEventDispatcher, NotebookLayoutChangedEvent } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher'; import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane'; -import { INotebookDiffEditorModel } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { INotebookDiffEditorModel, ITransformedDisplayOutputDto } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { FileService } from 'vs/platform/files/common/fileService'; import { IFileService } from 'vs/platform/files/common/files'; import { URI } from 'vs/base/common/uri'; @@ -42,6 +42,7 @@ import { BackLayerWebView } from 'vs/workbench/contrib/notebook/browser/diff/bac import { generateUuid } from 'vs/base/common/uuid'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { DiffNestedCellViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel'; +import { IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; const $ = DOM.$; @@ -178,6 +179,54 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD this._webviewTransparentCover.style.display = 'none'; } })); + + this._register(this._list.onDidChangeContentHeight(() => { + DOM.scheduleAtNextAnimationFrame(() => { + const scrollTop = this._list.scrollTop; + const scrollHeight = this._list.scrollHeight; + + if (!this._modifiedWebview) { + return; + } + + this._modifiedWebview!.element.style.height = `${scrollHeight}px`; + + if (this._modifiedWebview?.insetMapping) { + const updateItems: { diffElement: DiffElementViewModelBase, cell: IGenericCellViewModel, output: IDisplayOutputViewModel, cellTop: number }[] = []; + const removedItems: IDisplayOutputViewModel[] = []; + this._modifiedWebview?.insetMapping.forEach((value, key) => { + const cell = value.cell; + const viewIndex = this._list.indexOf(value.diffElement); + + if (viewIndex === undefined) { + return; + } + + if (cell.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (key.model as ITransformedDisplayOutputDto).outputId) < 0) { + // output is already gone + removedItems.push(key); + } + + const cellTop = this._list.getAbsoluteTopOfElement(value.diffElement); + if (this._modifiedWebview!.shouldUpdateInset(cell, key, cellTop)) { + updateItems.push({ + diffElement: value.diffElement, + cell: cell, + output: key, + cellTop: cellTop + }); + } + }); + + removedItems.forEach(output => this._modifiedWebview?.removeInset(output)); + + if (updateItems.length) { + this._modifiedWebview?.updateViewScrollTop(-scrollTop, false, updateItems); + } + } + + }); + })); } async setInput(input: NotebookDiffEditorInput, options: EditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { From 976b9b5cda29fbe46bbe90f5558605c75a039a77 Mon Sep 17 00:00:00 2001 From: rebornix Date: Tue, 15 Dec 2020 11:58:54 -0800 Subject: [PATCH 032/262] :lipstick: --- .../workbench/contrib/notebook/browser/diff/backLayerWebview2.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts index b41c94fde88..8b74d9ef9bd 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts @@ -22,7 +22,6 @@ import { preloadsScriptStr } from 'vs/workbench/contrib/notebook/browser/view/re import { FileAccess, Schemas } from 'vs/base/common/network'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common'; -import { DiffNestedCellViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel'; import { DiffElementViewModelBase, SideBySideDiffElementViewModel, SingleSideDiffElementViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; import { IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; From 65bc4153aed1e42427367cd5ca782cbd1bb3bcc4 Mon Sep 17 00:00:00 2001 From: rebornix Date: Tue, 15 Dec 2020 13:11:27 -0800 Subject: [PATCH 033/262] support scroll position syncing. --- .../browser/diff/backLayerWebview2.ts | 95 +++++++++---------- .../contrib/notebook/browser/diff/common.ts | 5 + .../browser/diff/diffNestedCellViewModel.ts | 13 ++- .../browser/diff/notebookTextDiffEditor.ts | 5 +- .../browser/diff/notebookTextDiffList.ts | 5 + .../contrib/notebook/browser/genericTypes.ts | 1 + 6 files changed, 74 insertions(+), 50 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts index 8b74d9ef9bd..79767a5f7ae 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts @@ -464,57 +464,56 @@ var requirejs = (function() { } else { (diffElement as SingleSideDiffElementViewModel).updateOutputHeight(outputIndex, outputHeight); } - // cell.updateOutputHeight(outputIndex, outputHeight); // this.notebookEditor.layoutNotebookCell(cell, cell.layoutInfo.totalHeight); } + } else if (data.type === 'mouseenter') { + const info = this.resolveOutputId(data.id); + if (info) { + const { cell } = info; + cell.outputIsHovered = true; + } + } else if (data.type === 'mouseleave') { + const info = this.resolveOutputId(data.id); + if (info) { + const { cell } = info; + cell.outputIsHovered = false; + } + // } 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 === 'did-scroll-wheel') { + this.notebookEditor.triggerScroll({ + ...data.payload, + preventDefault: () => { }, + stopPropagation: () => { } + }); + // } else if (data.type === 'focus-editor') { + // const info = this.resolveOutputId(data.id); + // if (info) { + // if (data.focusNext) { + // const idx = this.notebookEditor.viewModel?.getCellIndex(info.cell); + // if (typeof idx !== 'number') { + // return; + // } + + // const newCell = this.notebookEditor.viewModel?.viewCells[idx + 1]; + // if (!newCell) { + // return; + // } + + // this.notebookEditor.focusNotebookCell(newCell, 'editor'); + // } else { + // this.notebookEditor.focusNotebookCell(info.cell, 'editor'); + // } + // } + // } else if (data.type === 'clicked-data-url') { + // this._onDidClickDataLink(data); + // } else if (data.type === 'customRendererMessage') { + // this._onMessage.fire({ message: data.message, forRenderer: data.rendererId }); + // } + // return; } - // } else if (data.type === 'mouseenter') { - // const info = this.resolveOutputId(data.id); - // if (info) { - // const { cell } = info; - // cell.outputIsHovered = true; - // } - // } else if (data.type === 'mouseleave') { - // const info = this.resolveOutputId(data.id); - // if (info) { - // const { cell } = info; - // cell.outputIsHovered = false; - // } - // } 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 === 'did-scroll-wheel') { - // this.notebookEditor.triggerScroll({ - // ...data.payload, - // preventDefault: () => { }, - // stopPropagation: () => { } - // }); - // } else if (data.type === 'focus-editor') { - // const info = this.resolveOutputId(data.id); - // if (info) { - // if (data.focusNext) { - // const idx = this.notebookEditor.viewModel?.getCellIndex(info.cell); - // if (typeof idx !== 'number') { - // return; - // } - - // const newCell = this.notebookEditor.viewModel?.viewCells[idx + 1]; - // if (!newCell) { - // return; - // } - - // this.notebookEditor.focusNotebookCell(newCell, 'editor'); - // } else { - // this.notebookEditor.focusNotebookCell(info.cell, 'editor'); - // } - // } - // } else if (data.type === 'clicked-data-url') { - // this._onDidClickDataLink(data); - // } else if (data.type === 'customRendererMessage') { - // this._onMessage.fire({ message: data.message, forRenderer: data.rendererId }); - // } - // return; } this._onMessage.fire({ message: data }); diff --git a/src/vs/workbench/contrib/notebook/browser/diff/common.ts b/src/vs/workbench/contrib/notebook/browser/diff/common.ts index 0365d2ae16f..80b30b9c832 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/common.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/common.ts @@ -13,6 +13,7 @@ import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer'; +import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; export interface INotebookTextDiffEditor { readonly textModel?: NotebookTextModel; @@ -23,6 +24,10 @@ export interface INotebookTextDiffEditor { getOutputRenderer(): OutputRenderer; createInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: IDiffNestedCellViewModel, output: IInsetRenderOutput, offset: number, rightEditor: boolean): void; hideInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: IDiffNestedCellViewModel, output: IDisplayOutputViewModel): void; + /** + * Trigger the editor to scroll from scroll event programmatically + */ + triggerScroll(event: IMouseWheelEvent): void; } export interface IDiffNestedCellViewModel { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel.ts index e0817b93cbc..050b6feb951 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel.ts @@ -9,7 +9,7 @@ import { generateUuid } from 'vs/base/common/uuid'; import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer'; import { IDiffNestedCellViewModel } from 'vs/workbench/contrib/notebook/browser/diff/common'; import { IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; -import { ICellOutputViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { CellViewModelStateChangeEvent, ICellOutputViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellOutputViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; @@ -40,6 +40,17 @@ export class DiffNestedCellViewModel extends Disposable implements IDiffNestedCe return this.textModel.handle; } + protected readonly _onDidChangeState: Emitter = this._register(new Emitter()); + + private _hoveringOutput: boolean = false; + public get outputIsHovered(): boolean { + return this._hoveringOutput; + } + + public set outputIsHovered(v: boolean) { + this._hoveringOutput = v; + this._onDidChangeState.fire({ outputIsHoveredChanged: true }); + } private _outputViewModels: ICellOutputViewModel[]; get outputsViewModels() { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 96affc78bc6..fed830b7a9a 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -40,7 +40,7 @@ import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/outpu import { SequencerByKey } from 'vs/base/common/async'; import { BackLayerWebView } from 'vs/workbench/contrib/notebook/browser/diff/backLayerWebview2'; import { generateUuid } from 'vs/base/common/uuid'; -import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; +import { IMouseWheelEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { DiffNestedCellViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel'; import { IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; @@ -450,6 +450,9 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD return new Promise(resolve => { r = resolve; }); } + triggerScroll(event: IMouseWheelEvent) { + this._list.triggerScrollFromMouseWheelEvent(event); + } createInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: DiffNestedCellViewModel, output: IInsetRenderOutput, offset: number, rightEditor: boolean): void { this._insetModifyQueueByOutputId.queue(output.source.model.outputId, async () => { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts index 2c3c565a7d4..a879142635a 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts @@ -34,6 +34,7 @@ import { SelectionClipboardContributionID } from 'vs/workbench/contrib/codeEdito import { TabCompletionController } from 'vs/workbench/contrib/snippets/browser/tabCompletion'; import { AccessibilityHelpController } from 'vs/workbench/contrib/codeEditor/browser/accessibility/accessibility'; import { CodiconActionViewItem } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellActionView'; +import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; const fixedEditorOptions: IEditorOptions = { padding: { @@ -341,6 +342,10 @@ export class NotebookTextDiffList extends WorkbenchList Date: Tue, 15 Dec 2020 13:20:35 -0800 Subject: [PATCH 034/262] link clicking in the output webview --- .../browser/diff/backLayerWebview2.ts | 62 +++++++++++++++---- 1 file changed, 51 insertions(+), 11 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts index 79767a5f7ae..4c722f9a270 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts @@ -16,7 +16,7 @@ import { CellOutputKind, IDisplayOutput, INotebookRendererInfo, ITransformedDisp import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { IWebviewService, WebviewElement, WebviewContentPurpose } from 'vs/workbench/contrib/webview/browser/webview'; import { asWebviewUri } from 'vs/workbench/contrib/webview/common/webviewUri'; -import { dirname } from 'vs/base/common/resources'; +import { dirname, joinPath } from 'vs/base/common/resources'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { preloadsScriptStr } from 'vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads'; import { FileAccess, Schemas } from 'vs/base/common/network'; @@ -24,6 +24,10 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common'; import { DiffElementViewModelBase, SideBySideDiffElementViewModel, SingleSideDiffElementViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; import { IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; +import { getExtensionForMimeType } from 'vs/base/common/mime'; +import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { VSBuffer } from 'vs/base/common/buffer'; +import { IFileService } from 'vs/platform/files/common/files'; export interface WebviewIntialized { __vscode_notebook_message: boolean; @@ -241,6 +245,8 @@ export class BackLayerWebView extends Disposable { @INotebookService private readonly notebookService: INotebookService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, + @IFileDialogService private readonly fileDialogService: IFileDialogService, + @IFileService private readonly fileService: IFileService, ) { super(); @@ -478,10 +484,10 @@ var requirejs = (function() { const { cell } = info; cell.outputIsHovered = false; } - // } 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') { + // 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 === 'did-scroll-wheel') { this.notebookEditor.triggerScroll({ ...data.payload, @@ -507,19 +513,53 @@ var requirejs = (function() { // this.notebookEditor.focusNotebookCell(info.cell, 'editor'); // } // } - // } else if (data.type === 'clicked-data-url') { - // this._onDidClickDataLink(data); - // } else if (data.type === 'customRendererMessage') { - // this._onMessage.fire({ message: data.message, forRenderer: data.rendererId }); - // } - // return; + } else if (data.type === 'clicked-data-url') { + this._onDidClickDataLink(data); + } else if (data.type === 'customRendererMessage') { + this._onMessage.fire({ message: data.message, forRenderer: data.rendererId }); } + return; } + this._onMessage.fire({ message: data }); })); } + private async _onDidClickDataLink(event: IClickedDataUrlMessage): Promise { + const [splitStart, splitData] = event.data.split(';base64,'); + if (!splitData || !splitStart) { + return; + } + + const defaultDir = dirname(this.documentUri); + let defaultName: string; + if (event.downloadName) { + defaultName = event.downloadName; + } else { + const mimeType = splitStart.replace(/^data:/, ''); + const candidateExtension = mimeType && getExtensionForMimeType(mimeType); + defaultName = candidateExtension ? `download${candidateExtension}` : 'download'; + } + + const defaultUri = joinPath(defaultDir, defaultName); + const newFileUri = await this.fileDialogService.showSaveDialog({ + defaultUri + }); + if (!newFileUri) { + return; + } + + const decoded = atob(splitData); + const typedArray = new Uint8Array(decoded.length); + for (let i = 0; i < decoded.length; i++) { + typedArray[i] = decoded.charCodeAt(i); + } + + const buff = VSBuffer.wrap(typedArray); + await this.fileService.writeFile(newFileUri, buff); + await this.openerService.open(newFileUri); + } private _createInset(webviewService: IWebviewService, content: string) { const rootPath = isWeb ? FileAccess.asBrowserUri('', require) : FileAccess.asFileUri('', require); From a7cac8062304fb08b1b37c933460f7ffba031049 Mon Sep 17 00:00:00 2001 From: rebornix Date: Tue, 15 Dec 2020 13:37:29 -0800 Subject: [PATCH 035/262] no need to pass in cell for updateViewScrollTop. it only talks about output and offsets. --- .../browser/diff/backLayerWebview2.ts | 11 ++------ .../browser/diff/notebookTextDiffEditor.ts | 25 ++++++++++++++++--- .../notebook/browser/notebookEditorWidget.ts | 14 ++++++++--- .../view/renderers/backLayerWebView.ts | 6 ++--- 4 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts index 4c722f9a270..fb9472a3d5c 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts @@ -617,7 +617,7 @@ var requirejs = (function() { return true; } - updateViewScrollTop(top: number, forceDisplay: boolean, items: { diffElement: DiffElementViewModelBase, cell: IGenericCellViewModel, output: IDisplayOutputViewModel, cellTop: number }[]) { + updateViewScrollTop(top: number, forceDisplay: boolean, items: { cell: IGenericCellViewModel, output: IDisplayOutputViewModel, cellTop: number, outputOffset: number }[]) { if (this._disposed) { return; } @@ -625,14 +625,7 @@ var requirejs = (function() { const widgets: IContentWidgetTopRequest[] = items.map(item => { const outputCache = this.insetMapping.get(item.output)!; const id = outputCache.outputId; - // why? does it mean, we create new output view model every time? - const outputIndex = item.cell.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (item.output.model as ITransformedDisplayOutputDto).outputId); - let outputOffset = 0; - if (item.diffElement instanceof SideBySideDiffElementViewModel) { - outputOffset = item.cellTop + item.diffElement.getOutputOffsetInCell(false, outputIndex); - } else { - outputOffset = item.cellTop + (item.diffElement as SingleSideDiffElementViewModel).getOutputOffsetInCell(outputIndex); - } + const outputOffset = item.outputOffset; outputCache.cachedCreation.top = outputOffset; this.hiddenInsetMapping.delete(item.output); diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index fed830b7a9a..6cc6767d7c3 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -192,7 +192,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD this._modifiedWebview!.element.style.height = `${scrollHeight}px`; if (this._modifiedWebview?.insetMapping) { - const updateItems: { diffElement: DiffElementViewModelBase, cell: IGenericCellViewModel, output: IDisplayOutputViewModel, cellTop: number }[] = []; + const updateItems: { cell: IGenericCellViewModel, output: IDisplayOutputViewModel, cellTop: number, outputOffset: number }[] = []; const removedItems: IDisplayOutputViewModel[] = []; this._modifiedWebview?.insetMapping.forEach((value, key) => { const cell = value.cell; @@ -209,11 +209,21 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD const cellTop = this._list.getAbsoluteTopOfElement(value.diffElement); if (this._modifiedWebview!.shouldUpdateInset(cell, key, cellTop)) { + // TODO: why? does it mean, we create new output view model every time? + const outputIndex = cell.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (key.model as ITransformedDisplayOutputDto).outputId); + let outputOffset = 0; + if (value.diffElement instanceof SideBySideDiffElementViewModel) { + outputOffset = cellTop + value.diffElement.getOutputOffsetInCell(false, outputIndex); + } else { + outputOffset = cellTop + (value.diffElement as SingleSideDiffElementViewModel).getOutputOffsetInCell(outputIndex); + } + + updateItems.push({ - diffElement: value.diffElement, cell: cell, output: key, - cellTop: cellTop + cellTop: cellTop, + outputOffset: outputOffset }); } }); @@ -463,8 +473,15 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD } else { const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel); const scrollTop = this._list.scrollTop; + const outputIndex = cellViewModel.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (output.source.model as ITransformedDisplayOutputDto).outputId); + let outputOffset = 0; + if (cellDiffViewModel instanceof SideBySideDiffElementViewModel) { + outputOffset = cellTop + cellDiffViewModel.getOutputOffsetInCell(false, outputIndex); + } else { + outputOffset = cellTop + (cellDiffViewModel as SingleSideDiffElementViewModel).getOutputOffsetInCell(outputIndex); + } - this._modifiedWebview!.updateViewScrollTop(-scrollTop, true, [{ diffElement: cellDiffViewModel, cell: cellViewModel, output: output.source, cellTop }]); + this._modifiedWebview!.updateViewScrollTop(-scrollTop, true, [{ cell: cellViewModel, output: output.source, cellTop, outputOffset }]); } } }); diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index d7a80939d4c..dcfba890ac8 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -1016,7 +1016,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor this._webview!.element.style.height = `${scrollHeight}px`; if (this._webview?.insetMapping) { - const updateItems: { cell: CodeCellViewModel, output: IDisplayOutputViewModel, cellTop: number }[] = []; + const updateItems: { output: IDisplayOutputViewModel, cellTop: number, outputOffset: number }[] = []; const removedItems: IDisplayOutputViewModel[] = []; this._webview?.insetMapping.forEach((value, key) => { const cell = value.cell; @@ -1033,10 +1033,14 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor const cellTop = this._list.getAbsoluteTopOfElement(cell); if (this._webview!.shouldUpdateInset(cell, key, cellTop)) { + const outputIndex = cell.outputsViewModels.indexOf(key); + + const outputOffset = cellTop + cell.getOutputOffset(outputIndex); + updateItems.push({ - cell: cell, output: key, - cellTop: cellTop + cellTop: cellTop, + outputOffset }); } }); @@ -1860,8 +1864,10 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor } else { const cellTop = this._list.getAbsoluteTopOfElement(cell); const scrollTop = this._list.scrollTop; + const outputIndex = cell.outputsViewModels.indexOf(output.source); + const outputOffset = cellTop + cell.getOutputOffset(outputIndex); - this._webview!.updateViewScrollTop(-scrollTop, true, [{ cell, output: output.source, cellTop }]); + this._webview!.updateViewScrollTop(-scrollTop, true, [{ output: output.source, cellTop, outputOffset }]); } }); } diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index 7f81379160c..bed48e33859 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -609,7 +609,7 @@ var requirejs = (function() { return true; } - updateViewScrollTop(top: number, forceDisplay: boolean, items: { cell: CodeCellViewModel, output: IDisplayOutputViewModel, cellTop: number }[]) { + updateViewScrollTop(top: number, forceDisplay: boolean, items: { output: IDisplayOutputViewModel, cellTop: number, outputOffset: number }[]) { if (this._disposed) { return; } @@ -617,9 +617,7 @@ var requirejs = (function() { const widgets: IContentWidgetTopRequest[] = items.map(item => { const outputCache = this.insetMapping.get(item.output)!; const id = outputCache.outputId; - const outputIndex = item.cell.outputsViewModels.indexOf(item.output); - - const outputOffset = item.cellTop + item.cell.getOutputOffset(outputIndex); + const outputOffset = item.outputOffset; outputCache.cachedCreation.top = outputOffset; this.hiddenInsetMapping.delete(item.output); From 9c70421d47666acfce36212e0335d3b139b25002 Mon Sep 17 00:00:00 2001 From: rebornix Date: Tue, 15 Dec 2020 13:40:00 -0800 Subject: [PATCH 036/262] IDisplayOutputLayoutUpdateRequest. --- .../contrib/notebook/browser/diff/backLayerWebview2.ts | 4 ++-- .../notebook/browser/diff/notebookTextDiffEditor.ts | 8 +++----- src/vs/workbench/contrib/notebook/browser/genericTypes.ts | 8 +++++++- .../contrib/notebook/browser/notebookEditorWidget.ts | 3 ++- .../notebook/browser/view/renderers/backLayerWebView.ts | 3 ++- 5 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts index fb9472a3d5c..548bd9f3385 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts @@ -23,7 +23,7 @@ import { FileAccess, Schemas } from 'vs/base/common/network'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common'; import { DiffElementViewModelBase, SideBySideDiffElementViewModel, SingleSideDiffElementViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; -import { IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; +import { IDisplayOutputLayoutUpdateRequest, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; import { getExtensionForMimeType } from 'vs/base/common/mime'; import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { VSBuffer } from 'vs/base/common/buffer'; @@ -617,7 +617,7 @@ var requirejs = (function() { return true; } - updateViewScrollTop(top: number, forceDisplay: boolean, items: { cell: IGenericCellViewModel, output: IDisplayOutputViewModel, cellTop: number, outputOffset: number }[]) { + updateViewScrollTop(top: number, forceDisplay: boolean, items: IDisplayOutputLayoutUpdateRequest[]) { if (this._disposed) { return; } diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 6cc6767d7c3..03b60f4b9ba 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -42,7 +42,7 @@ import { BackLayerWebView } from 'vs/workbench/contrib/notebook/browser/diff/bac import { generateUuid } from 'vs/base/common/uuid'; import { IMouseWheelEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { DiffNestedCellViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel'; -import { IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; +import { IDisplayOutputLayoutUpdateRequest, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; const $ = DOM.$; @@ -192,7 +192,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD this._modifiedWebview!.element.style.height = `${scrollHeight}px`; if (this._modifiedWebview?.insetMapping) { - const updateItems: { cell: IGenericCellViewModel, output: IDisplayOutputViewModel, cellTop: number, outputOffset: number }[] = []; + const updateItems: IDisplayOutputLayoutUpdateRequest[] = []; const removedItems: IDisplayOutputViewModel[] = []; this._modifiedWebview?.insetMapping.forEach((value, key) => { const cell = value.cell; @@ -218,9 +218,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD outputOffset = cellTop + (value.diffElement as SingleSideDiffElementViewModel).getOutputOffsetInCell(outputIndex); } - updateItems.push({ - cell: cell, output: key, cellTop: cellTop, outputOffset: outputOffset @@ -481,7 +479,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD outputOffset = cellTop + (cellDiffViewModel as SingleSideDiffElementViewModel).getOutputOffsetInCell(outputIndex); } - this._modifiedWebview!.updateViewScrollTop(-scrollTop, true, [{ cell: cellViewModel, output: output.source, cellTop, outputOffset }]); + this._modifiedWebview!.updateViewScrollTop(-scrollTop, true, [{ output: output.source, cellTop, outputOffset }]); } } }); diff --git a/src/vs/workbench/contrib/notebook/browser/genericTypes.ts b/src/vs/workbench/contrib/notebook/browser/genericTypes.ts index 2a011a6697e..dc80abef4fa 100644 --- a/src/vs/workbench/contrib/notebook/browser/genericTypes.ts +++ b/src/vs/workbench/contrib/notebook/browser/genericTypes.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { URI } from 'vs/base/common/uri'; -import { ICellOutputViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { ICellOutputViewModel, IDisplayOutputViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; export interface IGenericCellViewModel { @@ -17,3 +17,9 @@ export interface IGenericCellViewModel { getOutputOffset(index: number): number; updateOutputHeight(index: number, height: number): void; } + +export interface IDisplayOutputLayoutUpdateRequest { + output: IDisplayOutputViewModel; + cellTop: number; + outputOffset: number; +} diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index dcfba890ac8..0a968822785 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -62,6 +62,7 @@ import { editorGutterModifiedBackground } from 'vs/workbench/contrib/scm/browser import { Webview } from 'vs/workbench/contrib/webview/browser/webview'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { configureKernelIcon, errorStateIcon, successStateIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons'; +import { IDisplayOutputLayoutUpdateRequest } from 'vs/workbench/contrib/notebook/browser/genericTypes'; const $ = DOM.$; @@ -1016,7 +1017,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor this._webview!.element.style.height = `${scrollHeight}px`; if (this._webview?.insetMapping) { - const updateItems: { output: IDisplayOutputViewModel, cellTop: number, outputOffset: number }[] = []; + const updateItems: IDisplayOutputLayoutUpdateRequest[] = []; const removedItems: IDisplayOutputViewModel[] = []; this._webview?.insetMapping.forEach((value, key) => { const cell = value.cell; diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index bed48e33859..99ec3784c74 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -26,6 +26,7 @@ import { IFileService } from 'vs/platform/files/common/files'; import { VSBuffer } from 'vs/base/common/buffer'; import { getExtensionForMimeType } from 'vs/base/common/mime'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { IDisplayOutputLayoutUpdateRequest } from 'vs/workbench/contrib/notebook/browser/genericTypes'; export interface WebviewIntialized { __vscode_notebook_message: boolean; @@ -609,7 +610,7 @@ var requirejs = (function() { return true; } - updateViewScrollTop(top: number, forceDisplay: boolean, items: { output: IDisplayOutputViewModel, cellTop: number, outputOffset: number }[]) { + updateViewScrollTop(top: number, forceDisplay: boolean, items: IDisplayOutputLayoutUpdateRequest[]) { if (this._disposed) { return; } From 9694d9f5c964620e6e07dd9315b1bc6996ae59d1 Mon Sep 17 00:00:00 2001 From: rebornix Date: Tue, 15 Dec 2020 14:58:09 -0800 Subject: [PATCH 037/262] move output layout update logic out of back layer webview. --- .../browser/diff/backLayerWebview2.ts | 55 ++++++-------- .../contrib/notebook/browser/diff/common.ts | 7 ++ .../browser/diff/diffElementViewModel.ts | 15 ++++ .../browser/diff/notebookTextDiffEditor.ts | 45 ++++++++--- .../contrib/notebook/browser/genericTypes.ts | 6 ++ .../notebook/browser/notebookBrowser.ts | 5 ++ .../notebook/browser/notebookEditorWidget.ts | 31 ++++++-- .../view/renderers/backLayerWebView.ts | 75 ++++++++++--------- .../viewModel/markdownCellViewModel.ts | 9 +++ 9 files changed, 163 insertions(+), 85 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts index 548bd9f3385..dfda7200276 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts @@ -23,7 +23,7 @@ import { FileAccess, Schemas } from 'vs/base/common/network'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common'; import { DiffElementViewModelBase, SideBySideDiffElementViewModel, SingleSideDiffElementViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; -import { IDisplayOutputLayoutUpdateRequest, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; +import { ICommonCellInfo, IDisplayOutputLayoutUpdateRequest, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; import { getExtensionForMimeType } from 'vs/base/common/mime'; import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { VSBuffer } from 'vs/base/common/buffer'; @@ -198,10 +198,9 @@ export type ToWebviewMessage = export type AnyMessage = FromWebviewMessage | ToWebviewMessage; -interface ICachedInset { +interface ICachedInset { outputId: string; - diffElement: DiffElementViewModelBase; - cell: IGenericCellViewModel; + cellInfo: K; renderer?: INotebookRendererInfo; cachedCreation: ICreationRequestMessage; } @@ -220,10 +219,10 @@ export interface INotebookWebviewMessage { } let version = 0; -export class BackLayerWebView extends Disposable { +export class BackLayerWebView extends Disposable { element: HTMLElement; webview: WebviewElement | undefined = undefined; - insetMapping: Map = new Map(); + insetMapping: Map> = new Map(); hiddenInsetMapping: Set = new Set(); reversedInsetMapping: Map = new Map(); localResourceRootsCache: URI[] | undefined = undefined; @@ -339,7 +338,7 @@ export class BackLayerWebView extends Disposable { }); } - private resolveOutputId(id: string): { cell: IGenericCellViewModel, diffElement: DiffElementViewModelBase, output: IDisplayOutputViewModel } | undefined { + private resolveOutputId(id: string): { cachedInset: ICachedInset, output: IDisplayOutputViewModel } | undefined { const output = this.reversedInsetMapping.get(id); if (!output) { return; @@ -352,7 +351,7 @@ export class BackLayerWebView extends Disposable { // this.insetMapping.get(output)!.cell = currCell as CodeCellViewModel; // } - return { cell: info.cell, diffElement: info.diffElement, output }; + return { cachedInset: info, output }; } async createWebview(): Promise { @@ -461,27 +460,21 @@ var requirejs = (function() { const height = data.data.height; const outputHeight = height; - const info = this.resolveOutputId(data.id); - if (info) { - const { diffElement, cell, output } = info; - const outputIndex = cell.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (output.model as ITransformedDisplayOutputDto).outputId); - if (diffElement instanceof SideBySideDiffElementViewModel) { - diffElement.updateOutputHeight(false, outputIndex, outputHeight); - } else { - (diffElement as SingleSideDiffElementViewModel).updateOutputHeight(outputIndex, outputHeight); - } - // this.notebookEditor.layoutNotebookCell(cell, cell.layoutInfo.totalHeight); + const resolvedResult = this.resolveOutputId(data.id); + if (resolvedResult) { + const { cachedInset, output } = resolvedResult; + this.notebookEditor.updateOutputHeight(cachedInset.cellInfo, output, outputHeight); } } else if (data.type === 'mouseenter') { - const info = this.resolveOutputId(data.id); - if (info) { - const { cell } = info; + const resolvedResult = this.resolveOutputId(data.id); + if (resolvedResult) { + const cell = this.notebookEditor.getCellByInfo(resolvedResult.cachedInset.cellInfo); cell.outputIsHovered = true; } } else if (data.type === 'mouseleave') { - const info = this.resolveOutputId(data.id); - if (info) { - const { cell } = info; + const resolvedResult = this.resolveOutputId(data.id); + if (resolvedResult) { + const cell = this.notebookEditor.getCellByInfo(resolvedResult.cachedInset.cellInfo); cell.outputIsHovered = false; } } else if (data.type === 'scroll-ack') { @@ -646,7 +639,7 @@ var requirejs = (function() { }); } - async createInset(cellDiffViewModel: DiffElementViewModelBase, cell: IGenericCellViewModel, content: IInsetRenderOutput, cellTop: number, offset: number) { + async createInset(cellInfo: T, content: IInsetRenderOutput, cellTop: number, offset: number) { if (this._disposed) { return; } @@ -660,7 +653,7 @@ var requirejs = (function() { this.hiddenInsetMapping.delete(content.source); this._sendMessageToWebview({ type: 'showOutput', - cellId: outputCache.cell.id, + cellId: outputCache.cellInfo.cellId, outputId: outputCache.outputId, top: initialTop }); @@ -670,7 +663,7 @@ var requirejs = (function() { const messageBase = { type: 'html', - cellId: cell.id, + cellId: cellInfo.cellId, top: initialTop, left: 0, requiredPreloads: [], @@ -708,7 +701,7 @@ var requirejs = (function() { } this._sendMessageToWebview(message); - this.insetMapping.set(content.source, { outputId: message.outputId, diffElement: cellDiffViewModel, cell, renderer, cachedCreation: 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); } @@ -728,9 +721,9 @@ var requirejs = (function() { this._sendMessageToWebview({ type: 'clearOutput', apiNamespace: outputCache.cachedCreation.apiNamespace, - cellUri: outputCache.cell.uri.toString(), + cellUri: outputCache.cellInfo.cellUri.toString(), outputId: id, - cellId: outputCache.cell.id + cellId: outputCache.cellInfo.cellId }); this.insetMapping.delete(output); this.reversedInsetMapping.delete(id); @@ -751,7 +744,7 @@ var requirejs = (function() { this._sendMessageToWebview({ type: 'hideOutput', outputId: outputCache.outputId, - cellId: outputCache.cell.id, + cellId: outputCache.cellInfo.cellId, }); } diff --git a/src/vs/workbench/contrib/notebook/browser/diff/common.ts b/src/vs/workbench/contrib/notebook/browser/diff/common.ts index 80b30b9c832..94e15720410 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/common.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/common.ts @@ -14,6 +14,11 @@ import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer'; import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; +import { ICommonCellInfo, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; + +export interface IDiffCellInfo extends ICommonCellInfo { + diffElement: DiffElementViewModelBase; +} export interface INotebookTextDiffEditor { readonly textModel?: NotebookTextModel; @@ -28,6 +33,8 @@ export interface INotebookTextDiffEditor { * Trigger the editor to scroll from scroll event programmatically */ triggerScroll(event: IMouseWheelEvent): void; + getCellByInfo(cellInfo: ICommonCellInfo): IGenericCellViewModel; + updateOutputHeight(cellInfo: ICommonCellInfo, output: IDisplayOutputViewModel, height: number): void; } export interface IDiffNestedCellViewModel { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts index e5a1415708f..464e55126eb 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts @@ -15,6 +15,8 @@ import { format } from 'vs/base/common/jsonFormatter'; import { applyEdits } from 'vs/base/common/jsonEdit'; import { NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { DiffNestedCellViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel'; +import { URI } from 'vs/base/common/uri'; +import { IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; export enum PropertyFoldingState { Expanded, @@ -131,6 +133,7 @@ export abstract class DiffElementViewModelBase extends Disposable { abstract checkIfOutputsModified(): boolean; abstract checkMetadataIfModified(): boolean; abstract layoutChange(): void; + abstract getCellByUri(cellUri: URI): IGenericCellViewModel; getComputedCellContainerWidth(layoutInfo: NotebookLayoutInfo, diffEditor: boolean, fullWidth: boolean) { if (fullWidth) { @@ -231,6 +234,14 @@ export class SideBySideDiffElementViewModel extends DiffElementViewModelBase { getOutputTotalHeight() { return Math.max(this.original.getOutputTotalHeight(), this.modified.getOutputTotalHeight()); } + + getCellByUri(cellUri: URI): IGenericCellViewModel { + if (cellUri.toString() === this.original.uri.toString()) { + return this.original; + } else { + return this.modified; + } + } } export class SingleSideDiffElementViewModel extends DiffElementViewModelBase { @@ -299,6 +310,10 @@ export class SingleSideDiffElementViewModel extends DiffElementViewModelBase { getOutputTotalHeight() { return this.cellViewModel?.getOutputTotalHeight() ?? 0; } + + getCellByUri(cellUri: URI): IGenericCellViewModel { + return this.cellViewModel!; + } } export function getFormatedMetadataJSON(documentTextModel: NotebookTextModel, metadata: NotebookCellMetadata, language?: string) { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 03b60f4b9ba..28befc58c99 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -24,7 +24,7 @@ import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; import { getZoomLevel } from 'vs/base/browser/browser'; import { IDisplayOutputViewModel, IInsetRenderOutput, INotebookEditor, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; -import { DIFF_CELL_MARGIN, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common'; +import { DIFF_CELL_MARGIN, IDiffCellInfo, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common'; import { Emitter } from 'vs/base/common/event'; import { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { NotebookDiffEditorEventDispatcher, NotebookLayoutChangedEvent } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher'; @@ -42,20 +42,22 @@ import { BackLayerWebView } from 'vs/workbench/contrib/notebook/browser/diff/bac import { generateUuid } from 'vs/base/common/uuid'; import { IMouseWheelEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { DiffNestedCellViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel'; -import { IDisplayOutputLayoutUpdateRequest, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; +import { ICommonCellInfo, IDisplayOutputLayoutUpdateRequest, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; const $ = DOM.$; export const IN_NOTEBOOK_TEXT_DIFF_EDITOR = new RawContextKey('isInNotebookTextDiffEditor', false); + export class NotebookTextDiffEditor extends EditorPane implements INotebookTextDiffEditor { static readonly ID: string = 'workbench.editor.notebookTextDiffEditor'; private _rootElement!: HTMLElement; private _overflowContainer!: HTMLElement; private _dimension: DOM.Dimension | null = null; + private _diffElementViewModels: DiffElementViewModelBase[] = []; private _list!: NotebookTextDiffList; - private _modifiedWebview: BackLayerWebView | null = null; + private _modifiedWebview: BackLayerWebView | null = null; private _webviewTransparentCover: HTMLElement | null = null; private _fontInfo: BareFontInfo | undefined; @@ -95,6 +97,18 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD this._outputRenderer = new OutputRenderer(this as unknown as INotebookEditor, this.instantiationService); } + updateOutputHeight(cellInfo: IDiffCellInfo, output: IDisplayOutputViewModel, outputHeight: number): void { + const diffElement = cellInfo.diffElement; + const cell = this.getCellByInfo(cellInfo); + const outputIndex = cell.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (output.model as ITransformedDisplayOutputDto).outputId); + + if (diffElement instanceof SideBySideDiffElementViewModel) { + diffElement.updateOutputHeight(false, outputIndex, outputHeight); + } else { + (diffElement as SingleSideDiffElementViewModel).updateOutputHeight(outputIndex, outputHeight); + } + } + protected createEditor(parent: HTMLElement): void { this._rootElement = DOM.append(parent, DOM.$('.notebook-text-diff-editor')); this._overflowContainer = document.createElement('div'); @@ -195,8 +209,12 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD const updateItems: IDisplayOutputLayoutUpdateRequest[] = []; const removedItems: IDisplayOutputViewModel[] = []; this._modifiedWebview?.insetMapping.forEach((value, key) => { - const cell = value.cell; - const viewIndex = this._list.indexOf(value.diffElement); + const cell = value.cellInfo.diffElement.modified; + if (!cell) { + return; + } + + const viewIndex = this._list.indexOf(value.cellInfo.diffElement); if (viewIndex === undefined) { return; @@ -207,15 +225,15 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD removedItems.push(key); } - const cellTop = this._list.getAbsoluteTopOfElement(value.diffElement); + const cellTop = this._list.getAbsoluteTopOfElement(value.cellInfo.diffElement); if (this._modifiedWebview!.shouldUpdateInset(cell, key, cellTop)) { // TODO: why? does it mean, we create new output view model every time? const outputIndex = cell.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (key.model as ITransformedDisplayOutputDto).outputId); let outputOffset = 0; - if (value.diffElement instanceof SideBySideDiffElementViewModel) { - outputOffset = cellTop + value.diffElement.getOutputOffsetInCell(false, outputIndex); + if (value.cellInfo.diffElement instanceof SideBySideDiffElementViewModel) { + outputOffset = cellTop + value.cellInfo.diffElement.getOutputOffsetInCell(false, outputIndex); } else { - outputOffset = cellTop + (value.diffElement as SingleSideDiffElementViewModel).getOutputOffsetInCell(outputIndex); + outputOffset = cellTop + (value.cellInfo.diffElement as SingleSideDiffElementViewModel).getOutputOffsetInCell(outputIndex); } updateItems.push({ @@ -293,7 +311,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD } private async _createModifiedWebview(id: string, resource: URI): Promise { - this._modifiedWebview = this.instantiationService.createInstance(BackLayerWebView, this, id, resource); + this._modifiedWebview = this.instantiationService.createInstance(BackLayerWebView, this, id, resource) as BackLayerWebView; // attach the webview container to the DOM tree first this._list.rowsContainer.insertAdjacentElement('afterbegin', this._modifiedWebview.element); await this._modifiedWebview.createWebview(); @@ -379,6 +397,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD )); } + this._diffElementViewModels = diffElementViewModels; this._list.splice(0, this._list.length, diffElementViewModels); if (this._revealFirst && firstChangeIndex !== -1) { @@ -467,7 +486,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD if (rightEditor) { if (!this._modifiedWebview!.insetMapping.has(output.source)) { const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel); - await this._modifiedWebview?.createInset(cellDiffViewModel, cellViewModel, output, cellTop, offset); + await this._modifiedWebview?.createInset({ diffElement: cellDiffViewModel, cellHandle: cellViewModel.handle, cellId: cellViewModel.id, cellUri: cellViewModel.uri }, output, cellTop, offset); } else { const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel); const scrollTop = this._list.scrollTop; @@ -485,6 +504,10 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD }); } + getCellByInfo(cellInfo: IDiffCellInfo): IGenericCellViewModel { + return cellInfo.diffElement.getCellByUri(cellInfo.cellUri); + } + removeInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: DiffNestedCellViewModel, output: IInsetRenderOutput) { } diff --git a/src/vs/workbench/contrib/notebook/browser/genericTypes.ts b/src/vs/workbench/contrib/notebook/browser/genericTypes.ts index dc80abef4fa..0ca27ab86c6 100644 --- a/src/vs/workbench/contrib/notebook/browser/genericTypes.ts +++ b/src/vs/workbench/contrib/notebook/browser/genericTypes.ts @@ -23,3 +23,9 @@ export interface IDisplayOutputLayoutUpdateRequest { cellTop: number; outputOffset: number; } + +export interface ICommonCellInfo { + cellId: string; + cellHandle: number; + cellUri: URI; +} diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index 5c8a46f1063..ea6da79cd8e 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -31,6 +31,7 @@ import { EditorOptions } from 'vs/workbench/common/editor'; import { IResourceEditorInput } from 'vs/platform/editor/common/editor'; import { IConstructorSignature1 } from 'vs/platform/instantiation/common/instantiation'; import { CellEditorStatusBar } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellWidgets'; +import { ICommonCellInfo } from 'vs/workbench/contrib/notebook/browser/genericTypes'; export const KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED = new RawContextKey('notebookFindWidgetFocused', false); @@ -185,6 +186,7 @@ export interface ICellViewModel { cellKind: CellKind; editState: CellEditState; focusMode: CellFocusMode; + outputIsHovered: boolean; getText(): string; getTextLength(): number; metadata: NotebookCellMetadata | undefined; @@ -528,6 +530,9 @@ export interface INotebookEditor extends IEditor { * @return The contribution or null if contribution not found. */ getContribution(id: string): T; + + getCellByInfo(cellInfo: ICommonCellInfo): ICellViewModel; + updateOutputHeight(cellInfo: ICommonCellInfo, output: IDisplayOutputViewModel, height: number): void; } export interface INotebookCellList { diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 0a968822785..706350f2caf 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -62,7 +62,7 @@ import { editorGutterModifiedBackground } from 'vs/workbench/contrib/scm/browser import { Webview } from 'vs/workbench/contrib/webview/browser/webview'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { configureKernelIcon, errorStateIcon, successStateIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons'; -import { IDisplayOutputLayoutUpdateRequest } from 'vs/workbench/contrib/notebook/browser/genericTypes'; +import { ICommonCellInfo, IDisplayOutputLayoutUpdateRequest } from 'vs/workbench/contrib/notebook/browser/genericTypes'; const $ = DOM.$; @@ -74,9 +74,9 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor private _overlayContainer!: HTMLElement; private _body!: HTMLElement; private _overflowContainer!: HTMLElement; - private _webview: BackLayerWebView | null = null; + private _webview: BackLayerWebView | null = null; private _webviewResolved: boolean = false; - private _webviewResolvePromise: Promise | null = null; + private _webviewResolvePromise: Promise | null> | null = null; private _webviewTransparentCover: HTMLElement | null = null; private _list!: INotebookCellList; private _dndController: CellDragAndDropController | null = null; @@ -893,7 +893,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor this._notebookExecuting?.set(notebookMetadata.runState === NotebookRunState.Running); } - private async _resolveWebview(): Promise { + private async _resolveWebview(): Promise | null> { if (!this.textModel) { return null; } @@ -1020,7 +1020,12 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor const updateItems: IDisplayOutputLayoutUpdateRequest[] = []; const removedItems: IDisplayOutputViewModel[] = []; this._webview?.insetMapping.forEach((value, key) => { - const cell = value.cell; + const cell = this.viewModel?.getCellByHandle(value.cellInfo.cellHandle); + if (!cell || !(cell instanceof CodeCellViewModel)) { + return; + } + + this.viewModel?.viewCells.find(cell => cell.handle === value.cellInfo.cellHandle); const viewIndex = this._list.getViewIndex(cell); if (viewIndex === undefined) { @@ -1861,7 +1866,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor if (!this._webview!.insetMapping.has(output.source)) { const cellTop = this._list.getAbsoluteTopOfElement(cell); - await this._webview!.createInset(cell, output, cellTop, offset); + await this._webview!.createInset({ cellId: cell.id, cellHandle: cell.handle, cellUri: cell.uri }, output, cellTop, offset); } else { const cellTop = this._list.getAbsoluteTopOfElement(cell); const scrollTop = this._list.scrollTop; @@ -1928,6 +1933,20 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor this._overlayContainer.classList.remove(className); } + getCellByInfo(cellInfo: ICommonCellInfo): ICellViewModel { + const { cellHandle } = cellInfo; + return this.viewModel?.viewCells.find(vc => vc.handle === cellHandle) as CodeCellViewModel; + } + + updateOutputHeight(cellInfo: ICommonCellInfo, output: IDisplayOutputViewModel, outputHeight: number): void { + const cell = this.viewModel?.viewCells.find(vc => vc.handle === cellInfo.cellHandle); + if (cell && cell instanceof CodeCellViewModel) { + const outputIndex = cell.outputsViewModels.indexOf(output); + cell.updateOutputHeight(outputIndex, outputHeight); + this.layoutNotebookCell(cell, cell.layoutInfo.totalHeight); + } + } + //#endregion diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index 99ec3784c74..528342eced6 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -26,7 +26,7 @@ import { IFileService } from 'vs/platform/files/common/files'; import { VSBuffer } from 'vs/base/common/buffer'; import { getExtensionForMimeType } from 'vs/base/common/mime'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { IDisplayOutputLayoutUpdateRequest } from 'vs/workbench/contrib/notebook/browser/genericTypes'; +import { ICommonCellInfo, IDisplayOutputLayoutUpdateRequest } from 'vs/workbench/contrib/notebook/browser/genericTypes'; export interface WebviewIntialized { __vscode_notebook_message: boolean; @@ -197,9 +197,9 @@ export type ToWebviewMessage = export type AnyMessage = FromWebviewMessage | ToWebviewMessage; -interface ICachedInset { +interface ICachedInset { outputId: string; - cell: CodeCellViewModel; + cellInfo: K; renderer?: INotebookRendererInfo; cachedCreation: ICreationRequestMessage; } @@ -218,10 +218,10 @@ export interface INotebookWebviewMessage { } let version = 0; -export class BackLayerWebView extends Disposable { +export class BackLayerWebView extends Disposable { element: HTMLElement; webview: WebviewElement | undefined = undefined; - insetMapping: Map = new Map(); + insetMapping: Map> = new Map(); hiddenInsetMapping: Set = new Set(); reversedInsetMapping: Map = new Map(); localResourceRootsCache: URI[] | undefined = undefined; @@ -337,20 +337,14 @@ export class BackLayerWebView extends Disposable { }); } - private resolveOutputId(id: string): { cell: CodeCellViewModel, output: IDisplayOutputViewModel } | undefined { + private resolveOutputId(id: string): { cellInfo: T, output: IDisplayOutputViewModel } | undefined { const output = this.reversedInsetMapping.get(id); if (!output) { return; } - const cell = this.insetMapping.get(output)!.cell; - - const currCell = this.notebookEditor.viewModel?.viewCells.find(vc => vc.handle === cell.handle); - if (currCell !== cell && currCell !== undefined) { - this.insetMapping.get(output)!.cell = currCell as CodeCellViewModel; - } - - return { cell: this.insetMapping.get(output)!.cell, output }; + const cellInfo = this.insetMapping.get(output)!.cellInfo; + return { cellInfo, output }; } async createWebview(): Promise { @@ -461,22 +455,24 @@ var requirejs = (function() { const info = this.resolveOutputId(data.id); if (info) { - const { cell, output } = info; - const outputIndex = cell.outputsViewModels.indexOf(output); - cell.updateOutputHeight(outputIndex, outputHeight); - this.notebookEditor.layoutNotebookCell(cell, cell.layoutInfo.totalHeight); + const { cellInfo, output } = info; + this.notebookEditor.updateOutputHeight(cellInfo, output, outputHeight); } } else if (data.type === 'mouseenter') { - const info = this.resolveOutputId(data.id); - if (info) { - const { cell } = info; - cell.outputIsHovered = true; + const resolvedResult = this.resolveOutputId(data.id); + if (resolvedResult) { + const latestCell = this.notebookEditor.getCellByInfo(resolvedResult.cellInfo); + if (latestCell) { + latestCell.outputIsHovered = true; + } } } else if (data.type === 'mouseleave') { - const info = this.resolveOutputId(data.id); - if (info) { - const { cell } = info; - cell.outputIsHovered = false; + const resolvedResult = this.resolveOutputId(data.id); + if (resolvedResult) { + const latestCell = this.notebookEditor.getCellByInfo(resolvedResult.cellInfo); + if (latestCell) { + latestCell.outputIsHovered = false; + } } } else if (data.type === 'scroll-ack') { // const date = new Date(); @@ -489,10 +485,15 @@ var requirejs = (function() { stopPropagation: () => { } }); } else if (data.type === 'focus-editor') { - const info = this.resolveOutputId(data.id); - if (info) { + const resolvedResult = this.resolveOutputId(data.id); + if (resolvedResult) { + const latestCell = this.notebookEditor.getCellByInfo(resolvedResult.cellInfo); + if (!latestCell) { + return; + } + if (data.focusNext) { - const idx = this.notebookEditor.viewModel?.getCellIndex(info.cell); + const idx = this.notebookEditor.viewModel?.getCellIndex(latestCell); if (typeof idx !== 'number') { return; } @@ -504,7 +505,7 @@ var requirejs = (function() { this.notebookEditor.focusNotebookCell(newCell, 'editor'); } else { - this.notebookEditor.focusNotebookCell(info.cell, 'editor'); + this.notebookEditor.focusNotebookCell(latestCell, 'editor'); } } } else if (data.type === 'clicked-data-url') { @@ -638,7 +639,7 @@ var requirejs = (function() { }); } - async createInset(cell: CodeCellViewModel, content: IInsetRenderOutput, cellTop: number, offset: number) { + async createInset(cellInfo: T, content: IInsetRenderOutput, cellTop: number, offset: number) { if (this._disposed) { return; } @@ -652,7 +653,7 @@ var requirejs = (function() { this.hiddenInsetMapping.delete(content.source); this._sendMessageToWebview({ type: 'showOutput', - cellId: outputCache.cell.id, + cellId: outputCache.cellInfo.cellId, outputId: outputCache.outputId, top: initialTop }); @@ -662,7 +663,7 @@ var requirejs = (function() { const messageBase = { type: 'html', - cellId: cell.id, + cellId: cellInfo.cellId, top: initialTop, left: 0, requiredPreloads: [], @@ -700,7 +701,7 @@ var requirejs = (function() { } this._sendMessageToWebview(message); - this.insetMapping.set(content.source, { outputId: message.outputId, cell, renderer, cachedCreation: 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); } @@ -720,9 +721,9 @@ var requirejs = (function() { this._sendMessageToWebview({ type: 'clearOutput', apiNamespace: outputCache.cachedCreation.apiNamespace, - cellUri: outputCache.cell.uri.toString(), + cellUri: outputCache.cellInfo.cellUri.toString(), outputId: id, - cellId: outputCache.cell.id + cellId: outputCache.cellInfo.cellId }); this.insetMapping.delete(output); this.reversedInsetMapping.delete(id); @@ -743,7 +744,7 @@ var requirejs = (function() { this._sendMessageToWebview({ type: 'hideOutput', outputId: outputCache.outputId, - cellId: outputCache.cell.id, + cellId: outputCache.cellInfo.cellId, }); } diff --git a/src/vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel.ts b/src/vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel.ts index 75e027a9e1c..cb88e6fe00c 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel.ts @@ -60,6 +60,15 @@ export class MarkdownCellViewModel extends BaseCellViewModel implements ICellVie return this.foldingDelegate.getFoldingState(this.foldingDelegate.getCellIndex(this)); } + private _hoveringOutput: boolean = false; + public get outputIsHovered(): boolean { + return this._hoveringOutput; + } + + public set outputIsHovered(v: boolean) { + this._hoveringOutput = v; + } + constructor( readonly viewType: string, readonly model: NotebookCellTextModel, From fa464a731cce285741d0267f4277d36bb7907e4e Mon Sep 17 00:00:00 2001 From: rebornix Date: Tue, 15 Dec 2020 14:59:42 -0800 Subject: [PATCH 038/262] :guard: --- .../contrib/notebook/browser/diff/backLayerWebview2.ts | 3 +-- .../contrib/notebook/browser/diff/notebookTextDiffEditor.ts | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts index dfda7200276..630aa43d37c 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts @@ -12,7 +12,7 @@ import * as UUID from 'vs/base/common/uuid'; import { IOpenerService, matchesScheme } from 'vs/platform/opener/common/opener'; import { CELL_MARGIN, CELL_RUN_GUTTER, CODE_CELL_LEFT_MARGIN, CELL_OUTPUT_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; import { IDisplayOutputViewModel, IInsetRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; -import { CellOutputKind, IDisplayOutput, INotebookRendererInfo, ITransformedDisplayOutputDto } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellOutputKind, IDisplayOutput, INotebookRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { IWebviewService, WebviewElement, WebviewContentPurpose } from 'vs/workbench/contrib/webview/browser/webview'; import { asWebviewUri } from 'vs/workbench/contrib/webview/common/webviewUri'; @@ -22,7 +22,6 @@ import { preloadsScriptStr } from 'vs/workbench/contrib/notebook/browser/view/re import { FileAccess, Schemas } from 'vs/base/common/network'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common'; -import { DiffElementViewModelBase, SideBySideDiffElementViewModel, SingleSideDiffElementViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; import { ICommonCellInfo, IDisplayOutputLayoutUpdateRequest, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; import { getExtensionForMimeType } from 'vs/base/common/mime'; import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 28befc58c99..6677d7712ae 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -42,7 +42,7 @@ import { BackLayerWebView } from 'vs/workbench/contrib/notebook/browser/diff/bac import { generateUuid } from 'vs/base/common/uuid'; import { IMouseWheelEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { DiffNestedCellViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel'; -import { ICommonCellInfo, IDisplayOutputLayoutUpdateRequest, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; +import { IDisplayOutputLayoutUpdateRequest, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; const $ = DOM.$; @@ -55,7 +55,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD private _rootElement!: HTMLElement; private _overflowContainer!: HTMLElement; private _dimension: DOM.Dimension | null = null; - private _diffElementViewModels: DiffElementViewModelBase[] = []; + // private _diffElementViewModels: DiffElementViewModelBase[] = []; private _list!: NotebookTextDiffList; private _modifiedWebview: BackLayerWebView | null = null; private _webviewTransparentCover: HTMLElement | null = null; @@ -397,7 +397,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD )); } - this._diffElementViewModels = diffElementViewModels; + // this._diffElementViewModels = diffElementViewModels; this._list.splice(0, this._list.length, diffElementViewModels); if (this._revealFirst && firstChangeIndex !== -1) { From c761670411560b4ed61525fa8b68c38cdfc70a69 Mon Sep 17 00:00:00 2001 From: rebornix Date: Tue, 15 Dec 2020 15:10:00 -0800 Subject: [PATCH 039/262] fix build errors --- .../browser/diff/backLayerWebview2.ts | 42 +++++++++---------- .../view/renderers/backLayerWebView.ts | 11 +++-- .../browser/view/renderers/cellContextKeys.ts | 5 +-- .../notebook/test/testNotebookEditor.ts | 9 +++- 4 files changed, 34 insertions(+), 33 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts index 630aa43d37c..edbba675077 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts @@ -20,13 +20,13 @@ import { dirname, joinPath } from 'vs/base/common/resources'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { preloadsScriptStr } from 'vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads'; import { FileAccess, Schemas } from 'vs/base/common/network'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common'; -import { ICommonCellInfo, IDisplayOutputLayoutUpdateRequest, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; -import { getExtensionForMimeType } from 'vs/base/common/mime'; import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { VSBuffer } from 'vs/base/common/buffer'; import { IFileService } from 'vs/platform/files/common/files'; +import { VSBuffer } from 'vs/base/common/buffer'; +import { getExtensionForMimeType } from 'vs/base/common/mime'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { ICommonCellInfo, IDisplayOutputLayoutUpdateRequest, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; export interface WebviewIntialized { __vscode_notebook_message: boolean; @@ -337,27 +337,21 @@ export class BackLayerWebView extends Disposable { }); } - private resolveOutputId(id: string): { cachedInset: ICachedInset, output: IDisplayOutputViewModel } | undefined { + private resolveOutputId(id: string): { cellInfo: T, output: IDisplayOutputViewModel } | undefined { const output = this.reversedInsetMapping.get(id); if (!output) { return; } - const info = this.insetMapping.get(output)!; - - // const currCell = this.notebookEditor.viewModel?.viewCells.find(vc => vc.handle === cell.handle); - // if (currCell !== cell && currCell !== undefined) { - // this.insetMapping.get(output)!.cell = currCell as CodeCellViewModel; - // } - - return { cachedInset: info, output }; + const cellInfo = this.insetMapping.get(output)!.cellInfo; + return { cellInfo, output }; } async createWebview(): Promise { let coreDependencies = ''; let resolveFunc: () => void; - this._initalized = new Promise((resolve) => { + this._initalized = new Promise((resolve, reject) => { resolveFunc = resolve; }); @@ -461,20 +455,24 @@ var requirejs = (function() { const resolvedResult = this.resolveOutputId(data.id); if (resolvedResult) { - const { cachedInset, output } = resolvedResult; - this.notebookEditor.updateOutputHeight(cachedInset.cellInfo, output, outputHeight); + const { cellInfo, output } = resolvedResult; + this.notebookEditor.updateOutputHeight(cellInfo, output, outputHeight); } } else if (data.type === 'mouseenter') { const resolvedResult = this.resolveOutputId(data.id); if (resolvedResult) { - const cell = this.notebookEditor.getCellByInfo(resolvedResult.cachedInset.cellInfo); - cell.outputIsHovered = true; + const latestCell = this.notebookEditor.getCellByInfo(resolvedResult.cellInfo); + if (latestCell) { + latestCell.outputIsHovered = true; + } } } else if (data.type === 'mouseleave') { const resolvedResult = this.resolveOutputId(data.id); if (resolvedResult) { - const cell = this.notebookEditor.getCellByInfo(resolvedResult.cachedInset.cellInfo); - cell.outputIsHovered = false; + const latestCell = this.notebookEditor.getCellByInfo(resolvedResult.cellInfo); + if (latestCell) { + latestCell.outputIsHovered = false; + } } } else if (data.type === 'scroll-ack') { // const date = new Date(); @@ -513,7 +511,6 @@ var requirejs = (function() { return; } - this._onMessage.fire({ message: data }); })); } @@ -570,7 +567,7 @@ var requirejs = (function() { }, undefined); let resolveFunc: () => void; - this._loaded = new Promise((resolve) => { + this._loaded = new Promise((resolve, reject) => { resolveFunc = resolve; }); @@ -618,7 +615,6 @@ var requirejs = (function() { const outputCache = this.insetMapping.get(item.output)!; const id = outputCache.outputId; const outputOffset = item.outputOffset; - outputCache.cachedCreation.top = outputOffset; this.hiddenInsetMapping.delete(item.output); diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index 528342eced6..a61496083ac 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -12,7 +12,6 @@ import * as UUID from 'vs/base/common/uuid'; import { IOpenerService, matchesScheme } from 'vs/platform/opener/common/opener'; import { CELL_MARGIN, CELL_RUN_GUTTER, CODE_CELL_LEFT_MARGIN, CELL_OUTPUT_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; import { IDisplayOutputViewModel, IInsetRenderOutput, INotebookEditor, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; -import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel'; import { CellOutputKind, IDisplayOutput, INotebookRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { IWebviewService, WebviewElement, WebviewContentPurpose } from 'vs/workbench/contrib/webview/browser/webview'; @@ -26,7 +25,7 @@ import { IFileService } from 'vs/platform/files/common/files'; import { VSBuffer } from 'vs/base/common/buffer'; import { getExtensionForMimeType } from 'vs/base/common/mime'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { ICommonCellInfo, IDisplayOutputLayoutUpdateRequest } from 'vs/workbench/contrib/notebook/browser/genericTypes'; +import { ICommonCellInfo, IDisplayOutputLayoutUpdateRequest, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; export interface WebviewIntialized { __vscode_notebook_message: boolean; @@ -453,9 +452,9 @@ var requirejs = (function() { const height = data.data.height; const outputHeight = height; - const info = this.resolveOutputId(data.id); - if (info) { - const { cellInfo, output } = info; + const resolvedResult = this.resolveOutputId(data.id); + if (resolvedResult) { + const { cellInfo, output } = resolvedResult; this.notebookEditor.updateOutputHeight(cellInfo, output, outputHeight); } } else if (data.type === 'mouseenter') { @@ -587,7 +586,7 @@ var requirejs = (function() { return webview; } - shouldUpdateInset(cell: CodeCellViewModel, output: IDisplayOutputViewModel, cellTop: number) { + shouldUpdateInset(cell: IGenericCellViewModel, output: IDisplayOutputViewModel, cellTop: number) { if (this._disposed) { return; } diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellContextKeys.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellContextKeys.ts index 3d138d8840a..bd6cacbaead 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellContextKeys.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellContextKeys.ts @@ -5,7 +5,6 @@ import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { INotebookTextModel, NotebookCellRunState } from 'vs/workbench/contrib/notebook/common/notebookCommon'; -import { BaseCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/baseCellViewModel'; import { NOTEBOOK_CELL_TYPE, NOTEBOOK_VIEW_TYPE, NOTEBOOK_CELL_EDITABLE, NOTEBOOK_CELL_RUNNABLE, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE, NOTEBOOK_CELL_RUN_STATE, NOTEBOOK_CELL_HAS_OUTPUTS, CellViewModelStateChangeEvent, CellEditState, NOTEBOOK_CELL_INPUT_COLLAPSED, NOTEBOOK_CELL_OUTPUT_COLLAPSED, NOTEBOOK_CELL_FOCUSED, INotebookEditor, NOTEBOOK_CELL_EDITOR_FOCUSED, CellFocusMode } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel'; import { MarkdownCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel'; @@ -32,7 +31,7 @@ export class CellContextKeyManager extends Disposable { private readonly contextKeyService: IContextKeyService, private readonly notebookEditor: INotebookEditor, private readonly notebookTextModel: INotebookTextModel, - private element: BaseCellViewModel + private element: CodeCellViewModel | MarkdownCellViewModel ) { super(); @@ -53,7 +52,7 @@ export class CellContextKeyManager extends Disposable { }); } - public updateForElement(element: BaseCellViewModel) { + public updateForElement(element: MarkdownCellViewModel | CodeCellViewModel) { this.elementDisposables.clear(); this.elementDisposables.add(element.onDidChangeState(e => this.onDidChangeState(e))); diff --git a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts index ea7c4180a81..cf5fe7a1636 100644 --- a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts @@ -12,7 +12,7 @@ import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; import { Range } from 'vs/editor/common/core/range'; import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo'; import { EditorModel } from 'vs/workbench/common/editor'; -import { ICellViewModel, INotebookEditor, INotebookEditorContribution, INotebookEditorMouseEvent, NotebookLayoutInfo, INotebookDeltaDecoration, INotebookEditorCreationOptions, NotebookEditorOptions, ICellOutputViewModel, IInsetRenderOutput } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { ICellViewModel, INotebookEditor, INotebookEditorContribution, INotebookEditorMouseEvent, NotebookLayoutInfo, INotebookDeltaDecoration, INotebookEditorCreationOptions, NotebookEditorOptions, ICellOutputViewModel, IInsetRenderOutput, IDisplayOutputViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer'; import { NotebookEventDispatcher } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher'; import { CellViewModel, IModelDecorationsChangeAccessor, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; @@ -36,6 +36,7 @@ import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService import { ScrollEvent } from 'vs/base/common/scrollable'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IFileStatWithMetadata } from 'vs/platform/files/common/files'; +import { ICommonCellInfo } from 'vs/workbench/contrib/notebook/browser/genericTypes'; export class TestCell extends NotebookCellTextModel { constructor( @@ -66,6 +67,12 @@ export class TestNotebookEditor implements INotebookEditor { constructor( ) { } + getCellByInfo(cellInfo: ICommonCellInfo): ICellViewModel { + throw new Error('Method not implemented.'); + } + updateOutputHeight(cellInfo: ICommonCellInfo, output: IDisplayOutputViewModel, height: number): void { + throw new Error('Method not implemented.'); + } async beginComputeContributedKernels(): Promise { return []; } From b56da5e92aa7ba18e9f42b4d4cf7ed06772ab65a Mon Sep 17 00:00:00 2001 From: rebornix Date: Tue, 15 Dec 2020 15:56:25 -0800 Subject: [PATCH 040/262] align backlayer 1 and 2 --- .../browser/diff/backLayerWebview2.ts | 31 ++++++++----------- .../contrib/notebook/browser/diff/common.ts | 2 ++ .../browser/diff/notebookTextDiffEditor.ts | 10 +++++- .../notebook/browser/notebookBrowser.ts | 2 ++ .../notebook/browser/notebookEditorWidget.ts | 14 +++++++++ .../view/renderers/backLayerWebView.ts | 12 +------ 6 files changed, 41 insertions(+), 30 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts index edbba675077..f77d7828d47 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts @@ -484,25 +484,20 @@ var requirejs = (function() { preventDefault: () => { }, stopPropagation: () => { } }); - // } else if (data.type === 'focus-editor') { - // const info = this.resolveOutputId(data.id); - // if (info) { - // if (data.focusNext) { - // const idx = this.notebookEditor.viewModel?.getCellIndex(info.cell); - // if (typeof idx !== 'number') { - // return; - // } + } else if (data.type === 'focus-editor') { + const resolvedResult = this.resolveOutputId(data.id); + if (resolvedResult) { + const latestCell = this.notebookEditor.getCellByInfo(resolvedResult.cellInfo); + if (!latestCell) { + return; + } - // const newCell = this.notebookEditor.viewModel?.viewCells[idx + 1]; - // if (!newCell) { - // return; - // } - - // this.notebookEditor.focusNotebookCell(newCell, 'editor'); - // } else { - // this.notebookEditor.focusNotebookCell(info.cell, 'editor'); - // } - // } + if (data.focusNext) { + this.notebookEditor.focusNextNotebookCell(latestCell, 'editor'); + } else { + this.notebookEditor.focusNotebookCell(latestCell, 'editor'); + } + } } else if (data.type === 'clicked-data-url') { this._onDidClickDataLink(data); } else if (data.type === 'customRendererMessage') { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/common.ts b/src/vs/workbench/contrib/notebook/browser/diff/common.ts index 94e15720410..fb6733298ed 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/common.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/common.ts @@ -34,6 +34,8 @@ export interface INotebookTextDiffEditor { */ triggerScroll(event: IMouseWheelEvent): void; getCellByInfo(cellInfo: ICommonCellInfo): IGenericCellViewModel; + focusNotebookCell(cell: IGenericCellViewModel, focus: 'editor' | 'container' | 'output'): void; + focusNextNotebookCell(cell: IGenericCellViewModel, focus: 'editor' | 'container' | 'output'): void; updateOutputHeight(cellInfo: ICommonCellInfo, output: IDisplayOutputViewModel, height: number): void; } diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 6677d7712ae..16f78c288a0 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -42,7 +42,7 @@ import { BackLayerWebView } from 'vs/workbench/contrib/notebook/browser/diff/bac import { generateUuid } from 'vs/base/common/uuid'; import { IMouseWheelEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { DiffNestedCellViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel'; -import { IDisplayOutputLayoutUpdateRequest, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; +import { ICommonCellInfo, IDisplayOutputLayoutUpdateRequest, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; const $ = DOM.$; @@ -97,6 +97,14 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD this._outputRenderer = new OutputRenderer(this as unknown as INotebookEditor, this.instantiationService); } + focusNotebookCell(cell: IGenericCellViewModel, focus: 'output' | 'editor' | 'container'): void { + // throw new Error('Method not implemented.'); + } + + focusNextNotebookCell(cell: IGenericCellViewModel, focus: 'output' | 'editor' | 'container'): void { + // throw new Error('Method not implemented.'); + } + updateOutputHeight(cellInfo: IDiffCellInfo, output: IDisplayOutputViewModel, outputHeight: number): void { const diffElement = cellInfo.diffElement; const cell = this.getCellByInfo(cellInfo); diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index ea6da79cd8e..ffb0ef98fa4 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -377,6 +377,8 @@ export interface INotebookEditor extends IEditor { */ focusNotebookCell(cell: ICellViewModel, focus: 'editor' | 'container' | 'output'): void; + focusNextNotebookCell(cell: ICellViewModel, focus: 'editor' | 'container' | 'output'): void; + /** * Execute the given notebook cell */ diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 706350f2caf..6e7d34aa768 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -1828,6 +1828,20 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor } } + focusNextNotebookCell(cell: ICellViewModel, focusItem: 'editor' | 'container' | 'output') { + const idx = this.viewModel?.getCellIndex(cell); + if (typeof idx !== 'number') { + return; + } + + const newCell = this.viewModel?.viewCells[idx + 1]; + if (!newCell) { + return; + } + + this.focusNotebookCell(newCell, focusItem); + } + //#endregion //#region MISC diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index a61496083ac..df8a4479b00 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -492,17 +492,7 @@ var requirejs = (function() { } if (data.focusNext) { - const idx = this.notebookEditor.viewModel?.getCellIndex(latestCell); - if (typeof idx !== 'number') { - return; - } - - const newCell = this.notebookEditor.viewModel?.viewCells[idx + 1]; - if (!newCell) { - return; - } - - this.notebookEditor.focusNotebookCell(newCell, 'editor'); + this.notebookEditor.focusNextNotebookCell(latestCell, 'editor'); } else { this.notebookEditor.focusNotebookCell(latestCell, 'editor'); } From 64f7c1b0444d41a2c8b9a9bd40638bd3b4deb039 Mon Sep 17 00:00:00 2001 From: rebornix Date: Tue, 15 Dec 2020 15:57:04 -0800 Subject: [PATCH 041/262] :lipstick: --- .../contrib/notebook/browser/diff/notebookTextDiffEditor.ts | 2 +- src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 16f78c288a0..98f32e0af59 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -42,7 +42,7 @@ import { BackLayerWebView } from 'vs/workbench/contrib/notebook/browser/diff/bac import { generateUuid } from 'vs/base/common/uuid'; import { IMouseWheelEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { DiffNestedCellViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel'; -import { ICommonCellInfo, IDisplayOutputLayoutUpdateRequest, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; +import { IDisplayOutputLayoutUpdateRequest, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; const $ = DOM.$; diff --git a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts index cf5fe7a1636..dacce8299ae 100644 --- a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts @@ -67,6 +67,9 @@ export class TestNotebookEditor implements INotebookEditor { constructor( ) { } + focusNextNotebookCell(cell: ICellViewModel, focus: 'editor' | 'container' | 'output'): void { + throw new Error('Method not implemented.'); + } getCellByInfo(cellInfo: ICommonCellInfo): ICellViewModel { throw new Error('Method not implemented.'); } From 05f69f7bbd3c090a103e3c07e1b8b73973bb60a9 Mon Sep 17 00:00:00 2001 From: rebornix Date: Tue, 15 Dec 2020 16:08:12 -0800 Subject: [PATCH 042/262] share the logic for renderers in webview --- .../notebook/browser/diff/backLayerWebview2.ts | 6 ++---- .../contrib/notebook/browser/diff/common.ts | 4 ++-- .../contrib/notebook/browser/genericTypes.ts | 11 ++++++++++- .../contrib/notebook/browser/notebookBrowser.ts | 6 +++--- .../notebook/browser/notebookEditorWidget.ts | 3 +++ .../browser/view/renderers/backLayerWebView.ts | 7 +++---- .../browser/viewModel/markdownCellViewModel.ts | 14 +++++++++++++- 7 files changed, 36 insertions(+), 15 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts index f77d7828d47..4dab3eba4d3 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts @@ -20,13 +20,12 @@ import { dirname, joinPath } from 'vs/base/common/resources'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { preloadsScriptStr } from 'vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads'; import { FileAccess, Schemas } from 'vs/base/common/network'; -import { INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common'; import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IFileService } from 'vs/platform/files/common/files'; import { VSBuffer } from 'vs/base/common/buffer'; import { getExtensionForMimeType } from 'vs/base/common/mime'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { ICommonCellInfo, IDisplayOutputLayoutUpdateRequest, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; +import { ICommonCellInfo, ICommonNotebookEditor, IDisplayOutputLayoutUpdateRequest, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; export interface WebviewIntialized { __vscode_notebook_message: boolean; @@ -235,7 +234,7 @@ export class BackLayerWebView extends Disposable { private _disposed = false; constructor( - public notebookEditor: INotebookTextDiffEditor, + public notebookEditor: ICommonNotebookEditor, public id: string, public documentUri: URI, @IWebviewService readonly webviewService: IWebviewService, @@ -253,7 +252,6 @@ export class BackLayerWebView extends Disposable { this.element.style.width = `calc(100% - ${CODE_CELL_LEFT_MARGIN + (CELL_MARGIN * 2) + CELL_RUN_GUTTER}px)`; this.element.style.height = '1400px'; this.element.style.position = 'absolute'; - // this.element.style.margin = `0px 0 0px ${CODE_CELL_LEFT_MARGIN + CELL_RUN_GUTTER}px`; } generateContent(outputNodePadding: number, coreDependencies: string, baseUrl: string) { return html` diff --git a/src/vs/workbench/contrib/notebook/browser/diff/common.ts b/src/vs/workbench/contrib/notebook/browser/diff/common.ts index fb6733298ed..9d7b73aeb6c 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/common.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/common.ts @@ -14,13 +14,13 @@ import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer'; import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; -import { ICommonCellInfo, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; +import { ICommonCellInfo, ICommonNotebookEditor, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; export interface IDiffCellInfo extends ICommonCellInfo { diffElement: DiffElementViewModelBase; } -export interface INotebookTextDiffEditor { +export interface INotebookTextDiffEditor extends ICommonNotebookEditor { readonly textModel?: NotebookTextModel; onMouseUp: Event<{ readonly event: MouseEvent; readonly target: DiffElementViewModelBase; }>; getOverflowContainerDomNode(): HTMLElement; diff --git a/src/vs/workbench/contrib/notebook/browser/genericTypes.ts b/src/vs/workbench/contrib/notebook/browser/genericTypes.ts index 0ca27ab86c6..80261d31163 100644 --- a/src/vs/workbench/contrib/notebook/browser/genericTypes.ts +++ b/src/vs/workbench/contrib/notebook/browser/genericTypes.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; import { URI } from 'vs/base/common/uri'; import { ICellOutputViewModel, IDisplayOutputViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; @@ -11,7 +12,7 @@ export interface IGenericCellViewModel { id: string; handle: number; uri: URI; - metadata: NotebookCellMetadata; + metadata: NotebookCellMetadata | undefined; outputIsHovered: boolean; outputsViewModels: ICellOutputViewModel[]; getOutputOffset(index: number): number; @@ -29,3 +30,11 @@ export interface ICommonCellInfo { cellHandle: number; cellUri: URI; } + +export interface ICommonNotebookEditor { + triggerScroll(event: IMouseWheelEvent): void; + getCellByInfo(cellInfo: ICommonCellInfo): IGenericCellViewModel; + focusNotebookCell(cell: IGenericCellViewModel, focus: 'editor' | 'container' | 'output'): void; + focusNextNotebookCell(cell: IGenericCellViewModel, focus: 'editor' | 'container' | 'output'): void; + updateOutputHeight(cellInfo: ICommonCellInfo, output: IDisplayOutputViewModel, height: number): void; +} diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index ffb0ef98fa4..744c663361f 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -31,7 +31,7 @@ import { EditorOptions } from 'vs/workbench/common/editor'; import { IResourceEditorInput } from 'vs/platform/editor/common/editor'; import { IConstructorSignature1 } from 'vs/platform/instantiation/common/instantiation'; import { CellEditorStatusBar } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellWidgets'; -import { ICommonCellInfo } from 'vs/workbench/contrib/notebook/browser/genericTypes'; +import { ICommonCellInfo, ICommonNotebookEditor, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; export const KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED = new RawContextKey('notebookFindWidgetFocused', false); @@ -175,7 +175,7 @@ export interface IStreamOutputViewModel extends ICellOutputViewModel { model: IStreamOutput; } -export interface ICellViewModel { +export interface ICellViewModel extends IGenericCellViewModel { readonly model: NotebookCellTextModel; readonly id: string; readonly textBuffer: IReadonlyTextBuffer; @@ -266,7 +266,7 @@ export interface IActiveNotebookEditor extends INotebookEditor { uri: URI; } -export interface INotebookEditor extends IEditor { +export interface INotebookEditor extends IEditor, ICommonNotebookEditor { isEmbedded: boolean; cursorNavigationMode: boolean; diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 6e7d34aa768..880ba066d17 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -904,6 +904,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor if (!this._webview) { this._webview = this.instantiationService.createInstance(BackLayerWebView, this, this.getId(), this.textModel!.uri); + this._webview.element.style.margin = `0px 0 0px ${CODE_CELL_LEFT_MARGIN + CELL_RUN_GUTTER}px`; + // attach the webview container to the DOM tree first this._list.rowsContainer.insertAdjacentElement('afterbegin', this._webview.element); } @@ -952,6 +954,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor private async _createWebview(id: string, resource: URI): Promise { this._webview = this.instantiationService.createInstance(BackLayerWebView, this, id, resource); + this._webview.element.style.margin = `0px 0 0px ${CODE_CELL_LEFT_MARGIN + CELL_RUN_GUTTER}px`; // attach the webview container to the DOM tree first this._list.rowsContainer.insertAdjacentElement('afterbegin', this._webview.element); } diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index df8a4479b00..4dab3eba4d3 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -11,7 +11,7 @@ import { URI } from 'vs/base/common/uri'; import * as UUID from 'vs/base/common/uuid'; import { IOpenerService, matchesScheme } from 'vs/platform/opener/common/opener'; import { CELL_MARGIN, CELL_RUN_GUTTER, CODE_CELL_LEFT_MARGIN, CELL_OUTPUT_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; -import { IDisplayOutputViewModel, IInsetRenderOutput, INotebookEditor, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { IDisplayOutputViewModel, IInsetRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellOutputKind, IDisplayOutput, INotebookRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { IWebviewService, WebviewElement, WebviewContentPurpose } from 'vs/workbench/contrib/webview/browser/webview'; @@ -25,7 +25,7 @@ import { IFileService } from 'vs/platform/files/common/files'; import { VSBuffer } from 'vs/base/common/buffer'; import { getExtensionForMimeType } from 'vs/base/common/mime'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { ICommonCellInfo, IDisplayOutputLayoutUpdateRequest, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; +import { ICommonCellInfo, ICommonNotebookEditor, IDisplayOutputLayoutUpdateRequest, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; export interface WebviewIntialized { __vscode_notebook_message: boolean; @@ -234,7 +234,7 @@ export class BackLayerWebView extends Disposable { private _disposed = false; constructor( - public notebookEditor: INotebookEditor, + public notebookEditor: ICommonNotebookEditor, public id: string, public documentUri: URI, @IWebviewService readonly webviewService: IWebviewService, @@ -252,7 +252,6 @@ export class BackLayerWebView extends Disposable { this.element.style.width = `calc(100% - ${CODE_CELL_LEFT_MARGIN + (CELL_MARGIN * 2) + CELL_RUN_GUTTER}px)`; this.element.style.height = '1400px'; this.element.style.position = 'absolute'; - this.element.style.margin = `0px 0 0px ${CODE_CELL_LEFT_MARGIN + CELL_RUN_GUTTER}px`; } generateContent(outputNodePadding: number, coreDependencies: string, baseUrl: string) { return html` diff --git a/src/vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel.ts b/src/vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel.ts index cb88e6fe00c..eae9ae0070c 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel.ts @@ -11,7 +11,7 @@ import * as nls from 'vs/nls'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { BOTTOM_CELL_TOOLBAR_GAP, BOTTOM_CELL_TOOLBAR_HEIGHT, CELL_BOTTOM_MARGIN, CELL_MARGIN, CELL_TOP_MARGIN, CODE_CELL_LEFT_MARGIN, COLLAPSED_INDICATOR_HEIGHT } from 'vs/workbench/contrib/notebook/browser/constants'; import { EditorFoldingStateDelegate } from 'vs/workbench/contrib/notebook/browser/contrib/fold/foldingModel'; -import { CellFindMatch, ICellViewModel, MarkdownCellLayoutChangeEvent, MarkdownCellLayoutInfo, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { CellFindMatch, ICellOutputViewModel, ICellViewModel, MarkdownCellLayoutChangeEvent, MarkdownCellLayoutInfo, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { MarkdownRenderer } from 'vs/editor/browser/core/markdownRenderer'; import { BaseCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/baseCellViewModel'; import { NotebookCellStateChangedEvent, NotebookEventDispatcher } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher'; @@ -93,6 +93,18 @@ export class MarkdownCellViewModel extends BaseCellViewModel implements ICellVie })); } + /** + * we put outputs stuff here to make compiler happy + */ + outputsViewModels: ICellOutputViewModel[] = []; + getOutputOffset(index: number): number { + // throw new Error('Method not implemented.'); + return -1; + } + updateOutputHeight(index: number, height: number): void { + // throw new Error('Method not implemented.'); + } + triggerfoldingStateChange() { this._onDidChangeState.fire({ foldingStateChanged: true }); } From 706b8ddf9834fb61b141e89d193a94ae0da2c33e Mon Sep 17 00:00:00 2001 From: rebornix Date: Tue, 15 Dec 2020 16:10:29 -0800 Subject: [PATCH 043/262] single backlayerwebview! --- .../browser/diff/backLayerWebview2.ts | 876 ------------------ .../browser/diff/notebookTextDiffEditor.ts | 2 +- 2 files changed, 1 insertion(+), 877 deletions(-) delete mode 100644 src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts diff --git a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts b/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts deleted file mode 100644 index 4dab3eba4d3..00000000000 --- a/src/vs/workbench/contrib/notebook/browser/diff/backLayerWebview2.ts +++ /dev/null @@ -1,876 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as DOM from 'vs/base/browser/dom'; -import { Emitter, Event } from 'vs/base/common/event'; -import { Disposable } from 'vs/base/common/lifecycle'; -import { isWeb } from 'vs/base/common/platform'; -import { URI } from 'vs/base/common/uri'; -import * as UUID from 'vs/base/common/uuid'; -import { IOpenerService, matchesScheme } from 'vs/platform/opener/common/opener'; -import { CELL_MARGIN, CELL_RUN_GUTTER, CODE_CELL_LEFT_MARGIN, CELL_OUTPUT_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; -import { IDisplayOutputViewModel, IInsetRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; -import { CellOutputKind, IDisplayOutput, INotebookRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookCommon'; -import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; -import { IWebviewService, WebviewElement, WebviewContentPurpose } from 'vs/workbench/contrib/webview/browser/webview'; -import { asWebviewUri } from 'vs/workbench/contrib/webview/common/webviewUri'; -import { dirname, joinPath } from 'vs/base/common/resources'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { preloadsScriptStr } from 'vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads'; -import { FileAccess, Schemas } from 'vs/base/common/network'; -import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { IFileService } from 'vs/platform/files/common/files'; -import { VSBuffer } from 'vs/base/common/buffer'; -import { getExtensionForMimeType } from 'vs/base/common/mime'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { ICommonCellInfo, ICommonNotebookEditor, IDisplayOutputLayoutUpdateRequest, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; - -export interface WebviewIntialized { - __vscode_notebook_message: boolean; - type: 'initialized' -} - -export interface IDimensionMessage { - __vscode_notebook_message: boolean; - type: 'dimension'; - id: string; - data: DOM.Dimension; -} - -export interface IMouseEnterMessage { - __vscode_notebook_message: boolean; - type: 'mouseenter'; - id: string; -} - -export interface IMouseLeaveMessage { - __vscode_notebook_message: boolean; - type: 'mouseleave'; - id: string; -} - -export interface IWheelMessage { - __vscode_notebook_message: boolean; - type: 'did-scroll-wheel'; - payload: any; -} - - -export interface IScrollAckMessage { - __vscode_notebook_message: boolean; - type: 'scroll-ack'; - data: { top: number }; - version: number; -} - -export interface IBlurOutputMessage { - __vscode_notebook_message: boolean; - type: 'focus-editor'; - id: string; - focusNext?: boolean; -} - -export interface IClickedDataUrlMessage { - __vscode_notebook_message: boolean; - type: 'clicked-data-url'; - data: string; - downloadName?: string; -} - -export interface IClearMessage { - type: 'clear'; -} - -export interface ICreationRequestMessage { - type: 'html'; - content: - | { type: RenderOutputType.Html; htmlContent: string } - | { type: RenderOutputType.Extension; output: IDisplayOutput; mimeType: string }; - cellId: string; - outputId: string; - top: number; - left: number; - requiredPreloads: ReadonlyArray; - initiallyHidden?: boolean; - apiNamespace?: string | undefined; -} - -export interface IContentWidgetTopRequest { - id: string; - top: number; - left: number; -} - -export interface IViewScrollTopRequestMessage { - type: 'view-scroll'; - top?: number; - forceDisplay: boolean; - widgets: IContentWidgetTopRequest[]; - version: number; -} - -export interface IScrollRequestMessage { - type: 'scroll'; - id: string; - top: number; - widgetTop?: number; - version: number; -} - -export interface IClearOutputRequestMessage { - type: 'clearOutput'; - cellId: string; - outputId: string; - cellUri: string; - apiNamespace: string | undefined; -} - -export interface IHideOutputMessage { - type: 'hideOutput'; - outputId: string; - cellId: string; -} - -export interface IShowOutputMessage { - type: 'showOutput'; - cellId: string; - outputId: string; - top: number; -} - -export interface IFocusOutputMessage { - type: 'focus-output'; - cellId: string; -} - -export interface IPreloadResource { - originalUri: string; - uri: string; -} - -export interface IUpdatePreloadResourceMessage { - type: 'preload'; - resources: IPreloadResource[]; - source: 'renderer' | 'kernel'; -} - -export interface IUpdateDecorationsMessage { - type: 'decorations'; - cellId: string; - addedClassNames: string[]; - removedClassNames: string[]; -} - -export interface ICustomRendererMessage { - __vscode_notebook_message: boolean; - type: 'customRendererMessage'; - rendererId: string; - message: unknown; -} - -export type FromWebviewMessage = - | WebviewIntialized - | IDimensionMessage - | IMouseEnterMessage - | IMouseLeaveMessage - | IWheelMessage - | IScrollAckMessage - | IBlurOutputMessage - | ICustomRendererMessage - | IClickedDataUrlMessage; - -export type ToWebviewMessage = - | IClearMessage - | IFocusOutputMessage - | ICreationRequestMessage - | IViewScrollTopRequestMessage - | IScrollRequestMessage - | IClearOutputRequestMessage - | IHideOutputMessage - | IShowOutputMessage - | IUpdatePreloadResourceMessage - | IUpdateDecorationsMessage - | ICustomRendererMessage; - -export type AnyMessage = FromWebviewMessage | ToWebviewMessage; - -interface ICachedInset { - outputId: string; - cellInfo: K; - renderer?: INotebookRendererInfo; - cachedCreation: ICreationRequestMessage; -} - -function html(strings: TemplateStringsArray, ...values: any[]): string { - let str = ''; - strings.forEach((string, i) => { - str += string + (values[i] || ''); - }); - return str; -} - -export interface INotebookWebviewMessage { - message: unknown; - forRenderer?: string; -} - -let version = 0; -export class BackLayerWebView extends Disposable { - element: HTMLElement; - webview: WebviewElement | undefined = undefined; - insetMapping: Map> = new Map(); - hiddenInsetMapping: Set = new Set(); - reversedInsetMapping: Map = new Map(); - localResourceRootsCache: URI[] | undefined = undefined; - rendererRootsCache: URI[] = []; - kernelRootsCache: URI[] = []; - private readonly _onMessage = this._register(new Emitter()); - private readonly _preloadsCache = new Set(); - public readonly onMessage: Event = this._onMessage.event; - private _loaded!: Promise; - private _initalized?: Promise; - private _disposed = false; - - constructor( - public notebookEditor: ICommonNotebookEditor, - public id: string, - public documentUri: URI, - @IWebviewService readonly webviewService: IWebviewService, - @IOpenerService readonly openerService: IOpenerService, - @INotebookService private readonly notebookService: INotebookService, - @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, - @IFileDialogService private readonly fileDialogService: IFileDialogService, - @IFileService private readonly fileService: IFileService, - ) { - super(); - - this.element = document.createElement('div'); - - this.element.style.width = `calc(100% - ${CODE_CELL_LEFT_MARGIN + (CELL_MARGIN * 2) + CELL_RUN_GUTTER}px)`; - this.element.style.height = '1400px'; - this.element.style.position = 'absolute'; - } - generateContent(outputNodePadding: number, coreDependencies: string, baseUrl: string) { - return html` - - - - - - - - - ${coreDependencies} -
- - - `; - } - - postRendererMessage(rendererId: string, message: any) { - this._sendMessageToWebview({ - __vscode_notebook_message: true, - type: 'customRendererMessage', - message, - rendererId - }); - } - - private resolveOutputId(id: string): { cellInfo: T, output: IDisplayOutputViewModel } | undefined { - const output = this.reversedInsetMapping.get(id); - if (!output) { - return; - } - - const cellInfo = this.insetMapping.get(output)!.cellInfo; - return { cellInfo, output }; - } - - async createWebview(): Promise { - let coreDependencies = ''; - let resolveFunc: () => void; - - this._initalized = new Promise((resolve, reject) => { - resolveFunc = resolve; - }); - - const baseUrl = asWebviewUri(this.environmentService, this.id, dirname(this.documentUri)); - - if (!isWeb) { - const loaderUri = FileAccess.asFileUri('vs/loader.js', require); - const loader = asWebviewUri(this.environmentService, this.id, loaderUri); - - coreDependencies = ``; - const htmlContent = this.generateContent(CELL_OUTPUT_PADDING, coreDependencies, baseUrl.toString()); - this._initialize(htmlContent); - resolveFunc!(); - } else { - const loaderUri = FileAccess.asBrowserUri('vs/loader.js', require); - - fetch(loaderUri.toString(true)).then(async response => { - if (response.status !== 200) { - throw new Error(response.statusText); - } - - const loaderJs = await response.text(); - - coreDependencies = ` - - -`; - - const htmlContent = this.generateContent(CELL_OUTPUT_PADDING, coreDependencies, baseUrl.toString()); - this._initialize(htmlContent); - resolveFunc!(); - }); - } - - await this._initalized; - } - - private async _initialize(content: string) { - if (!document.body.contains(this.element)) { - throw new Error('Element is already detached from the DOM tree'); - } - - this.webview = this._createInset(this.webviewService, content); - this.webview.mountTo(this.element); - this._register(this.webview); - - this._register(this.webview.onDidClickLink(link => { - if (this._disposed) { - return; - } - - if (!link) { - return; - } - - if (matchesScheme(link, Schemas.http) || matchesScheme(link, Schemas.https) || matchesScheme(link, Schemas.mailto) - || matchesScheme(link, Schemas.command)) { - this.openerService.open(link, { fromUserGesture: true }); - } - })); - - this._register(this.webview.onDidReload(() => { - if (this._disposed) { - return; - } - - let renderers = new Set(); - for (const inset of this.insetMapping.values()) { - if (inset.renderer) { - renderers.add(inset.renderer); - } - } - - this._preloadsCache.clear(); - this.updateRendererPreloads(renderers); - - for (const [output, inset] of this.insetMapping.entries()) { - this._sendMessageToWebview({ ...inset.cachedCreation, initiallyHidden: this.hiddenInsetMapping.has(output) }); - } - })); - - this._register(this.webview.onMessage((data: FromWebviewMessage) => { - if (this._disposed) { - return; - } - - if (data.__vscode_notebook_message) { - if (data.type === 'dimension') { - const height = data.data.height; - const outputHeight = height; - - const resolvedResult = this.resolveOutputId(data.id); - if (resolvedResult) { - const { cellInfo, output } = resolvedResult; - this.notebookEditor.updateOutputHeight(cellInfo, output, outputHeight); - } - } else if (data.type === 'mouseenter') { - const resolvedResult = this.resolveOutputId(data.id); - if (resolvedResult) { - const latestCell = this.notebookEditor.getCellByInfo(resolvedResult.cellInfo); - if (latestCell) { - latestCell.outputIsHovered = true; - } - } - } else if (data.type === 'mouseleave') { - const resolvedResult = this.resolveOutputId(data.id); - if (resolvedResult) { - const latestCell = this.notebookEditor.getCellByInfo(resolvedResult.cellInfo); - if (latestCell) { - latestCell.outputIsHovered = false; - } - } - } 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 === 'did-scroll-wheel') { - this.notebookEditor.triggerScroll({ - ...data.payload, - preventDefault: () => { }, - stopPropagation: () => { } - }); - } else if (data.type === 'focus-editor') { - const resolvedResult = this.resolveOutputId(data.id); - if (resolvedResult) { - const latestCell = this.notebookEditor.getCellByInfo(resolvedResult.cellInfo); - if (!latestCell) { - return; - } - - if (data.focusNext) { - this.notebookEditor.focusNextNotebookCell(latestCell, 'editor'); - } else { - this.notebookEditor.focusNotebookCell(latestCell, 'editor'); - } - } - } else if (data.type === 'clicked-data-url') { - this._onDidClickDataLink(data); - } else if (data.type === 'customRendererMessage') { - this._onMessage.fire({ message: data.message, forRenderer: data.rendererId }); - } - return; - } - - this._onMessage.fire({ message: data }); - })); - } - - private async _onDidClickDataLink(event: IClickedDataUrlMessage): Promise { - const [splitStart, splitData] = event.data.split(';base64,'); - if (!splitData || !splitStart) { - return; - } - - const defaultDir = dirname(this.documentUri); - let defaultName: string; - if (event.downloadName) { - defaultName = event.downloadName; - } else { - const mimeType = splitStart.replace(/^data:/, ''); - const candidateExtension = mimeType && getExtensionForMimeType(mimeType); - defaultName = candidateExtension ? `download${candidateExtension}` : 'download'; - } - - const defaultUri = joinPath(defaultDir, defaultName); - const newFileUri = await this.fileDialogService.showSaveDialog({ - defaultUri - }); - if (!newFileUri) { - return; - } - - const decoded = atob(splitData); - const typedArray = new Uint8Array(decoded.length); - for (let i = 0; i < decoded.length; i++) { - typedArray[i] = decoded.charCodeAt(i); - } - - const buff = VSBuffer.wrap(typedArray); - await this.fileService.writeFile(newFileUri, buff); - await this.openerService.open(newFileUri); - } - - private _createInset(webviewService: IWebviewService, content: string) { - const rootPath = isWeb ? FileAccess.asBrowserUri('', require) : FileAccess.asFileUri('', require); - - const workspaceFolders = this.contextService.getWorkspace().folders.map(x => x.uri); - - this.localResourceRootsCache = [...this.notebookService.getNotebookProviderResourceRoots(), ...workspaceFolders, rootPath]; - - const webview = webviewService.createWebviewElement(this.id, { - purpose: WebviewContentPurpose.NotebookRenderer, - enableFindWidget: false, - }, { - allowMultipleAPIAcquire: true, - allowScripts: true, - localResourceRoots: this.localResourceRootsCache - }, undefined); - - let resolveFunc: () => void; - this._loaded = new Promise((resolve, reject) => { - resolveFunc = resolve; - }); - - const dispose = webview.onMessage((data: FromWebviewMessage) => { - if (data.__vscode_notebook_message && data.type === 'initialized') { - resolveFunc(); - dispose.dispose(); - } - }); - - webview.html = content; - return webview; - } - - shouldUpdateInset(cell: IGenericCellViewModel, output: IDisplayOutputViewModel, cellTop: number) { - if (this._disposed) { - return; - } - - if (cell.metadata?.outputCollapsed) { - return false; - } - - const outputCache = this.insetMapping.get(output)!; - const outputIndex = cell.outputsViewModels.indexOf(output); - const outputOffset = cellTop + cell.getOutputOffset(outputIndex); - - if (this.hiddenInsetMapping.has(output)) { - return true; - } - - if (outputOffset === outputCache.cachedCreation.top) { - return false; - } - - return true; - } - - updateViewScrollTop(top: number, forceDisplay: boolean, items: IDisplayOutputLayoutUpdateRequest[]) { - if (this._disposed) { - return; - } - - const widgets: IContentWidgetTopRequest[] = items.map(item => { - const outputCache = this.insetMapping.get(item.output)!; - const id = outputCache.outputId; - const outputOffset = item.outputOffset; - outputCache.cachedCreation.top = outputOffset; - this.hiddenInsetMapping.delete(item.output); - - return { - id: id, - top: outputOffset, - left: 0 - }; - }); - - this._sendMessageToWebview({ - top, - type: 'view-scroll', - version: version++, - forceDisplay, - widgets: widgets - }); - } - - async createInset(cellInfo: T, content: IInsetRenderOutput, cellTop: number, offset: number) { - if (this._disposed) { - return; - } - - const initialTop = cellTop + offset; - - if (this.insetMapping.has(content.source)) { - const outputCache = this.insetMapping.get(content.source); - - if (outputCache) { - this.hiddenInsetMapping.delete(content.source); - this._sendMessageToWebview({ - type: 'showOutput', - cellId: outputCache.cellInfo.cellId, - outputId: outputCache.outputId, - top: initialTop - }); - return; - } - } - - const messageBase = { - type: 'html', - cellId: cellInfo.cellId, - top: initialTop, - 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; - message = { - ...messageBase, - outputId: output.outputId, - apiNamespace: content.renderer.id, - requiredPreloads: await this.updateRendererPreloads([content.renderer]), - content: { - type: RenderOutputType.Extension, - mimeType: content.mimeType, - output: { - outputKind: CellOutputKind.Rich, - metadata: output.metadata, - data: output.data, - }, - }, - }; - } else { - message = { - ...messageBase, - outputId: UUID.generateUuid(), - content: { - type: content.type, - htmlContent: content.htmlContent, - } - }; - } - - 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); - } - - removeInset(output: IDisplayOutputViewModel) { - if (this._disposed) { - return; - } - - const outputCache = this.insetMapping.get(output); - if (!outputCache) { - return; - } - - const id = outputCache.outputId; - - this._sendMessageToWebview({ - type: 'clearOutput', - apiNamespace: outputCache.cachedCreation.apiNamespace, - cellUri: outputCache.cellInfo.cellUri.toString(), - outputId: id, - cellId: outputCache.cellInfo.cellId - }); - this.insetMapping.delete(output); - this.reversedInsetMapping.delete(id); - } - - hideInset(output: IDisplayOutputViewModel) { - if (this._disposed) { - return; - } - - const outputCache = this.insetMapping.get(output); - if (!outputCache) { - return; - } - - this.hiddenInsetMapping.add(output); - - this._sendMessageToWebview({ - type: 'hideOutput', - outputId: outputCache.outputId, - cellId: outputCache.cellInfo.cellId, - }); - } - - clearInsets() { - if (this._disposed) { - return; - } - - this._sendMessageToWebview({ - type: 'clear' - }); - - this.insetMapping = new Map(); - this.reversedInsetMapping = new Map(); - } - - focusWebview() { - if (this._disposed) { - return; - } - - this.webview?.focus(); - } - - focusOutput(cellId: string) { - if (this._disposed) { - return; - } - - this.webview?.focus(); - setTimeout(() => { // Need this, or focus decoration is not shown. No clue. - this._sendMessageToWebview({ - type: 'focus-output', - cellId, - }); - }, 50); - } - - deltaCellOutputContainerClassNames(cellId: string, added: string[], removed: string[]) { - this._sendMessageToWebview({ - type: 'decorations', - cellId, - addedClassNames: added, - removedClassNames: removed - }); - - } - - async updateKernelPreloads(extensionLocations: URI[], preloads: URI[]) { - if (this._disposed) { - return; - } - - await this._loaded; - - const resources: IPreloadResource[] = []; - for (const preload of preloads) { - const uri = this.environmentService.isExtensionDevelopment && (preload.scheme === 'http' || preload.scheme === 'https') - ? preload : asWebviewUri(this.environmentService, this.id, preload); - - if (!this._preloadsCache.has(uri.toString())) { - resources.push({ uri: uri.toString(), originalUri: preload.toString() }); - this._preloadsCache.add(uri.toString()); - } - } - - if (!resources.length) { - return; - } - - this.kernelRootsCache = [...extensionLocations, ...this.kernelRootsCache]; - this._updatePreloads(resources, 'kernel'); - } - - async updateRendererPreloads(renderers: Iterable) { - if (this._disposed) { - return []; - } - - await this._loaded; - - const requiredPreloads: IPreloadResource[] = []; - const resources: IPreloadResource[] = []; - const extensionLocations: URI[] = []; - for (const rendererInfo of renderers) { - extensionLocations.push(rendererInfo.extensionLocation); - for (const preload of [rendererInfo.entrypoint, ...rendererInfo.preloads]) { - const uri = asWebviewUri(this.environmentService, this.id, preload); - const resource: IPreloadResource = { uri: uri.toString(), originalUri: preload.toString() }; - requiredPreloads.push(resource); - - if (!this._preloadsCache.has(uri.toString())) { - resources.push(resource); - this._preloadsCache.add(uri.toString()); - } - } - } - - if (!resources.length) { - return requiredPreloads; - } - - this.rendererRootsCache = extensionLocations; - this._updatePreloads(resources, 'renderer'); - return requiredPreloads; - } - - private _updatePreloads(resources: IPreloadResource[], source: 'renderer' | 'kernel') { - if (!this.webview) { - return; - } - - const mixedResourceRoots = [...(this.localResourceRootsCache || []), ...this.rendererRootsCache, ...this.kernelRootsCache]; - - this.webview.localResourcesRoot = mixedResourceRoots; - - this._sendMessageToWebview({ - type: 'preload', - resources: resources, - source: source - }); - } - - private _sendMessageToWebview(message: ToWebviewMessage) { - if (this._disposed) { - return; - } - - this.webview?.postMessage(message); - } - - clearPreloadsCache() { - this._preloadsCache.clear(); - } - - dispose() { - this._disposed = true; - this.webview?.dispose(); - super.dispose(); - } -} diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 98f32e0af59..0963288f036 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -38,11 +38,11 @@ import { IDiffChange } from 'vs/base/common/diff/diff'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer'; import { SequencerByKey } from 'vs/base/common/async'; -import { BackLayerWebView } from 'vs/workbench/contrib/notebook/browser/diff/backLayerWebview2'; import { generateUuid } from 'vs/base/common/uuid'; import { IMouseWheelEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { DiffNestedCellViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel'; import { IDisplayOutputLayoutUpdateRequest, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; +import { BackLayerWebView } from 'vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView'; const $ = DOM.$; From 86838823e3b919095d19dcfec53ae8f4a1142639 Mon Sep 17 00:00:00 2001 From: rebornix Date: Tue, 15 Dec 2020 16:17:47 -0800 Subject: [PATCH 044/262] move genericTypes into notebookBrowser --- .../contrib/notebook/browser/diff/common.ts | 3 +- .../browser/diff/diffElementViewModel.ts | 3 +- .../browser/diff/diffNestedCellViewModel.ts | 3 +- .../browser/diff/notebookTextDiffEditor.ts | 3 +- .../contrib/notebook/browser/genericTypes.ts | 40 ------------------- .../notebook/browser/notebookBrowser.ts | 36 ++++++++++++++++- .../notebook/browser/notebookEditorWidget.ts | 3 +- .../view/renderers/backLayerWebView.ts | 3 +- .../notebook/test/testNotebookEditor.ts | 3 +- 9 files changed, 42 insertions(+), 55 deletions(-) delete mode 100644 src/vs/workbench/contrib/notebook/browser/genericTypes.ts diff --git a/src/vs/workbench/contrib/notebook/browser/diff/common.ts b/src/vs/workbench/contrib/notebook/browser/diff/common.ts index 9d7b73aeb6c..e8a45767398 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/common.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/common.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IDisplayOutputViewModel, IInsetRenderOutput, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { ICommonCellInfo, ICommonNotebookEditor, IDisplayOutputViewModel, IGenericCellViewModel, IInsetRenderOutput, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { DiffElementViewModelBase } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; import { Event } from 'vs/base/common/event'; import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; @@ -14,7 +14,6 @@ import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer'; import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; -import { ICommonCellInfo, ICommonNotebookEditor, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; export interface IDiffCellInfo extends ICommonCellInfo { diffElement: DiffElementViewModelBase; diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts index 464e55126eb..cfb29fecca0 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts @@ -7,7 +7,7 @@ import { NotebookDiffEditorEventDispatcher } from 'vs/workbench/contrib/notebook import { Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { CellDiffViewModelLayoutChangeEvent, DIFF_CELL_MARGIN } from 'vs/workbench/contrib/notebook/browser/diff/common'; -import { NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { IGenericCellViewModel, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; import { hash } from 'vs/base/common/hash'; @@ -16,7 +16,6 @@ import { applyEdits } from 'vs/base/common/jsonEdit'; import { NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { DiffNestedCellViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel'; import { URI } from 'vs/base/common/uri'; -import { IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; export enum PropertyFoldingState { Expanded, diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel.ts index 050b6feb951..f5bdbfc8037 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel.ts @@ -8,8 +8,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { generateUuid } from 'vs/base/common/uuid'; import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer'; import { IDiffNestedCellViewModel } from 'vs/workbench/contrib/notebook/browser/diff/common'; -import { IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; -import { CellViewModelStateChangeEvent, ICellOutputViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { CellViewModelStateChangeEvent, ICellOutputViewModel, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellOutputViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 0963288f036..f19a874b806 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -23,7 +23,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; import { getZoomLevel } from 'vs/base/browser/browser'; -import { IDisplayOutputViewModel, IInsetRenderOutput, INotebookEditor, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { IDisplayOutputLayoutUpdateRequest, IDisplayOutputViewModel, IGenericCellViewModel, IInsetRenderOutput, INotebookEditor, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { DIFF_CELL_MARGIN, IDiffCellInfo, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common'; import { Emitter } from 'vs/base/common/event'; import { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; @@ -41,7 +41,6 @@ import { SequencerByKey } from 'vs/base/common/async'; import { generateUuid } from 'vs/base/common/uuid'; import { IMouseWheelEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { DiffNestedCellViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel'; -import { IDisplayOutputLayoutUpdateRequest, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; import { BackLayerWebView } from 'vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView'; const $ = DOM.$; diff --git a/src/vs/workbench/contrib/notebook/browser/genericTypes.ts b/src/vs/workbench/contrib/notebook/browser/genericTypes.ts deleted file mode 100644 index 80261d31163..00000000000 --- a/src/vs/workbench/contrib/notebook/browser/genericTypes.ts +++ /dev/null @@ -1,40 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; -import { URI } from 'vs/base/common/uri'; -import { ICellOutputViewModel, IDisplayOutputViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; -import { NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; - -export interface IGenericCellViewModel { - id: string; - handle: number; - uri: URI; - metadata: NotebookCellMetadata | undefined; - outputIsHovered: boolean; - outputsViewModels: ICellOutputViewModel[]; - getOutputOffset(index: number): number; - updateOutputHeight(index: number, height: number): void; -} - -export interface IDisplayOutputLayoutUpdateRequest { - output: IDisplayOutputViewModel; - cellTop: number; - outputOffset: number; -} - -export interface ICommonCellInfo { - cellId: string; - cellHandle: number; - cellUri: URI; -} - -export interface ICommonNotebookEditor { - triggerScroll(event: IMouseWheelEvent): void; - getCellByInfo(cellInfo: ICommonCellInfo): IGenericCellViewModel; - focusNotebookCell(cell: IGenericCellViewModel, focus: 'editor' | 'container' | 'output'): void; - focusNextNotebookCell(cell: IGenericCellViewModel, focus: 'editor' | 'container' | 'output'): void; - updateOutputHeight(cellInfo: ICommonCellInfo, output: IDisplayOutputViewModel, height: number): void; -} diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index 744c663361f..024bdb5aa2c 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -31,7 +31,6 @@ import { EditorOptions } from 'vs/workbench/common/editor'; import { IResourceEditorInput } from 'vs/platform/editor/common/editor'; import { IConstructorSignature1 } from 'vs/platform/instantiation/common/instantiation'; import { CellEditorStatusBar } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellWidgets'; -import { ICommonCellInfo, ICommonNotebookEditor, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; export const KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED = new RawContextKey('notebookFindWidgetFocused', false); @@ -67,6 +66,41 @@ export const EXECUTE_CELL_COMMAND_ID = 'notebook.cell.execute'; export const NOTEBOOK_HAS_MULTIPLE_KERNELS = new RawContextKey('notebookHasMultipleKernels', false); + +// These are types shared by the Notebook Editor and Notebook Diff Editor + +export interface IGenericCellViewModel { + id: string; + handle: number; + uri: URI; + metadata: NotebookCellMetadata | undefined; + outputIsHovered: boolean; + outputsViewModels: ICellOutputViewModel[]; + getOutputOffset(index: number): number; + updateOutputHeight(index: number, height: number): void; +} + +export interface IDisplayOutputLayoutUpdateRequest { + output: IDisplayOutputViewModel; + cellTop: number; + outputOffset: number; +} + +export interface ICommonCellInfo { + cellId: string; + cellHandle: number; + cellUri: URI; +} + +export interface ICommonNotebookEditor { + triggerScroll(event: IMouseWheelEvent): void; + getCellByInfo(cellInfo: ICommonCellInfo): IGenericCellViewModel; + focusNotebookCell(cell: IGenericCellViewModel, focus: 'editor' | 'container' | 'output'): void; + focusNextNotebookCell(cell: IGenericCellViewModel, focus: 'editor' | 'container' | 'output'): void; + updateOutputHeight(cellInfo: ICommonCellInfo, output: IDisplayOutputViewModel, height: number): void; +} + + export interface NotebookLayoutInfo { width: number; height: number; diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 880ba066d17..b69f21df8bb 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -42,7 +42,7 @@ import { Memento, MementoObject } from 'vs/workbench/common/memento'; import { PANEL_BORDER } from 'vs/workbench/common/theme'; import { debugIconStartForeground } from 'vs/workbench/contrib/debug/browser/debugToolBar'; import { BOTTOM_CELL_TOOLBAR_GAP, BOTTOM_CELL_TOOLBAR_HEIGHT, CELL_BOTTOM_MARGIN, CELL_MARGIN, CELL_RUN_GUTTER, CELL_TOP_MARGIN, CODE_CELL_LEFT_MARGIN, COLLAPSED_INDICATOR_HEIGHT, SCROLLABLE_ELEMENT_PADDING_TOP } from 'vs/workbench/contrib/notebook/browser/constants'; -import { CellEditState, CellFocusMode, IActiveNotebookEditor, ICellOutputViewModel, ICellViewModel, IDisplayOutputViewModel, IInsetRenderOutput, INotebookCellList, INotebookDeltaDecoration, INotebookEditor, INotebookEditorContribution, INotebookEditorContributionDescription, INotebookEditorCreationOptions, INotebookEditorMouseEvent, NotebookEditorOptions, NotebookLayoutInfo, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_RUNNABLE, NOTEBOOK_HAS_MULTIPLE_KERNELS, NOTEBOOK_OUTPUT_FOCUSED } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { CellEditState, CellFocusMode, IActiveNotebookEditor, ICellOutputViewModel, ICellViewModel, ICommonCellInfo, IDisplayOutputLayoutUpdateRequest, IDisplayOutputViewModel, IInsetRenderOutput, INotebookCellList, INotebookDeltaDecoration, INotebookEditor, INotebookEditorContribution, INotebookEditorContributionDescription, INotebookEditorCreationOptions, INotebookEditorMouseEvent, NotebookEditorOptions, NotebookLayoutInfo, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_RUNNABLE, NOTEBOOK_HAS_MULTIPLE_KERNELS, NOTEBOOK_OUTPUT_FOCUSED } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { NotebookEditorExtensionsRegistry } from 'vs/workbench/contrib/notebook/browser/notebookEditorExtensions'; import { NotebookKernelProviderAssociation, NotebookKernelProviderAssociations, notebookKernelProviderAssociationsSettingId } from 'vs/workbench/contrib/notebook/browser/notebookKernelAssociation'; import { NotebookCellList } from 'vs/workbench/contrib/notebook/browser/view/notebookCellList'; @@ -62,7 +62,6 @@ import { editorGutterModifiedBackground } from 'vs/workbench/contrib/scm/browser import { Webview } from 'vs/workbench/contrib/webview/browser/webview'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { configureKernelIcon, errorStateIcon, successStateIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons'; -import { ICommonCellInfo, IDisplayOutputLayoutUpdateRequest } from 'vs/workbench/contrib/notebook/browser/genericTypes'; const $ = DOM.$; diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index 4dab3eba4d3..c70ac956800 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -11,7 +11,7 @@ import { URI } from 'vs/base/common/uri'; import * as UUID from 'vs/base/common/uuid'; import { IOpenerService, matchesScheme } from 'vs/platform/opener/common/opener'; import { CELL_MARGIN, CELL_RUN_GUTTER, CODE_CELL_LEFT_MARGIN, CELL_OUTPUT_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; -import { IDisplayOutputViewModel, IInsetRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { ICommonCellInfo, ICommonNotebookEditor, IDisplayOutputLayoutUpdateRequest, IDisplayOutputViewModel, IGenericCellViewModel, IInsetRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellOutputKind, IDisplayOutput, INotebookRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { IWebviewService, WebviewElement, WebviewContentPurpose } from 'vs/workbench/contrib/webview/browser/webview'; @@ -25,7 +25,6 @@ import { IFileService } from 'vs/platform/files/common/files'; import { VSBuffer } from 'vs/base/common/buffer'; import { getExtensionForMimeType } from 'vs/base/common/mime'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { ICommonCellInfo, ICommonNotebookEditor, IDisplayOutputLayoutUpdateRequest, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/genericTypes'; export interface WebviewIntialized { __vscode_notebook_message: boolean; diff --git a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts index dacce8299ae..c624881feb9 100644 --- a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts @@ -12,7 +12,7 @@ import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; import { Range } from 'vs/editor/common/core/range'; import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo'; import { EditorModel } from 'vs/workbench/common/editor'; -import { ICellViewModel, INotebookEditor, INotebookEditorContribution, INotebookEditorMouseEvent, NotebookLayoutInfo, INotebookDeltaDecoration, INotebookEditorCreationOptions, NotebookEditorOptions, ICellOutputViewModel, IInsetRenderOutput, IDisplayOutputViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { ICellViewModel, INotebookEditor, INotebookEditorContribution, INotebookEditorMouseEvent, NotebookLayoutInfo, INotebookDeltaDecoration, INotebookEditorCreationOptions, NotebookEditorOptions, ICellOutputViewModel, IInsetRenderOutput, IDisplayOutputViewModel, ICommonCellInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer'; import { NotebookEventDispatcher } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher'; import { CellViewModel, IModelDecorationsChangeAccessor, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; @@ -36,7 +36,6 @@ import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService import { ScrollEvent } from 'vs/base/common/scrollable'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IFileStatWithMetadata } from 'vs/platform/files/common/files'; -import { ICommonCellInfo } from 'vs/workbench/contrib/notebook/browser/genericTypes'; export class TestCell extends NotebookCellTextModel { constructor( From f6a796b66935124037a903ab4b5031331b73e57c Mon Sep 17 00:00:00 2001 From: rebornix Date: Tue, 15 Dec 2020 16:22:04 -0800 Subject: [PATCH 045/262] grouping types in notebookBrowser --- .../notebook/browser/notebookBrowser.ts | 118 +++++++++--------- 1 file changed, 62 insertions(+), 56 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index 024bdb5aa2c..6707689f601 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -32,6 +32,7 @@ import { IResourceEditorInput } from 'vs/platform/editor/common/editor'; import { IConstructorSignature1 } from 'vs/platform/instantiation/common/instantiation'; import { CellEditorStatusBar } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellWidgets'; +//#region Context Keys export const KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED = new RawContextKey('notebookFindWidgetFocused', false); // Is Notebook @@ -57,17 +58,73 @@ export const NOTEBOOK_CELL_RUN_STATE = new RawContextKey('notebookCellRu export const NOTEBOOK_CELL_HAS_OUTPUTS = new RawContextKey('notebookCellHasOutputs', false); // bool export const NOTEBOOK_CELL_INPUT_COLLAPSED = new RawContextKey('notebookCellInputIsCollapsed', false); // bool export const NOTEBOOK_CELL_OUTPUT_COLLAPSED = new RawContextKey('notebookCellOutputIsCollapsed', false); // bool +// Kernels +export const NOTEBOOK_HAS_MULTIPLE_KERNELS = new RawContextKey('notebookHasMultipleKernels', false); -// Shared commands +//#endregion + +//#region Shared commands export const EXPAND_CELL_CONTENT_COMMAND_ID = 'notebook.cell.expandCellContent'; export const EXECUTE_CELL_COMMAND_ID = 'notebook.cell.execute'; -// Kernels +//#endregion -export const NOTEBOOK_HAS_MULTIPLE_KERNELS = new RawContextKey('notebookHasMultipleKernels', false); +//#region Output related types +export const enum RenderOutputType { + None, + Html, + Extension +} + +export interface IRenderNoOutput { + type: RenderOutputType.None; + hasDynamicHeight: boolean; +} + +export interface IRenderPlainHtmlOutput { + type: RenderOutputType.Html; + source: IDisplayOutputViewModel; + htmlContent: string; + hasDynamicHeight: boolean; +} + +export interface IRenderOutputViaExtension { + type: RenderOutputType.Extension; + source: IDisplayOutputViewModel; + mimeType: string; + renderer: INotebookRendererInfo; +} + +export type IInsetRenderOutput = IRenderPlainHtmlOutput | IRenderOutputViaExtension; +export type IRenderOutput = IRenderNoOutput | IInsetRenderOutput; + +export const outputHasDynamicHeight = (o: IRenderOutput) => o.type !== RenderOutputType.Extension && o.hasDynamicHeight; -// These are types shared by the Notebook Editor and Notebook Diff Editor +export interface ICellOutputViewModel { + model: IProcessedOutput; + isDisplayOutput(): this is IDisplayOutputViewModel; + isErrorOutput(): this is IErrorOutputViewModel; + isStreamOutput(): this is IStreamOutputViewModel; +} + +export interface IDisplayOutputViewModel extends ICellOutputViewModel { + model: ITransformedDisplayOutputDto; + resolveMimeTypes(textModel: NotebookTextModel): [readonly IOrderedMimeType[], number]; + pickedMimeType: number; +} + +export interface IErrorOutputViewModel extends ICellOutputViewModel { + model: IErrorOutput; +} + +export interface IStreamOutputViewModel extends ICellOutputViewModel { + model: IStreamOutput; +} + +//#endregion + +//#region Shared types between the Notebook Editor and Notebook Diff Editor, they are mostly used for output rendering export interface IGenericCellViewModel { id: string; @@ -100,6 +157,7 @@ export interface ICommonNotebookEditor { updateOutputHeight(cellInfo: ICommonCellInfo, output: IDisplayOutputViewModel, height: number): void; } +//#endregion export interface NotebookLayoutInfo { width: number; @@ -157,58 +215,6 @@ export interface MarkdownCellLayoutChangeEvent { totalHeight?: number; } -export const enum RenderOutputType { - None, - Html, - Extension -} - -export interface IRenderNoOutput { - type: RenderOutputType.None; - hasDynamicHeight: boolean; -} - -export interface IRenderPlainHtmlOutput { - type: RenderOutputType.Html; - source: IDisplayOutputViewModel; - htmlContent: string; - hasDynamicHeight: boolean; -} - -export interface IRenderOutputViaExtension { - type: RenderOutputType.Extension; - source: IDisplayOutputViewModel; - mimeType: string; - renderer: INotebookRendererInfo; -} - -export type IInsetRenderOutput = IRenderPlainHtmlOutput | IRenderOutputViaExtension; -export type IRenderOutput = IRenderNoOutput | IInsetRenderOutput; - -export const outputHasDynamicHeight = (o: IRenderOutput) => o.type !== RenderOutputType.Extension && o.hasDynamicHeight; - - -export interface ICellOutputViewModel { - model: IProcessedOutput; - isDisplayOutput(): this is IDisplayOutputViewModel; - isErrorOutput(): this is IErrorOutputViewModel; - isStreamOutput(): this is IStreamOutputViewModel; -} - -export interface IDisplayOutputViewModel extends ICellOutputViewModel { - model: ITransformedDisplayOutputDto; - resolveMimeTypes(textModel: NotebookTextModel): [readonly IOrderedMimeType[], number]; - pickedMimeType: number; -} - -export interface IErrorOutputViewModel extends ICellOutputViewModel { - model: IErrorOutput; -} - -export interface IStreamOutputViewModel extends ICellOutputViewModel { - model: IStreamOutput; -} - export interface ICellViewModel extends IGenericCellViewModel { readonly model: NotebookCellTextModel; readonly id: string; From d2aebcd2c58c626f9927c95c64c4d501ae105e92 Mon Sep 17 00:00:00 2001 From: rebornix Date: Tue, 15 Dec 2020 16:55:49 -0800 Subject: [PATCH 046/262] absolute positioned borders elements --- .../contrib/notebook/browser/diff/common.ts | 12 +++++++++-- .../notebook/browser/diff/diffComponents.ts | 7 +++++++ .../notebook/browser/diff/notebookDiff.css | 20 ++++++++++++++++++ .../browser/diff/notebookTextDiffEditor.ts | 5 ++++- .../browser/diff/notebookTextDiffList.ts | 21 +++++++++++++++++++ 5 files changed, 62 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/common.ts b/src/vs/workbench/contrib/notebook/browser/diff/common.ts index e8a45767398..987772ddd3d 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/common.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/common.ts @@ -42,7 +42,14 @@ export interface IDiffNestedCellViewModel { } -export interface CellDiffSingleSideRenderTemplate { +export interface CellDiffCommonRenderTemplate { + readonly leftBorder: HTMLElement; + readonly rightBorder: HTMLElement; + readonly topBorder: HTMLElement; + readonly bottomBorder: HTMLElement; +} + +export interface CellDiffSingleSideRenderTemplate extends CellDiffCommonRenderTemplate { readonly container: HTMLElement; readonly body: HTMLElement; readonly diffEditorContainer: HTMLElement; @@ -53,10 +60,11 @@ export interface CellDiffSingleSideRenderTemplate { readonly metadataInfoContainer: HTMLElement; readonly outputHeaderContainer: HTMLElement; readonly outputInfoContainer: HTMLElement; + } -export interface CellDiffSideBySideRenderTemplate { +export interface CellDiffSideBySideRenderTemplate extends CellDiffCommonRenderTemplate { readonly container: HTMLElement; readonly body: HTMLElement; readonly diffEditorContainer: HTMLElement; diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts index 2771f8b135b..3d2c5c1176b 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts @@ -258,6 +258,7 @@ abstract class AbstractElementRenderer extends Disposable { this._outputEditorDisposeStore = new DisposableStore(); this._register(this._metadataEditorDisposeStore); this._register(cell.onDidLayoutChange(e => this.layout(e))); + this._register(cell.onDidLayoutChange(e => this.updateBorders())); this.buildBody(); } @@ -595,6 +596,12 @@ abstract class AbstractElementRenderer extends Disposable { ); } + updateBorders() { + this.templateData.leftBorder.style.height = `${this.cell.totalHeight - 32}px`; + this.templateData.rightBorder.style.height = `${this.cell.totalHeight - 32}px`; + this.templateData.bottomBorder.style.top = `${this.cell.totalHeight - 32}px`; + } + dispose() { this._isDisposed = true; super.dispose(); diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css index ba600aa00c7..687e8282be2 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css @@ -21,6 +21,26 @@ flex-direction: row; } +.notebook-text-diff-editor .cell-body .border-container { + position: absolute; + width: calc(100% - 32px); +} + +.notebook-text-diff-editor .cell-body .border-container .top-border, +.notebook-text-diff-editor .cell-body .border-container .bottom-border { + position: absolute; + width: 100%; +} + +.notebook-text-diff-editor .cell-body .border-container .left-border, +.notebook-text-diff-editor .cell-body .border-container .right-border { + position: absolute; +} + +.notebook-text-diff-editor .cell-body .border-container .right-border { + left: 100%; +} + .notebook-text-diff-editor .cell-body.right { flex-direction: row-reverse; } diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index f19a874b806..67c1697c55e 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -593,7 +593,10 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD registerThemingParticipant((theme, collector) => { const cellBorderColor = theme.getColor(notebookCellBorder); if (cellBorderColor) { - collector.addRule(`.notebook-text-diff-editor .cell-body { border: 1px solid ${cellBorderColor};}`); + collector.addRule(`.notebook-text-diff-editor .cell-body .border-container .top-border { border-top: 1px solid ${cellBorderColor};}`); + collector.addRule(`.notebook-text-diff-editor .cell-body .border-container .bottom-border { border-top: 1px solid ${cellBorderColor};}`); + collector.addRule(`.notebook-text-diff-editor .cell-body .border-container .left-border { border-left: 1px solid ${cellBorderColor};}`); + collector.addRule(`.notebook-text-diff-editor .cell-body .border-container .right-border { border-right: 1px solid ${cellBorderColor};}`); collector.addRule(`.notebook-text-diff-editor .cell-diff-editor-container .output-header-container, .notebook-text-diff-editor .cell-diff-editor-container .metadata-header-container { border-top: 1px solid ${cellBorderColor}; diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts index a879142635a..464e6f083ef 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts @@ -148,6 +148,12 @@ export class CellDiffSingleSideRenderer implements IListRenderer Date: Tue, 15 Dec 2020 16:56:18 -0800 Subject: [PATCH 047/262] :guard: --- .../contrib/notebook/browser/view/renderers/webviewPreloads.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts index 6565898f513..a79a6da2443 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts @@ -20,7 +20,7 @@ declare module globalThis { }); } -declare var acquireVsCodeApi: () => ({ +declare let acquireVsCodeApi: () => ({ getState(): { [key: string]: unknown; }; setState(data: { [key: string]: unknown; }): void; postMessage: (msg: unknown) => void; From fec4672c27af221bae64904b9e1a1e1a12c75750 Mon Sep 17 00:00:00 2001 From: rebornix Date: Tue, 15 Dec 2020 17:01:22 -0800 Subject: [PATCH 048/262] output diff container css class clearing --- .../contrib/notebook/browser/diff/diffComponents.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts index 3d2c5c1176b..8e87cb20574 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts @@ -814,6 +814,10 @@ export class DeletedElement extends SingleSideDiffElement { }); } + if (this._diagonalFill) { + this._diagonalFill.style.height = `${this.cell.totalHeight - 32}px`; + } + this.layoutNotebookCell(); }); } @@ -967,6 +971,7 @@ export class ModifiedElement extends AbstractElementRenderer { buildBody() { const body = this.templateData.body; this._diffEditorContainer = this.templateData.diffEditorContainer; + body.classList.remove('left', 'right', 'full'); switch (this.style) { case 'left': body.classList.add('left'); From 2118388b0e1f4de16f4fc6b9a35efe6bc3f9bef8 Mon Sep 17 00:00:00 2001 From: rebornix Date: Tue, 15 Dec 2020 17:12:34 -0800 Subject: [PATCH 049/262] two webviews --- .../notebook/browser/diff/diffComponents.ts | 19 ++-- .../browser/diff/notebookTextDiffEditor.ts | 102 ++++++++++-------- .../notebook/browser/notebookEditorWidget.ts | 2 + .../view/renderers/backLayerWebView.ts | 1 - 4 files changed, 69 insertions(+), 55 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts index 8e87cb20574..1b7f3d406de 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts @@ -823,17 +823,18 @@ export class DeletedElement extends SingleSideDiffElement { } _buildOutputContainer() { - // this._outputView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell.modified!, this._outputViewContainer!); - // this._outputView.render(); - // this.layout({ outputView: true }); + this._outputLeftView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell, this.cell.original!, false, this._outputViewContainer!); + this._outputLeftView.render(); + this.cell.layoutChange(); } _showOutputs() { - + this._outputLeftView?.render(); + this.cell.layoutChange(); } _hideOutputs() { - + this._outputLeftView?.hideOutputs(); } } @@ -895,18 +896,18 @@ export class InsertElement extends SingleSideDiffElement { } _buildOutputContainer() { - this._outputLeftView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell, this.cell.modified!, true, this._outputViewContainer!); - this._outputLeftView.render(); + this._outputRightView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell, this.cell.modified!, true, this._outputViewContainer!); + this._outputRightView.render(); this.cell.layoutChange(); } _showOutputs() { - this._outputLeftView?.render(); + this._outputRightView?.render(); this.cell.layoutChange(); } _hideOutputs() { - this._outputLeftView?.hideOutputs(); + this._outputRightView?.hideOutputs(); } layout(state: { outerWidth?: boolean, editorHeight?: boolean, metadataEditor?: boolean, outputEditor?: boolean, outputView?: boolean }) { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 67c1697c55e..940d1f3dd8e 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -57,6 +57,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD // private _diffElementViewModels: DiffElementViewModelBase[] = []; private _list!: NotebookTextDiffList; private _modifiedWebview: BackLayerWebView | null = null; + private _originalWebview: BackLayerWebView | null = null; private _webviewTransparentCover: HTMLElement | null = null; private _fontInfo: BareFontInfo | undefined; @@ -206,55 +207,53 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD const scrollTop = this._list.scrollTop; const scrollHeight = this._list.scrollHeight; - if (!this._modifiedWebview) { - return; - } + if (this._modifiedWebview) { + this._modifiedWebview!.element.style.height = `${scrollHeight}px`; - this._modifiedWebview!.element.style.height = `${scrollHeight}px`; - - if (this._modifiedWebview?.insetMapping) { - const updateItems: IDisplayOutputLayoutUpdateRequest[] = []; - const removedItems: IDisplayOutputViewModel[] = []; - this._modifiedWebview?.insetMapping.forEach((value, key) => { - const cell = value.cellInfo.diffElement.modified; - if (!cell) { - return; - } - - const viewIndex = this._list.indexOf(value.cellInfo.diffElement); - - if (viewIndex === undefined) { - return; - } - - if (cell.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (key.model as ITransformedDisplayOutputDto).outputId) < 0) { - // output is already gone - removedItems.push(key); - } - - const cellTop = this._list.getAbsoluteTopOfElement(value.cellInfo.diffElement); - if (this._modifiedWebview!.shouldUpdateInset(cell, key, cellTop)) { - // TODO: why? does it mean, we create new output view model every time? - const outputIndex = cell.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (key.model as ITransformedDisplayOutputDto).outputId); - let outputOffset = 0; - if (value.cellInfo.diffElement instanceof SideBySideDiffElementViewModel) { - outputOffset = cellTop + value.cellInfo.diffElement.getOutputOffsetInCell(false, outputIndex); - } else { - outputOffset = cellTop + (value.cellInfo.diffElement as SingleSideDiffElementViewModel).getOutputOffsetInCell(outputIndex); + if (this._modifiedWebview?.insetMapping) { + const updateItems: IDisplayOutputLayoutUpdateRequest[] = []; + const removedItems: IDisplayOutputViewModel[] = []; + this._modifiedWebview?.insetMapping.forEach((value, key) => { + const cell = value.cellInfo.diffElement.modified; + if (!cell) { + return; } - updateItems.push({ - output: key, - cellTop: cellTop, - outputOffset: outputOffset - }); + const viewIndex = this._list.indexOf(value.cellInfo.diffElement); + + if (viewIndex === undefined) { + return; + } + + if (cell.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (key.model as ITransformedDisplayOutputDto).outputId) < 0) { + // output is already gone + removedItems.push(key); + } + + const cellTop = this._list.getAbsoluteTopOfElement(value.cellInfo.diffElement); + if (this._modifiedWebview!.shouldUpdateInset(cell, key, cellTop)) { + // TODO: why? does it mean, we create new output view model every time? + const outputIndex = cell.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (key.model as ITransformedDisplayOutputDto).outputId); + let outputOffset = 0; + if (value.cellInfo.diffElement instanceof SideBySideDiffElementViewModel) { + outputOffset = cellTop + value.cellInfo.diffElement.getOutputOffsetInCell(false, outputIndex); + } else { + outputOffset = cellTop + (value.cellInfo.diffElement as SingleSideDiffElementViewModel).getOutputOffsetInCell(outputIndex); + } + + updateItems.push({ + output: key, + cellTop: cellTop, + outputOffset: outputOffset + }); + } + }); + + removedItems.forEach(output => this._modifiedWebview?.removeInset(output)); + + if (updateItems.length) { + this._modifiedWebview?.updateViewScrollTop(-scrollTop, false, updateItems); } - }); - - removedItems.forEach(output => this._modifiedWebview?.removeInset(output)); - - if (updateItems.length) { - this._modifiedWebview?.updateViewScrollTop(-scrollTop, false, updateItems); } } @@ -311,6 +310,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD } })); + await this._createOriginalWebview(generateUuid(), this._model.original.resource); await this._createModifiedWebview(generateUuid(), this._model.modified.resource); this._eventDispatcher = new NotebookDiffEditorEventDispatcher(); @@ -322,9 +322,19 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD // attach the webview container to the DOM tree first this._list.rowsContainer.insertAdjacentElement('afterbegin', this._modifiedWebview.element); await this._modifiedWebview.createWebview(); + this._modifiedWebview.element.style.width = `calc(50%)`; this._modifiedWebview.element.style.left = `calc(50%)`; } + private async _createOriginalWebview(id: string, resource: URI): Promise { + this._originalWebview = this.instantiationService.createInstance(BackLayerWebView, this, id, resource) as BackLayerWebView; + // attach the webview container to the DOM tree first + this._list.rowsContainer.insertAdjacentElement('afterbegin', this._originalWebview.element); + await this._originalWebview.createWebview(); + this._originalWebview.element.style.width = `calc(50%)`; + this._originalWebview.element.style.left = `0`; + } + private async _resolveStats(resource: URI) { if (resource.scheme === Schemas.untitled) { return undefined; @@ -507,6 +517,8 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD this._modifiedWebview!.updateViewScrollTop(-scrollTop, true, [{ output: output.source, cellTop, outputOffset }]); } + } else { + } }); } diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index b69f21df8bb..065966363b2 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -903,6 +903,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor if (!this._webview) { this._webview = this.instantiationService.createInstance(BackLayerWebView, this, this.getId(), this.textModel!.uri); + this._webview.element.style.width = `calc(100% - ${CODE_CELL_LEFT_MARGIN + (CELL_MARGIN * 2) + CELL_RUN_GUTTER}px)`; this._webview.element.style.margin = `0px 0 0px ${CODE_CELL_LEFT_MARGIN + CELL_RUN_GUTTER}px`; // attach the webview container to the DOM tree first @@ -953,6 +954,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor private async _createWebview(id: string, resource: URI): Promise { this._webview = this.instantiationService.createInstance(BackLayerWebView, this, id, resource); + this._webview.element.style.width = `calc(100% - ${CODE_CELL_LEFT_MARGIN + (CELL_MARGIN * 2) + CELL_RUN_GUTTER}px)`; this._webview.element.style.margin = `0px 0 0px ${CODE_CELL_LEFT_MARGIN + CELL_RUN_GUTTER}px`; // attach the webview container to the DOM tree first this._list.rowsContainer.insertAdjacentElement('afterbegin', this._webview.element); diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index c70ac956800..61e743d4a45 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -248,7 +248,6 @@ export class BackLayerWebView extends Disposable { this.element = document.createElement('div'); - this.element.style.width = `calc(100% - ${CODE_CELL_LEFT_MARGIN + (CELL_MARGIN * 2) + CELL_RUN_GUTTER}px)`; this.element.style.height = '1400px'; this.element.style.position = 'absolute'; } From 1741bbf7e6f6b0b02eb3eab4cce71c39832c74c5 Mon Sep 17 00:00:00 2001 From: rebornix Date: Tue, 15 Dec 2020 17:19:19 -0800 Subject: [PATCH 050/262] render deleted output --- .../browser/diff/notebookTextDiffEditor.ts | 19 +++++++++++++++++-- .../browser/diff/notebookTextDiffList.ts | 4 ++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 940d1f3dd8e..9f9b201220e 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -331,8 +331,8 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD // attach the webview container to the DOM tree first this._list.rowsContainer.insertAdjacentElement('afterbegin', this._originalWebview.element); await this._originalWebview.createWebview(); - this._originalWebview.element.style.width = `calc(50%)`; - this._originalWebview.element.style.left = `0`; + this._originalWebview.element.style.width = `calc(50% - 16px)`; + this._originalWebview.element.style.left = `16px`; } private async _resolveStats(resource: URI) { @@ -518,7 +518,22 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD this._modifiedWebview!.updateViewScrollTop(-scrollTop, true, [{ output: output.source, cellTop, outputOffset }]); } } else { + if (!this._originalWebview!.insetMapping.has(output.source)) { + const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel); + await this._originalWebview?.createInset({ diffElement: cellDiffViewModel, cellHandle: cellViewModel.handle, cellId: cellViewModel.id, cellUri: cellViewModel.uri }, output, cellTop, offset); + } else { + const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel); + const scrollTop = this._list.scrollTop; + const outputIndex = cellViewModel.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (output.source.model as ITransformedDisplayOutputDto).outputId); + let outputOffset = 0; + if (cellDiffViewModel instanceof SideBySideDiffElementViewModel) { + outputOffset = cellTop + cellDiffViewModel.getOutputOffsetInCell(true, outputIndex); + } else { + outputOffset = cellTop + (cellDiffViewModel as SingleSideDiffElementViewModel).getOutputOffsetInCell(outputIndex); + } + this._originalWebview!.updateViewScrollTop(-scrollTop, true, [{ output: output.source, cellTop, outputOffset }]); + } } }); } diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts index 464e6f083ef..34447188f77 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts @@ -189,6 +189,8 @@ export class CellDiffSingleSideRenderer implements IListRenderer Date: Tue, 15 Dec 2020 17:21:42 -0800 Subject: [PATCH 051/262] hide inset and update layout for the left webview. --- .../browser/diff/notebookTextDiffEditor.ts | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 9f9b201220e..58303b87995 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -257,6 +257,56 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD } } + if (this._originalWebview) { + this._originalWebview.element.style.height = `${scrollHeight}px`; + + if (this._originalWebview.insetMapping) { + const updateItems: IDisplayOutputLayoutUpdateRequest[] = []; + const removedItems: IDisplayOutputViewModel[] = []; + this._originalWebview.insetMapping.forEach((value, key) => { + const cell = value.cellInfo.diffElement.modified; + if (!cell) { + return; + } + + const viewIndex = this._list.indexOf(value.cellInfo.diffElement); + + if (viewIndex === undefined) { + return; + } + + if (cell.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (key.model as ITransformedDisplayOutputDto).outputId) < 0) { + // output is already gone + removedItems.push(key); + } + + const cellTop = this._list.getAbsoluteTopOfElement(value.cellInfo.diffElement); + if (this._originalWebview!.shouldUpdateInset(cell, key, cellTop)) { + // TODO: why? does it mean, we create new output view model every time? + const outputIndex = cell.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (key.model as ITransformedDisplayOutputDto).outputId); + let outputOffset = 0; + if (value.cellInfo.diffElement instanceof SideBySideDiffElementViewModel) { + outputOffset = cellTop + value.cellInfo.diffElement.getOutputOffsetInCell(true, outputIndex); + } else { + outputOffset = cellTop + (value.cellInfo.diffElement as SingleSideDiffElementViewModel).getOutputOffsetInCell(outputIndex); + } + + updateItems.push({ + output: key, + cellTop: cellTop, + outputOffset: outputOffset + }); + } + }); + + removedItems.forEach(output => this._originalWebview?.removeInset(output)); + + if (updateItems.length) { + this._originalWebview?.updateViewScrollTop(-scrollTop, false, updateItems); + } + } + } + }); })); } @@ -548,6 +598,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD hideInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: DiffNestedCellViewModel, output: IDisplayOutputViewModel) { this._modifiedWebview?.hideInset(output); + this._originalWebview?.hideInset(output); } // private async _resolveWebview(rightEditor: boolean): Promise { From 6a342fe0a47dddf075f8a3d13458107e3afe736a Mon Sep 17 00:00:00 2001 From: rebornix Date: Wed, 16 Dec 2020 08:22:13 -0800 Subject: [PATCH 052/262] update original webview based on original text model. --- .../browser/diff/notebookTextDiffEditor.ts | 17 ++++++++++++++++- .../browser/view/renderers/backLayerWebView.ts | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 58303b87995..cc9a8753c53 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -76,6 +76,12 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD private _revealFirst: boolean; private readonly _insetModifyQueueByOutputId = new SequencerByKey(); + private _isDisposed: boolean = false; + + get isDisposed() { + return this._isDisposed; + } + constructor( @IInstantiationService readonly instantiationService: IInstantiationService, @IThemeService readonly themeService: IThemeService, @@ -204,6 +210,10 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD this._register(this._list.onDidChangeContentHeight(() => { DOM.scheduleAtNextAnimationFrame(() => { + if (this._isDisposed) { + return; + } + const scrollTop = this._list.scrollTop; const scrollHeight = this._list.scrollHeight; @@ -264,7 +274,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD const updateItems: IDisplayOutputLayoutUpdateRequest[] = []; const removedItems: IDisplayOutputViewModel[] = []; this._originalWebview.insetMapping.forEach((value, key) => { - const cell = value.cellInfo.diffElement.modified; + const cell = value.cellInfo.diffElement.original; if (!cell) { return; } @@ -666,6 +676,11 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD this._eventDispatcher?.emit([new NotebookLayoutChangedEvent({ width: true, fontInfo: true }, this.getLayoutInfo())]); } + + dispose() { + this._isDisposed = true; + super.dispose(); + } } registerThemingParticipant((theme, collector) => { diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index 61e743d4a45..faa02519988 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -10,7 +10,7 @@ import { isWeb } from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; import * as UUID from 'vs/base/common/uuid'; import { IOpenerService, matchesScheme } from 'vs/platform/opener/common/opener'; -import { CELL_MARGIN, CELL_RUN_GUTTER, CODE_CELL_LEFT_MARGIN, CELL_OUTPUT_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; +import { CELL_OUTPUT_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; import { ICommonCellInfo, ICommonNotebookEditor, IDisplayOutputLayoutUpdateRequest, IDisplayOutputViewModel, IGenericCellViewModel, IInsetRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellOutputKind, IDisplayOutput, INotebookRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; From 21b1da3fb082096188b2375950e6e76a3cd2ed29 Mon Sep 17 00:00:00 2001 From: rebornix Date: Wed, 16 Dec 2020 11:52:47 -0800 Subject: [PATCH 053/262] absolute layout for side by side output diffing --- .../notebook/browser/diff/notebookDiff.css | 19 ++- .../browser/diff/notebookTextDiffEditor.ts | 153 +++++++----------- .../view/renderers/backLayerWebView.ts | 2 +- 3 files changed, 73 insertions(+), 101 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css index 687e8282be2..19dff4b753a 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css @@ -158,6 +158,11 @@ position: relative; } +.monaco-workbench .notebook-text-diff-editor .cell-body .output-view-container .output-plaintext { + white-space: pre; + overflow-x: hidden; +} + .monaco-workbench .notebook-text-diff-editor .cell-body.left .output-view-container .output-inner-container, .monaco-workbench .notebook-text-diff-editor .cell-body.right .output-view-container .output-inner-container { width: 100%; @@ -170,16 +175,22 @@ box-sizing: border-box; } -.monaco-workbench .notebook-text-diff-editor .cell-body.full .output-info-container.modified .output-view-container .output-view-container-left, +.monaco-workbench .notebook-text-diff-editor .cell-body.full .output-info-container.modified .output-view-container .output-view-container-left { + top: 0; + position: absolute; + left: 0; +} + .monaco-workbench .notebook-text-diff-editor .cell-body.full .output-info-container.modified .output-view-container .output-view-container-right { - width: 50%; - display: inline-block; + position: absolute; + top: 0; + left: 50%; } .monaco-workbench .notebook-text-diff-editor .cell-body.full .output-info-container.modified .output-view-container .output-view-container-left, .monaco-workbench .notebook-text-diff-editor .cell-body.full .output-info-container.modified .output-view-container .output-view-container-right { width: 50%; - position: relative; + display: inline-block; } .monaco-workbench .notebook-text-diff-editor .cell-body.full .output-info-container.modified .output-view-container .output-view-container-left div.foreground, diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index cc9a8753c53..77845695074 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -41,7 +41,7 @@ import { SequencerByKey } from 'vs/base/common/async'; import { generateUuid } from 'vs/base/common/uuid'; import { IMouseWheelEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { DiffNestedCellViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel'; -import { BackLayerWebView } from 'vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView'; +import { BackLayerWebView, ICachedInset } from 'vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView'; const $ = DOM.$; @@ -218,109 +218,70 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD const scrollHeight = this._list.scrollHeight; if (this._modifiedWebview) { - this._modifiedWebview!.element.style.height = `${scrollHeight}px`; - - if (this._modifiedWebview?.insetMapping) { - const updateItems: IDisplayOutputLayoutUpdateRequest[] = []; - const removedItems: IDisplayOutputViewModel[] = []; - this._modifiedWebview?.insetMapping.forEach((value, key) => { - const cell = value.cellInfo.diffElement.modified; - if (!cell) { - return; - } - - const viewIndex = this._list.indexOf(value.cellInfo.diffElement); - - if (viewIndex === undefined) { - return; - } - - if (cell.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (key.model as ITransformedDisplayOutputDto).outputId) < 0) { - // output is already gone - removedItems.push(key); - } - - const cellTop = this._list.getAbsoluteTopOfElement(value.cellInfo.diffElement); - if (this._modifiedWebview!.shouldUpdateInset(cell, key, cellTop)) { - // TODO: why? does it mean, we create new output view model every time? - const outputIndex = cell.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (key.model as ITransformedDisplayOutputDto).outputId); - let outputOffset = 0; - if (value.cellInfo.diffElement instanceof SideBySideDiffElementViewModel) { - outputOffset = cellTop + value.cellInfo.diffElement.getOutputOffsetInCell(false, outputIndex); - } else { - outputOffset = cellTop + (value.cellInfo.diffElement as SingleSideDiffElementViewModel).getOutputOffsetInCell(outputIndex); - } - - updateItems.push({ - output: key, - cellTop: cellTop, - outputOffset: outputOffset - }); - } - }); - - removedItems.forEach(output => this._modifiedWebview?.removeInset(output)); - - if (updateItems.length) { - this._modifiedWebview?.updateViewScrollTop(-scrollTop, false, updateItems); - } - } + this._updateOutputsOffsetsInWebview(scrollTop, scrollHeight, this._modifiedWebview, (diffElement: DiffElementViewModelBase) => { + return diffElement.modified; + }); } if (this._originalWebview) { - this._originalWebview.element.style.height = `${scrollHeight}px`; - - if (this._originalWebview.insetMapping) { - const updateItems: IDisplayOutputLayoutUpdateRequest[] = []; - const removedItems: IDisplayOutputViewModel[] = []; - this._originalWebview.insetMapping.forEach((value, key) => { - const cell = value.cellInfo.diffElement.original; - if (!cell) { - return; - } - - const viewIndex = this._list.indexOf(value.cellInfo.diffElement); - - if (viewIndex === undefined) { - return; - } - - if (cell.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (key.model as ITransformedDisplayOutputDto).outputId) < 0) { - // output is already gone - removedItems.push(key); - } - - const cellTop = this._list.getAbsoluteTopOfElement(value.cellInfo.diffElement); - if (this._originalWebview!.shouldUpdateInset(cell, key, cellTop)) { - // TODO: why? does it mean, we create new output view model every time? - const outputIndex = cell.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (key.model as ITransformedDisplayOutputDto).outputId); - let outputOffset = 0; - if (value.cellInfo.diffElement instanceof SideBySideDiffElementViewModel) { - outputOffset = cellTop + value.cellInfo.diffElement.getOutputOffsetInCell(true, outputIndex); - } else { - outputOffset = cellTop + (value.cellInfo.diffElement as SingleSideDiffElementViewModel).getOutputOffsetInCell(outputIndex); - } - - updateItems.push({ - output: key, - cellTop: cellTop, - outputOffset: outputOffset - }); - } - }); - - removedItems.forEach(output => this._originalWebview?.removeInset(output)); - - if (updateItems.length) { - this._originalWebview?.updateViewScrollTop(-scrollTop, false, updateItems); - } - } + this._updateOutputsOffsetsInWebview(scrollTop, scrollHeight, this._originalWebview, (diffElement: DiffElementViewModelBase) => { + return diffElement.original; + }); } - }); })); } + private _updateOutputsOffsetsInWebview(scrollTop: number, scrollHeight: number, activeWebview: BackLayerWebView, getActiveNestedCell: (diffElement: DiffElementViewModelBase) => DiffNestedCellViewModel | undefined) { + activeWebview.element.style.height = `${scrollHeight}px`; + + if (activeWebview.insetMapping) { + const updateItems: IDisplayOutputLayoutUpdateRequest[] = []; + const removedItems: IDisplayOutputViewModel[] = []; + activeWebview.insetMapping.forEach((value, key) => { + const cell = getActiveNestedCell(value.cellInfo.diffElement); + if (!cell) { + return; + } + + const viewIndex = this._list.indexOf(value.cellInfo.diffElement); + + if (viewIndex === undefined) { + return; + } + + if (cell.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (key.model as ITransformedDisplayOutputDto).outputId) < 0) { + // output is already gone + removedItems.push(key); + } + + const cellTop = this._list.getAbsoluteTopOfElement(value.cellInfo.diffElement); + if (activeWebview.shouldUpdateInset(cell, key, cellTop)) { + // TODO: why? does it mean, we create new output view model every time? + const outputIndex = cell.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (key.model as ITransformedDisplayOutputDto).outputId); + let outputOffset = 0; + if (value.cellInfo.diffElement instanceof SideBySideDiffElementViewModel) { + outputOffset = cellTop + value.cellInfo.diffElement.getOutputOffsetInCell(false, outputIndex); + } else { + outputOffset = cellTop + (value.cellInfo.diffElement as SingleSideDiffElementViewModel).getOutputOffsetInCell(outputIndex); + } + + updateItems.push({ + output: key, + cellTop: cellTop, + outputOffset: outputOffset + }); + } + }); + + removedItems.forEach(output => activeWebview.removeInset(output)); + + if (updateItems.length) { + activeWebview.updateViewScrollTop(-scrollTop, false, updateItems); + } + } + } + async setInput(input: NotebookDiffEditorInput, options: EditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { await super.setInput(input, options, context, token); diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index faa02519988..18d1c33c037 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -195,7 +195,7 @@ export type ToWebviewMessage = export type AnyMessage = FromWebviewMessage | ToWebviewMessage; -interface ICachedInset { +export interface ICachedInset { outputId: string; cellInfo: K; renderer?: INotebookRendererInfo; From 0055e658c996ecd8cf7be088d5b89ce41dea4c55 Mon Sep 17 00:00:00 2001 From: rebornix Date: Wed, 16 Dec 2020 17:08:39 -0800 Subject: [PATCH 054/262] style polish --- .../contrib/notebook/browser/diff/notebookDiff.css | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css index 19dff4b753a..406c9ab1387 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css @@ -168,11 +168,14 @@ width: 100%; padding: 0px 8px; box-sizing: border-box; + overflow-x: hidden; } + .monaco-workbench .notebook-text-diff-editor .cell-body.full .output-view-container .output-inner-container { width: calc(100% - 16px); padding: 4px 8px; box-sizing: border-box; + overflow-x: hidden; } .monaco-workbench .notebook-text-diff-editor .cell-body.full .output-info-container.modified .output-view-container .output-view-container-left { @@ -213,7 +216,9 @@ } .monaco-workbench .notebook-text-diff-editor .output-view-container .error pre.traceback { - margin: 8px 0; + box-sizing: border-box; + padding: 8px 0; + margin: 0px; } .monaco-workbench .notebook-text-diff-editor .output-view-container .error .traceback > span { From 7c4757dd0ce09f1acaf287d566e19457a0f4f8fc Mon Sep 17 00:00:00 2001 From: rebornix Date: Wed, 16 Dec 2020 17:11:04 -0800 Subject: [PATCH 055/262] private _ --- .../browser/diff/diffElementOutputs.ts | 112 +++++++++--------- .../browser/diff/notebookTextDiffEditor.ts | 2 +- 2 files changed, 57 insertions(+), 57 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts index 0361db6bed1..17915f5a007 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts @@ -23,14 +23,14 @@ export class OutputElement extends Disposable { renderResult?: IRenderOutput; constructor( - private notebookEditor: INotebookTextDiffEditor, - private notebookTextModel: NotebookTextModel, - private notebookService: INotebookService, - private cellViewModel: DiffElementViewModelBase, - private modified: boolean, + private _notebookEditor: INotebookTextDiffEditor, + private _notebookTextModel: NotebookTextModel, + private _notebookService: INotebookService, + private _diffElementViewModel: DiffElementViewModelBase, + private _modified: boolean, - private cell: DiffNestedCellViewModel, - private outputContainer: HTMLElement, + private _nestedCell: DiffNestedCellViewModel, + private _outputContainer: HTMLElement, readonly output: ICellOutputViewModel ) { super(); @@ -41,19 +41,19 @@ export class OutputElement extends Disposable { let result: IRenderOutput | undefined = undefined; if (this.output.isDisplayOutput()) { - const [mimeTypes, pick] = this.output.resolveMimeTypes(this.notebookTextModel); + const [mimeTypes, pick] = this.output.resolveMimeTypes(this._notebookTextModel); const pickedMimeTypeRenderer = mimeTypes[pick]; const innerContainer = DOM.$('.output-inner-container'); DOM.append(outputItemDiv, innerContainer); if (pickedMimeTypeRenderer.rendererId !== BUILTIN_RENDERER_ID) { - const renderer = this.notebookService.getRendererInfo(pickedMimeTypeRenderer.rendererId); + const renderer = this._notebookService.getRendererInfo(pickedMimeTypeRenderer.rendererId); result = renderer ? { type: RenderOutputType.Extension, renderer, source: this.output, mimeType: pickedMimeTypeRenderer.mimeType } - : this.notebookEditor.getOutputRenderer().render(this.output, innerContainer, pickedMimeTypeRenderer.mimeType, this.notebookTextModel.uri,); + : this._notebookEditor.getOutputRenderer().render(this.output, innerContainer, pickedMimeTypeRenderer.mimeType, this._notebookTextModel.uri,); } else { - result = this.notebookEditor.getOutputRenderer().render(this.output, innerContainer, pickedMimeTypeRenderer.mimeType, this.notebookTextModel.uri); + result = this._notebookEditor.getOutputRenderer().render(this.output, innerContainer, pickedMimeTypeRenderer.mimeType, this._notebookTextModel.uri); } this.output.pickedMimeType = pick; @@ -62,7 +62,7 @@ export class OutputElement extends Disposable { const innerContainer = DOM.$('.output-inner-container'); DOM.append(outputItemDiv, innerContainer); - result = this.notebookEditor.getOutputRenderer().render(this.output, innerContainer, undefined, this.notebookTextModel.uri); + result = this._notebookEditor.getOutputRenderer().render(this.output, innerContainer, undefined, this._notebookTextModel.uri); } this.domNode = outputItemDiv; @@ -74,21 +74,21 @@ export class OutputElement extends Disposable { } if (beforeElement) { - this.outputContainer.insertBefore(outputItemDiv, beforeElement); + this._outputContainer.insertBefore(outputItemDiv, beforeElement); } else { - this.outputContainer.appendChild(outputItemDiv); + this._outputContainer.appendChild(outputItemDiv); } if (result.type !== RenderOutputType.None) { // this.viewCell.selfSizeMonitoring = true; - this.notebookEditor.createInset( - this.cellViewModel, - this.cell, + this._notebookEditor.createInset( + this._diffElementViewModel, + this._nestedCell, result, this.getOutputOffsetInCell(index), - this.cellViewModel instanceof SideBySideDiffElementViewModel - ? this.modified - : this.cellViewModel.type === 'insert' + this._diffElementViewModel instanceof SideBySideDiffElementViewModel + ? this._modified + : this._diffElementViewModel.type === 'insert' ); } else { outputItemDiv.classList.add('foreground', 'output-element'); @@ -105,7 +105,7 @@ export class OutputElement extends Disposable { // }; const elementSizeObserver = getResizesObserver(outputItemDiv, undefined, () => { - if (this.outputContainer && document.body.contains(this.outputContainer)) { + if (this._outputContainer && document.body.contains(this._outputContainer)) { const height = Math.ceil(elementSizeObserver.getHeight()); if (clientHeight === height) { @@ -133,75 +133,75 @@ export class OutputElement extends Disposable { } getCellOutputCurrentIndex() { - if (this.cellViewModel instanceof SideBySideDiffElementViewModel) { - if (this.modified) { - return this.cellViewModel.modified.outputs.indexOf(this.output.model); + if (this._diffElementViewModel instanceof SideBySideDiffElementViewModel) { + if (this._modified) { + return this._diffElementViewModel.modified.outputs.indexOf(this.output.model); } else { - return this.cellViewModel.original.outputs.indexOf(this.output.model); + return this._diffElementViewModel.original.outputs.indexOf(this.output.model); } } else { - return (this.cellViewModel as SingleSideDiffElementViewModel).cellViewModel!.outputs.indexOf(this.output.model); + return (this._diffElementViewModel as SingleSideDiffElementViewModel).cellViewModel!.outputs.indexOf(this.output.model); } } updateHeight(index: number, height: number) { - if (this.cellViewModel instanceof SideBySideDiffElementViewModel) { - this.cellViewModel.updateOutputHeight(!this.modified, index, height); + if (this._diffElementViewModel instanceof SideBySideDiffElementViewModel) { + this._diffElementViewModel.updateOutputHeight(!this._modified, index, height); } else { - (this.cellViewModel as SingleSideDiffElementViewModel).updateOutputHeight(index, height); + (this._diffElementViewModel as SingleSideDiffElementViewModel).updateOutputHeight(index, height); } } getOutputOffsetInContainer(index: number) { - if (this.cellViewModel instanceof SideBySideDiffElementViewModel) { - return this.cellViewModel.getOutputOffsetInContainer(!this.modified, index); + if (this._diffElementViewModel instanceof SideBySideDiffElementViewModel) { + return this._diffElementViewModel.getOutputOffsetInContainer(!this._modified, index); } else { - return (this.cellViewModel as SingleSideDiffElementViewModel).getOutputOffsetInContainer(index); + return (this._diffElementViewModel as SingleSideDiffElementViewModel).getOutputOffsetInContainer(index); } } getOutputOffsetInCell(index: number) { - if (this.cellViewModel instanceof SideBySideDiffElementViewModel) { - return this.cellViewModel.getOutputOffsetInCell(!this.modified, index); + if (this._diffElementViewModel instanceof SideBySideDiffElementViewModel) { + return this._diffElementViewModel.getOutputOffsetInCell(!this._modified, index); } else { - return (this.cellViewModel as SingleSideDiffElementViewModel).getOutputOffsetInCell(index); + return (this._diffElementViewModel as SingleSideDiffElementViewModel).getOutputOffsetInCell(index); } } } export class OutputContainer extends Disposable { private _outputViewModels: ICellOutputViewModel[]; - private outputEntries = new Map(); + private _outputEntries = new Map(); constructor( private _editor: INotebookTextDiffEditor, - private notebookTextModel: NotebookTextModel, - private diffElementViewModel: DiffElementViewModelBase, - private cellViewModel: DiffNestedCellViewModel, - private modified: boolean, - private outputContainer: HTMLElement, - @INotebookService private notebookService: INotebookService, + private _notebookTextModel: NotebookTextModel, + private _diffElementViewModel: DiffElementViewModelBase, + private _nestedCellViewModel: DiffNestedCellViewModel, + private _modified: boolean, + private _outputContainer: HTMLElement, + @INotebookService private _notebookService: INotebookService, // @IQuickInputService private readonly quickInputService: IQuickInputService, - @IOpenerService readonly openerService: IOpenerService, - @ITextFileService readonly textFileService: ITextFileService, + @IOpenerService readonly _openerService: IOpenerService, + @ITextFileService readonly _textFileService: ITextFileService, ) { super(); - this._outputViewModels = cellViewModel.outputs.map(output => new CellOutputViewModel(output, notebookService)); + this._outputViewModels = _nestedCellViewModel.outputs.map(output => new CellOutputViewModel(output, _notebookService)); // TODO, onDidChangeOutputs // viewCell.onDidChangeLayout // say the height of the cell editor changes - this._register(this.diffElementViewModel.onDidLayoutChange(() => { - this.outputEntries.forEach((value, key) => { - const index = cellViewModel.outputs.indexOf(key.model); + this._register(this._diffElementViewModel.onDidLayoutChange(() => { + this._outputEntries.forEach((value, key) => { + const index = _nestedCellViewModel.outputs.indexOf(key.model); if (index >= 0) { - if (this.diffElementViewModel instanceof SideBySideDiffElementViewModel) { - const top = this.diffElementViewModel.getOutputOffsetInContainer(!this.modified, index); + if (this._diffElementViewModel instanceof SideBySideDiffElementViewModel) { + const top = this._diffElementViewModel.getOutputOffsetInContainer(!this._modified, index); value.domNode.style.top = `${top}px`; } else { - const top = (this.diffElementViewModel as SingleSideDiffElementViewModel).getOutputOffsetInContainer(index); + const top = (this._diffElementViewModel as SingleSideDiffElementViewModel).getOutputOffsetInContainer(index); value.domNode.style.top = `${top}px`; } } @@ -220,19 +220,19 @@ export class OutputContainer extends Disposable { } hideOutputs() { - this.outputEntries.forEach((outputElement, cellOutputViewModel) => { + this._outputEntries.forEach((outputElement, cellOutputViewModel) => { if (cellOutputViewModel.isDisplayOutput()) { - this._editor.hideInset(this.diffElementViewModel, this.cellViewModel, cellOutputViewModel); + this._editor.hideInset(this._diffElementViewModel, this._nestedCellViewModel, cellOutputViewModel); } }); } private _renderOutput(currOutput: ICellOutputViewModel, index: number, beforeElement?: HTMLElement) { - if (!this.outputEntries.has(currOutput)) { - this.outputEntries.set(currOutput, new OutputElement(this._editor, this.notebookTextModel, this.notebookService, this.diffElementViewModel, this.modified, this.cellViewModel, this.outputContainer, currOutput)); + if (!this._outputEntries.has(currOutput)) { + this._outputEntries.set(currOutput, new OutputElement(this._editor, this._notebookTextModel, this._notebookService, this._diffElementViewModel, this._modified, this._nestedCellViewModel, this._outputContainer, currOutput)); } - const renderElement = this.outputEntries.get(currOutput)!; + const renderElement = this._outputEntries.get(currOutput)!; renderElement.render(index, beforeElement); } } diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 77845695074..3956a9a525d 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -41,7 +41,7 @@ import { SequencerByKey } from 'vs/base/common/async'; import { generateUuid } from 'vs/base/common/uuid'; import { IMouseWheelEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { DiffNestedCellViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel'; -import { BackLayerWebView, ICachedInset } from 'vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView'; +import { BackLayerWebView } from 'vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView'; const $ = DOM.$; From 732c73ef796706455a541fdc03cdbc2134873f40 Mon Sep 17 00:00:00 2001 From: rebornix Date: Wed, 16 Dec 2020 17:12:19 -0800 Subject: [PATCH 056/262] diffBrowser. --- .../workbench/contrib/notebook/browser/diff/diffComponents.ts | 2 +- .../contrib/notebook/browser/diff/diffElementOutputs.ts | 2 +- .../contrib/notebook/browser/diff/diffElementViewModel.ts | 2 +- .../contrib/notebook/browser/diff/diffNestedCellViewModel.ts | 2 +- .../browser/diff/{common.ts => notebookDiffEditorBrowser.ts} | 0 .../contrib/notebook/browser/diff/notebookTextDiffEditor.ts | 2 +- .../contrib/notebook/browser/diff/notebookTextDiffList.ts | 2 +- 7 files changed, 6 insertions(+), 6 deletions(-) rename src/vs/workbench/contrib/notebook/browser/diff/{common.ts => notebookDiffEditorBrowser.ts} (100%) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts index 1b7f3d406de..f140b91c806 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts @@ -8,7 +8,7 @@ import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IDiffEditorOptions, IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { DiffElementViewModelBase, getFormatedMetadataJSON, PropertyFoldingState, SideBySideDiffElementViewModel, SingleSideDiffElementViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; -import { CellDiffSideBySideRenderTemplate, CellDiffSingleSideRenderTemplate, DIFF_CELL_MARGIN, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common'; +import { CellDiffSideBySideRenderTemplate, CellDiffSingleSideRenderTemplate, DIFF_CELL_MARGIN, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser'; import { EDITOR_BOTTOM_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts index 17915f5a007..9f46bc83c53 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts @@ -7,7 +7,7 @@ import * as DOM from 'vs/base/browser/dom'; import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { DiffElementViewModelBase, SideBySideDiffElementViewModel, SingleSideDiffElementViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; -import { INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common'; +import { INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser'; import { ICellOutputViewModel, IRenderOutput, outputHasDynamicHeight, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { getResizesObserver } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellWidgets'; import { CellOutputViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel'; diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts index cfb29fecca0..a9cf7903172 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts @@ -6,7 +6,7 @@ import { NotebookDiffEditorEventDispatcher } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher'; import { Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; -import { CellDiffViewModelLayoutChangeEvent, DIFF_CELL_MARGIN } from 'vs/workbench/contrib/notebook/browser/diff/common'; +import { CellDiffViewModelLayoutChangeEvent, DIFF_CELL_MARGIN } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser'; import { IGenericCellViewModel, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel.ts index f5bdbfc8037..b50ef8b3104 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel.ts @@ -7,7 +7,7 @@ import { Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { generateUuid } from 'vs/base/common/uuid'; import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer'; -import { IDiffNestedCellViewModel } from 'vs/workbench/contrib/notebook/browser/diff/common'; +import { IDiffNestedCellViewModel } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser'; import { CellViewModelStateChangeEvent, ICellOutputViewModel, IGenericCellViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellOutputViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; diff --git a/src/vs/workbench/contrib/notebook/browser/diff/common.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts similarity index 100% rename from src/vs/workbench/contrib/notebook/browser/diff/common.ts rename to src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 3956a9a525d..473f3cac33f 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -24,7 +24,7 @@ import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; import { getZoomLevel } from 'vs/base/browser/browser'; import { IDisplayOutputLayoutUpdateRequest, IDisplayOutputViewModel, IGenericCellViewModel, IInsetRenderOutput, INotebookEditor, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; -import { DIFF_CELL_MARGIN, IDiffCellInfo, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common'; +import { DIFF_CELL_MARGIN, IDiffCellInfo, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser'; import { Emitter } from 'vs/base/common/event'; import { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { NotebookDiffEditorEventDispatcher, NotebookLayoutChangedEvent } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher'; diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts index 34447188f77..d559e05d973 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts @@ -15,7 +15,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IListService, IWorkbenchListOptions, WorkbenchList } from 'vs/platform/list/browser/listService'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { DiffElementViewModelBase, SideBySideDiffElementViewModel, SingleSideDiffElementViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; -import { CellDiffSideBySideRenderTemplate, CellDiffSingleSideRenderTemplate, DIFF_CELL_MARGIN, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common'; +import { CellDiffSideBySideRenderTemplate, CellDiffSingleSideRenderTemplate, DIFF_CELL_MARGIN, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser'; import { isMacintosh } from 'vs/base/common/platform'; import { DeletedElement, InsertElement, ModifiedElement } from 'vs/workbench/contrib/notebook/browser/diff/diffComponents'; import { CodeEditorWidget, ICodeEditorWidgetOptions } from 'vs/editor/browser/widget/codeEditorWidget'; From cb2167fdb227208fed87a61ff10d6b7d2049300c Mon Sep 17 00:00:00 2001 From: rebornix Date: Thu, 17 Dec 2020 10:22:08 -0800 Subject: [PATCH 057/262] Output transformers take ICommonNotebookEditor --- .../browser/diff/diffElementOutputs.ts | 2 +- .../browser/diff/diffNestedCellViewModel.ts | 4 +- .../browser/diff/notebookTextDiffEditor.ts | 56 ++++++++++++++++++- .../notebook/browser/notebookBrowser.ts | 8 +++ .../notebook/browser/notebookEditorWidget.ts | 14 ++++- .../notebook/browser/notebookRegistry.ts | 6 +- .../browser/view/output/outputRenderer.ts | 4 +- .../view/output/transforms/errorTransform.ts | 4 +- .../view/output/transforms/richTransform.ts | 12 ++-- .../view/output/transforms/streamTransform.ts | 4 +- .../browser/viewModel/cellOutputViewModel.ts | 4 +- .../browser/viewModel/codeCellViewModel.ts | 4 +- 12 files changed, 97 insertions(+), 25 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts index 9f46bc83c53..47351651b0b 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts @@ -186,7 +186,7 @@ export class OutputContainer extends Disposable { ) { super(); - this._outputViewModels = _nestedCellViewModel.outputs.map(output => new CellOutputViewModel(output, _notebookService)); + this._outputViewModels = _nestedCellViewModel.outputs.map(output => new CellOutputViewModel(_nestedCellViewModel, output, _notebookService)); // TODO, onDidChangeOutputs diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel.ts index b50ef8b3104..bd9f8d2ad2a 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel.ts @@ -69,11 +69,11 @@ export class DiffNestedCellViewModel extends Disposable implements IDiffNestedCe super(); this._id = generateUuid(); - this._outputViewModels = this.textModel.outputs.map(output => new CellOutputViewModel(output, this._notebookService)); + this._outputViewModels = this.textModel.outputs.map(output => new CellOutputViewModel(this, output, this._notebookService)); this._register(this.textModel.onDidChangeOutputs((splices) => { splices.reverse().forEach(splice => { this._outputCollection.splice(splice[0], splice[1], ...splice[2].map(() => 0)); - this._outputViewModels.splice(splice[0], splice[1], ...splice[2].map(output => new CellOutputViewModel(output, this._notebookService))); + this._outputViewModels.splice(splice[0], splice[1], ...splice[2].map(output => new CellOutputViewModel(this, output, this._notebookService))); }); this._outputsTop = null; diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 473f3cac33f..9ed315ea3f2 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -29,7 +29,7 @@ import { Emitter } from 'vs/base/common/event'; import { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { NotebookDiffEditorEventDispatcher, NotebookLayoutChangedEvent } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher'; import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane'; -import { INotebookDiffEditorModel, ITransformedDisplayOutputDto } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellUri, INotebookDiffEditorModel, ITransformedDisplayOutputDto } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { FileService } from 'vs/platform/files/common/fileService'; import { IFileService } from 'vs/platform/files/common/files'; import { URI } from 'vs/base/common/uri'; @@ -54,7 +54,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD private _rootElement!: HTMLElement; private _overflowContainer!: HTMLElement; private _dimension: DOM.Dimension | null = null; - // private _diffElementViewModels: DiffElementViewModelBase[] = []; + private _diffElementViewModels: DiffElementViewModelBase[] = []; private _list!: NotebookTextDiffList; private _modifiedWebview: BackLayerWebView | null = null; private _originalWebview: BackLayerWebView | null = null; @@ -435,7 +435,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD )); } - // this._diffElementViewModels = diffElementViewModels; + this._diffElementViewModels = diffElementViewModels; this._list.splice(0, this._list.length, diffElementViewModels); if (this._revealFirst && firstChangeIndex !== -1) { @@ -621,6 +621,56 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD }; } + getCellOutputLayoutInfo(nestedCell: DiffNestedCellViewModel) { + if (!this._model) { + throw new Error('Editor is not attached to model yet'); + } + const documentModel = CellUri.parse(nestedCell.uri); + if (!documentModel) { + throw new Error('Nested cell in the diff editor has wrong Uri'); + } + + const belongToOriginalDocument = this._model.original.notebook.uri.toString() === documentModel.notebook.toString(); + const viewModel = this._diffElementViewModels.find(element => { + const textModel = belongToOriginalDocument ? element.original : element.modified; + if (!textModel) { + return false; + } + + if (textModel.uri.toString() === nestedCell.uri.toString()) { + return true; + } + + return false; + }); + + if (!viewModel) { + throw new Error('Nested cell in the diff editor does not match any diff element'); + } + + if (viewModel.type === 'unchanged') { + return this.getLayoutInfo(); + } + + if (viewModel.type === 'insert' || viewModel.type === 'delete') { + return { + width: this._dimension!.width / 2, + height: this._dimension!.height / 2, + fontInfo: this._fontInfo! + }; + } + + if (viewModel.checkIfOutputsModified()) { + return { + width: this._dimension!.width / 2, + height: this._dimension!.height / 2, + fontInfo: this._fontInfo! + }; + } else { + return this.getLayoutInfo(); + } + } + layout(dimension: DOM.Dimension): void { this._rootElement.classList.toggle('mid-width', dimension.width < 1000 && dimension.width >= 600); this._rootElement.classList.toggle('narrow-width', dimension.width < 600); diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index 6707689f601..f9360dc25ab 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -102,6 +102,7 @@ export const outputHasDynamicHeight = (o: IRenderOutput) => o.type !== RenderOut export interface ICellOutputViewModel { + cellViewModel: IGenericCellViewModel; model: IProcessedOutput; isDisplayOutput(): this is IDisplayOutputViewModel; isErrorOutput(): this is IErrorOutputViewModel; @@ -149,7 +150,14 @@ export interface ICommonCellInfo { cellUri: URI; } +export interface INotebookCellOutputLayoutInfo { + width: number; + height: number; + fontInfo: BareFontInfo; +} + export interface ICommonNotebookEditor { + getCellOutputLayoutInfo(cell: IGenericCellViewModel): INotebookCellOutputLayoutInfo; triggerScroll(event: IMouseWheelEvent): void; getCellByInfo(cellInfo: ICommonCellInfo): IGenericCellViewModel; focusNotebookCell(cell: IGenericCellViewModel, focus: 'editor' | 'container' | 'output'): void; diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 065966363b2..40cdf985b20 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -42,7 +42,7 @@ import { Memento, MementoObject } from 'vs/workbench/common/memento'; import { PANEL_BORDER } from 'vs/workbench/common/theme'; import { debugIconStartForeground } from 'vs/workbench/contrib/debug/browser/debugToolBar'; import { BOTTOM_CELL_TOOLBAR_GAP, BOTTOM_CELL_TOOLBAR_HEIGHT, CELL_BOTTOM_MARGIN, CELL_MARGIN, CELL_RUN_GUTTER, CELL_TOP_MARGIN, CODE_CELL_LEFT_MARGIN, COLLAPSED_INDICATOR_HEIGHT, SCROLLABLE_ELEMENT_PADDING_TOP } from 'vs/workbench/contrib/notebook/browser/constants'; -import { CellEditState, CellFocusMode, IActiveNotebookEditor, ICellOutputViewModel, ICellViewModel, ICommonCellInfo, IDisplayOutputLayoutUpdateRequest, IDisplayOutputViewModel, IInsetRenderOutput, INotebookCellList, INotebookDeltaDecoration, INotebookEditor, INotebookEditorContribution, INotebookEditorContributionDescription, INotebookEditorCreationOptions, INotebookEditorMouseEvent, NotebookEditorOptions, NotebookLayoutInfo, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_RUNNABLE, NOTEBOOK_HAS_MULTIPLE_KERNELS, NOTEBOOK_OUTPUT_FOCUSED } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { CellEditState, CellFocusMode, IActiveNotebookEditor, ICellOutputViewModel, ICellViewModel, ICommonCellInfo, IDisplayOutputLayoutUpdateRequest, IDisplayOutputViewModel, IGenericCellViewModel, IInsetRenderOutput, INotebookCellList, INotebookCellOutputLayoutInfo, INotebookDeltaDecoration, INotebookEditor, INotebookEditorContribution, INotebookEditorContributionDescription, INotebookEditorCreationOptions, INotebookEditorMouseEvent, NotebookEditorOptions, NotebookLayoutInfo, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_RUNNABLE, NOTEBOOK_HAS_MULTIPLE_KERNELS, NOTEBOOK_OUTPUT_FOCUSED } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { NotebookEditorExtensionsRegistry } from 'vs/workbench/contrib/notebook/browser/notebookEditorExtensions'; import { NotebookKernelProviderAssociation, NotebookKernelProviderAssociations, notebookKernelProviderAssociationsSettingId } from 'vs/workbench/contrib/notebook/browser/notebookKernelAssociation'; import { NotebookCellList } from 'vs/workbench/contrib/notebook/browser/view/notebookCellList'; @@ -1870,6 +1870,18 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor }; } + getCellOutputLayoutInfo(cell: IGenericCellViewModel): INotebookCellOutputLayoutInfo { + if (!this._list) { + throw new Error('Editor is not initalized successfully'); + } + + return { + width: this._dimension!.width, + height: this._dimension!.height, + fontInfo: this._fontInfo! + }; + } + triggerScroll(event: IMouseWheelEvent) { this._list.triggerScrollFromMouseWheelEvent(event); } diff --git a/src/vs/workbench/contrib/notebook/browser/notebookRegistry.ts b/src/vs/workbench/contrib/notebook/browser/notebookRegistry.ts index abf2220cc6c..e97746c124c 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookRegistry.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookRegistry.ts @@ -5,9 +5,9 @@ import { CellOutputKind } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { BrandedService, IConstructorSignature1 } from 'vs/platform/instantiation/common/instantiation'; -import { INotebookEditor, IOutputTransformContribution } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { ICommonNotebookEditor, IOutputTransformContribution } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; -export type IOutputTransformCtor = IConstructorSignature1; +export type IOutputTransformCtor = IConstructorSignature1; export interface IOutputTransformDescription { id: string; @@ -20,7 +20,7 @@ export const NotebookRegistry = new class NotebookRegistryImpl { readonly outputTransforms: IOutputTransformDescription[] = []; - registerOutputTransform(id: string, kind: CellOutputKind, ctor: { new(editor: INotebookEditor, ...services: Services): IOutputTransformContribution }): void { + registerOutputTransform(id: string, kind: CellOutputKind, ctor: { new(editor: ICommonNotebookEditor, ...services: Services): IOutputTransformContribution }): void { this.outputTransforms.push({ id: id, kind: kind, ctor: ctor as IOutputTransformCtor }); } diff --git a/src/vs/workbench/contrib/notebook/browser/view/output/outputRenderer.ts b/src/vs/workbench/contrib/notebook/browser/view/output/outputRenderer.ts index 5d21b1cc3c2..39da33ff413 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/output/outputRenderer.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/output/outputRenderer.ts @@ -6,7 +6,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { NotebookRegistry } from 'vs/workbench/contrib/notebook/browser/notebookRegistry'; import { onUnexpectedError } from 'vs/base/common/errors'; -import { ICellOutputViewModel, INotebookEditor, IOutputTransformContribution, IRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { ICellOutputViewModel, ICommonNotebookEditor, IOutputTransformContribution, IRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { URI } from 'vs/base/common/uri'; export class OutputRenderer { @@ -14,7 +14,7 @@ export class OutputRenderer { protected readonly _mimeTypeMapping: { [key: number]: IOutputTransformContribution; }; constructor( - notebookEditor: INotebookEditor, + notebookEditor: ICommonNotebookEditor, private readonly instantiationService: IInstantiationService ) { this._contributions = {}; diff --git a/src/vs/workbench/contrib/notebook/browser/view/output/transforms/errorTransform.ts b/src/vs/workbench/contrib/notebook/browser/view/output/transforms/errorTransform.ts index 43586d0d998..8a0e7216d60 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/output/transforms/errorTransform.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/output/transforms/errorTransform.ts @@ -8,11 +8,11 @@ import { NotebookRegistry } from 'vs/workbench/contrib/notebook/browser/notebook import { RGBA, Color } from 'vs/base/common/color'; import { ansiColorIdentifiers } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { IErrorOutputViewModel, INotebookEditor, IOutputTransformContribution, IRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { ICommonNotebookEditor, IErrorOutputViewModel, IOutputTransformContribution, IRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; class ErrorTransform implements IOutputTransformContribution { constructor( - public editor: INotebookEditor, + public editor: ICommonNotebookEditor, @IThemeService private readonly themeService: IThemeService ) { } diff --git a/src/vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform.ts b/src/vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform.ts index eb29fc42dd1..420f309b407 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/output/transforms/richTransform.ts @@ -6,7 +6,7 @@ import { CellOutputKind } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { NotebookRegistry } from 'vs/workbench/contrib/notebook/browser/notebookRegistry'; import * as DOM from 'vs/base/browser/dom'; -import { IDisplayOutputViewModel, INotebookEditor, IOutputTransformContribution, IRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { ICommonNotebookEditor, IDisplayOutputViewModel, IOutputTransformContribution, IRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { isArray } from 'vs/base/common/types'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; @@ -25,7 +25,7 @@ class RichRenderer implements IOutputTransformContribution { private _richMimeTypeRenderers = new Map IRenderOutput>(); constructor( - public notebookEditor: INotebookEditor, + public notebookEditor: ICommonNotebookEditor, @IInstantiationService private readonly instantiationService: IInstantiationService, @IModelService private readonly modelService: IModelService, @IModeService private readonly modeService: IModeService, @@ -94,8 +94,8 @@ class RichRenderer implements IOutputTransformContribution { const textModel = this.modelService.createModel(str, mode, resource, false); editor.setModel(textModel); - const width = this.notebookEditor.getLayoutInfo().width; - const fontInfo = this.notebookEditor.getLayoutInfo().fontInfo; + const width = this.notebookEditor.getCellOutputLayoutInfo(output.cellViewModel).width; + const fontInfo = this.notebookEditor.getCellOutputLayoutInfo(output.cellViewModel).fontInfo; const height = Math.min(textModel.getLineCount(), 16) * (fontInfo.lineHeight || 18); editor.layout({ @@ -127,8 +127,8 @@ class RichRenderer implements IOutputTransformContribution { const textModel = this.modelService.createModel(str, mode, resource, false); editor.setModel(textModel); - const width = this.notebookEditor.getLayoutInfo().width; - const fontInfo = this.notebookEditor.getLayoutInfo().fontInfo; + const width = this.notebookEditor.getCellOutputLayoutInfo(output.cellViewModel).width; + const fontInfo = this.notebookEditor.getCellOutputLayoutInfo(output.cellViewModel).fontInfo; const height = Math.min(textModel.getLineCount(), 16) * (fontInfo.lineHeight || 18); editor.layout({ diff --git a/src/vs/workbench/contrib/notebook/browser/view/output/transforms/streamTransform.ts b/src/vs/workbench/contrib/notebook/browser/view/output/transforms/streamTransform.ts index 446c169057b..5f6f9b7737a 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/output/transforms/streamTransform.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/output/transforms/streamTransform.ts @@ -6,7 +6,7 @@ import * as DOM from 'vs/base/browser/dom'; import { CellOutputKind } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { NotebookRegistry } from 'vs/workbench/contrib/notebook/browser/notebookRegistry'; -import { INotebookEditor, IOutputTransformContribution, IRenderOutput, IStreamOutputViewModel, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { ICommonNotebookEditor, IOutputTransformContribution, IRenderOutput, IStreamOutputViewModel, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { truncatedArrayOfString } from 'vs/workbench/contrib/notebook/browser/view/output/transforms/textHelper'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; @@ -14,7 +14,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService'; class StreamRenderer implements IOutputTransformContribution { constructor( - editor: INotebookEditor, + editor: ICommonNotebookEditor, @IOpenerService readonly openerService: IOpenerService, @ITextFileService readonly textFileService: ITextFileService, @IThemeService readonly themeService: IThemeService diff --git a/src/vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel.ts b/src/vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel.ts index 6f3b8bdd43b..505c173fd6e 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Disposable } from 'vs/base/common/lifecycle'; -import { ICellOutputViewModel, IDisplayOutputViewModel, IErrorOutputViewModel, IStreamOutputViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { ICellOutputViewModel, IDisplayOutputViewModel, IErrorOutputViewModel, IGenericCellViewModel, IStreamOutputViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; import { CellOutputKind, IOrderedMimeType, IProcessedOutput, ITransformedDisplayOutputDto, RENDERER_NOT_AVAILABLE } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; @@ -24,11 +24,13 @@ export class CellOutputViewModel extends Disposable implements ICellOutputViewMo } constructor( + readonly cellViewModel: IGenericCellViewModel, private readonly _outputData: IProcessedOutput, private readonly _notebookService: INotebookService ) { super(); } + isStreamOutput(): this is IStreamOutputViewModel { return this._outputData.outputKind === CellOutputKind.Text; } diff --git a/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts b/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts index 497b93760da..1e8f4a83feb 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts @@ -79,12 +79,12 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod @INotebookService private _notebookService: INotebookService ) { super(viewType, model, UUID.generateUuid(), configurationService); - this._outputViewModels = this.model.outputs.map(output => new CellOutputViewModel(output, this._notebookService)); + this._outputViewModels = this.model.outputs.map(output => new CellOutputViewModel(this, output, this._notebookService)); this._register(this.model.onDidChangeOutputs((splices) => { splices.reverse().forEach(splice => { this._outputCollection.splice(splice[0], splice[1], ...splice[2].map(() => 0)); - this._outputViewModels.splice(splice[0], splice[1], ...splice[2].map(output => new CellOutputViewModel(output, this._notebookService))); + this._outputViewModels.splice(splice[0], splice[1], ...splice[2].map(output => new CellOutputViewModel(this, output, this._notebookService))); }); this._outputsTop = null; From 710360b7db4472f2674b010d8becb5c7a865de3f Mon Sep 17 00:00:00 2001 From: rebornix Date: Thu, 17 Dec 2020 10:22:29 -0800 Subject: [PATCH 058/262] resolveNotebookContentProviders does not take arguments. --- src/vs/workbench/api/common/extHostApiCommands.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vs/workbench/api/common/extHostApiCommands.ts b/src/vs/workbench/api/common/extHostApiCommands.ts index 08b2543a4a7..972664cdeba 100644 --- a/src/vs/workbench/api/common/extHostApiCommands.ts +++ b/src/vs/workbench/api/common/extHostApiCommands.ts @@ -275,9 +275,9 @@ const newCommands: ApiCommand[] = [ new ApiCommand( 'vscode.resolveNotebookContentProviders', '_resolveNotebookContentProvider', 'Resolve Notebook Content Providers', [ - new ApiCommandArgument('viewType', '', v => typeof v === 'string', v => v), - new ApiCommandArgument('displayName', '', v => typeof v === 'string', v => v), - new ApiCommandArgument('options', '', v => typeof v === 'object', v => v), + // new ApiCommandArgument('viewType', '', v => typeof v === 'string', v => v), + // new ApiCommandArgument('displayName', '', v => typeof v === 'string', v => v), + // new ApiCommandArgument('options', '', v => typeof v === 'object', v => v), ], new ApiCommandResult<{ viewType: string; From 877dad976eb50e29f31c8cdcb9cbe9df835f7ed9 Mon Sep 17 00:00:00 2001 From: rebornix Date: Thu, 17 Dec 2020 11:05:32 -0800 Subject: [PATCH 059/262] load renderers. --- .../notebook/browser/diff/diffComponents.ts | 3 ++- .../notebook/browser/diff/diffElementViewModel.ts | 2 +- .../browser/diff/notebookTextDiffEditor.ts | 15 ++++++++++----- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts index f140b91c806..549aaeccc82 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts @@ -1081,7 +1081,8 @@ export class ModifiedElement extends AbstractElementRenderer { } _hideOutputs() { - + this._outputLeftView?.hideOutputs(); + this._outputRightView?.hideOutputs(); } updateSourceEditor(): void { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts index a9cf7903172..5ffd45089d0 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts @@ -195,7 +195,7 @@ export class SideBySideDiffElementViewModel extends DiffElementViewModelBase { } checkIfOutputsModified() { - return !this.documentTextModel.transientOptions.transientOutputs && this.type === 'modified' && hash(this.original?.outputs ?? []) !== hash(this.modified?.outputs ?? []); + return !this.documentTextModel.transientOptions.transientOutputs && hash(this.original?.outputs ?? []) !== hash(this.modified?.outputs ?? []); } checkMetadataIfModified(): boolean { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 9ed315ea3f2..88693033af3 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -117,7 +117,12 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD const outputIndex = cell.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (output.model as ITransformedDisplayOutputDto).outputId); if (diffElement instanceof SideBySideDiffElementViewModel) { - diffElement.updateOutputHeight(false, outputIndex, outputHeight); + const info = CellUri.parse(cellInfo.cellUri); + if (!info) { + return; + } + + diffElement.updateOutputHeight(info.notebook.toString() === this._model?.original.resource.toString(), outputIndex, outputHeight); } else { (diffElement as SingleSideDiffElementViewModel).updateOutputHeight(outputIndex, outputHeight); } @@ -220,19 +225,19 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD if (this._modifiedWebview) { this._updateOutputsOffsetsInWebview(scrollTop, scrollHeight, this._modifiedWebview, (diffElement: DiffElementViewModelBase) => { return diffElement.modified; - }); + }, false); } if (this._originalWebview) { this._updateOutputsOffsetsInWebview(scrollTop, scrollHeight, this._originalWebview, (diffElement: DiffElementViewModelBase) => { return diffElement.original; - }); + }, true); } }); })); } - private _updateOutputsOffsetsInWebview(scrollTop: number, scrollHeight: number, activeWebview: BackLayerWebView, getActiveNestedCell: (diffElement: DiffElementViewModelBase) => DiffNestedCellViewModel | undefined) { + private _updateOutputsOffsetsInWebview(scrollTop: number, scrollHeight: number, activeWebview: BackLayerWebView, getActiveNestedCell: (diffElement: DiffElementViewModelBase) => DiffNestedCellViewModel | undefined, original: boolean) { activeWebview.element.style.height = `${scrollHeight}px`; if (activeWebview.insetMapping) { @@ -261,7 +266,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD const outputIndex = cell.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (key.model as ITransformedDisplayOutputDto).outputId); let outputOffset = 0; if (value.cellInfo.diffElement instanceof SideBySideDiffElementViewModel) { - outputOffset = cellTop + value.cellInfo.diffElement.getOutputOffsetInCell(false, outputIndex); + outputOffset = cellTop + value.cellInfo.diffElement.getOutputOffsetInCell(original, outputIndex); } else { outputOffset = cellTop + (value.cellInfo.diffElement as SingleSideDiffElementViewModel).getOutputOffsetInCell(outputIndex); } From c5d42b277220bc535d6723fa33db3d3ec37b4408 Mon Sep 17 00:00:00 2001 From: rebornix Date: Thu, 17 Dec 2020 12:38:05 -0800 Subject: [PATCH 060/262] renderers layout update --- .../notebook/browser/diff/diffComponents.ts | 24 ++++++++++++-- .../browser/diff/diffElementOutputs.ts | 2 +- .../browser/diff/notebookDiffEditorBrowser.ts | 6 ++-- .../browser/diff/notebookTextDiffEditor.ts | 33 +++++++++++++------ .../notebook/browser/notebookBrowser.ts | 4 +-- .../notebook/browser/notebookEditorWidget.ts | 2 +- .../view/renderers/backLayerWebView.ts | 11 ++++++- .../browser/view/renderers/webviewPreloads.ts | 1 + .../notebook/test/testNotebookEditor.ts | 2 +- 9 files changed, 64 insertions(+), 21 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts index 549aaeccc82..9fe8b05ff56 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts @@ -933,7 +933,6 @@ export class InsertElement extends SingleSideDiffElement { }); } - this.layoutNotebookCell(); if (this._diagonalFill) { @@ -1071,15 +1070,36 @@ export class ModifiedElement extends AbstractElementRenderer { this._outputRightView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell, this.cell.modified!, true, this._outputRightContainer!); this._outputRightView.render(); + const originalOutputRenderListener = this.notebookEditor.onDidDynamicOutputRendered(e => { + if (e.cell.uri.toString() === this.cell.original.uri.toString()) { + this.notebookEditor.deltaCellOutputContainerClassNames(true, this.cell.original.id, ['nb-cellDeleted'], []); + originalOutputRenderListener.dispose(); + } + }); + + const modifiedOutputRenderListener = this.notebookEditor.onDidDynamicOutputRendered(e => { + if (e.cell.uri.toString() === this.cell.modified.uri.toString()) { + this.notebookEditor.deltaCellOutputContainerClassNames(false, this.cell.modified.id, ['nb-cellAdded'], []); + modifiedOutputRenderListener.dispose(); + } + }); + + this._decorate(); this.cell.layoutChange(); } _showOutputs() { this._outputLeftView?.render(); this._outputRightView?.render(); + this._decorate(); this.cell.layoutChange(); } + _decorate() { + this.notebookEditor.deltaCellOutputContainerClassNames(true, this.cell.original.id, ['nb-cellDeleted'], []); + this.notebookEditor.deltaCellOutputContainerClassNames(false, this.cell.modified.id, ['nb-cellAdded'], []); + } + _hideOutputs() { this._outputLeftView?.hideOutputs(); this._outputRightView?.hideOutputs(); @@ -1179,8 +1199,6 @@ export class ModifiedElement extends AbstractElementRenderer { this.cell.editorHeight = contentHeight; } - - layout(state: { outerWidth?: boolean, editorHeight?: boolean, metadataEditor?: boolean, outputEditor?: boolean, outputView?: boolean }) { DOM.scheduleAtNextAnimationFrame(() => { if (state.editorHeight) { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts index 47351651b0b..c6507df68b1 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts @@ -85,7 +85,7 @@ export class OutputElement extends Disposable { this._diffElementViewModel, this._nestedCell, result, - this.getOutputOffsetInCell(index), + () => this.getOutputOffsetInCell(index), this._diffElementViewModel instanceof SideBySideDiffElementViewModel ? this._modified : this._diffElementViewModel.type === 'insert' diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts index 987772ddd3d..a78970d4475 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts @@ -22,11 +22,12 @@ export interface IDiffCellInfo extends ICommonCellInfo { export interface INotebookTextDiffEditor extends ICommonNotebookEditor { readonly textModel?: NotebookTextModel; onMouseUp: Event<{ readonly event: MouseEvent; readonly target: DiffElementViewModelBase; }>; + onDidDynamicOutputRendered: Event<{ cell: IGenericCellViewModel, output: IDisplayOutputViewModel }>; getOverflowContainerDomNode(): HTMLElement; getLayoutInfo(): NotebookLayoutInfo; layoutNotebookCell(cell: DiffElementViewModelBase, height: number): void; getOutputRenderer(): OutputRenderer; - createInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: IDiffNestedCellViewModel, output: IInsetRenderOutput, offset: number, rightEditor: boolean): void; + createInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: IDiffNestedCellViewModel, output: IInsetRenderOutput, getOffset: () => number, rightEditor: boolean): void; hideInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: IDiffNestedCellViewModel, output: IDisplayOutputViewModel): void; /** * Trigger the editor to scroll from scroll event programmatically @@ -35,7 +36,8 @@ export interface INotebookTextDiffEditor extends ICommonNotebookEditor { getCellByInfo(cellInfo: ICommonCellInfo): IGenericCellViewModel; focusNotebookCell(cell: IGenericCellViewModel, focus: 'editor' | 'container' | 'output'): void; focusNextNotebookCell(cell: IGenericCellViewModel, focus: 'editor' | 'container' | 'output'): void; - updateOutputHeight(cellInfo: ICommonCellInfo, output: IDisplayOutputViewModel, height: number): void; + updateOutputHeight(cellInfo: ICommonCellInfo, output: IDisplayOutputViewModel, height: number, isInit: boolean): void; + deltaCellOutputContainerClassNames(original: boolean, cellId: string, added: string[], removed: string[]): void; } export interface IDiffNestedCellViewModel { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 88693033af3..d975eb351f1 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -76,6 +76,10 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD private _revealFirst: boolean; private readonly _insetModifyQueueByOutputId = new SequencerByKey(); + protected _onDidDynamicOutputRendered = new Emitter<{ cell: IGenericCellViewModel, output: IDisplayOutputViewModel }>(); + onDidDynamicOutputRendered = this._onDidDynamicOutputRendered.event; + + private _isDisposed: boolean = false; get isDisposed() { @@ -111,7 +115,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD // throw new Error('Method not implemented.'); } - updateOutputHeight(cellInfo: IDiffCellInfo, output: IDisplayOutputViewModel, outputHeight: number): void { + updateOutputHeight(cellInfo: IDiffCellInfo, output: IDisplayOutputViewModel, outputHeight: number, isInit: boolean): void { const diffElement = cellInfo.diffElement; const cell = this.getCellByInfo(cellInfo); const outputIndex = cell.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (output.model as ITransformedDisplayOutputDto).outputId); @@ -126,6 +130,10 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD } else { (diffElement as SingleSideDiffElementViewModel).updateOutputHeight(outputIndex, outputHeight); } + + if (isInit) { + this._onDidDynamicOutputRendered.fire({ cell, output }); + } } protected createEditor(parent: HTMLElement): void { @@ -219,17 +227,14 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD return; } - const scrollTop = this._list.scrollTop; - const scrollHeight = this._list.scrollHeight; - if (this._modifiedWebview) { - this._updateOutputsOffsetsInWebview(scrollTop, scrollHeight, this._modifiedWebview, (diffElement: DiffElementViewModelBase) => { + this._updateOutputsOffsetsInWebview(this._list.scrollTop, this._list.scrollHeight, this._modifiedWebview, (diffElement: DiffElementViewModelBase) => { return diffElement.modified; }, false); } if (this._originalWebview) { - this._updateOutputsOffsetsInWebview(scrollTop, scrollHeight, this._originalWebview, (diffElement: DiffElementViewModelBase) => { + this._updateOutputsOffsetsInWebview(this._list.scrollTop, this._list.scrollHeight, this._originalWebview, (diffElement: DiffElementViewModelBase) => { return diffElement.original; }, true); } @@ -524,12 +529,12 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD this._list.triggerScrollFromMouseWheelEvent(event); } - createInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: DiffNestedCellViewModel, output: IInsetRenderOutput, offset: number, rightEditor: boolean): void { - this._insetModifyQueueByOutputId.queue(output.source.model.outputId, async () => { + createInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: DiffNestedCellViewModel, output: IInsetRenderOutput, getOffset: () => number, rightEditor: boolean): void { + this._insetModifyQueueByOutputId.queue(output.source.model.outputId + (rightEditor ? '-right' : 'left'), async () => { if (rightEditor) { if (!this._modifiedWebview!.insetMapping.has(output.source)) { const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel); - await this._modifiedWebview?.createInset({ diffElement: cellDiffViewModel, cellHandle: cellViewModel.handle, cellId: cellViewModel.id, cellUri: cellViewModel.uri }, output, cellTop, offset); + await this._modifiedWebview?.createInset({ diffElement: cellDiffViewModel, cellHandle: cellViewModel.handle, cellId: cellViewModel.id, cellUri: cellViewModel.uri }, output, cellTop, getOffset()); } else { const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel); const scrollTop = this._list.scrollTop; @@ -546,7 +551,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD } else { if (!this._originalWebview!.insetMapping.has(output.source)) { const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel); - await this._originalWebview?.createInset({ diffElement: cellDiffViewModel, cellHandle: cellViewModel.handle, cellId: cellViewModel.id, cellUri: cellViewModel.uri }, output, cellTop, offset); + await this._originalWebview?.createInset({ diffElement: cellDiffViewModel, cellHandle: cellViewModel.handle, cellId: cellViewModel.id, cellUri: cellViewModel.uri }, output, cellTop, getOffset()); } else { const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel); const scrollTop = this._list.scrollTop; @@ -614,6 +619,14 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD return this._outputRenderer; } + deltaCellOutputContainerClassNames(original: boolean, cellId: string, added: string[], removed: string[]) { + if (original) { + this._originalWebview?.deltaCellOutputContainerClassNames(cellId, added, removed); + } else { + this._modifiedWebview?.deltaCellOutputContainerClassNames(cellId, added, removed); + } + } + getLayoutInfo(): NotebookLayoutInfo { if (!this._list) { throw new Error('Editor is not initalized successfully'); diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index f9360dc25ab..a7031ca27e8 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -162,7 +162,7 @@ export interface ICommonNotebookEditor { getCellByInfo(cellInfo: ICommonCellInfo): IGenericCellViewModel; focusNotebookCell(cell: IGenericCellViewModel, focus: 'editor' | 'container' | 'output'): void; focusNextNotebookCell(cell: IGenericCellViewModel, focus: 'editor' | 'container' | 'output'): void; - updateOutputHeight(cellInfo: ICommonCellInfo, output: IDisplayOutputViewModel, height: number): void; + updateOutputHeight(cellInfo: ICommonCellInfo, output: IDisplayOutputViewModel, height: number, isInit: boolean): void; } //#endregion @@ -582,7 +582,7 @@ export interface INotebookEditor extends IEditor, ICommonNotebookEditor { getContribution(id: string): T; getCellByInfo(cellInfo: ICommonCellInfo): ICellViewModel; - updateOutputHeight(cellInfo: ICommonCellInfo, output: IDisplayOutputViewModel, height: number): void; + updateOutputHeight(cellInfo: ICommonCellInfo, output: IDisplayOutputViewModel, height: number, isInit: boolean): void; } export interface INotebookCellList { diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 40cdf985b20..f755014de6e 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -1968,7 +1968,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor return this.viewModel?.viewCells.find(vc => vc.handle === cellHandle) as CodeCellViewModel; } - updateOutputHeight(cellInfo: ICommonCellInfo, output: IDisplayOutputViewModel, outputHeight: number): void { + updateOutputHeight(cellInfo: ICommonCellInfo, output: IDisplayOutputViewModel, outputHeight: number, isInit: boolean): void { const cell = this.viewModel?.viewCells.find(vc => vc.handle === cellInfo.cellHandle); if (cell && cell instanceof CodeCellViewModel) { const outputIndex = cell.outputsViewModels.indexOf(output); diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index 18d1c33c037..e5b7bc40023 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -35,6 +35,7 @@ export interface IDimensionMessage { __vscode_notebook_message: boolean; type: 'dimension'; id: string; + init: boolean; data: DOM.Dimension; } @@ -269,6 +270,14 @@ export class BackLayerWebView extends Disposable { background-color: var(--vscode-notebook-symbolHighlightBackground); } + #container > div.nb-cellDeleted > div { + background-color: var(--vscode-diffEditor-removedTextBackground); + } + + #container > div.nb-cellAdded > div { + background-color: var(--vscode-diffEditor-insertedTextBackground); + } + #container > div > div > div { overflow-x: scroll; } @@ -452,7 +461,7 @@ var requirejs = (function() { const resolvedResult = this.resolveOutputId(data.id); if (resolvedResult) { const { cellInfo, output } = resolvedResult; - this.notebookEditor.updateOutputHeight(cellInfo, output, outputHeight); + this.notebookEditor.updateOutputHeight(cellInfo, output, outputHeight, !!data.init); } } else if (data.type === 'mouseenter') { const resolvedResult = this.resolveOutputId(data.id); diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts index a79a6da2443..d13b052b189 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/webviewPreloads.ts @@ -474,6 +474,7 @@ function webviewPreloads() { __vscode_notebook_message: true, type: 'dimension', id: outputId, + init: true, data: { height: outputNode.clientHeight } diff --git a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts index c624881feb9..0cf9e2612af 100644 --- a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts @@ -72,7 +72,7 @@ export class TestNotebookEditor implements INotebookEditor { getCellByInfo(cellInfo: ICommonCellInfo): ICellViewModel { throw new Error('Method not implemented.'); } - updateOutputHeight(cellInfo: ICommonCellInfo, output: IDisplayOutputViewModel, height: number): void { + updateOutputHeight(cellInfo: ICommonCellInfo, output: IDisplayOutputViewModel, height: number, isInit: boolean): void { throw new Error('Method not implemented.'); } async beginComputeContributedKernels(): Promise { From 681a3e413d0e99e00c009abeabf9a08faab66d80 Mon Sep 17 00:00:00 2001 From: rebornix Date: Thu, 17 Dec 2020 14:24:35 -0800 Subject: [PATCH 061/262] :build: --- .../notebook/browser/diff/diffComponents.ts | 30 +++++++++-- .../browser/diff/diffElementViewModel.ts | 14 ++++++ .../browser/diff/notebookDiffActions.ts | 50 ++++++++++++++++++- .../contrib/notebook/browser/notebookIcons.ts | 2 + .../notebook/test/testNotebookEditor.ts | 5 +- 5 files changed, 94 insertions(+), 7 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts index 9fe8b05ff56..956d050d807 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts @@ -33,8 +33,6 @@ import { collapsedIcon, expandedIcon } from 'vs/workbench/contrib/notebook/brows import { renderCodicons } from 'vs/base/browser/codicons'; import { OutputContainer } from 'vs/workbench/contrib/notebook/browser/diff/diffElementOutputs'; -const RENDER_RICH_OUTPUT = true; - const fixedEditorOptions: IEditorOptions = { padding: { top: 12, @@ -284,9 +282,15 @@ abstract class AbstractElementRenderer extends Disposable { } } - updateOutputRendering() { + updateOutputRendering(renderRichOutput: boolean = true) { if (this.cell.outputFoldingState === PropertyFoldingState.Expanded) { - if (RENDER_RICH_OUTPUT) { + if (renderRichOutput) { + if (this._outputEditorContainer) { + this._hideOutputs(); + this._outputEditorContainer.style.display = 'none'; + this._outputEditorDisposeStore.clear(); + } + this._outputInfoContainer.style.display = 'block'; if (!this._outputViewContainer) { @@ -297,7 +301,16 @@ abstract class AbstractElementRenderer extends Disposable { this._showOutputs(); // this.cell.layoutChange(); } + + this.cell.layoutChange(); + } else { + if (this._outputInfoContainer) { + this._hideOutputs(); + this._outputInfoContainer.style.display = 'none'; + this._outputEditorDisposeStore.clear(); + } + this._outputInfoContainer.style.display = 'block'; if (!this._outputEditorContainer || !this._outputEditor) { @@ -305,11 +318,14 @@ abstract class AbstractElementRenderer extends Disposable { this._outputEditorContainer = DOM.append(this._outputInfoContainer, DOM.$('.output-editor-container')); this._buildOutputEditor(); } else { + this._outputEditorContainer.style.display = 'block'; this.cell.outputHeight = this._outputEditor.getContentHeight(); } + + this.cell.layoutChange(); } } else { - if (RENDER_RICH_OUTPUT) { + if (renderRichOutput) { this._hideOutputs(); this._outputInfoContainer.style.display = 'none'; this._outputEditorDisposeStore.clear(); @@ -963,6 +979,10 @@ export class ModifiedElement extends AbstractElementRenderer { @IContextKeyService protected readonly contextKeyService: IContextKeyService ) { super(notebookEditor, cell, templateData, 'full', instantiationService, modeService, modelService, contextMenuService, keybindingService, notificationService, menuService, contextKeyService); + + this._register(cell.onDidStateChange(() => { + this.updateOutputRendering(this.cell.renderOutput); + })); } styleContainer(container: HTMLElement): void { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts index 5ffd45089d0..1dd0d4fe179 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts @@ -27,6 +27,9 @@ export abstract class DiffElementViewModelBase extends Disposable { public outputFoldingState: PropertyFoldingState; protected _layoutInfoEmitter = new Emitter(); onDidLayoutChange = this._layoutInfoEmitter.event; + protected _stateChangeEmitter = new Emitter<{ renderOutput: boolean; }>(); + onDidStateChange = this._stateChangeEmitter.event; + protected _layoutInfo!: { width: number; @@ -88,6 +91,17 @@ export abstract class DiffElementViewModelBase extends Disposable { return this._layoutInfo.metadataHeight; } + private _renderOutput = true; + + set renderOutput(value: boolean) { + this._renderOutput = value; + this._stateChangeEmitter.fire({ renderOutput: this._renderOutput }); + } + + get renderOutput() { + return this._renderOutput; + } + get totalHeight() { return this._layoutInfo.editorHeight + this._layoutInfo.editorMargin diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts index b88069d4fc4..5b3d84c23b8 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts @@ -11,7 +11,7 @@ import { ActiveEditorContext, viewColumnToEditorGroup } from 'vs/workbench/commo import { DiffElementViewModelBase } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; import { NotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor'; import { NotebookDiffEditorInput } from 'vs/workbench/contrib/notebook/browser/notebookDiffEditorInput'; -import { openAsTextIcon, revertIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons'; +import { openAsTextIcon, revertIcon, showOutputRawIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -81,6 +81,53 @@ registerAction2(class extends Action2 { } }); +// registerAction2(class extends Action2 { +// constructor() { +// super( +// { +// id: 'notebook.diff.cell.switchOutputRenderingStyle', +// title: localize('notebook.diff.cell.switchOutputRenderingStyle', "Switch Outputs Rendering"), +// icon: renderOutputIcon, +// f1: false, +// menu: { +// id: MenuId.NotebookDiffCellOutputsTitle +// } +// } +// ); +// } +// run(accessor: ServicesAccessor, context?: { cell: DiffElementViewModelBase }) { +// if (!context) { +// return; +// } + +// context.cell.renderOutput = true; +// } +// }); + + +registerAction2(class extends Action2 { + constructor() { + super( + { + id: 'notebook.diff.cell.switchOutputRenderingStyleToText', + title: localize('notebook.diff.cell.switchOutputRenderingStyleToText', "View outputs raw data"), + icon: showOutputRawIcon, + f1: false, + menu: { + id: MenuId.NotebookDiffCellOutputsTitle + }, + } + ); + } + run(accessor: ServicesAccessor, context?: { cell: DiffElementViewModelBase }) { + if (!context) { + return; + } + + context.cell.renderOutput = !context.cell.renderOutput; + } +}); + registerAction2(class extends Action2 { constructor() { super( @@ -111,6 +158,7 @@ registerAction2(class extends Action2 { } }); + registerAction2(class extends Action2 { constructor() { super( diff --git a/src/vs/workbench/contrib/notebook/browser/notebookIcons.ts b/src/vs/workbench/contrib/notebook/browser/notebookIcons.ts index 6780f1fa93f..ce2b0248ce2 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookIcons.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookIcons.ts @@ -29,4 +29,6 @@ export const collapsedIcon = registerIcon('notebook-collapsed', Codicon.chevronR export const expandedIcon = registerIcon('notebook-expanded', Codicon.chevronDown, localize('expandedIcon', 'Icon to annotated a expanded section in notebook editors.')); export const openAsTextIcon = registerIcon('notebook-open-as-text', Codicon.fileCode, localize('openAsTextIcon', 'Icon to open the notebook in a text editor.')); export const revertIcon = registerIcon('notebook-revert', Codicon.discard, localize('revertIcon', 'Icon to revert in notebook editors.')); +export const renderOutputIcon = registerIcon('notebook-render-output', Codicon.preview, localize('renderOutputIcon', 'Icon to render output in diff editor.')); +export const showOutputRawIcon = registerIcon('notebook-show-output-raw', Codicon.fileCode, localize('showOutputRawIcon', 'Icon to show output raw data.')); export const mimetypeIcon = registerIcon('notebook-mimetype', Codicon.code, localize('mimetypeIcon', 'Icon for a mime type in notebook editors.')); diff --git a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts index 0cf9e2612af..2efea75e07b 100644 --- a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts @@ -12,7 +12,7 @@ import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; import { Range } from 'vs/editor/common/core/range'; import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo'; import { EditorModel } from 'vs/workbench/common/editor'; -import { ICellViewModel, INotebookEditor, INotebookEditorContribution, INotebookEditorMouseEvent, NotebookLayoutInfo, INotebookDeltaDecoration, INotebookEditorCreationOptions, NotebookEditorOptions, ICellOutputViewModel, IInsetRenderOutput, IDisplayOutputViewModel, ICommonCellInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { ICellViewModel, INotebookEditor, INotebookEditorContribution, INotebookEditorMouseEvent, NotebookLayoutInfo, INotebookDeltaDecoration, INotebookEditorCreationOptions, NotebookEditorOptions, ICellOutputViewModel, IInsetRenderOutput, IDisplayOutputViewModel, ICommonCellInfo, IGenericCellViewModel, INotebookCellOutputLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer'; import { NotebookEventDispatcher } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher'; import { CellViewModel, IModelDecorationsChangeAccessor, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; @@ -66,6 +66,9 @@ export class TestNotebookEditor implements INotebookEditor { constructor( ) { } + getCellOutputLayoutInfo(cell: IGenericCellViewModel): INotebookCellOutputLayoutInfo { + throw new Error('Method not implemented.'); + } focusNextNotebookCell(cell: ICellViewModel, focus: 'editor' | 'container' | 'output'): void { throw new Error('Method not implemented.'); } From 819161c7bcaf78343f2397a871677b6c72aaa5cd Mon Sep 17 00:00:00 2001 From: rebornix Date: Thu, 17 Dec 2020 14:42:24 -0800 Subject: [PATCH 062/262] DiffSide enum to replace boolean. --- .../notebook/browser/diff/diffComponents.ts | 18 ++++++------- .../browser/diff/diffElementOutputs.ts | 22 ++++++++-------- .../browser/diff/diffElementViewModel.ts | 14 +++++----- .../browser/diff/notebookDiffEditorBrowser.ts | 9 +++++-- .../browser/diff/notebookTextDiffEditor.ts | 26 +++++++++---------- 5 files changed, 47 insertions(+), 42 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts index 956d050d807..30dfeb6d1ac 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts @@ -8,7 +8,7 @@ import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IDiffEditorOptions, IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { DiffElementViewModelBase, getFormatedMetadataJSON, PropertyFoldingState, SideBySideDiffElementViewModel, SingleSideDiffElementViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; -import { CellDiffSideBySideRenderTemplate, CellDiffSingleSideRenderTemplate, DIFF_CELL_MARGIN, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser'; +import { CellDiffSideBySideRenderTemplate, CellDiffSingleSideRenderTemplate, DiffSide, DIFF_CELL_MARGIN, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser'; import { EDITOR_BOTTOM_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; @@ -839,7 +839,7 @@ export class DeletedElement extends SingleSideDiffElement { } _buildOutputContainer() { - this._outputLeftView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell, this.cell.original!, false, this._outputViewContainer!); + this._outputLeftView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell, this.cell.original!, DiffSide.Original, this._outputViewContainer!); this._outputLeftView.render(); this.cell.layoutChange(); } @@ -912,7 +912,7 @@ export class InsertElement extends SingleSideDiffElement { } _buildOutputContainer() { - this._outputRightView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell, this.cell.modified!, true, this._outputViewContainer!); + this._outputRightView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell, this.cell.modified!, DiffSide.Modified, this._outputViewContainer!); this._outputRightView.render(); this.cell.layoutChange(); } @@ -1085,21 +1085,21 @@ export class ModifiedElement extends AbstractElementRenderer { this._outputLeftContainer = DOM.append(this._outputViewContainer!, DOM.$('.output-view-container-left')); this._outputRightContainer = DOM.append(this._outputViewContainer!, DOM.$('.output-view-container-right')); // We should use the original text model here - this._outputLeftView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell, this.cell.original!, false, this._outputLeftContainer!); + this._outputLeftView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell, this.cell.original!, DiffSide.Original, this._outputLeftContainer!); this._outputLeftView.render(); - this._outputRightView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell, this.cell.modified!, true, this._outputRightContainer!); + this._outputRightView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell, this.cell.modified!, DiffSide.Modified, this._outputRightContainer!); this._outputRightView.render(); const originalOutputRenderListener = this.notebookEditor.onDidDynamicOutputRendered(e => { if (e.cell.uri.toString() === this.cell.original.uri.toString()) { - this.notebookEditor.deltaCellOutputContainerClassNames(true, this.cell.original.id, ['nb-cellDeleted'], []); + this.notebookEditor.deltaCellOutputContainerClassNames(DiffSide.Original, this.cell.original.id, ['nb-cellDeleted'], []); originalOutputRenderListener.dispose(); } }); const modifiedOutputRenderListener = this.notebookEditor.onDidDynamicOutputRendered(e => { if (e.cell.uri.toString() === this.cell.modified.uri.toString()) { - this.notebookEditor.deltaCellOutputContainerClassNames(false, this.cell.modified.id, ['nb-cellAdded'], []); + this.notebookEditor.deltaCellOutputContainerClassNames(DiffSide.Modified, this.cell.modified.id, ['nb-cellAdded'], []); modifiedOutputRenderListener.dispose(); } }); @@ -1116,8 +1116,8 @@ export class ModifiedElement extends AbstractElementRenderer { } _decorate() { - this.notebookEditor.deltaCellOutputContainerClassNames(true, this.cell.original.id, ['nb-cellDeleted'], []); - this.notebookEditor.deltaCellOutputContainerClassNames(false, this.cell.modified.id, ['nb-cellAdded'], []); + this.notebookEditor.deltaCellOutputContainerClassNames(DiffSide.Original, this.cell.original.id, ['nb-cellDeleted'], []); + this.notebookEditor.deltaCellOutputContainerClassNames(DiffSide.Modified, this.cell.modified.id, ['nb-cellAdded'], []); } _hideOutputs() { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts index c6507df68b1..3c2e001525d 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts @@ -7,7 +7,7 @@ import * as DOM from 'vs/base/browser/dom'; import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { DiffElementViewModelBase, SideBySideDiffElementViewModel, SingleSideDiffElementViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; -import { INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser'; +import { DiffSide, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser'; import { ICellOutputViewModel, IRenderOutput, outputHasDynamicHeight, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { getResizesObserver } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellWidgets'; import { CellOutputViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel'; @@ -27,7 +27,7 @@ export class OutputElement extends Disposable { private _notebookTextModel: NotebookTextModel, private _notebookService: INotebookService, private _diffElementViewModel: DiffElementViewModelBase, - private _modified: boolean, + private _diffVersion: DiffSide, private _nestedCell: DiffNestedCellViewModel, private _outputContainer: HTMLElement, @@ -87,8 +87,8 @@ export class OutputElement extends Disposable { result, () => this.getOutputOffsetInCell(index), this._diffElementViewModel instanceof SideBySideDiffElementViewModel - ? this._modified - : this._diffElementViewModel.type === 'insert' + ? this._diffVersion + : this._diffElementViewModel.type === 'insert' ? DiffSide.Modified : DiffSide.Original ); } else { outputItemDiv.classList.add('foreground', 'output-element'); @@ -134,7 +134,7 @@ export class OutputElement extends Disposable { getCellOutputCurrentIndex() { if (this._diffElementViewModel instanceof SideBySideDiffElementViewModel) { - if (this._modified) { + if (this._diffVersion === DiffSide.Modified) { return this._diffElementViewModel.modified.outputs.indexOf(this.output.model); } else { return this._diffElementViewModel.original.outputs.indexOf(this.output.model); @@ -146,7 +146,7 @@ export class OutputElement extends Disposable { updateHeight(index: number, height: number) { if (this._diffElementViewModel instanceof SideBySideDiffElementViewModel) { - this._diffElementViewModel.updateOutputHeight(!this._modified, index, height); + this._diffElementViewModel.updateOutputHeight(this._diffVersion, index, height); } else { (this._diffElementViewModel as SingleSideDiffElementViewModel).updateOutputHeight(index, height); } @@ -154,7 +154,7 @@ export class OutputElement extends Disposable { getOutputOffsetInContainer(index: number) { if (this._diffElementViewModel instanceof SideBySideDiffElementViewModel) { - return this._diffElementViewModel.getOutputOffsetInContainer(!this._modified, index); + return this._diffElementViewModel.getOutputOffsetInContainer(this._diffVersion, index); } else { return (this._diffElementViewModel as SingleSideDiffElementViewModel).getOutputOffsetInContainer(index); } @@ -162,7 +162,7 @@ export class OutputElement extends Disposable { getOutputOffsetInCell(index: number) { if (this._diffElementViewModel instanceof SideBySideDiffElementViewModel) { - return this._diffElementViewModel.getOutputOffsetInCell(!this._modified, index); + return this._diffElementViewModel.getOutputOffsetInCell(this._diffVersion, index); } else { return (this._diffElementViewModel as SingleSideDiffElementViewModel).getOutputOffsetInCell(index); } @@ -177,7 +177,7 @@ export class OutputContainer extends Disposable { private _notebookTextModel: NotebookTextModel, private _diffElementViewModel: DiffElementViewModelBase, private _nestedCellViewModel: DiffNestedCellViewModel, - private _modified: boolean, + private _diffVersion: DiffSide, private _outputContainer: HTMLElement, @INotebookService private _notebookService: INotebookService, // @IQuickInputService private readonly quickInputService: IQuickInputService, @@ -198,7 +198,7 @@ export class OutputContainer extends Disposable { const index = _nestedCellViewModel.outputs.indexOf(key.model); if (index >= 0) { if (this._diffElementViewModel instanceof SideBySideDiffElementViewModel) { - const top = this._diffElementViewModel.getOutputOffsetInContainer(!this._modified, index); + const top = this._diffElementViewModel.getOutputOffsetInContainer(this._diffVersion, index); value.domNode.style.top = `${top}px`; } else { const top = (this._diffElementViewModel as SingleSideDiffElementViewModel).getOutputOffsetInContainer(index); @@ -229,7 +229,7 @@ export class OutputContainer extends Disposable { private _renderOutput(currOutput: ICellOutputViewModel, index: number, beforeElement?: HTMLElement) { if (!this._outputEntries.has(currOutput)) { - this._outputEntries.set(currOutput, new OutputElement(this._editor, this._notebookTextModel, this._notebookService, this._diffElementViewModel, this._modified, this._nestedCellViewModel, this._outputContainer, currOutput)); + this._outputEntries.set(currOutput, new OutputElement(this._editor, this._notebookTextModel, this._notebookService, this._diffElementViewModel, this._diffVersion, this._nestedCellViewModel, this._outputContainer, currOutput)); } const renderElement = this._outputEntries.get(currOutput)!; diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts index 1dd0d4fe179..d95720fb199 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts @@ -6,7 +6,7 @@ import { NotebookDiffEditorEventDispatcher } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher'; import { Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; -import { CellDiffViewModelLayoutChangeEvent, DIFF_CELL_MARGIN } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser'; +import { CellDiffViewModelLayoutChangeEvent, DiffSide, DIFF_CELL_MARGIN } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser'; import { IGenericCellViewModel, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; @@ -216,24 +216,24 @@ export class SideBySideDiffElementViewModel extends DiffElementViewModelBase { return hash(getFormatedMetadataJSON(this.documentTextModel, this.original?.metadata || {}, this.original?.language)) !== hash(getFormatedMetadataJSON(this.documentTextModel, this.modified?.metadata ?? {}, this.modified?.language)); } - updateOutputHeight(original: boolean, index: number, height: number) { - if (original) { + updateOutputHeight(diffSide: DiffSide, index: number, height: number) { + if (diffSide === DiffSide.Original) { this.original.updateOutputHeight(index, height); } else { this.modified.updateOutputHeight(index, height); } } - getOutputOffsetInContainer(original: boolean, index: number) { - if (original) { + getOutputOffsetInContainer(diffSide: DiffSide, index: number) { + if (diffSide === DiffSide.Original) { return this.original.getOutputOffset(index); } else { return this.modified.getOutputOffset(index); } } - getOutputOffsetInCell(original: boolean, index: number) { - const offsetInOutputsContainer = this.getOutputOffsetInContainer(original, index); + getOutputOffsetInCell(diffSide: DiffSide, index: number) { + const offsetInOutputsContainer = this.getOutputOffsetInContainer(diffSide, index); return this._layoutInfo.editorHeight + this._layoutInfo.editorMargin diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts index a78970d4475..50e07189d1b 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts @@ -15,6 +15,11 @@ import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer'; import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; +export enum DiffSide { + Original = 0, + Modified = 1 +} + export interface IDiffCellInfo extends ICommonCellInfo { diffElement: DiffElementViewModelBase; } @@ -27,7 +32,7 @@ export interface INotebookTextDiffEditor extends ICommonNotebookEditor { getLayoutInfo(): NotebookLayoutInfo; layoutNotebookCell(cell: DiffElementViewModelBase, height: number): void; getOutputRenderer(): OutputRenderer; - createInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: IDiffNestedCellViewModel, output: IInsetRenderOutput, getOffset: () => number, rightEditor: boolean): void; + createInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: IDiffNestedCellViewModel, output: IInsetRenderOutput, getOffset: () => number, diffSide: DiffSide): void; hideInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: IDiffNestedCellViewModel, output: IDisplayOutputViewModel): void; /** * Trigger the editor to scroll from scroll event programmatically @@ -37,7 +42,7 @@ export interface INotebookTextDiffEditor extends ICommonNotebookEditor { focusNotebookCell(cell: IGenericCellViewModel, focus: 'editor' | 'container' | 'output'): void; focusNextNotebookCell(cell: IGenericCellViewModel, focus: 'editor' | 'container' | 'output'): void; updateOutputHeight(cellInfo: ICommonCellInfo, output: IDisplayOutputViewModel, height: number, isInit: boolean): void; - deltaCellOutputContainerClassNames(original: boolean, cellId: string, added: string[], removed: string[]): void; + deltaCellOutputContainerClassNames(diffSide: DiffSide, cellId: string, added: string[], removed: string[]): void; } export interface IDiffNestedCellViewModel { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index d975eb351f1..b546e4de0cc 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -24,7 +24,7 @@ import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; import { getZoomLevel } from 'vs/base/browser/browser'; import { IDisplayOutputLayoutUpdateRequest, IDisplayOutputViewModel, IGenericCellViewModel, IInsetRenderOutput, INotebookEditor, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; -import { DIFF_CELL_MARGIN, IDiffCellInfo, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser'; +import { DiffSide, DIFF_CELL_MARGIN, IDiffCellInfo, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser'; import { Emitter } from 'vs/base/common/event'; import { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { NotebookDiffEditorEventDispatcher, NotebookLayoutChangedEvent } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher'; @@ -126,7 +126,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD return; } - diffElement.updateOutputHeight(info.notebook.toString() === this._model?.original.resource.toString(), outputIndex, outputHeight); + diffElement.updateOutputHeight(info.notebook.toString() === this._model?.original.resource.toString() ? DiffSide.Original : DiffSide.Modified, outputIndex, outputHeight); } else { (diffElement as SingleSideDiffElementViewModel).updateOutputHeight(outputIndex, outputHeight); } @@ -230,19 +230,19 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD if (this._modifiedWebview) { this._updateOutputsOffsetsInWebview(this._list.scrollTop, this._list.scrollHeight, this._modifiedWebview, (diffElement: DiffElementViewModelBase) => { return diffElement.modified; - }, false); + }, DiffSide.Modified); } if (this._originalWebview) { this._updateOutputsOffsetsInWebview(this._list.scrollTop, this._list.scrollHeight, this._originalWebview, (diffElement: DiffElementViewModelBase) => { return diffElement.original; - }, true); + }, DiffSide.Original); } }); })); } - private _updateOutputsOffsetsInWebview(scrollTop: number, scrollHeight: number, activeWebview: BackLayerWebView, getActiveNestedCell: (diffElement: DiffElementViewModelBase) => DiffNestedCellViewModel | undefined, original: boolean) { + private _updateOutputsOffsetsInWebview(scrollTop: number, scrollHeight: number, activeWebview: BackLayerWebView, getActiveNestedCell: (diffElement: DiffElementViewModelBase) => DiffNestedCellViewModel | undefined, diffSide: DiffSide) { activeWebview.element.style.height = `${scrollHeight}px`; if (activeWebview.insetMapping) { @@ -271,7 +271,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD const outputIndex = cell.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (key.model as ITransformedDisplayOutputDto).outputId); let outputOffset = 0; if (value.cellInfo.diffElement instanceof SideBySideDiffElementViewModel) { - outputOffset = cellTop + value.cellInfo.diffElement.getOutputOffsetInCell(original, outputIndex); + outputOffset = cellTop + value.cellInfo.diffElement.getOutputOffsetInCell(diffSide, outputIndex); } else { outputOffset = cellTop + (value.cellInfo.diffElement as SingleSideDiffElementViewModel).getOutputOffsetInCell(outputIndex); } @@ -529,9 +529,9 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD this._list.triggerScrollFromMouseWheelEvent(event); } - createInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: DiffNestedCellViewModel, output: IInsetRenderOutput, getOffset: () => number, rightEditor: boolean): void { - this._insetModifyQueueByOutputId.queue(output.source.model.outputId + (rightEditor ? '-right' : 'left'), async () => { - if (rightEditor) { + createInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: DiffNestedCellViewModel, output: IInsetRenderOutput, getOffset: () => number, diffSide: DiffSide): void { + this._insetModifyQueueByOutputId.queue(output.source.model.outputId + (diffSide === DiffSide.Modified ? '-right' : 'left'), async () => { + if (diffSide === DiffSide.Modified) { if (!this._modifiedWebview!.insetMapping.has(output.source)) { const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel); await this._modifiedWebview?.createInset({ diffElement: cellDiffViewModel, cellHandle: cellViewModel.handle, cellId: cellViewModel.id, cellUri: cellViewModel.uri }, output, cellTop, getOffset()); @@ -541,7 +541,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD const outputIndex = cellViewModel.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (output.source.model as ITransformedDisplayOutputDto).outputId); let outputOffset = 0; if (cellDiffViewModel instanceof SideBySideDiffElementViewModel) { - outputOffset = cellTop + cellDiffViewModel.getOutputOffsetInCell(false, outputIndex); + outputOffset = cellTop + cellDiffViewModel.getOutputOffsetInCell(diffSide, outputIndex); } else { outputOffset = cellTop + (cellDiffViewModel as SingleSideDiffElementViewModel).getOutputOffsetInCell(outputIndex); } @@ -558,7 +558,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD const outputIndex = cellViewModel.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (output.source.model as ITransformedDisplayOutputDto).outputId); let outputOffset = 0; if (cellDiffViewModel instanceof SideBySideDiffElementViewModel) { - outputOffset = cellTop + cellDiffViewModel.getOutputOffsetInCell(true, outputIndex); + outputOffset = cellTop + cellDiffViewModel.getOutputOffsetInCell(diffSide, outputIndex); } else { outputOffset = cellTop + (cellDiffViewModel as SingleSideDiffElementViewModel).getOutputOffsetInCell(outputIndex); } @@ -619,8 +619,8 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD return this._outputRenderer; } - deltaCellOutputContainerClassNames(original: boolean, cellId: string, added: string[], removed: string[]) { - if (original) { + deltaCellOutputContainerClassNames(diffSide: DiffSide, cellId: string, added: string[], removed: string[]) { + if (diffSide === DiffSide.Original) { this._originalWebview?.deltaCellOutputContainerClassNames(cellId, added, removed); } else { this._modifiedWebview?.deltaCellOutputContainerClassNames(cellId, added, removed); From 6d378dbadea7e31bb0ab1b9a9a3c3a0484253022 Mon Sep 17 00:00:00 2001 From: rebornix Date: Thu, 17 Dec 2020 14:52:14 -0800 Subject: [PATCH 063/262] no more casting for Single/SidebySide diff view model. --- .../browser/diff/diffElementOutputs.ts | 25 +++++-------------- .../browser/diff/diffElementViewModel.ts | 7 ++++-- .../browser/diff/notebookTextDiffEditor.ts | 19 +++----------- 3 files changed, 15 insertions(+), 36 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts index 3c2e001525d..f5f326cba67 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts @@ -27,8 +27,7 @@ export class OutputElement extends Disposable { private _notebookTextModel: NotebookTextModel, private _notebookService: INotebookService, private _diffElementViewModel: DiffElementViewModelBase, - private _diffVersion: DiffSide, - + private _diffSide: DiffSide, private _nestedCell: DiffNestedCellViewModel, private _outputContainer: HTMLElement, readonly output: ICellOutputViewModel @@ -87,7 +86,7 @@ export class OutputElement extends Disposable { result, () => this.getOutputOffsetInCell(index), this._diffElementViewModel instanceof SideBySideDiffElementViewModel - ? this._diffVersion + ? this._diffSide : this._diffElementViewModel.type === 'insert' ? DiffSide.Modified : DiffSide.Original ); } else { @@ -134,7 +133,7 @@ export class OutputElement extends Disposable { getCellOutputCurrentIndex() { if (this._diffElementViewModel instanceof SideBySideDiffElementViewModel) { - if (this._diffVersion === DiffSide.Modified) { + if (this._diffSide === DiffSide.Modified) { return this._diffElementViewModel.modified.outputs.indexOf(this.output.model); } else { return this._diffElementViewModel.original.outputs.indexOf(this.output.model); @@ -145,27 +144,15 @@ export class OutputElement extends Disposable { } updateHeight(index: number, height: number) { - if (this._diffElementViewModel instanceof SideBySideDiffElementViewModel) { - this._diffElementViewModel.updateOutputHeight(this._diffVersion, index, height); - } else { - (this._diffElementViewModel as SingleSideDiffElementViewModel).updateOutputHeight(index, height); - } + this._diffElementViewModel.updateOutputHeight(this._diffSide, index, height); } getOutputOffsetInContainer(index: number) { - if (this._diffElementViewModel instanceof SideBySideDiffElementViewModel) { - return this._diffElementViewModel.getOutputOffsetInContainer(this._diffVersion, index); - } else { - return (this._diffElementViewModel as SingleSideDiffElementViewModel).getOutputOffsetInContainer(index); - } + return this._diffElementViewModel.getOutputOffsetInContainer(this._diffSide, index); } getOutputOffsetInCell(index: number) { - if (this._diffElementViewModel instanceof SideBySideDiffElementViewModel) { - return this._diffElementViewModel.getOutputOffsetInCell(this._diffVersion, index); - } else { - return (this._diffElementViewModel as SingleSideDiffElementViewModel).getOutputOffsetInCell(index); - } + return this._diffElementViewModel.getOutputOffsetInCell(this._diffSide, index); } } diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts index d95720fb199..b1cace76689 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts @@ -147,6 +147,9 @@ export abstract class DiffElementViewModelBase extends Disposable { abstract checkMetadataIfModified(): boolean; abstract layoutChange(): void; abstract getCellByUri(cellUri: URI): IGenericCellViewModel; + abstract getOutputOffsetInCell(diffSide: DiffSide, index: number): number; + abstract getOutputOffsetInContainer(diffSide: DiffSide, index: number): number; + abstract updateOutputHeight(diffSide: DiffSide, index: number, height: number): void; getComputedCellContainerWidth(layoutInfo: NotebookLayoutInfo, diffEditor: boolean, fullWidth: boolean) { if (fullWidth) { @@ -300,7 +303,7 @@ export class SingleSideDiffElementViewModel extends DiffElementViewModelBase { return false; } - updateOutputHeight(index: number, height: number) { + updateOutputHeight(diffSide: DiffSide, index: number, height: number) { this.cellViewModel?.updateOutputHeight(index, height); } @@ -308,7 +311,7 @@ export class SingleSideDiffElementViewModel extends DiffElementViewModelBase { return this.cellViewModel!.getOutputOffset(index); } - getOutputOffsetInCell(index: number) { + getOutputOffsetInCell(diffSide: DiffSide, index: number) { const offsetInOutputsContainer = this.cellViewModel!.getOutputOffset(index); return this._layoutInfo.editorHeight diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index b546e4de0cc..09556fb7302 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -128,7 +128,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD diffElement.updateOutputHeight(info.notebook.toString() === this._model?.original.resource.toString() ? DiffSide.Original : DiffSide.Modified, outputIndex, outputHeight); } else { - (diffElement as SingleSideDiffElementViewModel).updateOutputHeight(outputIndex, outputHeight); + diffElement.updateOutputHeight(diffElement.type === 'insert' ? DiffSide.Modified : DiffSide.Original, outputIndex, outputHeight); } if (isInit) { @@ -269,12 +269,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD if (activeWebview.shouldUpdateInset(cell, key, cellTop)) { // TODO: why? does it mean, we create new output view model every time? const outputIndex = cell.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (key.model as ITransformedDisplayOutputDto).outputId); - let outputOffset = 0; - if (value.cellInfo.diffElement instanceof SideBySideDiffElementViewModel) { - outputOffset = cellTop + value.cellInfo.diffElement.getOutputOffsetInCell(diffSide, outputIndex); - } else { - outputOffset = cellTop + (value.cellInfo.diffElement as SingleSideDiffElementViewModel).getOutputOffsetInCell(outputIndex); - } + const outputOffset = cellTop + value.cellInfo.diffElement.getOutputOffsetInCell(diffSide, outputIndex); updateItems.push({ output: key, @@ -543,7 +538,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD if (cellDiffViewModel instanceof SideBySideDiffElementViewModel) { outputOffset = cellTop + cellDiffViewModel.getOutputOffsetInCell(diffSide, outputIndex); } else { - outputOffset = cellTop + (cellDiffViewModel as SingleSideDiffElementViewModel).getOutputOffsetInCell(outputIndex); + outputOffset = cellTop + (cellDiffViewModel as SingleSideDiffElementViewModel).getOutputOffsetInCell(diffSide, outputIndex); } this._modifiedWebview!.updateViewScrollTop(-scrollTop, true, [{ output: output.source, cellTop, outputOffset }]); @@ -556,13 +551,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel); const scrollTop = this._list.scrollTop; const outputIndex = cellViewModel.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (output.source.model as ITransformedDisplayOutputDto).outputId); - let outputOffset = 0; - if (cellDiffViewModel instanceof SideBySideDiffElementViewModel) { - outputOffset = cellTop + cellDiffViewModel.getOutputOffsetInCell(diffSide, outputIndex); - } else { - outputOffset = cellTop + (cellDiffViewModel as SingleSideDiffElementViewModel).getOutputOffsetInCell(outputIndex); - } - + const outputOffset = cellTop + cellDiffViewModel.getOutputOffsetInCell(diffSide, outputIndex); this._originalWebview!.updateViewScrollTop(-scrollTop, true, [{ output: output.source, cellTop, outputOffset }]); } } From 1c2d88e68baa63583c230f65328851134c357df8 Mon Sep 17 00:00:00 2001 From: rebornix Date: Thu, 17 Dec 2020 14:58:40 -0800 Subject: [PATCH 064/262] fewer weird as cast --- .../browser/diff/diffElementOutputs.ts | 23 ++++--------------- .../browser/diff/diffElementViewModel.ts | 13 +++++++++-- .../browser/diff/notebookTextDiffEditor.ts | 9 ++------ 3 files changed, 18 insertions(+), 27 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts index f5f326cba67..55c9d7b4fda 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts @@ -132,15 +132,7 @@ export class OutputElement extends Disposable { } getCellOutputCurrentIndex() { - if (this._diffElementViewModel instanceof SideBySideDiffElementViewModel) { - if (this._diffSide === DiffSide.Modified) { - return this._diffElementViewModel.modified.outputs.indexOf(this.output.model); - } else { - return this._diffElementViewModel.original.outputs.indexOf(this.output.model); - } - } else { - return (this._diffElementViewModel as SingleSideDiffElementViewModel).cellViewModel!.outputs.indexOf(this.output.model); - } + return this._diffElementViewModel.getNestedCellViewModel(this._diffSide).outputs.indexOf(this.output.model); } updateHeight(index: number, height: number) { @@ -164,7 +156,7 @@ export class OutputContainer extends Disposable { private _notebookTextModel: NotebookTextModel, private _diffElementViewModel: DiffElementViewModelBase, private _nestedCellViewModel: DiffNestedCellViewModel, - private _diffVersion: DiffSide, + private _diffSide: DiffSide, private _outputContainer: HTMLElement, @INotebookService private _notebookService: INotebookService, // @IQuickInputService private readonly quickInputService: IQuickInputService, @@ -184,13 +176,8 @@ export class OutputContainer extends Disposable { this._outputEntries.forEach((value, key) => { const index = _nestedCellViewModel.outputs.indexOf(key.model); if (index >= 0) { - if (this._diffElementViewModel instanceof SideBySideDiffElementViewModel) { - const top = this._diffElementViewModel.getOutputOffsetInContainer(this._diffVersion, index); - value.domNode.style.top = `${top}px`; - } else { - const top = (this._diffElementViewModel as SingleSideDiffElementViewModel).getOutputOffsetInContainer(index); - value.domNode.style.top = `${top}px`; - } + const top = this._diffElementViewModel.getOutputOffsetInContainer(this._diffSide, index); + value.domNode.style.top = `${top}px`; } }); })); @@ -216,7 +203,7 @@ export class OutputContainer extends Disposable { private _renderOutput(currOutput: ICellOutputViewModel, index: number, beforeElement?: HTMLElement) { if (!this._outputEntries.has(currOutput)) { - this._outputEntries.set(currOutput, new OutputElement(this._editor, this._notebookTextModel, this._notebookService, this._diffElementViewModel, this._diffVersion, this._nestedCellViewModel, this._outputContainer, currOutput)); + this._outputEntries.set(currOutput, new OutputElement(this._editor, this._notebookTextModel, this._notebookService, this._diffElementViewModel, this._diffSide, this._nestedCellViewModel, this._outputContainer, currOutput)); } const renderElement = this._outputEntries.get(currOutput)!; diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts index b1cace76689..116569e0ae6 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts @@ -150,6 +150,7 @@ export abstract class DiffElementViewModelBase extends Disposable { abstract getOutputOffsetInCell(diffSide: DiffSide, index: number): number; abstract getOutputOffsetInContainer(diffSide: DiffSide, index: number): number; abstract updateOutputHeight(diffSide: DiffSide, index: number, height: number): void; + abstract getNestedCellViewModel(diffSide: DiffSide): DiffNestedCellViewModel; getComputedCellContainerWidth(layoutInfo: NotebookLayoutInfo, diffEditor: boolean, fullWidth: boolean) { if (fullWidth) { @@ -251,6 +252,10 @@ export class SideBySideDiffElementViewModel extends DiffElementViewModelBase { return Math.max(this.original.getOutputTotalHeight(), this.modified.getOutputTotalHeight()); } + getNestedCellViewModel(diffSide: DiffSide): DiffNestedCellViewModel { + throw new Error('Method not implemented.'); + } + getCellByUri(cellUri: URI): IGenericCellViewModel { if (cellUri.toString() === this.original.uri.toString()) { return this.original; @@ -262,7 +267,7 @@ export class SideBySideDiffElementViewModel extends DiffElementViewModelBase { export class SingleSideDiffElementViewModel extends DiffElementViewModelBase { get cellViewModel() { - return this.type === 'insert' ? this.modified : this.original; + return this.type === 'insert' ? this.modified! : this.original!; } constructor( @@ -278,6 +283,10 @@ export class SingleSideDiffElementViewModel extends DiffElementViewModelBase { })); } + getNestedCellViewModel(diffSide: DiffSide): DiffNestedCellViewModel { + return this.type === 'insert' ? this.modified! : this.original!; + } + layoutChange() { let outputHeight = this.outputFoldingState === PropertyFoldingState.Collapsed ? 0 : this.getOutputTotalHeight(); this._layoutInfo = { @@ -307,7 +316,7 @@ export class SingleSideDiffElementViewModel extends DiffElementViewModelBase { this.cellViewModel?.updateOutputHeight(index, height); } - getOutputOffsetInContainer(index: number) { + getOutputOffsetInContainer(diffSide: DiffSide, index: number) { return this.cellViewModel!.getOutputOffset(index); } diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 09556fb7302..06d9e9844f9 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -104,7 +104,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD this._register(this._modifiedResourceDisposableStore); // TODO - this._outputRenderer = new OutputRenderer(this as unknown as INotebookEditor, this.instantiationService); + this._outputRenderer = new OutputRenderer(this, this.instantiationService); } focusNotebookCell(cell: IGenericCellViewModel, focus: 'output' | 'editor' | 'container'): void { @@ -535,12 +535,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD const scrollTop = this._list.scrollTop; const outputIndex = cellViewModel.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (output.source.model as ITransformedDisplayOutputDto).outputId); let outputOffset = 0; - if (cellDiffViewModel instanceof SideBySideDiffElementViewModel) { - outputOffset = cellTop + cellDiffViewModel.getOutputOffsetInCell(diffSide, outputIndex); - } else { - outputOffset = cellTop + (cellDiffViewModel as SingleSideDiffElementViewModel).getOutputOffsetInCell(diffSide, outputIndex); - } - + outputOffset = cellTop + cellDiffViewModel.getOutputOffsetInCell(diffSide, outputIndex); this._modifiedWebview!.updateViewScrollTop(-scrollTop, true, [{ output: output.source, cellTop, outputOffset }]); } } else { From 8d5b2904fa2031788bb06d8db86785fd055386eb Mon Sep 17 00:00:00 2001 From: rebornix Date: Thu, 17 Dec 2020 14:59:04 -0800 Subject: [PATCH 065/262] :lipstick: --- .../contrib/notebook/browser/diff/diffElementOutputs.ts | 2 +- .../contrib/notebook/browser/diff/notebookTextDiffEditor.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts index 55c9d7b4fda..b93b348e5c4 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts @@ -6,7 +6,7 @@ import * as DOM from 'vs/base/browser/dom'; import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { DiffElementViewModelBase, SideBySideDiffElementViewModel, SingleSideDiffElementViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; +import { DiffElementViewModelBase, SideBySideDiffElementViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; import { DiffSide, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser'; import { ICellOutputViewModel, IRenderOutput, outputHasDynamicHeight, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { getResizesObserver } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellWidgets'; diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 06d9e9844f9..dfdc8b8d6ba 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -23,7 +23,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; import { getZoomLevel } from 'vs/base/browser/browser'; -import { IDisplayOutputLayoutUpdateRequest, IDisplayOutputViewModel, IGenericCellViewModel, IInsetRenderOutput, INotebookEditor, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { IDisplayOutputLayoutUpdateRequest, IDisplayOutputViewModel, IGenericCellViewModel, IInsetRenderOutput, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { DiffSide, DIFF_CELL_MARGIN, IDiffCellInfo, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser'; import { Emitter } from 'vs/base/common/event'; import { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; From 3337693651f0f3d38bc5ea5c26a7d3c2594bee6c Mon Sep 17 00:00:00 2001 From: rebornix Date: Thu, 17 Dec 2020 15:08:25 -0800 Subject: [PATCH 066/262] dedup. --- .../browser/diff/notebookTextDiffEditor.ts | 35 +++++++------------ 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index dfdc8b8d6ba..e586bde9000 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -526,29 +526,20 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD createInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: DiffNestedCellViewModel, output: IInsetRenderOutput, getOffset: () => number, diffSide: DiffSide): void { this._insetModifyQueueByOutputId.queue(output.source.model.outputId + (diffSide === DiffSide.Modified ? '-right' : 'left'), async () => { - if (diffSide === DiffSide.Modified) { - if (!this._modifiedWebview!.insetMapping.has(output.source)) { - const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel); - await this._modifiedWebview?.createInset({ diffElement: cellDiffViewModel, cellHandle: cellViewModel.handle, cellId: cellViewModel.id, cellUri: cellViewModel.uri }, output, cellTop, getOffset()); - } else { - const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel); - const scrollTop = this._list.scrollTop; - const outputIndex = cellViewModel.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (output.source.model as ITransformedDisplayOutputDto).outputId); - let outputOffset = 0; - outputOffset = cellTop + cellDiffViewModel.getOutputOffsetInCell(diffSide, outputIndex); - this._modifiedWebview!.updateViewScrollTop(-scrollTop, true, [{ output: output.source, cellTop, outputOffset }]); - } + const activeWebview = diffSide === DiffSide.Modified ? this._modifiedWebview : this._originalWebview; + if (!activeWebview) { + return; + } + + if (!activeWebview.insetMapping.has(output.source)) { + const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel); + await activeWebview.createInset({ diffElement: cellDiffViewModel, cellHandle: cellViewModel.handle, cellId: cellViewModel.id, cellUri: cellViewModel.uri }, output, cellTop, getOffset()); } else { - if (!this._originalWebview!.insetMapping.has(output.source)) { - const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel); - await this._originalWebview?.createInset({ diffElement: cellDiffViewModel, cellHandle: cellViewModel.handle, cellId: cellViewModel.id, cellUri: cellViewModel.uri }, output, cellTop, getOffset()); - } else { - const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel); - const scrollTop = this._list.scrollTop; - const outputIndex = cellViewModel.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (output.source.model as ITransformedDisplayOutputDto).outputId); - const outputOffset = cellTop + cellDiffViewModel.getOutputOffsetInCell(diffSide, outputIndex); - this._originalWebview!.updateViewScrollTop(-scrollTop, true, [{ output: output.source, cellTop, outputOffset }]); - } + const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel); + const scrollTop = this._list.scrollTop; + const outputIndex = cellViewModel.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (output.source.model as ITransformedDisplayOutputDto).outputId); + const outputOffset = cellTop + cellDiffViewModel.getOutputOffsetInCell(diffSide, outputIndex); + activeWebview.updateViewScrollTop(-scrollTop, true, [{ output: output.source, cellTop, outputOffset }]); } }); } From 71d63c7f741aa637e15d6e2189c54726e2e8236f Mon Sep 17 00:00:00 2001 From: rebornix Date: Thu, 17 Dec 2020 16:39:30 -0800 Subject: [PATCH 067/262] no transform for ITransformOutput --- .../browser/diff/notebookTextDiffEditor.ts | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index e586bde9000..a55bb3a7954 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -29,7 +29,7 @@ import { Emitter } from 'vs/base/common/event'; import { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { NotebookDiffEditorEventDispatcher, NotebookLayoutChangedEvent } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher'; import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane'; -import { CellUri, INotebookDiffEditorModel, ITransformedDisplayOutputDto } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellUri, INotebookDiffEditorModel } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { FileService } from 'vs/platform/files/common/fileService'; import { IFileService } from 'vs/platform/files/common/files'; import { URI } from 'vs/base/common/uri'; @@ -118,7 +118,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD updateOutputHeight(cellInfo: IDiffCellInfo, output: IDisplayOutputViewModel, outputHeight: number, isInit: boolean): void { const diffElement = cellInfo.diffElement; const cell = this.getCellByInfo(cellInfo); - const outputIndex = cell.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (output.model as ITransformedDisplayOutputDto).outputId); + const outputIndex = cell.outputsViewModels.findIndex(viewModel => viewModel.model === output.model); if (diffElement instanceof SideBySideDiffElementViewModel) { const info = CellUri.parse(cellInfo.cellUri); @@ -260,23 +260,24 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD return; } - if (cell.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (key.model as ITransformedDisplayOutputDto).outputId) < 0) { + if (cell.outputsViewModels.findIndex(viewModel => viewModel.model === key.model) < 0) { // output is already gone removedItems.push(key); + } else { + const cellTop = this._list.getAbsoluteTopOfElement(value.cellInfo.diffElement); + if (activeWebview.shouldUpdateInset(cell, key, cellTop)) { + // TODO: why? does it mean, we create new output view model every time? + const outputIndex = cell.outputsViewModels.findIndex(viewModel => viewModel.model === key.model); + const outputOffset = cellTop + value.cellInfo.diffElement.getOutputOffsetInCell(diffSide, outputIndex); + + updateItems.push({ + output: key, + cellTop: cellTop, + outputOffset: outputOffset + }); + } } - const cellTop = this._list.getAbsoluteTopOfElement(value.cellInfo.diffElement); - if (activeWebview.shouldUpdateInset(cell, key, cellTop)) { - // TODO: why? does it mean, we create new output view model every time? - const outputIndex = cell.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (key.model as ITransformedDisplayOutputDto).outputId); - const outputOffset = cellTop + value.cellInfo.diffElement.getOutputOffsetInCell(diffSide, outputIndex); - - updateItems.push({ - output: key, - cellTop: cellTop, - outputOffset: outputOffset - }); - } }); removedItems.forEach(output => activeWebview.removeInset(output)); @@ -537,7 +538,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD } else { const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel); const scrollTop = this._list.scrollTop; - const outputIndex = cellViewModel.outputsViewModels.findIndex(viewModel => (viewModel.model as ITransformedDisplayOutputDto).outputId === (output.source.model as ITransformedDisplayOutputDto).outputId); + const outputIndex = cellViewModel.outputsViewModels.findIndex(viewModel => viewModel.model === output.source.model); const outputOffset = cellTop + cellDiffViewModel.getOutputOffsetInCell(diffSide, outputIndex); activeWebview.updateViewScrollTop(-scrollTop, true, [{ output: output.source, cellTop, outputOffset }]); } From d46abd43537dcc0835408316cb8704416bbbd986 Mon Sep 17 00:00:00 2001 From: rebornix Date: Thu, 17 Dec 2020 17:41:35 -0800 Subject: [PATCH 068/262] avoid plain/text being rendered multiple times --- .../notebook/browser/diff/diffComponents.ts | 249 +++++++++++------- .../browser/diff/diffElementOutputs.ts | 11 + .../browser/diff/diffElementViewModel.ts | 6 +- .../browser/diff/notebookDiffEditorBrowser.ts | 1 + .../browser/diff/notebookTextDiffEditor.ts | 21 +- 5 files changed, 188 insertions(+), 100 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts index 30dfeb6d1ac..9bf86b83dc4 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts @@ -284,63 +284,50 @@ abstract class AbstractElementRenderer extends Disposable { updateOutputRendering(renderRichOutput: boolean = true) { if (this.cell.outputFoldingState === PropertyFoldingState.Expanded) { + this._outputInfoContainer.style.display = 'block'; if (renderRichOutput) { - if (this._outputEditorContainer) { - this._hideOutputs(); - this._outputEditorContainer.style.display = 'none'; - this._outputEditorDisposeStore.clear(); - } - - this._outputInfoContainer.style.display = 'block'; - - if (!this._outputViewContainer) { - this._outputViewContainer = DOM.append(this._outputInfoContainer, DOM.$('.output-view-container')); - this._buildOutputContainer(); - } else { - // todo, show insets - this._showOutputs(); - // this.cell.layoutChange(); - } - - this.cell.layoutChange(); + this._hideOutputsRaw(); + this._buildOutputRendererContainer(); + this._showOutputsRenderer(); } else { - if (this._outputInfoContainer) { - this._hideOutputs(); - this._outputInfoContainer.style.display = 'none'; - this._outputEditorDisposeStore.clear(); - } - - this._outputInfoContainer.style.display = 'block'; - - if (!this._outputEditorContainer || !this._outputEditor) { - // create editor - this._outputEditorContainer = DOM.append(this._outputInfoContainer, DOM.$('.output-editor-container')); - this._buildOutputEditor(); - } else { - this._outputEditorContainer.style.display = 'block'; - this.cell.outputHeight = this._outputEditor.getContentHeight(); - } - - this.cell.layoutChange(); + this._hideOutputsRenderer(); + this._buildOutputRawContainer(); + this._showOutputsRaw(); } } else { - if (renderRichOutput) { - this._hideOutputs(); - this._outputInfoContainer.style.display = 'none'; - this._outputEditorDisposeStore.clear(); - this.cell.layoutChange(); - } else { - this._outputInfoContainer.style.display = 'none'; - this._outputEditorDisposeStore.clear(); - this.cell.layoutChange(); - } + this._outputInfoContainer.style.display = 'none'; + + this._hideOutputsRaw(); + this._hideOutputsRenderer(); + } + + this.cell.layoutChange(); + } + + private _buildOutputRawContainer() { + if (!this._outputEditorContainer) { + this._outputEditorContainer = DOM.append(this._outputInfoContainer, DOM.$('.output-editor-container')); + this._buildOutputEditor(); } } - abstract _buildOutputContainer(): void; - abstract _hideOutputs(): void; - abstract _showOutputs(): void; + private _showOutputsRaw() { + if (this._outputEditorContainer) { + this._outputEditorContainer.style.display = 'block'; + this.cell.outputHeight = this._outputEditor!.getContentHeight(); + } + } + + private _hideOutputsRaw() { + if (this._outputEditorContainer) { + this._outputEditorContainer.style.display = 'none'; + } + } + + abstract _buildOutputRendererContainer(): void; + abstract _hideOutputsRenderer(): void; + abstract _showOutputsRenderer(): void; private _applySanitizedMetadataChanges(currentMetadata: NotebookCellMetadata, newMetadata: any) { let result: { [key: string]: any } = {}; @@ -838,19 +825,46 @@ export class DeletedElement extends SingleSideDiffElement { }); } - _buildOutputContainer() { - this._outputLeftView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell, this.cell.original!, DiffSide.Original, this._outputViewContainer!); - this._outputLeftView.render(); - this.cell.layoutChange(); + _buildOutputRendererContainer() { + if (!this._outputViewContainer) { + this._outputViewContainer = DOM.append(this._outputInfoContainer, DOM.$('.output-view-container')); + + this._outputLeftView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell, this.cell.original!, DiffSide.Original, this._outputViewContainer!); + this._register(this._outputLeftView); + this._outputLeftView.render(); + + const removedOutputRenderListener = this.notebookEditor.onDidDynamicOutputRendered(e => { + if (e.cell.uri.toString() === this.cell.original!.uri.toString()) { + this.notebookEditor.deltaCellOutputContainerClassNames(DiffSide.Original, this.cell.original!.id, ['nb-cellDeleted'], []); + removedOutputRenderListener.dispose(); + } + }); + + this._register(removedOutputRenderListener); + } + + this._outputViewContainer.style.display = 'block'; } - _showOutputs() { - this._outputLeftView?.render(); - this.cell.layoutChange(); + _decorate() { + this.notebookEditor.deltaCellOutputContainerClassNames(DiffSide.Original, this.cell.original!.id, ['nb-cellDeleted'], []); } - _hideOutputs() { - this._outputLeftView?.hideOutputs(); + _showOutputsRenderer() { + if (this._outputViewContainer) { + this._outputViewContainer.style.display = 'block'; + + this._outputLeftView?.showOutputs(); + this._decorate(); + } + } + + _hideOutputsRenderer() { + if (this._outputViewContainer) { + this._outputViewContainer.style.display = 'none'; + + this._outputLeftView?.hideOutputs(); + } } } @@ -911,19 +925,42 @@ export class InsertElement extends SingleSideDiffElement { }); } - _buildOutputContainer() { - this._outputRightView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell, this.cell.modified!, DiffSide.Modified, this._outputViewContainer!); - this._outputRightView.render(); - this.cell.layoutChange(); + _buildOutputRendererContainer() { + if (!this._outputViewContainer) { + this._outputViewContainer = DOM.append(this._outputInfoContainer, DOM.$('.output-view-container')); + this._outputRightView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell, this.cell.modified!, DiffSide.Modified, this._outputViewContainer!); + this._register(this._outputRightView); + this._outputRightView.render(); + + const insertOutputRenderListener = this.notebookEditor.onDidDynamicOutputRendered(e => { + if (e.cell.uri.toString() === this.cell.modified!.uri.toString()) { + this.notebookEditor.deltaCellOutputContainerClassNames(DiffSide.Modified, this.cell.modified!.id, ['nb-cellAdded'], []); + insertOutputRenderListener.dispose(); + } + }); + this._register(insertOutputRenderListener); + } + + this._outputViewContainer.style.display = 'block'; } - _showOutputs() { - this._outputRightView?.render(); - this.cell.layoutChange(); + _decorate() { + this.notebookEditor.deltaCellOutputContainerClassNames(DiffSide.Modified, this.cell.modified!.id, ['nb-cellAdded'], []); } - _hideOutputs() { - this._outputRightView?.hideOutputs(); + _showOutputsRenderer() { + if (this._outputViewContainer) { + this._outputViewContainer.style.display = 'block'; + this._outputRightView?.showOutputs(); + this._decorate(); + } + } + + _hideOutputsRenderer() { + if (this._outputViewContainer) { + this._outputViewContainer.style.display = 'none'; + this._outputRightView?.hideOutputs(); + } } layout(state: { outerWidth?: boolean, editorHeight?: boolean, metadataEditor?: boolean, outputEditor?: boolean, outputView?: boolean }) { @@ -1081,38 +1118,40 @@ export class ModifiedElement extends AbstractElementRenderer { this._outputHeader.buildHeader(); } - _buildOutputContainer() { - this._outputLeftContainer = DOM.append(this._outputViewContainer!, DOM.$('.output-view-container-left')); - this._outputRightContainer = DOM.append(this._outputViewContainer!, DOM.$('.output-view-container-right')); - // We should use the original text model here - this._outputLeftView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell, this.cell.original!, DiffSide.Original, this._outputLeftContainer!); - this._outputLeftView.render(); - this._outputRightView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell, this.cell.modified!, DiffSide.Modified, this._outputRightContainer!); - this._outputRightView.render(); + _buildOutputRendererContainer() { + if (!this._outputViewContainer) { + this._outputViewContainer = DOM.append(this._outputInfoContainer, DOM.$('.output-view-container')); + this._outputLeftContainer = DOM.append(this._outputViewContainer!, DOM.$('.output-view-container-left')); + this._outputRightContainer = DOM.append(this._outputViewContainer!, DOM.$('.output-view-container-right')); + // We should use the original text model here + this._outputLeftView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell, this.cell.original!, DiffSide.Original, this._outputLeftContainer!); + this._outputLeftView.render(); + this._register(this._outputLeftView); + this._outputRightView = this.instantiationService.createInstance(OutputContainer, this.notebookEditor, this.notebookEditor.textModel!, this.cell, this.cell.modified!, DiffSide.Modified, this._outputRightContainer!); + this._outputRightView.render(); + this._register(this._outputRightView); - const originalOutputRenderListener = this.notebookEditor.onDidDynamicOutputRendered(e => { - if (e.cell.uri.toString() === this.cell.original.uri.toString()) { - this.notebookEditor.deltaCellOutputContainerClassNames(DiffSide.Original, this.cell.original.id, ['nb-cellDeleted'], []); - originalOutputRenderListener.dispose(); - } - }); + const originalOutputRenderListener = this.notebookEditor.onDidDynamicOutputRendered(e => { + if (e.cell.uri.toString() === this.cell.original.uri.toString()) { + this.notebookEditor.deltaCellOutputContainerClassNames(DiffSide.Original, this.cell.original.id, ['nb-cellDeleted'], []); + originalOutputRenderListener.dispose(); + } + }); - const modifiedOutputRenderListener = this.notebookEditor.onDidDynamicOutputRendered(e => { - if (e.cell.uri.toString() === this.cell.modified.uri.toString()) { - this.notebookEditor.deltaCellOutputContainerClassNames(DiffSide.Modified, this.cell.modified.id, ['nb-cellAdded'], []); - modifiedOutputRenderListener.dispose(); - } - }); + const modifiedOutputRenderListener = this.notebookEditor.onDidDynamicOutputRendered(e => { + if (e.cell.uri.toString() === this.cell.modified.uri.toString()) { + this.notebookEditor.deltaCellOutputContainerClassNames(DiffSide.Modified, this.cell.modified.id, ['nb-cellAdded'], []); + modifiedOutputRenderListener.dispose(); + } + }); - this._decorate(); - this.cell.layoutChange(); - } + this._register(originalOutputRenderListener); + this._register(modifiedOutputRenderListener); - _showOutputs() { - this._outputLeftView?.render(); - this._outputRightView?.render(); - this._decorate(); - this.cell.layoutChange(); + this._decorate(); + } + + this._outputViewContainer.style.display = 'block'; } _decorate() { @@ -1120,9 +1159,23 @@ export class ModifiedElement extends AbstractElementRenderer { this.notebookEditor.deltaCellOutputContainerClassNames(DiffSide.Modified, this.cell.modified.id, ['nb-cellAdded'], []); } - _hideOutputs() { - this._outputLeftView?.hideOutputs(); - this._outputRightView?.hideOutputs(); + _showOutputsRenderer() { + if (this._outputViewContainer) { + this._outputViewContainer.style.display = 'block'; + + this._outputLeftView?.showOutputs(); + this._outputRightView?.showOutputs(); + this._decorate(); + } + } + + _hideOutputsRenderer() { + if (this._outputViewContainer) { + this._outputViewContainer.style.display = 'none'; + + this._outputLeftView?.hideOutputs(); + this._outputRightView?.hideOutputs(); + } } updateSourceEditor(): void { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts index b93b348e5c4..1d76d0473c9 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts @@ -193,6 +193,17 @@ export class OutputContainer extends Disposable { } } + showOutputs() { + for (let index = 0; index < this._outputViewModels.length; index++) { + const currOutput = this._outputViewModels[index]; + + if (currOutput.isDisplayOutput()) { + // always add to the end + this._editor.showInset(this._diffElementViewModel, currOutput.cellViewModel, currOutput, this._diffSide); + } + } + } + hideOutputs() { this._outputEntries.forEach((outputElement, cellOutputViewModel) => { if (cellOutputViewModel.isDisplayOutput()) { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts index 116569e0ae6..7ff9fcf54f6 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts @@ -249,7 +249,11 @@ export class SideBySideDiffElementViewModel extends DiffElementViewModelBase { } getOutputTotalHeight() { - return Math.max(this.original.getOutputTotalHeight(), this.modified.getOutputTotalHeight()); + if (this.renderOutput) { + return Math.max(this.original.getOutputTotalHeight(), this.modified.getOutputTotalHeight()); + } else { + return this._layoutInfo.outputHeight; + } } getNestedCellViewModel(diffSide: DiffSide): DiffNestedCellViewModel { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts index 50e07189d1b..62a398904f3 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts @@ -33,6 +33,7 @@ export interface INotebookTextDiffEditor extends ICommonNotebookEditor { layoutNotebookCell(cell: DiffElementViewModelBase, height: number): void; getOutputRenderer(): OutputRenderer; createInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: IDiffNestedCellViewModel, output: IInsetRenderOutput, getOffset: () => number, diffSide: DiffSide): void; + showInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: IDiffNestedCellViewModel, displayOutput: IDisplayOutputViewModel, diffSide: DiffSide): void; hideInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: IDiffNestedCellViewModel, output: IDisplayOutputViewModel): void; /** * Trigger the editor to scroll from scroll event programmatically diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index a55bb3a7954..28513cb0135 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -349,7 +349,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD // attach the webview container to the DOM tree first this._list.rowsContainer.insertAdjacentElement('afterbegin', this._modifiedWebview.element); await this._modifiedWebview.createWebview(); - this._modifiedWebview.element.style.width = `calc(50%)`; + this._modifiedWebview.element.style.width = `calc(50% - 16px)`; this._modifiedWebview.element.style.left = `calc(50%)`; } @@ -553,6 +553,25 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD } + showInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: DiffNestedCellViewModel, displayOutput: IDisplayOutputViewModel, diffSide: DiffSide) { + this._insetModifyQueueByOutputId.queue(displayOutput.model.outputId + (diffSide === DiffSide.Modified ? '-right' : 'left'), async () => { + const activeWebview = diffSide === DiffSide.Modified ? this._modifiedWebview : this._originalWebview; + if (!activeWebview) { + return; + } + + if (!activeWebview.insetMapping.has(displayOutput)) { + return; + } + + const cellTop = this._list.getAbsoluteTopOfElement(cellDiffViewModel); + const scrollTop = this._list.scrollTop; + const outputIndex = cellViewModel.outputsViewModels.findIndex(viewModel => viewModel.model === displayOutput.model); + const outputOffset = cellTop + cellDiffViewModel.getOutputOffsetInCell(diffSide, outputIndex); + activeWebview.updateViewScrollTop(-scrollTop, true, [{ output: displayOutput, cellTop, outputOffset }]); + }); + } + hideInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: DiffNestedCellViewModel, output: IDisplayOutputViewModel) { this._modifiedWebview?.hideInset(output); this._originalWebview?.hideInset(output); From 141572a2b21da35a08a7595f8ba8d1bb341ccd80 Mon Sep 17 00:00:00 2001 From: rebornix Date: Thu, 17 Dec 2020 17:53:19 -0800 Subject: [PATCH 069/262] render outputs in text by default. --- .../contrib/notebook/browser/diff/diffComponents.ts | 12 ++++++------ .../notebook/browser/diff/diffElementViewModel.ts | 8 ++++++-- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts index 9bf86b83dc4..70a3a290eb5 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts @@ -83,7 +83,7 @@ class PropertyHeader extends Disposable { readonly propertyHeaderContainer: HTMLElement, readonly notebookEditor: INotebookTextDiffEditor, readonly accessor: { - updateInfoRendering: () => void; + updateInfoRendering: (renderOutput: boolean) => void; checkIfModified: (cell: DiffElementViewModelBase) => boolean; getFoldingState: (cell: DiffElementViewModelBase) => PropertyFoldingState; updateFoldingState: (cell: DiffElementViewModelBase, newState: PropertyFoldingState) => void; @@ -172,7 +172,7 @@ class PropertyHeader extends Disposable { const oldFoldingState = this.accessor.getFoldingState(this.cell); this.accessor.updateFoldingState(this.cell, oldFoldingState === PropertyFoldingState.Expanded ? PropertyFoldingState.Collapsed : PropertyFoldingState.Expanded); this._updateFoldingIcon(); - this.accessor.updateInfoRendering(); + this.accessor.updateInfoRendering(this.cell.renderOutput); } } @@ -180,7 +180,7 @@ class PropertyHeader extends Disposable { })); this._updateFoldingIcon(); - this.accessor.updateInfoRendering(); + this.accessor.updateInfoRendering(this.cell.renderOutput); } refresh() { @@ -282,7 +282,7 @@ abstract class AbstractElementRenderer extends Disposable { } } - updateOutputRendering(renderRichOutput: boolean = true) { + updateOutputRendering(renderRichOutput: boolean) { if (this.cell.outputFoldingState === PropertyFoldingState.Expanded) { this._outputInfoContainer.style.display = 'block'; if (renderRichOutput) { @@ -566,7 +566,7 @@ abstract class AbstractElementRenderer extends Disposable { this._outputEditor = this.instantiationService.createInstance(CodeEditorWidget, this._outputEditorContainer!, { ...fixedEditorOptions, dimension: { - width: this.cell.getComputedCellContainerWidth(this.notebookEditor.getLayoutInfo(), false, true), + width: this.cell.getComputedCellContainerWidth(this.notebookEditor.getLayoutInfo(), false, this.cell.type === 'unchanged' || this.cell.type === 'modified'), height: 0 }, overflowWidgetsDomNode: this.notebookEditor.getOverflowContainerDomNode() @@ -981,7 +981,7 @@ export class InsertElement extends SingleSideDiffElement { if (state.outputEditor || state.outerWidth) { this._outputEditor?.layout({ - width: this.cell.getComputedCellContainerWidth(this.notebookEditor.getLayoutInfo(), false, true), + width: this.cell.getComputedCellContainerWidth(this.notebookEditor.getLayoutInfo(), false, false), height: this.cell.outputHeight }); } diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts index 7ff9fcf54f6..1b1fe014d41 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts @@ -91,7 +91,7 @@ export abstract class DiffElementViewModelBase extends Disposable { return this._layoutInfo.metadataHeight; } - private _renderOutput = true; + private _renderOutput = false; set renderOutput(value: boolean) { this._renderOutput = value; @@ -337,7 +337,11 @@ export class SingleSideDiffElementViewModel extends DiffElementViewModelBase { } getOutputTotalHeight() { - return this.cellViewModel?.getOutputTotalHeight() ?? 0; + if (this.renderOutput) { + return this.cellViewModel?.getOutputTotalHeight() ?? 0; + } else { + return this._layoutInfo.outputHeight; + } } getCellByUri(cellUri: URI): IGenericCellViewModel { From 5e865477065e9cc361f14784722ef2419dcd5b90 Mon Sep 17 00:00:00 2001 From: rebornix Date: Thu, 17 Dec 2020 19:56:06 -0800 Subject: [PATCH 070/262] only show render style switcher when the property is expanded --- .../notebook/browser/diff/diffComponents.ts | 34 ++++++++++++++----- .../browser/diff/notebookDiffActions.ts | 27 ++++++++++----- .../browser/diff/notebookDiffEditorBrowser.ts | 3 ++ 3 files changed, 46 insertions(+), 18 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts index 70a3a290eb5..022b28ded62 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts @@ -8,7 +8,7 @@ import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IDiffEditorOptions, IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { DiffElementViewModelBase, getFormatedMetadataJSON, PropertyFoldingState, SideBySideDiffElementViewModel, SingleSideDiffElementViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; -import { CellDiffSideBySideRenderTemplate, CellDiffSingleSideRenderTemplate, DiffSide, DIFF_CELL_MARGIN, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser'; +import { CellDiffSideBySideRenderTemplate, CellDiffSingleSideRenderTemplate, DiffSide, DIFF_CELL_MARGIN, INotebookTextDiffEditor, NOTEBOOK_DIFF_CELL_PROPERTY, NOTEBOOK_DIFF_CELL_PROPERTY_EXPANDED } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser'; import { EDITOR_BOTTOM_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; @@ -24,7 +24,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { IAction } from 'vs/base/common/actions'; import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; -import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { Delayer } from 'vs/base/common/async'; import { CodiconActionViewItem } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellActionView'; import { getEditorTopPadding } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; @@ -77,6 +77,7 @@ class PropertyHeader extends Disposable { protected _statusSpan!: HTMLElement; protected _toolbar!: ToolBar; protected _menu!: IMenu; + protected _propertyExpanded?: IContextKey; constructor( readonly cell: DiffElementViewModelBase, @@ -133,14 +134,23 @@ class PropertyHeader extends Disposable { cell: this.cell }; - this._menu = this.menuService.createMenu(this.accessor.menuId, this.contextKeyService); + const scopedContextKeyService = this.contextKeyService.createScoped(cellToolbarContainer); + const propertyChanged = NOTEBOOK_DIFF_CELL_PROPERTY.bindTo(scopedContextKeyService); + propertyChanged.set(metadataChanged); + this._propertyExpanded = NOTEBOOK_DIFF_CELL_PROPERTY_EXPANDED.bindTo(scopedContextKeyService); + + this._menu = this.menuService.createMenu(this.accessor.menuId, scopedContextKeyService); this._register(this._menu); - if (metadataChanged) { + const actions: IAction[] = []; + createAndFillInActionBarActions(this._menu, { shouldForwardArgs: true }, actions); + this._toolbar.setActions(actions); + + this._register(this._menu.onDidChange(() => { const actions: IAction[] = []; createAndFillInActionBarActions(this._menu, { shouldForwardArgs: true }, actions); this._toolbar.setActions(actions); - } + })); this._register(this.notebookEditor.onMouseUp(e => { if (!e.event.target) { @@ -202,9 +212,12 @@ class PropertyHeader extends Disposable { private _updateFoldingIcon() { if (this.accessor.getFoldingState(this.cell) === PropertyFoldingState.Collapsed) { DOM.reset(this._foldingIndicator, ...renderCodicons(ThemeIcon.asCodiconLabel(collapsedIcon))); + this._propertyExpanded?.set(false); } else { DOM.reset(this._foldingIndicator, ...renderCodicons(ThemeIcon.asCodiconLabel(expandedIcon))); + this._propertyExpanded?.set(true); } + } } @@ -258,6 +271,10 @@ abstract class AbstractElementRenderer extends Disposable { this._register(cell.onDidLayoutChange(e => this.layout(e))); this._register(cell.onDidLayoutChange(e => this.updateBorders())); this.buildBody(); + + this._register(cell.onDidStateChange(() => { + this.updateOutputRendering(this.cell.renderOutput); + })); } abstract buildBody(): void; @@ -758,6 +775,7 @@ export class DeletedElement extends SingleSideDiffElement { } styleContainer(container: HTMLElement) { + container.classList.remove('inserted'); container.classList.add('removed'); } @@ -887,6 +905,7 @@ export class InsertElement extends SingleSideDiffElement { } styleContainer(container: HTMLElement): void { + container.classList.remove('removed'); container.classList.add('inserted'); } @@ -1016,13 +1035,10 @@ export class ModifiedElement extends AbstractElementRenderer { @IContextKeyService protected readonly contextKeyService: IContextKeyService ) { super(notebookEditor, cell, templateData, 'full', instantiationService, modeService, modelService, contextMenuService, keybindingService, notificationService, menuService, contextKeyService); - - this._register(cell.onDidStateChange(() => { - this.updateOutputRendering(this.cell.renderOutput); - })); } styleContainer(container: HTMLElement): void { + container.classList.remove('inserted', 'removed'); } buildBody() { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts index 5b3d84c23b8..0bd867fa6aa 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts @@ -9,6 +9,7 @@ import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/act import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ActiveEditorContext, viewColumnToEditorGroup } from 'vs/workbench/common/editor'; import { DiffElementViewModelBase } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; +import { NOTEBOOK_DIFF_CELL_PROPERTY, NOTEBOOK_DIFF_CELL_PROPERTY_EXPANDED } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser'; import { NotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor'; import { NotebookDiffEditorInput } from 'vs/workbench/contrib/notebook/browser/notebookDiffEditorInput'; import { openAsTextIcon, revertIcon, showOutputRawIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons'; @@ -60,8 +61,10 @@ registerAction2(class extends Action2 { icon: revertIcon, f1: false, menu: { - id: MenuId.NotebookDiffCellMetadataTitle - } + id: MenuId.NotebookDiffCellMetadataTitle, + when: NOTEBOOK_DIFF_CELL_PROPERTY + }, + precondition: NOTEBOOK_DIFF_CELL_PROPERTY } ); } @@ -110,12 +113,13 @@ registerAction2(class extends Action2 { super( { id: 'notebook.diff.cell.switchOutputRenderingStyleToText', - title: localize('notebook.diff.cell.switchOutputRenderingStyleToText', "View outputs raw data"), + title: localize('notebook.diff.cell.switchOutputRenderingStyleToText', "Switch Output Rendering"), icon: showOutputRawIcon, f1: false, menu: { - id: MenuId.NotebookDiffCellOutputsTitle - }, + id: MenuId.NotebookDiffCellOutputsTitle, + when: NOTEBOOK_DIFF_CELL_PROPERTY_EXPANDED + } } ); } @@ -137,8 +141,10 @@ registerAction2(class extends Action2 { icon: revertIcon, f1: false, menu: { - id: MenuId.NotebookDiffCellOutputsTitle - } + id: MenuId.NotebookDiffCellOutputsTitle, + when: NOTEBOOK_DIFF_CELL_PROPERTY + }, + precondition: NOTEBOOK_DIFF_CELL_PROPERTY } ); } @@ -168,8 +174,11 @@ registerAction2(class extends Action2 { icon: revertIcon, f1: false, menu: { - id: MenuId.NotebookDiffCellInputTitle - } + id: MenuId.NotebookDiffCellInputTitle, + when: NOTEBOOK_DIFF_CELL_PROPERTY + }, + precondition: NOTEBOOK_DIFF_CELL_PROPERTY + } ); } diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts index 62a398904f3..f5b2de9e665 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts @@ -14,6 +14,7 @@ import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer'; import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; +import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; export enum DiffSide { Original = 0, @@ -97,3 +98,5 @@ export interface CellDiffViewModelLayoutChangeEvent { } export const DIFF_CELL_MARGIN = 16; +export const NOTEBOOK_DIFF_CELL_PROPERTY = new RawContextKey('notebookDiffCellPropertyChanged', false); +export const NOTEBOOK_DIFF_CELL_PROPERTY_EXPANDED = new RawContextKey('notebookDiffCellPropertyExpanded', false); From 58985749f9acab9f633657b546283145cf2f074c Mon Sep 17 00:00:00 2001 From: rebornix Date: Fri, 18 Dec 2020 09:24:55 -0800 Subject: [PATCH 071/262] memory leak --- src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts index 022b28ded62..91a1ff50d29 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts @@ -135,6 +135,7 @@ class PropertyHeader extends Disposable { }; const scopedContextKeyService = this.contextKeyService.createScoped(cellToolbarContainer); + this._register(scopedContextKeyService); const propertyChanged = NOTEBOOK_DIFF_CELL_PROPERTY.bindTo(scopedContextKeyService); propertyChanged.set(metadataChanged); this._propertyExpanded = NOTEBOOK_DIFF_CELL_PROPERTY_EXPANDED.bindTo(scopedContextKeyService); From b4a22eba377442084daf3efa57f0fff1cc8327a6 Mon Sep 17 00:00:00 2001 From: rebornix Date: Fri, 18 Dec 2020 10:35:51 -0800 Subject: [PATCH 072/262] recompute output height in diff view model. --- .../notebook/browser/diff/diffComponents.ts | 69 +++--- .../browser/diff/diffElementViewModel.ts | 223 ++++++++++-------- .../browser/diff/notebookDiffEditorBrowser.ts | 18 +- 3 files changed, 178 insertions(+), 132 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts index 91a1ff50d29..4b2402e0c3e 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts @@ -319,8 +319,6 @@ abstract class AbstractElementRenderer extends Disposable { this._hideOutputsRaw(); this._hideOutputsRenderer(); } - - this.cell.layoutChange(); } private _buildOutputRawContainer() { @@ -333,13 +331,14 @@ abstract class AbstractElementRenderer extends Disposable { private _showOutputsRaw() { if (this._outputEditorContainer) { this._outputEditorContainer.style.display = 'block'; - this.cell.outputHeight = this._outputEditor!.getContentHeight(); + this.cell.rawOutputHeight = this._outputEditor!.getContentHeight(); } } private _hideOutputsRaw() { if (this._outputEditorContainer) { this._outputEditorContainer.style.display = 'none'; + this.cell.rawOutputHeight = 0; } } @@ -563,11 +562,11 @@ abstract class AbstractElementRenderer extends Disposable { modified: modifiedModel }); - this.cell.outputHeight = this._outputEditor.getContentHeight(); + this.cell.rawOutputHeight = this._outputEditor.getContentHeight(); this._register(this._outputEditor.onDidContentSizeChange((e) => { if (e.contentHeightChanged && this.cell.outputFoldingState === PropertyFoldingState.Expanded) { - this.cell.outputHeight = e.contentHeight; + this.cell.rawOutputHeight = e.contentHeight; } })); @@ -601,11 +600,11 @@ abstract class AbstractElementRenderer extends Disposable { const outputModel = this.modelService.createModel(originaloutputSource, mode, undefined, true); this._outputEditor.setModel(outputModel); - this.cell.outputHeight = this._outputEditor.getContentHeight(); + this.cell.rawOutputHeight = this._outputEditor.getContentHeight(); this._register(this._outputEditor.onDidContentSizeChange((e) => { if (e.contentHeightChanged && this.cell.outputFoldingState === PropertyFoldingState.Expanded) { - this.cell.outputHeight = e.contentHeight; + this.cell.rawOutputHeight = e.contentHeight; } })); } @@ -613,14 +612,14 @@ abstract class AbstractElementRenderer extends Disposable { protected layoutNotebookCell() { this.notebookEditor.layoutNotebookCell( this.cell, - this.cell.totalHeight + this.cell.layoutInfo.totalHeight ); } updateBorders() { - this.templateData.leftBorder.style.height = `${this.cell.totalHeight - 32}px`; - this.templateData.rightBorder.style.height = `${this.cell.totalHeight - 32}px`; - this.templateData.bottomBorder.style.top = `${this.cell.totalHeight - 32}px`; + this.templateData.leftBorder.style.height = `${this.cell.layoutInfo.totalHeight - 32}px`; + this.templateData.rightBorder.style.height = `${this.cell.layoutInfo.totalHeight - 32}px`; + this.templateData.bottomBorder.style.top = `${this.cell.layoutInfo.totalHeight - 32}px`; } dispose() { @@ -716,7 +715,7 @@ abstract class SingleSideDiffElement extends AbstractElementRenderer { this._metadataHeader.buildHeader(); if (this.notebookEditor.textModel?.transientOptions.transientOutputs) { - this.cell.outputHeight = 0; + this.cell.rawOutputHeight = 0; this.cell.outputStatusHeight = 0; this.templateData.outputHeaderContainer.style.display = 'none'; this.templateData.outputInfoContainer.style.display = 'none'; @@ -795,7 +794,7 @@ export class DeletedElement extends SingleSideDiffElement { this.cell.editorHeight = editorHeight; this._register(this._editor.onDidContentSizeChange((e) => { - if (e.contentHeightChanged && this.cell.editorHeight !== e.contentHeight) { + if (e.contentHeightChanged && this.cell.layoutInfo.editorHeight !== e.contentHeight) { this.cell.editorHeight = e.contentHeight; } })); @@ -813,31 +812,31 @@ export class DeletedElement extends SingleSideDiffElement { }); } - layout(state: { outerWidth?: boolean, editorHeight?: boolean, metadataEditor?: boolean, outputEditor?: boolean }) { + layout(state: { outerWidth?: boolean, editorHeight?: boolean, metadataEditor?: boolean, outputTotalHeight?: boolean }) { DOM.scheduleAtNextAnimationFrame(() => { if (state.editorHeight || state.outerWidth) { this._editor.layout({ width: this.cell.getComputedCellContainerWidth(this.notebookEditor.getLayoutInfo(), false, false), - height: this.cell.editorHeight + height: this.cell.layoutInfo.editorHeight }); } if (state.metadataEditor || state.outerWidth) { this._metadataEditor?.layout({ width: this.cell.getComputedCellContainerWidth(this.notebookEditor.getLayoutInfo(), false, false), - height: this.cell.metadataHeight + height: this.cell.layoutInfo.metadataHeight }); } - if (state.outputEditor || state.outerWidth) { + if (state.outputTotalHeight || state.outerWidth) { this._outputEditor?.layout({ width: this.cell.getComputedCellContainerWidth(this.notebookEditor.getLayoutInfo(), false, false), - height: this.cell.outputHeight + height: this.cell.layoutInfo.outputTotalHeight }); } if (this._diagonalFill) { - this._diagonalFill.style.height = `${this.cell.totalHeight - 32}px`; + this._diagonalFill.style.height = `${this.cell.layoutInfo.totalHeight - 32}px`; } this.layoutNotebookCell(); @@ -927,7 +926,7 @@ export class InsertElement extends SingleSideDiffElement { this.cell.editorHeight = editorHeight; this._register(this._editor.onDidContentSizeChange((e) => { - if (e.contentHeightChanged && this.cell.editorHeight !== e.contentHeight) { + if (e.contentHeightChanged && this.cell.layoutInfo.editorHeight !== e.contentHeight) { this.cell.editorHeight = e.contentHeight; } })); @@ -983,33 +982,33 @@ export class InsertElement extends SingleSideDiffElement { } } - layout(state: { outerWidth?: boolean, editorHeight?: boolean, metadataEditor?: boolean, outputEditor?: boolean, outputView?: boolean }) { + layout(state: { outerWidth?: boolean, editorHeight?: boolean, metadataEditor?: boolean, outputTotalHeight?: boolean }) { DOM.scheduleAtNextAnimationFrame(() => { if (state.editorHeight || state.outerWidth) { this._editor.layout({ width: this.cell.getComputedCellContainerWidth(this.notebookEditor.getLayoutInfo(), false, false), - height: this.cell.editorHeight + height: this.cell.layoutInfo.editorHeight }); } if (state.metadataEditor || state.outerWidth) { this._metadataEditor?.layout({ width: this.cell.getComputedCellContainerWidth(this.notebookEditor.getLayoutInfo(), false, true), - height: this.cell.metadataHeight + height: this.cell.layoutInfo.metadataHeight }); } - if (state.outputEditor || state.outerWidth) { + if (state.outputTotalHeight || state.outerWidth) { this._outputEditor?.layout({ width: this.cell.getComputedCellContainerWidth(this.notebookEditor.getLayoutInfo(), false, false), - height: this.cell.outputHeight + height: this.cell.layoutInfo.outputTotalHeight }); } this.layoutNotebookCell(); if (this._diagonalFill) { - this._diagonalFill.style.height = `${this.cell.editorHeight + this.cell.editorMargin + this.cell.metadataStatusHeight + this.cell.metadataHeight + this.cell.outputHeight + this.cell.outputStatusHeight}px`; + this._diagonalFill.style.height = `${this.cell.layoutInfo.editorHeight + this.cell.layoutInfo.editorMargin + this.cell.layoutInfo.metadataStatusHeight + this.cell.layoutInfo.metadataHeight + this.cell.layoutInfo.outputTotalHeight + this.cell.layoutInfo.outputStatusHeight}px`; } }); } @@ -1093,7 +1092,7 @@ export class ModifiedElement extends AbstractElementRenderer { this._metadataHeader.buildHeader(); if (this.notebookEditor.textModel?.transientOptions.transientOutputs) { - this.cell.outputHeight = 0; + this.cell.rawOutputHeight = 0; this.cell.outputStatusHeight = 0; this.templateData.outputHeaderContainer.style.display = 'none'; this.templateData.outputInfoContainer.style.display = 'none'; @@ -1213,7 +1212,7 @@ export class ModifiedElement extends AbstractElementRenderer { this._editorContainer.style.height = `${editorHeight}px`; this._register(this._editor.onDidContentSizeChange((e) => { - if (e.contentHeightChanged && this.cell.editorHeight !== e.contentHeight) { + if (e.contentHeightChanged && this.cell.layoutInfo.editorHeight !== e.contentHeight) { this.cell.editorHeight = e.contentHeight; } })); @@ -1289,31 +1288,31 @@ export class ModifiedElement extends AbstractElementRenderer { this.cell.editorHeight = contentHeight; } - layout(state: { outerWidth?: boolean, editorHeight?: boolean, metadataEditor?: boolean, outputEditor?: boolean, outputView?: boolean }) { + layout(state: { outerWidth?: boolean, editorHeight?: boolean, metadataEditor?: boolean, outputTotalHeight?: boolean }) { DOM.scheduleAtNextAnimationFrame(() => { if (state.editorHeight) { - this._editorContainer.style.height = `${this.cell.editorHeight}px`; + this._editorContainer.style.height = `${this.cell.layoutInfo.editorHeight}px`; this._editor!.layout({ width: this._editor!.getViewWidth(), - height: this.cell.editorHeight + height: this.cell.layoutInfo.editorHeight }); } if (state.outerWidth) { - this._editorContainer.style.height = `${this.cell.editorHeight}px`; + this._editorContainer.style.height = `${this.cell.layoutInfo.editorHeight}px`; this._editor!.layout(); } if (state.metadataEditor || state.outerWidth) { if (this._metadataEditorContainer) { - this._metadataEditorContainer.style.height = `${this.cell.metadataHeight}px`; + this._metadataEditorContainer.style.height = `${this.cell.layoutInfo.metadataHeight}px`; this._metadataEditor?.layout(); } } - if (state.outputEditor || state.outerWidth) { + if (state.outputTotalHeight || state.outerWidth) { if (this._outputEditorContainer) { - this._outputEditorContainer.style.height = `${this.cell.outputHeight}px`; + this._outputEditorContainer.style.height = `${this.cell.layoutInfo.outputTotalHeight}px`; this._outputEditor?.layout(); } } diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts index 1b1fe014d41..6dddaca31bc 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts @@ -6,7 +6,7 @@ import { NotebookDiffEditorEventDispatcher } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher'; import { Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; -import { CellDiffViewModelLayoutChangeEvent, DiffSide, DIFF_CELL_MARGIN } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser'; +import { CellDiffViewModelLayoutChangeEvent, DiffSide, DIFF_CELL_MARGIN, IDiffElementLayoutInfo } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser'; import { IGenericCellViewModel, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; @@ -22,6 +22,12 @@ export enum PropertyFoldingState { Collapsed } +type ILayoutInfoDelta0 = { [K in keyof IDiffElementLayoutInfo]?: number; }; +interface ILayoutInfoDelta extends ILayoutInfoDelta0 { + rawOutputHeight?: number; + recomputeOutput?: boolean; +} + export abstract class DiffElementViewModelBase extends Disposable { public metadataFoldingState: PropertyFoldingState; public outputFoldingState: PropertyFoldingState; @@ -29,72 +35,53 @@ export abstract class DiffElementViewModelBase extends Disposable { onDidLayoutChange = this._layoutInfoEmitter.event; protected _stateChangeEmitter = new Emitter<{ renderOutput: boolean; }>(); onDidStateChange = this._stateChangeEmitter.event; + protected _layoutInfo!: IDiffElementLayoutInfo; - - protected _layoutInfo!: { - width: number; - editorHeight: number; - editorMargin: number; - metadataStatusHeight: number; - metadataHeight: number; - outputStatusHeight: number; - outputHeight: number; - bodyMargin: number; - }; - - set outputHeight(height: number) { - this._layoutInfo.outputHeight = height; - this._fireLayoutChangeEvent({ outputEditor: true, outputView: true }); + set rawOutputHeight(height: number) { + this._layout({ rawOutputHeight: height }); } - get outputHeight() { - return this._layoutInfo.outputHeight; + get rawOutputHeight() { + throw new Error('Use Cell.layoutInfo.rawOutputHeight'); } set outputStatusHeight(height: number) { - this._layoutInfo.outputStatusHeight = height; - this._fireLayoutChangeEvent({}); + this._layout({ outputStatusHeight: height }); } get outputStatusHeight() { - return this._layoutInfo.outputStatusHeight; + throw new Error('Use Cell.layoutInfo.outputStatusHeight'); } set editorHeight(height: number) { - this._layoutInfo.editorHeight = height; - this._fireLayoutChangeEvent({ editorHeight: true }); + this._layout({ editorHeight: height }); } get editorHeight() { - return this._layoutInfo.editorHeight; + throw new Error('Use Cell.layoutInfo.editorHeight'); } - set editorMargin(height: number) { - this._layoutInfo.editorMargin = height; - this._fireLayoutChangeEvent({}); + set editorMargin(margin: number) { + this._layout({ editorMargin: margin }); } get editorMargin() { - return this._layoutInfo.editorMargin; - } - - get metadataStatusHeight() { - return this._layoutInfo.metadataStatusHeight; + throw new Error('Use Cell.layoutInfo.editorMargin'); } set metadataHeight(height: number) { - this._layoutInfo.metadataHeight = height; - this._fireLayoutChangeEvent({ metadataEditor: true }); + this._layout({ metadataHeight: height }); } get metadataHeight() { - return this._layoutInfo.metadataHeight; + throw new Error('Use Cell.layoutInfo.metadataHeight'); } private _renderOutput = false; set renderOutput(value: boolean) { this._renderOutput = value; + this._layout({ recomputeOutput: true }); this._stateChangeEmitter.fire({ renderOutput: this._renderOutput }); } @@ -102,14 +89,8 @@ export abstract class DiffElementViewModelBase extends Disposable { return this._renderOutput; } - get totalHeight() { - return this._layoutInfo.editorHeight - + this._layoutInfo.editorMargin - + this._layoutInfo.metadataHeight - + this._layoutInfo.metadataStatusHeight - + this._layoutInfo.outputHeight - + this._layoutInfo.outputStatusHeight - + this._layoutInfo.bodyMargin; + get layoutInfo(): IDiffElementLayoutInfo { + return this._layoutInfo; } constructor( @@ -126,12 +107,13 @@ export abstract class DiffElementViewModelBase extends Disposable { editorMargin: 0, metadataHeight: 0, metadataStatusHeight: 25, - outputHeight: 0, + rawOutputHeight: 0, + outputTotalHeight: 0, outputStatusHeight: 25, - bodyMargin: 32 + bodyMargin: 32, + totalHeight: 82 }; - this.metadataFoldingState = PropertyFoldingState.Collapsed; this.outputFoldingState = PropertyFoldingState.Collapsed; @@ -139,13 +121,104 @@ export abstract class DiffElementViewModelBase extends Disposable { this._layoutInfoEmitter.fire({ outerWidth: true }); })); } - private _fireLayoutChangeEvent(state: { outerWidth?: boolean, editorHeight?: boolean, metadataEditor?: boolean, outputEditor?: boolean, outputView?: boolean }) { + + layoutChange() { + this._layout({ recomputeOutput: true }); + } + + protected _layout(delta: ILayoutInfoDelta) { + const width = delta.width !== undefined ? delta.width : this._layoutInfo.width; + const editorHeight = delta.editorHeight !== undefined ? delta.editorHeight : this._layoutInfo.editorHeight; + const editorMargin = delta.editorMargin !== undefined ? delta.editorMargin : this._layoutInfo.editorMargin; + const metadataHeight = delta.metadataHeight !== undefined ? delta.metadataHeight : this._layoutInfo.metadataHeight; + const metadataStatusHeight = delta.metadataStatusHeight !== undefined ? delta.metadataStatusHeight : this._layoutInfo.metadataStatusHeight; + const rawOutputHeight = delta.rawOutputHeight !== undefined ? delta.rawOutputHeight : this._layoutInfo.rawOutputHeight; + const outputStatusHeight = delta.outputStatusHeight !== undefined ? delta.outputStatusHeight : this._layoutInfo.outputStatusHeight; + const bodyMargin = delta.bodyMargin !== undefined ? delta.bodyMargin : this._layoutInfo.bodyMargin; + const outputHeight = (delta.recomputeOutput || delta.rawOutputHeight !== undefined) ? this._getOutputTotalHeight(rawOutputHeight) : this._layoutInfo.outputTotalHeight; + + const totalHeight = editorHeight + + editorMargin + + metadataHeight + + metadataStatusHeight + + outputHeight + + outputStatusHeight + + bodyMargin; + + const newLayout: IDiffElementLayoutInfo = { + width: width, + editorHeight: editorHeight, + editorMargin: editorMargin, + metadataHeight: metadataHeight, + metadataStatusHeight: metadataStatusHeight, + outputTotalHeight: outputHeight, + outputStatusHeight: outputStatusHeight, + bodyMargin: bodyMargin, + rawOutputHeight: rawOutputHeight, + totalHeight: totalHeight + }; + + const changeEvent: CellDiffViewModelLayoutChangeEvent = {}; + + if (newLayout.width !== this._layoutInfo.width) { + changeEvent.width = true; + } + + if (newLayout.editorHeight !== this._layoutInfo.editorHeight) { + changeEvent.editorHeight = true; + } + + if (newLayout.editorMargin !== this._layoutInfo.editorMargin) { + changeEvent.editorMargin = true; + } + + if (newLayout.metadataHeight !== this._layoutInfo.metadataHeight) { + changeEvent.metadataHeight = true; + } + + if (newLayout.metadataStatusHeight !== this._layoutInfo.metadataStatusHeight) { + changeEvent.metadataStatusHeight = true; + } + + if (newLayout.outputTotalHeight !== this._layoutInfo.outputTotalHeight) { + changeEvent.outputTotalHeight = true; + } + + if (newLayout.outputStatusHeight !== this._layoutInfo.outputStatusHeight) { + changeEvent.outputStatusHeight = true; + } + + if (newLayout.bodyMargin !== this._layoutInfo.bodyMargin) { + changeEvent.bodyMargin = true; + } + + if (newLayout.totalHeight !== this._layoutInfo.totalHeight) { + changeEvent.totalHeight = true; + } + + this._layoutInfo = newLayout; + this._fireLayoutChangeEvent(changeEvent); + } + + private _getOutputTotalHeight(rawOutputHeight: number) { + if (this.outputFoldingState === PropertyFoldingState.Collapsed) { + return 0; + } + + if (this.renderOutput) { + return this.getRichOutputTotalHeight(); + } else { + return rawOutputHeight; + } + } + + private _fireLayoutChangeEvent(state: CellDiffViewModelLayoutChangeEvent) { this._layoutInfoEmitter.fire(state); } abstract checkIfOutputsModified(): boolean; abstract checkMetadataIfModified(): boolean; - abstract layoutChange(): void; + abstract getRichOutputTotalHeight(): number; abstract getCellByUri(cellUri: URI): IGenericCellViewModel; abstract getOutputOffsetInCell(diffSide: DiffSide, index: number): number; abstract getOutputOffsetInContainer(diffSide: DiffSide, index: number): number; @@ -188,30 +261,14 @@ export class SideBySideDiffElementViewModel extends DiffElementViewModelBase { } this._register(this.original.onDidChangeOutputLayout(() => { - this.layoutChange(); + this._layout({ recomputeOutput: true }); })); this._register(this.modified.onDidChangeOutputLayout(() => { - this.layoutChange(); + this._layout({ recomputeOutput: true }); })); } - layoutChange() { - let outputHeight = this.outputFoldingState === PropertyFoldingState.Collapsed ? 0 : this.getOutputTotalHeight(); - this._layoutInfo = { - width: this._layoutInfo.width, - editorHeight: this._layoutInfo.editorHeight, - editorMargin: this._layoutInfo.editorMargin, - metadataHeight: this._layoutInfo.metadataHeight, - metadataStatusHeight: this._layoutInfo.metadataStatusHeight, - outputHeight: outputHeight, - outputStatusHeight: this._layoutInfo.outputStatusHeight, - bodyMargin: this._layoutInfo.bodyMargin - }; - - this._layoutInfoEmitter.fire({}); - } - checkIfOutputsModified() { return !this.documentTextModel.transientOptions.transientOutputs && hash(this.original?.outputs ?? []) !== hash(this.modified?.outputs ?? []); } @@ -248,12 +305,8 @@ export class SideBySideDiffElementViewModel extends DiffElementViewModelBase { + offsetInOutputsContainer; } - getOutputTotalHeight() { - if (this.renderOutput) { - return Math.max(this.original.getOutputTotalHeight(), this.modified.getOutputTotalHeight()); - } else { - return this._layoutInfo.outputHeight; - } + getRichOutputTotalHeight() { + return Math.max(this.original.getOutputTotalHeight(), this.modified.getOutputTotalHeight()); } getNestedCellViewModel(diffSide: DiffSide): DiffNestedCellViewModel { @@ -283,7 +336,7 @@ export class SingleSideDiffElementViewModel extends DiffElementViewModelBase { ) { super(documentTextModel, original, modified, type, editorEventDispatcher); this._register(this.cellViewModel!.onDidChangeOutputLayout(() => { - this.layoutChange(); + this._layout({ recomputeOutput: true }); })); } @@ -291,22 +344,6 @@ export class SingleSideDiffElementViewModel extends DiffElementViewModelBase { return this.type === 'insert' ? this.modified! : this.original!; } - layoutChange() { - let outputHeight = this.outputFoldingState === PropertyFoldingState.Collapsed ? 0 : this.getOutputTotalHeight(); - this._layoutInfo = { - width: this._layoutInfo.width, - editorHeight: this._layoutInfo.editorHeight, - editorMargin: this._layoutInfo.editorMargin, - metadataHeight: this._layoutInfo.metadataHeight, - metadataStatusHeight: this._layoutInfo.metadataStatusHeight, - outputHeight: outputHeight, - outputStatusHeight: this._layoutInfo.outputStatusHeight, - bodyMargin: this._layoutInfo.bodyMargin - }; - - this._layoutInfoEmitter.fire({}); - } - checkIfOutputsModified(): boolean { return false; @@ -336,12 +373,8 @@ export class SingleSideDiffElementViewModel extends DiffElementViewModelBase { + offsetInOutputsContainer; } - getOutputTotalHeight() { - if (this.renderOutput) { - return this.cellViewModel?.getOutputTotalHeight() ?? 0; - } else { - return this._layoutInfo.outputHeight; - } + getRichOutputTotalHeight() { + return this.cellViewModel?.getOutputTotalHeight() ?? 0; } getCellByUri(cellUri: URI): IGenericCellViewModel { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts index f5b2de9e665..71aa2810077 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts @@ -88,10 +88,24 @@ export interface CellDiffSideBySideRenderTemplate extends CellDiffCommonRenderTe readonly outputInfoContainer: HTMLElement; } -export interface CellDiffViewModelLayoutChangeEvent { +export interface IDiffElementLayoutInfo { + totalHeight: number; + width: number; + editorHeight: number; + editorMargin: number; + metadataHeight: number; + metadataStatusHeight: number; + rawOutputHeight: number; + outputTotalHeight: number; + outputStatusHeight: number; + bodyMargin: number +} + +type IDiffElementSelfLayoutChangeEvent = { [K in keyof IDiffElementLayoutInfo]?: boolean }; + +export interface CellDiffViewModelLayoutChangeEvent extends IDiffElementSelfLayoutChangeEvent { font?: BareFontInfo; outerWidth?: boolean; - editorHeight?: boolean; metadataEditor?: boolean; outputEditor?: boolean; outputView?: boolean; From 6ad37a351ff1535b21b6510b77cccc8d5aaf7254 Mon Sep 17 00:00:00 2001 From: rebornix Date: Fri, 18 Dec 2020 11:11:14 -0800 Subject: [PATCH 073/262] cache metadata and output height. --- .../notebook/browser/diff/diffComponents.ts | 64 +++++++++++++----- .../notebook/browser/diff/notebookDiff.css | 5 +- .../browser/diff/notebookTextDiffList.ts | 65 +------------------ 3 files changed, 52 insertions(+), 82 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts index 4b2402e0c3e..78f41f233d7 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts @@ -10,7 +10,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { DiffElementViewModelBase, getFormatedMetadataJSON, PropertyFoldingState, SideBySideDiffElementViewModel, SingleSideDiffElementViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; import { CellDiffSideBySideRenderTemplate, CellDiffSingleSideRenderTemplate, DiffSide, DIFF_CELL_MARGIN, INotebookTextDiffEditor, NOTEBOOK_DIFF_CELL_PROPERTY, NOTEBOOK_DIFF_CELL_PROPERTY_EXPANDED } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser'; import { EDITOR_BOTTOM_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; -import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; +import { CodeEditorWidget, ICodeEditorWidgetOptions } from 'vs/editor/browser/widget/codeEditorWidget'; import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; import { IModelService } from 'vs/editor/common/services/modelService'; import { IModeService } from 'vs/editor/common/services/modeService'; @@ -32,8 +32,16 @@ import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { collapsedIcon, expandedIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons'; import { renderCodicons } from 'vs/base/browser/codicons'; import { OutputContainer } from 'vs/workbench/contrib/notebook/browser/diff/diffElementOutputs'; +import { EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions'; +import { ContextMenuController } from 'vs/editor/contrib/contextmenu/contextmenu'; +import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2'; +import { SuggestController } from 'vs/editor/contrib/suggest/suggestController'; +import { AccessibilityHelpController } from 'vs/workbench/contrib/codeEditor/browser/accessibility/accessibility'; +import { MenuPreventer } from 'vs/workbench/contrib/codeEditor/browser/menuPreventer'; +import { SelectionClipboardContributionID } from 'vs/workbench/contrib/codeEditor/browser/selectionClipboard'; +import { TabCompletionController } from 'vs/workbench/contrib/snippets/browser/tabCompletion'; -const fixedEditorOptions: IEditorOptions = { +export const fixedEditorOptions: IEditorOptions = { padding: { top: 12, bottom: 12 @@ -63,13 +71,29 @@ const fixedEditorOptions: IEditorOptions = { readOnly: true }; -const fixedDiffEditorOptions: IDiffEditorOptions = { +export function getOptimizedNestedCodeEditorWidgetOptions(): ICodeEditorWidgetOptions { + return { + isSimpleWidget: false, + contributions: EditorExtensionsRegistry.getSomeEditorContributions([ + MenuPreventer.ID, + SelectionClipboardContributionID, + ContextMenuController.ID, + SuggestController.ID, + SnippetController2.ID, + TabCompletionController.ID, + AccessibilityHelpController.ID + ]) + }; +} + +export const fixedDiffEditorOptions: IDiffEditorOptions = { ...fixedEditorOptions, glyphMargin: true, enableSplitViewResizing: false, renderIndicators: false, readOnly: false, isInEmbeddedEditor: true, + renderOverviewRuler: false }; class PropertyHeader extends Disposable { @@ -439,10 +463,13 @@ abstract class AbstractElementRenderer extends Disposable { ignoreTrimWhitespace: false, automaticLayout: false, dimension: { - height: 0, - width: 0 + height: this.cell.layoutInfo.metadataHeight, + width: this.cell.getComputedCellContainerWidth(this.notebookEditor.getLayoutInfo(), true, true) } - }, {}); + }, { + originalEditor: getOptimizedNestedCodeEditorWidgetOptions(), + modifiedEditor: getOptimizedNestedCodeEditorWidgetOptions() + }); this._register(this._metadataEditor); this._metadataEditorContainer?.classList.add('diff'); @@ -491,7 +518,7 @@ abstract class AbstractElementRenderer extends Disposable { ...fixedEditorOptions, dimension: { width: this.cell.getComputedCellContainerWidth(this.notebookEditor.getLayoutInfo(), false, true), - height: 0 + height: this.cell.layoutInfo.metadataHeight }, overflowWidgetsDomNode: this.notebookEditor.getOverflowContainerDomNode(), readOnly: false @@ -549,7 +576,10 @@ abstract class AbstractElementRenderer extends Disposable { height: 0, width: 0 } - }, {}); + }, { + originalEditor: getOptimizedNestedCodeEditorWidgetOptions(), + modifiedEditor: getOptimizedNestedCodeEditorWidgetOptions() + }); this._register(this._outputEditor); this._outputEditorContainer?.classList.add('diff'); @@ -583,8 +613,8 @@ abstract class AbstractElementRenderer extends Disposable { this._outputEditor = this.instantiationService.createInstance(CodeEditorWidget, this._outputEditorContainer!, { ...fixedEditorOptions, dimension: { - width: this.cell.getComputedCellContainerWidth(this.notebookEditor.getLayoutInfo(), false, this.cell.type === 'unchanged' || this.cell.type === 'modified'), - height: 0 + width: this.cell.getComputedCellContainerWidth(this.notebookEditor.getLayoutInfo(), false, this.cell.type === 'unchanged' || this.cell.type === 'modified') - 32, + height: this.cell.layoutInfo.rawOutputHeight }, overflowWidgetsDomNode: this.notebookEditor.getOverflowContainerDomNode() }, {}); @@ -812,7 +842,7 @@ export class DeletedElement extends SingleSideDiffElement { }); } - layout(state: { outerWidth?: boolean, editorHeight?: boolean, metadataEditor?: boolean, outputTotalHeight?: boolean }) { + layout(state: { outerWidth?: boolean, editorHeight?: boolean, metadataHeight?: boolean, outputTotalHeight?: boolean }) { DOM.scheduleAtNextAnimationFrame(() => { if (state.editorHeight || state.outerWidth) { this._editor.layout({ @@ -821,7 +851,7 @@ export class DeletedElement extends SingleSideDiffElement { }); } - if (state.metadataEditor || state.outerWidth) { + if (state.metadataHeight || state.outerWidth) { this._metadataEditor?.layout({ width: this.cell.getComputedCellContainerWidth(this.notebookEditor.getLayoutInfo(), false, false), height: this.cell.layoutInfo.metadataHeight @@ -982,7 +1012,7 @@ export class InsertElement extends SingleSideDiffElement { } } - layout(state: { outerWidth?: boolean, editorHeight?: boolean, metadataEditor?: boolean, outputTotalHeight?: boolean }) { + layout(state: { outerWidth?: boolean, editorHeight?: boolean, metadataHeight?: boolean, outputTotalHeight?: boolean }) { DOM.scheduleAtNextAnimationFrame(() => { if (state.editorHeight || state.outerWidth) { this._editor.layout({ @@ -991,7 +1021,7 @@ export class InsertElement extends SingleSideDiffElement { }); } - if (state.metadataEditor || state.outerWidth) { + if (state.metadataHeight || state.outerWidth) { this._metadataEditor?.layout({ width: this.cell.getComputedCellContainerWidth(this.notebookEditor.getLayoutInfo(), false, true), height: this.cell.layoutInfo.metadataHeight @@ -1198,7 +1228,7 @@ export class ModifiedElement extends AbstractElementRenderer { const modifiedCell = this.cell.modified!; const lineCount = modifiedCell.textModel.textBuffer.getLineCount(); const lineHeight = this.notebookEditor.getLayoutInfo().fontInfo.lineHeight || 17; - const editorHeight = lineCount * lineHeight + getEditorTopPadding() + EDITOR_BOTTOM_PADDING; + const editorHeight = this.cell.layoutInfo.editorHeight !== 0 ? this.cell.layoutInfo.editorHeight : lineCount * lineHeight + getEditorTopPadding() + EDITOR_BOTTOM_PADDING; this._editorContainer = this.templateData.editorContainer; this._editor = this.templateData.sourceEditor; @@ -1288,7 +1318,7 @@ export class ModifiedElement extends AbstractElementRenderer { this.cell.editorHeight = contentHeight; } - layout(state: { outerWidth?: boolean, editorHeight?: boolean, metadataEditor?: boolean, outputTotalHeight?: boolean }) { + layout(state: { outerWidth?: boolean, editorHeight?: boolean, metadataHeight?: boolean, outputTotalHeight?: boolean }) { DOM.scheduleAtNextAnimationFrame(() => { if (state.editorHeight) { this._editorContainer.style.height = `${this.cell.layoutInfo.editorHeight}px`; @@ -1303,7 +1333,7 @@ export class ModifiedElement extends AbstractElementRenderer { this._editor!.layout(); } - if (state.metadataEditor || state.outerWidth) { + if (state.metadataHeight || state.outerWidth) { if (this._metadataEditorContainer) { this._metadataEditorContainer.style.height = `${this.cell.layoutInfo.metadataHeight}px`; this._metadataEditor?.layout(); diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css index 406c9ab1387..fd2087e2831 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css @@ -60,11 +60,12 @@ .notebook-text-diff-editor .cell-body .cell-diff-editor-container .output-editor-container.diff, .notebook-text-diff-editor .cell-body .cell-diff-editor-container .editor-container.diff { /** 100% + diffOverviewWidth */ - width: calc(100% + 30px); + width: calc(100%); } .notebook-text-diff-editor .cell-body .cell-diff-editor-container .metadata-editor-container .monaco-diff-editor .diffOverview, -.notebook-text-diff-editor .cell-body .cell-diff-editor-container .editor-container.diff .monaco-diff-editor .diffOverview { +.notebook-text-diff-editor .cell-body .cell-diff-editor-container .editor-container.diff .monaco-diff-editor .diffOverview, +.notebook-text-diff-editor .cell-body .cell-diff-editor-container .output-editor-container.diff .monaco-diff-editor .diffOverview { display: none; } diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts index d559e05d973..4f93b9c556e 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts @@ -17,78 +17,17 @@ import { IThemeService } from 'vs/platform/theme/common/themeService'; import { DiffElementViewModelBase, SideBySideDiffElementViewModel, SingleSideDiffElementViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; import { CellDiffSideBySideRenderTemplate, CellDiffSingleSideRenderTemplate, DIFF_CELL_MARGIN, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser'; import { isMacintosh } from 'vs/base/common/platform'; -import { DeletedElement, InsertElement, ModifiedElement } from 'vs/workbench/contrib/notebook/browser/diff/diffComponents'; -import { CodeEditorWidget, ICodeEditorWidgetOptions } from 'vs/editor/browser/widget/codeEditorWidget'; +import { DeletedElement, fixedDiffEditorOptions, fixedEditorOptions, getOptimizedNestedCodeEditorWidgetOptions, InsertElement, ModifiedElement } from 'vs/workbench/contrib/notebook/browser/diff/diffComponents'; +import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; import { IDiffEditorOptions, IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; import { IMenuService, MenuItemAction } from 'vs/platform/actions/common/actions'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { INotificationService } from 'vs/platform/notification/common/notification'; -import { EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions'; -import { ContextMenuController } from 'vs/editor/contrib/contextmenu/contextmenu'; -import { SnippetController2 } from 'vs/editor/contrib/snippet/snippetController2'; -import { SuggestController } from 'vs/editor/contrib/suggest/suggestController'; -import { MenuPreventer } from 'vs/workbench/contrib/codeEditor/browser/menuPreventer'; -import { SelectionClipboardContributionID } from 'vs/workbench/contrib/codeEditor/browser/selectionClipboard'; -import { TabCompletionController } from 'vs/workbench/contrib/snippets/browser/tabCompletion'; -import { AccessibilityHelpController } from 'vs/workbench/contrib/codeEditor/browser/accessibility/accessibility'; import { CodiconActionViewItem } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellActionView'; import { IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; -const fixedEditorOptions: IEditorOptions = { - padding: { - top: 12, - bottom: 12 - }, - scrollBeyondLastLine: false, - scrollbar: { - verticalScrollbarSize: 14, - horizontal: 'auto', - useShadows: true, - verticalHasArrows: false, - horizontalHasArrows: false, - alwaysConsumeMouseWheel: false - }, - renderLineHighlightOnlyWhenFocus: true, - overviewRulerLanes: 0, - selectOnLineNumbers: false, - wordWrap: 'off', - lineNumbers: 'off', - lineDecorationsWidth: 0, - glyphMargin: false, - fixedOverflowWidgets: true, - minimap: { enabled: false }, - renderValidationDecorations: 'on', - renderLineHighlight: 'none', - readOnly: true -}; - -const fixedDiffEditorOptions: IDiffEditorOptions = { - ...fixedEditorOptions, - glyphMargin: true, - enableSplitViewResizing: false, - renderIndicators: false, - readOnly: false, - isInEmbeddedEditor: true, - renderOverviewRuler: false -}; - -export function getOptimizedNestedCodeEditorWidgetOptions(): ICodeEditorWidgetOptions { - return { - isSimpleWidget: false, - contributions: EditorExtensionsRegistry.getSomeEditorContributions([ - MenuPreventer.ID, - SelectionClipboardContributionID, - ContextMenuController.ID, - SuggestController.ID, - SnippetController2.ID, - TabCompletionController.ID, - AccessibilityHelpController.ID - ]) - }; -} - export class NotebookCellTextDiffListDelegate implements IListVirtualDelegate { // private readonly lineHeight: number; From 87629065098e23f5975561c10d09a3aa6e1aabf8 Mon Sep 17 00:00:00 2001 From: rebornix Date: Fri, 18 Dec 2020 11:11:30 -0800 Subject: [PATCH 074/262] :lipstick: --- .../contrib/notebook/browser/diff/notebookTextDiffList.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts index 4f93b9c556e..aeae2339c57 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts @@ -19,7 +19,6 @@ import { CellDiffSideBySideRenderTemplate, CellDiffSingleSideRenderTemplate, DIF import { isMacintosh } from 'vs/base/common/platform'; import { DeletedElement, fixedDiffEditorOptions, fixedEditorOptions, getOptimizedNestedCodeEditorWidgetOptions, InsertElement, ModifiedElement } from 'vs/workbench/contrib/notebook/browser/diff/diffComponents'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; -import { IDiffEditorOptions, IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; import { IMenuService, MenuItemAction } from 'vs/platform/actions/common/actions'; From 71a733b4aa01210209c1c13b087bd21de315c815 Mon Sep 17 00:00:00 2001 From: rebornix Date: Fri, 18 Dec 2020 11:23:12 -0800 Subject: [PATCH 075/262] finally fixed the OutputViewModel leak --- .../notebook/browser/diff/diffElementOutputs.ts | 10 ++++------ .../notebook/browser/viewModel/cellOutputViewModel.ts | 3 +++ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts index 1d76d0473c9..676d9d092ef 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts @@ -149,7 +149,6 @@ export class OutputElement extends Disposable { } export class OutputContainer extends Disposable { - private _outputViewModels: ICellOutputViewModel[]; private _outputEntries = new Map(); constructor( private _editor: INotebookTextDiffEditor, @@ -165,7 +164,6 @@ export class OutputContainer extends Disposable { ) { super(); - this._outputViewModels = _nestedCellViewModel.outputs.map(output => new CellOutputViewModel(_nestedCellViewModel, output, _notebookService)); // TODO, onDidChangeOutputs @@ -185,8 +183,8 @@ export class OutputContainer extends Disposable { render() { // TODO, outputs to render (should have a limit) - for (let index = 0; index < this._outputViewModels.length; index++) { - const currOutput = this._outputViewModels[index]; + for (let index = 0; index < this._nestedCellViewModel.outputsViewModels.length; index++) { + const currOutput = this._nestedCellViewModel.outputsViewModels[index]; // always add to the end this._renderOutput(currOutput, index, undefined); @@ -194,8 +192,8 @@ export class OutputContainer extends Disposable { } showOutputs() { - for (let index = 0; index < this._outputViewModels.length; index++) { - const currOutput = this._outputViewModels[index]; + for (let index = 0; index < this._nestedCellViewModel.outputsViewModels.length; index++) { + const currOutput = this._nestedCellViewModel.outputsViewModels[index]; if (currOutput.isDisplayOutput()) { // always add to the end diff --git a/src/vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel.ts b/src/vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel.ts index 505c173fd6e..34194aa5820 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel.ts @@ -9,7 +9,9 @@ import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/no import { CellOutputKind, IOrderedMimeType, IProcessedOutput, ITransformedDisplayOutputDto, RENDERER_NOT_AVAILABLE } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; +let handle = 0; export class CellOutputViewModel extends Disposable implements ICellOutputViewModel { + outputHandle = handle++; get model() { return this._outputData; } @@ -29,6 +31,7 @@ export class CellOutputViewModel extends Disposable implements ICellOutputViewMo private readonly _notebookService: INotebookService ) { super(); + console.log('create cell', this.outputHandle); } isStreamOutput(): this is IStreamOutputViewModel { From 361877735ce09241282d2ebbe5c4023d609f65d5 Mon Sep 17 00:00:00 2001 From: rebornix Date: Fri, 18 Dec 2020 11:23:34 -0800 Subject: [PATCH 076/262] :lipstick: --- .../contrib/notebook/browser/diff/diffElementOutputs.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts index 676d9d092ef..6b49729e661 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts @@ -10,7 +10,6 @@ import { DiffElementViewModelBase, SideBySideDiffElementViewModel } from 'vs/wor import { DiffSide, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser'; import { ICellOutputViewModel, IRenderOutput, outputHasDynamicHeight, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { getResizesObserver } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellWidgets'; -import { CellOutputViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/cellOutputViewModel'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; import { BUILTIN_RENDERER_ID } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; From 9970299016a0345ff30b39be2dc15ae46d4aa4ec Mon Sep 17 00:00:00 2001 From: rebornix Date: Fri, 18 Dec 2020 11:39:23 -0800 Subject: [PATCH 077/262] dispose webviews after switching models. --- .../notebook/browser/diff/notebookDiffActions.ts | 4 ++-- .../notebook/browser/diff/notebookTextDiffEditor.ts | 13 +++++++++++++ .../notebook/browser/diff/notebookTextDiffList.ts | 4 ++++ .../contrib/notebook/browser/notebookIcons.ts | 1 - .../browser/viewModel/cellOutputViewModel.ts | 1 - 5 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts index 0bd867fa6aa..0911630f6d8 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts @@ -12,7 +12,7 @@ import { DiffElementViewModelBase } from 'vs/workbench/contrib/notebook/browser/ import { NOTEBOOK_DIFF_CELL_PROPERTY, NOTEBOOK_DIFF_CELL_PROPERTY_EXPANDED } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser'; import { NotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor'; import { NotebookDiffEditorInput } from 'vs/workbench/contrib/notebook/browser/notebookDiffEditorInput'; -import { openAsTextIcon, revertIcon, showOutputRawIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons'; +import { openAsTextIcon, renderOutputIcon, revertIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -114,7 +114,7 @@ registerAction2(class extends Action2 { { id: 'notebook.diff.cell.switchOutputRenderingStyleToText', title: localize('notebook.diff.cell.switchOutputRenderingStyleToText', "Switch Output Rendering"), - icon: showOutputRawIcon, + icon: renderOutputIcon, f1: false, menu: { id: MenuId.NotebookDiffCellOutputsTitle, diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 28513cb0135..d42c8a0c75b 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -291,6 +291,19 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD async setInput(input: NotebookDiffEditorInput, options: EditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise { await super.setInput(input, options, context, token); + const model = await input.resolve(); + if (this._model !== model) { + this._originalWebview?.dispose(); + this._originalWebview?.element.remove(); + this._originalWebview = null; + this._modifiedWebview?.dispose(); + this._modifiedWebview?.element.remove(); + this._modifiedWebview = null; + + this._modifiedResourceDisposableStore.clear(); + this._list.clear(); + } + this._model = await input.resolve(); if (this._model === null) { return; diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts index aeae2339c57..00eb7c927da 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList.ts @@ -309,6 +309,10 @@ export class NotebookTextDiffList extends WorkbenchList Date: Fri, 18 Dec 2020 11:54:04 -0800 Subject: [PATCH 078/262] webview cover. --- .../notebook/browser/diff/notebookDiff.css | 5 +++++ .../browser/diff/notebookTextDiffEditor.ts | 16 +++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css index fd2087e2831..9fcdb65fd75 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css @@ -21,6 +21,11 @@ flex-direction: row; } +.notebook-text-diff-editor .webview-cover { + user-select: initial; + -webkit-user-select: initial; +} + .notebook-text-diff-editor .cell-body .border-container { position: absolute; width: calc(100% - 32px); diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index d42c8a0c75b..0f7015a9402 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -221,6 +221,10 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD } })); + this._register(this._list.onDidScroll(e => { + this._webviewTransparentCover!.style.top = `${e.scrollTop}px`; + })); + this._register(this._list.onDidChangeContentHeight(() => { DOM.scheduleAtNextAnimationFrame(() => { if (this._isDisposed) { @@ -707,10 +711,20 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD if (this._modifiedWebview) { - this._modifiedWebview.element.style.width = `${this._dimension.width / 2}px`; + this._modifiedWebview.element.style.width = `calc(50% - 16px)`; this._modifiedWebview.element.style.left = `calc(50%)`; } + if (this._originalWebview) { + this._originalWebview.element.style.width = `calc(50% - 16px)`; + this._originalWebview.element.style.left = `16px`; + } + + if (this._webviewTransparentCover) { + this._webviewTransparentCover.style.height = `${dimension.height}px`; + this._webviewTransparentCover.style.width = `${dimension.width}px`; + } + this._eventDispatcher?.emit([new NotebookLayoutChangedEvent({ width: true, fontInfo: true }, this.getLayoutInfo())]); } From a207b50937df01d066967b232bd65658e6f92231 Mon Sep 17 00:00:00 2001 From: rebornix Date: Fri, 18 Dec 2020 12:01:10 -0800 Subject: [PATCH 079/262] dispose webview scroll event when switching models. --- .../browser/diff/notebookTextDiffEditor.ts | 66 +++++++++++-------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 0f7015a9402..9767934cdc0 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -79,6 +79,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD protected _onDidDynamicOutputRendered = new Emitter<{ cell: IGenericCellViewModel, output: IDisplayOutputViewModel }>(); onDidDynamicOutputRendered = this._onDidDynamicOutputRendered.event; + private _localStore: DisposableStore = this._register(new DisposableStore()); private _isDisposed: boolean = false; @@ -225,25 +226,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD this._webviewTransparentCover!.style.top = `${e.scrollTop}px`; })); - this._register(this._list.onDidChangeContentHeight(() => { - DOM.scheduleAtNextAnimationFrame(() => { - if (this._isDisposed) { - return; - } - if (this._modifiedWebview) { - this._updateOutputsOffsetsInWebview(this._list.scrollTop, this._list.scrollHeight, this._modifiedWebview, (diffElement: DiffElementViewModelBase) => { - return diffElement.modified; - }, DiffSide.Modified); - } - - if (this._originalWebview) { - this._updateOutputsOffsetsInWebview(this._list.scrollTop, this._list.scrollHeight, this._originalWebview, (diffElement: DiffElementViewModelBase) => { - return diffElement.original; - }, DiffSide.Original); - } - }); - })); } private _updateOutputsOffsetsInWebview(scrollTop: number, scrollHeight: number, activeWebview: BackLayerWebView, getActiveNestedCell: (diffElement: DiffElementViewModelBase) => DiffNestedCellViewModel | undefined, diffSide: DiffSide) { @@ -297,15 +280,9 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD const model = await input.resolve(); if (this._model !== model) { - this._originalWebview?.dispose(); - this._originalWebview?.element.remove(); - this._originalWebview = null; - this._modifiedWebview?.dispose(); - this._modifiedWebview?.element.remove(); - this._modifiedWebview = null; - - this._modifiedResourceDisposableStore.clear(); - this._list.clear(); + this._detachModel(); + this._model = model; + this._attachModel(); } this._model = await input.resolve(); @@ -361,6 +338,41 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD await this.updateLayout(); } + private _detachModel() { + this._localStore.clear(); + this._originalWebview?.dispose(); + this._originalWebview?.element.remove(); + this._originalWebview = null; + this._modifiedWebview?.dispose(); + this._modifiedWebview?.element.remove(); + this._modifiedWebview = null; + + this._modifiedResourceDisposableStore.clear(); + this._list.clear(); + + } + private _attachModel() { + this._localStore.add(this._list.onDidChangeContentHeight(() => { + DOM.scheduleAtNextAnimationFrame(() => { + if (this._isDisposed) { + return; + } + + if (this._modifiedWebview) { + this._updateOutputsOffsetsInWebview(this._list.scrollTop, this._list.scrollHeight, this._modifiedWebview, (diffElement: DiffElementViewModelBase) => { + return diffElement.modified; + }, DiffSide.Modified); + } + + if (this._originalWebview) { + this._updateOutputsOffsetsInWebview(this._list.scrollTop, this._list.scrollHeight, this._originalWebview, (diffElement: DiffElementViewModelBase) => { + return diffElement.original; + }, DiffSide.Original); + } + }); + })); + } + private async _createModifiedWebview(id: string, resource: URI): Promise { this._modifiedWebview = this.instantiationService.createInstance(BackLayerWebView, this, id, resource) as BackLayerWebView; // attach the webview container to the DOM tree first From 8b23b938a387ef1e118c9c6c1ac0d52c77a44ee6 Mon Sep 17 00:00:00 2001 From: rebornix Date: Mon, 21 Dec 2020 15:01:15 -0800 Subject: [PATCH 080/262] split point takes renderOverviewRuler into account --- src/vs/editor/browser/widget/diffEditorWidget.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/vs/editor/browser/widget/diffEditorWidget.ts b/src/vs/editor/browser/widget/diffEditorWidget.ts index 805c96eb040..9385401c31a 100644 --- a/src/vs/editor/browser/widget/diffEditorWidget.ts +++ b/src/vs/editor/browser/widget/diffEditorWidget.ts @@ -1201,7 +1201,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE this._overviewViewportDomElement.setHeight(30); this._originalEditor.layout({ width: splitPoint, height: (height - reviewHeight) }); - this._modifiedEditor.layout({ width: width - splitPoint - DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH, height: (height - reviewHeight) }); + this._modifiedEditor.layout({ width: width - splitPoint - (this._renderOverviewRuler ? DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH : 0), height: (height - reviewHeight) }); if (this._originalOverviewRuler || this._modifiedOverviewRuler) { this._layoutOverviewRulers(); @@ -1255,6 +1255,12 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE return (this._elementSizeObserver.getHeight() - this._getReviewHeight()); }, + getOptions: () => { + return { + renderOverviewRuler: this._renderOverviewRuler + }; + }, + getContainerDomNode: () => { return this._containerDomElement; }, @@ -1384,6 +1390,7 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE interface IDataSource { getWidth(): number; getHeight(): number; + getOptions(): { renderOverviewRuler: boolean; }; getContainerDomNode(): HTMLElement; relayoutEditors(): void; @@ -1843,7 +1850,7 @@ class DiffEditorWidgetSideBySide extends DiffEditorWidgetStyle implements IVerti public layout(sashRatio: number | null = this._sashRatio): number { const w = this._dataSource.getWidth(); - const contentWidth = w - DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH; + const contentWidth = w - (this._dataSource.getOptions().renderOverviewRuler ? DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH : 0); let sashPosition = Math.floor((sashRatio || 0.5) * contentWidth); const midPoint = Math.floor(0.5 * contentWidth); @@ -1876,7 +1883,7 @@ class DiffEditorWidgetSideBySide extends DiffEditorWidgetStyle implements IVerti private _onSashDrag(e: ISashEvent): void { const w = this._dataSource.getWidth(); - const contentWidth = w - DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH; + const contentWidth = w - (this._dataSource.getOptions().renderOverviewRuler ? DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH : 0); const sashPosition = this.layout((this._startSashPosition! + (e.currentX - e.startX)) / contentWidth); this._sashRatio = sashPosition / contentWidth; From d345d1bd827c9d62d363592e054af230766086a3 Mon Sep 17 00:00:00 2001 From: rebornix Date: Mon, 21 Dec 2020 15:47:26 -0800 Subject: [PATCH 081/262] mime type switcher --- .../browser/diff/diffElementOutputs.ts | 109 +++++++++++++++++- .../notebook/browser/diff/notebookDiff.css | 22 +++- .../browser/diff/notebookDiffEditorBrowser.ts | 1 + .../browser/diff/notebookTextDiffEditor.ts | 22 +++- .../notebook/browser/notebookEditorWidget.ts | 6 +- .../view/renderers/backLayerWebView.ts | 15 ++- .../browser/view/renderers/webviewPreloads.ts | 5 +- 7 files changed, 160 insertions(+), 20 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts index 6b49729e661..e40bdb78c73 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementOutputs.ts @@ -4,17 +4,27 @@ *--------------------------------------------------------------------------------------------*/ import * as DOM from 'vs/base/browser/dom'; +import * as nls from 'vs/nls'; import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { DiffElementViewModelBase, SideBySideDiffElementViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffElementViewModel'; import { DiffSide, INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser'; -import { ICellOutputViewModel, IRenderOutput, outputHasDynamicHeight, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { ICellOutputViewModel, IDisplayOutputViewModel, IRenderOutput, outputHasDynamicHeight, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { getResizesObserver } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellWidgets'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; import { BUILTIN_RENDERER_ID } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { DiffNestedCellViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel'; +import { ThemeIcon } from 'vs/platform/theme/common/themeService'; +import { mimetypeIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons'; +import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; +import { KeyCode } from 'vs/base/common/keyCodes'; +import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput'; + +interface IMimeTypeRenderer extends IQuickPickItem { + index: number; +} export class OutputElement extends Disposable { readonly resizeListener = new DisposableStore(); @@ -25,6 +35,7 @@ export class OutputElement extends Disposable { private _notebookEditor: INotebookTextDiffEditor, private _notebookTextModel: NotebookTextModel, private _notebookService: INotebookService, + private _quickInputService: IQuickInputService, private _diffElementViewModel: DiffElementViewModelBase, private _diffSide: DiffSide, private _nestedCell: DiffNestedCellViewModel, @@ -41,6 +52,31 @@ export class OutputElement extends Disposable { if (this.output.isDisplayOutput()) { const [mimeTypes, pick] = this.output.resolveMimeTypes(this._notebookTextModel); const pickedMimeTypeRenderer = mimeTypes[pick]; + if (mimeTypes.length > 1) { + outputItemDiv.style.position = 'relative'; + const mimeTypePicker = DOM.$('.multi-mimetype-output'); + mimeTypePicker.classList.add(...ThemeIcon.asClassNameArray(mimetypeIcon)); + mimeTypePicker.tabIndex = 0; + mimeTypePicker.title = nls.localize('mimeTypePicker', "Choose a different output mimetype, available mimetypes: {0}", mimeTypes.map(mimeType => mimeType.mimeType).join(', ')); + outputItemDiv.appendChild(mimeTypePicker); + this.resizeListener.add(DOM.addStandardDisposableListener(mimeTypePicker, 'mousedown', async e => { + if (e.leftButton) { + e.preventDefault(); + e.stopPropagation(); + await this.pickActiveMimeTypeRenderer(this._notebookTextModel, this.output as IDisplayOutputViewModel); + } + })); + + this.resizeListener.add((DOM.addDisposableListener(mimeTypePicker, DOM.EventType.KEY_DOWN, async e => { + const event = new StandardKeyboardEvent(e); + if ((event.equals(KeyCode.Enter) || event.equals(KeyCode.Space))) { + e.preventDefault(); + e.stopPropagation(); + await this.pickActiveMimeTypeRenderer(this._notebookTextModel, this.output as IDisplayOutputViewModel); + } + }))); + } + const innerContainer = DOM.$('.output-inner-container'); DOM.append(outputItemDiv, innerContainer); @@ -130,6 +166,73 @@ export class OutputElement extends Disposable { } } + private async pickActiveMimeTypeRenderer(notebookTextModel: NotebookTextModel, viewModel: IDisplayOutputViewModel) { + const [mimeTypes, currIndex] = viewModel.resolveMimeTypes(notebookTextModel); + + const items = mimeTypes.filter(mimeType => mimeType.isTrusted).map((mimeType, index): IMimeTypeRenderer => ({ + label: mimeType.mimeType, + id: mimeType.mimeType, + index: index, + picked: index === currIndex, + detail: this.generateRendererInfo(mimeType.rendererId), + description: index === currIndex ? nls.localize('curruentActiveMimeType', "Currently Active") : undefined + })); + + const picker = this._quickInputService.createQuickPick(); + picker.items = items; + picker.activeItems = items.filter(item => !!item.picked); + picker.placeholder = items.length !== mimeTypes.length + ? nls.localize('promptChooseMimeTypeInSecure.placeHolder', "Select mimetype to render for current output. Rich mimetypes are available only when the notebook is trusted") + : nls.localize('promptChooseMimeType.placeHolder', "Select mimetype to render for current output"); + + const pick = await new Promise(resolve => { + picker.onDidAccept(() => { + resolve(picker.selectedItems.length === 1 ? (picker.selectedItems[0] as IMimeTypeRenderer).index : undefined); + picker.dispose(); + }); + picker.show(); + }); + + if (pick === undefined) { + return; + } + + if (pick !== currIndex) { + // user chooses another mimetype + const index = this._nestedCell.outputsViewModels.indexOf(viewModel); + const nextElement = this.domNode.nextElementSibling; + this.resizeListener.clear(); + const element = this.domNode; + if (element) { + element.parentElement?.removeChild(element); + this._notebookEditor.removeInset( + this._diffElementViewModel, + this._nestedCell, + viewModel, + this._diffSide + ); + } + + viewModel.pickedMimeType = pick; + this.render(index, nextElement as HTMLElement); + } + } + + private generateRendererInfo(renderId: string | undefined): string { + if (renderId === undefined || renderId === BUILTIN_RENDERER_ID) { + return nls.localize('builtinRenderInfo', "built-in"); + } + + const renderInfo = this._notebookService.getRendererInfo(renderId); + + if (renderInfo) { + const displayName = renderInfo.displayName !== '' ? renderInfo.displayName : renderInfo.id; + return `${displayName} (${renderInfo.extensionId.value})`; + } + + return nls.localize('builtinRenderInfo', "built-in"); + } + getCellOutputCurrentIndex() { return this._diffElementViewModel.getNestedCellViewModel(this._diffSide).outputs.indexOf(this.output.model); } @@ -157,7 +260,7 @@ export class OutputContainer extends Disposable { private _diffSide: DiffSide, private _outputContainer: HTMLElement, @INotebookService private _notebookService: INotebookService, - // @IQuickInputService private readonly quickInputService: IQuickInputService, + @IQuickInputService private readonly _quickInputService: IQuickInputService, @IOpenerService readonly _openerService: IOpenerService, @ITextFileService readonly _textFileService: ITextFileService, @@ -211,7 +314,7 @@ export class OutputContainer extends Disposable { private _renderOutput(currOutput: ICellOutputViewModel, index: number, beforeElement?: HTMLElement) { if (!this._outputEntries.has(currOutput)) { - this._outputEntries.set(currOutput, new OutputElement(this._editor, this._notebookTextModel, this._notebookService, this._diffElementViewModel, this._diffSide, this._nestedCellViewModel, this._outputContainer, currOutput)); + this._outputEntries.set(currOutput, new OutputElement(this._editor, this._notebookTextModel, this._notebookService, this._quickInputService, this._diffElementViewModel, this._diffSide, this._nestedCellViewModel, this._outputContainer, currOutput)); } const renderElement = this._outputEntries.get(currOutput)!; diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css index 9fcdb65fd75..0dfb2d146e5 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiff.css @@ -177,9 +177,17 @@ overflow-x: hidden; } +.monaco-workbench .notebook-text-diff-editor .cell-body.left .output-view-container .output-inner-container { + padding: 0px 8px 0px 24px; +} + +.monaco-workbench .notebook-text-diff-editor .cell-body.right .output-view-container .output-inner-container { + padding: 0px 8px 0px 24px; +} + .monaco-workbench .notebook-text-diff-editor .cell-body.full .output-view-container .output-inner-container { - width: calc(100% - 16px); - padding: 4px 8px; + width: 100%; + padding: 4px 8px 4px 24px; box-sizing: border-box; overflow-x: hidden; } @@ -234,3 +242,13 @@ .monaco-workbench .notebook-text-diff-editor .output-view-container .display img { max-width: 100%; } + +.monaco-workbench .notebook-text-diff-editor .output-view-container .multi-mimetype-output { + position: absolute; + /* top: 4px; */ + left: 0px; + width: 16px; + height: 16px; + cursor: pointer; + padding: 4px; +} diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts index 71aa2810077..611b0f264b0 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffEditorBrowser.ts @@ -35,6 +35,7 @@ export interface INotebookTextDiffEditor extends ICommonNotebookEditor { getOutputRenderer(): OutputRenderer; createInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: IDiffNestedCellViewModel, output: IInsetRenderOutput, getOffset: () => number, diffSide: DiffSide): void; showInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: IDiffNestedCellViewModel, displayOutput: IDisplayOutputViewModel, diffSide: DiffSide): void; + removeInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: IDiffNestedCellViewModel, output: IDisplayOutputViewModel, diffSide: DiffSide): void; hideInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: IDiffNestedCellViewModel, output: IDisplayOutputViewModel): void; /** * Trigger the editor to scroll from scroll event programmatically diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index 9767934cdc0..5b1418e6207 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -42,6 +42,7 @@ import { generateUuid } from 'vs/base/common/uuid'; import { IMouseWheelEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { DiffNestedCellViewModel } from 'vs/workbench/contrib/notebook/browser/diff/diffNestedCellViewModel'; import { BackLayerWebView } from 'vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView'; +import { CELL_OUTPUT_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; const $ = DOM.$; @@ -374,7 +375,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD } private async _createModifiedWebview(id: string, resource: URI): Promise { - this._modifiedWebview = this.instantiationService.createInstance(BackLayerWebView, this, id, resource) as BackLayerWebView; + this._modifiedWebview = this.instantiationService.createInstance(BackLayerWebView, this, id, resource, { outputNodePadding: CELL_OUTPUT_PADDING, outputNodeLeftPadding: 24 }) as BackLayerWebView; // attach the webview container to the DOM tree first this._list.rowsContainer.insertAdjacentElement('afterbegin', this._modifiedWebview.element); await this._modifiedWebview.createWebview(); @@ -383,7 +384,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD } private async _createOriginalWebview(id: string, resource: URI): Promise { - this._originalWebview = this.instantiationService.createInstance(BackLayerWebView, this, id, resource) as BackLayerWebView; + this._originalWebview = this.instantiationService.createInstance(BackLayerWebView, this, id, resource, { outputNodePadding: CELL_OUTPUT_PADDING, outputNodeLeftPadding: 24 }) as BackLayerWebView; // attach the webview container to the DOM tree first this._list.rowsContainer.insertAdjacentElement('afterbegin', this._originalWebview.element); await this._originalWebview.createWebview(); @@ -578,8 +579,19 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD return cellInfo.diffElement.getCellByUri(cellInfo.cellUri); } - removeInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: DiffNestedCellViewModel, output: IInsetRenderOutput) { + removeInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: DiffNestedCellViewModel, displayOutput: IDisplayOutputViewModel, diffSide: DiffSide) { + this._insetModifyQueueByOutputId.queue(displayOutput.model.outputId + (diffSide === DiffSide.Modified ? '-right' : 'left'), async () => { + const activeWebview = diffSide === DiffSide.Modified ? this._modifiedWebview : this._originalWebview; + if (!activeWebview) { + return; + } + if (!activeWebview.insetMapping.has(displayOutput)) { + return; + } + + activeWebview.removeInset(displayOutput); + }); } showInset(cellDiffViewModel: DiffElementViewModelBase, cellViewModel: DiffNestedCellViewModel, displayOutput: IDisplayOutputViewModel, diffSide: DiffSide) { @@ -778,6 +790,7 @@ registerThemingParticipant((theme, collector) => { collector.addRule( ` .monaco-workbench .notebook-text-diff-editor .cell-body.full .output-info-container.modified .output-view-container .output-view-container-right div.foreground { background-color: ${added}; } + .monaco-workbench .notebook-text-diff-editor .cell-body.right .output-info-container .output-view-container div.foreground { background-color: ${added}; } ` ); collector.addRule(` @@ -798,7 +811,6 @@ registerThemingParticipant((theme, collector) => { ); collector.addRule(` .notebook-text-diff-editor .cell-body .cell-diff-editor-container.inserted .output-editor-container { background-color: ${added}; } - .notebook-text-diff-editor .cell-body .cell-diff-editor-container.inserted .output-inner-container { background-color: ${added}; } .notebook-text-diff-editor .cell-body .cell-diff-editor-container.inserted .output-editor-container .monaco-editor .margin, .notebook-text-diff-editor .cell-body .cell-diff-editor-container.inserted .output-editor-container .monaco-editor .monaco-editor-background { background-color: ${added}; @@ -816,6 +828,8 @@ registerThemingParticipant((theme, collector) => { collector.addRule( ` .monaco-workbench .notebook-text-diff-editor .cell-body.full .output-info-container.modified .output-view-container .output-view-container-left div.foreground { background-color: ${removed}; } + .monaco-workbench .notebook-text-diff-editor .cell-body.left .output-info-container .output-view-container div.foreground { background-color: ${removed}; } + ` ); collector.addRule(` diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 368a8b9f1b8..de69656b802 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -40,7 +40,7 @@ import { EditorMemento } from 'vs/workbench/browser/parts/editor/editorPane'; import { IEditorMemento } from 'vs/workbench/common/editor'; import { Memento, MementoObject } from 'vs/workbench/common/memento'; import { PANEL_BORDER } from 'vs/workbench/common/theme'; -import { BOTTOM_CELL_TOOLBAR_GAP, BOTTOM_CELL_TOOLBAR_HEIGHT, CELL_BOTTOM_MARGIN, CELL_MARGIN, CELL_RUN_GUTTER, CELL_TOP_MARGIN, CODE_CELL_LEFT_MARGIN, COLLAPSED_INDICATOR_HEIGHT, SCROLLABLE_ELEMENT_PADDING_TOP } from 'vs/workbench/contrib/notebook/browser/constants'; +import { BOTTOM_CELL_TOOLBAR_GAP, BOTTOM_CELL_TOOLBAR_HEIGHT, CELL_BOTTOM_MARGIN, CELL_MARGIN, CELL_OUTPUT_PADDING, CELL_RUN_GUTTER, CELL_TOP_MARGIN, CODE_CELL_LEFT_MARGIN, COLLAPSED_INDICATOR_HEIGHT, SCROLLABLE_ELEMENT_PADDING_TOP } from 'vs/workbench/contrib/notebook/browser/constants'; import { CellEditState, CellFocusMode, IActiveNotebookEditor, ICellOutputViewModel, ICellViewModel, ICommonCellInfo, IDisplayOutputLayoutUpdateRequest, IDisplayOutputViewModel, IGenericCellViewModel, IInsetRenderOutput, INotebookCellList, INotebookCellOutputLayoutInfo, INotebookDeltaDecoration, INotebookEditor, INotebookEditorContribution, INotebookEditorContributionDescription, INotebookEditorCreationOptions, INotebookEditorMouseEvent, NotebookEditorOptions, NotebookLayoutInfo, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_RUNNABLE, NOTEBOOK_HAS_MULTIPLE_KERNELS, NOTEBOOK_OUTPUT_FOCUSED } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { NotebookEditorExtensionsRegistry } from 'vs/workbench/contrib/notebook/browser/notebookEditorExtensions'; import { NotebookKernelProviderAssociation, NotebookKernelProviderAssociations, notebookKernelProviderAssociationsSettingId } from 'vs/workbench/contrib/notebook/browser/notebookKernelAssociation'; @@ -902,7 +902,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor } if (!this._webview) { - this._webview = this.instantiationService.createInstance(BackLayerWebView, this, this.getId(), this.textModel!.uri); + this._webview = this.instantiationService.createInstance(BackLayerWebView, this, this.getId(), this.textModel!.uri, { outputNodePadding: CELL_OUTPUT_PADDING, outputNodeLeftPadding: CELL_OUTPUT_PADDING }); this._webview.element.style.width = `calc(100% - ${CODE_CELL_LEFT_MARGIN + (CELL_MARGIN * 2) + CELL_RUN_GUTTER}px)`; this._webview.element.style.margin = `0px 0 0px ${CODE_CELL_LEFT_MARGIN + CELL_RUN_GUTTER}px`; @@ -953,7 +953,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor } private async _createWebview(id: string, resource: URI): Promise { - this._webview = this.instantiationService.createInstance(BackLayerWebView, this, id, resource); + this._webview = this.instantiationService.createInstance(BackLayerWebView, this, id, resource, { outputNodePadding: CELL_OUTPUT_PADDING, outputNodeLeftPadding: CELL_OUTPUT_PADDING }); this._webview.element.style.width = `calc(100% - ${CODE_CELL_LEFT_MARGIN + (CELL_MARGIN * 2) + CELL_RUN_GUTTER}px)`; this._webview.element.style.margin = `0px 0 0px ${CODE_CELL_LEFT_MARGIN + CELL_RUN_GUTTER}px`; // attach the webview container to the DOM tree first diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index e5b7bc40023..bb7cbb456f3 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -10,7 +10,6 @@ import { isWeb } from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; import * as UUID from 'vs/base/common/uuid'; import { IOpenerService, matchesScheme } from 'vs/platform/opener/common/opener'; -import { CELL_OUTPUT_PADDING } from 'vs/workbench/contrib/notebook/browser/constants'; import { ICommonCellInfo, ICommonNotebookEditor, IDisplayOutputLayoutUpdateRequest, IDisplayOutputViewModel, IGenericCellViewModel, IInsetRenderOutput, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellOutputKind, IDisplayOutput, INotebookRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; @@ -237,6 +236,10 @@ export class BackLayerWebView extends Disposable { public notebookEditor: ICommonNotebookEditor, public id: string, public documentUri: URI, + public options: { + outputNodePadding: number, + outputNodeLeftPadding: number + }, @IWebviewService readonly webviewService: IWebviewService, @IOpenerService readonly openerService: IOpenerService, @INotebookService private readonly notebookService: INotebookService, @@ -252,7 +255,7 @@ export class BackLayerWebView extends Disposable { this.element.style.height = '1400px'; this.element.style.position = 'absolute'; } - generateContent(outputNodePadding: number, coreDependencies: string, baseUrl: string) { + generateContent(coreDependencies: string, baseUrl: string) { return html` @@ -261,7 +264,7 @@ export class BackLayerWebView extends Disposable {