From f9fb40f63310323cd80e2a06fca36d9df2db9e57 Mon Sep 17 00:00:00 2001 From: rebornix Date: Sun, 6 Nov 2022 21:12:36 -0800 Subject: [PATCH] Separate content and overlay. --- .../docs/viewport-rendering.drawio.svg | 294 +++++++++--------- .../notebook/browser/notebookEditorWidget.ts | 9 +- .../contrib/notebook/browser/view/cellPart.ts | 137 +++++++- .../browser/view/cellParts/cellComments.ts | 4 +- .../browser/view/cellParts/cellContextKeys.ts | 4 +- .../browser/view/cellParts/cellDecorations.ts | 4 +- .../browser/view/cellParts/cellDnd.ts | 4 +- .../view/cellParts/cellEditorOptions.ts | 4 +- .../browser/view/cellParts/cellExecution.ts | 4 +- .../browser/view/cellParts/cellFocus.ts | 4 +- .../view/cellParts/cellFocusIndicator.ts | 4 +- .../browser/view/cellParts/cellOutput.ts | 4 +- .../browser/view/cellParts/cellProgressBar.ts | 4 +- .../browser/view/cellParts/cellStatusPart.ts | 4 +- .../browser/view/cellParts/cellToolbars.ts | 148 ++++++--- .../browser/view/cellParts/codeCell.ts | 18 +- .../view/cellParts/codeCellRunToolbar.ts | 4 +- .../view/cellParts/collapsedCellInput.ts | 4 +- .../view/cellParts/collapsedCellOutput.ts | 4 +- .../browser/view/cellParts/foldedCellHint.ts | 4 +- .../browser/view/cellParts/markupCell.ts | 2 +- .../browser/view/renderers/cellRenderer.ts | 10 +- 22 files changed, 430 insertions(+), 248 deletions(-) diff --git a/src/vs/workbench/contrib/notebook/browser/docs/viewport-rendering.drawio.svg b/src/vs/workbench/contrib/notebook/browser/docs/viewport-rendering.drawio.svg index c10662c48d3..6a51b66c723 100644 --- a/src/vs/workbench/contrib/notebook/browser/docs/viewport-rendering.drawio.svg +++ b/src/vs/workbench/contrib/notebook/browser/docs/viewport-rendering.drawio.svg @@ -1,22 +1,22 @@ - + - - - + + + - +
-
-
+
+
Render Viewport
- + Render Viewport @@ -24,100 +24,100 @@ - +
-
-
+
+
Notebook List View
- + Notebook List View - - - - - + + + + + - +
-
-
+
+
Render Template
- + Render Template - - - - - + + + + + - +
-
-
+
+
Render Element
- + Render Element - + - +
-
-
+
+
Get Dynamic Height
- + Get Dynamic Height - - - - - - + + + + + + - +
-
-
+
+
Create Cell Templates/Parts
- + Create Cell Templates/Parts @@ -125,10 +125,10 @@ - +
-
-
+
+
Toolbar
@@ -142,10 +142,10 @@ - +
-
-
+
+
Editor
@@ -159,10 +159,10 @@ - +
-
-
+
+
Statusbar
@@ -173,64 +173,64 @@ - - - + + + - +
-
-
+
+
Code Cell
- + Code Cell - + - +
-
-
+
+
Render Cell Parts
- + Render Cell Parts - - - - - - - + + + + + + + - +
-
-
+
+
CellPart read DOM
- + CellPart read DOM @@ -238,81 +238,81 @@ - +
-
-
+
+
Update layout info
- + Update layout info - - - - + + + + - -
-
-
+ +
+
+
Toolbar.renderCell
- + Toolbar.renderCell - + - -
-
-
+ +
+
+
Toolbar.renderCell
- + Toolbar.renderCell - + - -
-
-
- Toolbar.renderCell + +
+
+
+ Toolbar.didRenderCell
- - Toolbar.renderCell + + Toolbar.didRenderCell - +
-
-
+
+
Toolbar.renderCell
@@ -326,10 +326,10 @@ - +
-
-
+
+
Toolbar.renderCell
@@ -343,10 +343,10 @@ - +
-
-
+
+
Toolbar.prepareLayout @@ -359,44 +359,44 @@ - - - - - - - + + + + + + + - +
-
-
+
+
Cell Layout Change
- + Cell Layout Change - + - +
-
-
+
+
Cell Part updateInternalLayoutNow
- + Cell Part updateInternalLayoutNow @@ -404,10 +404,10 @@ - +
-
-
+
+
Toolbar.renderCell
@@ -421,10 +421,10 @@ - +
-
-
+
+
Toolbar.renderCell
@@ -438,10 +438,10 @@ - +
-
-
+
+
Toolbar.updateInternalLayoutNow @@ -457,10 +457,10 @@ - +
-
-
+
+
Next Frame
@@ -474,10 +474,10 @@ - +
-
-
+
+
DOM Read @@ -493,10 +493,10 @@ - +
-
-
+
+
DOM Write diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index f54262aa0b9..feacb3e2174 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -89,7 +89,14 @@ const $ = DOM.$; export function getDefaultNotebookCreationOptions(): INotebookEditorCreationOptions { // We inlined the id to avoid loading comment contrib in tests - const skipContributions = ['editor.contrib.review', FloatingClickMenu.ID]; + const skipContributions = [ + 'editor.contrib.review', + FloatingClickMenu.ID, + 'editor.contrib.dirtydiff', + 'editor.contrib.testingOutputPeek', + 'editor.contrib.testingDecorations', + 'store.contrib.stickyScrollController' + ]; const contributions = EditorExtensionsRegistry.getEditorContributions().filter(c => skipContributions.indexOf(c.id) === -1); return { diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellPart.ts b/src/vs/workbench/contrib/notebook/browser/view/cellPart.ts index c61b9864c17..71e583dd9d8 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellPart.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellPart.ts @@ -3,12 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; +import * as DOM from 'vs/base/browser/dom'; +import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; import { ICellViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellViewModelStateChangeEvent } from 'vs/workbench/contrib/notebook/browser/notebookViewEvents'; import { ICellExecutionStateChangedEvent } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService'; -export abstract class CellPart extends Disposable { +export abstract class CellContentPart extends Disposable { protected currentCell: ICellViewModel | undefined; protected cellDisposables = new DisposableStore(); @@ -16,6 +17,12 @@ export abstract class CellPart extends Disposable { super(); } + /** + * Prepare model for cell part rendering + * No DOM operations recommended within this operation + */ + prepareRenderCell(element: ICellViewModel): void { } + /** * Update the DOM for the cell `element` */ @@ -57,49 +64,149 @@ export abstract class CellPart extends Disposable { updateForExecutionState(element: ICellViewModel, e: ICellExecutionStateChangedEvent): void { } } -export class CellPartsCollection { +export abstract class CellOverlayPart extends Disposable { + protected currentCell: ICellViewModel | undefined; + protected cellDisposables = new DisposableStore(); - constructor( - private readonly parts: readonly CellPart[], - ) { } - - concat(other: readonly CellPart[]): CellPartsCollection { - return new CellPartsCollection(this.parts.concat(other)); + constructor() { + super(); } + /** + * Prepare model for cell part rendering + * No DOM operations recommended within this operation + */ + prepareRenderCell(element: ICellViewModel): void { } + + /** + * Update the DOM for the cell `element` + */ renderCell(element: ICellViewModel): void { - for (const part of this.parts) { + this.currentCell = element; + this.didRenderCell(element); + } + + protected didRenderCell(element: ICellViewModel): void { } + + /** + * Dispose any disposables generated from `didRenderCell` + */ + unrenderCell(element: ICellViewModel): void { + this.currentCell = undefined; + this.cellDisposables.clear(); + } + + /** + * Update internal DOM (top positions) per cell layout info change + * Note that a cell part doesn't need to call `DOM.scheduleNextFrame`, + * the list view will ensure that layout call is invoked in the right frame + */ + updateInternalLayoutNow(element: ICellViewModel): void { } + + /** + * Update per cell state change + */ + updateState(element: ICellViewModel, e: CellViewModelStateChangeEvent): void { } + + /** + * Update per execution state change. + */ + updateForExecutionState(element: ICellViewModel, e: ICellExecutionStateChangedEvent): void { } +} + +export class CellPartsCollection { + private _scheduledOverlayRendering: IDisposable | undefined; + private _scheduledOverlayUpdateState: IDisposable | undefined; + private _scheduledOverlayUpdateExecutionState: IDisposable | undefined; + + constructor( + private readonly contentParts: readonly CellContentPart[], + private readonly overlayParts: readonly CellOverlayPart[] + ) { } + + concatContentPart(other: readonly CellContentPart[]): CellPartsCollection { + return new CellPartsCollection(this.contentParts.concat(other), this.overlayParts); + } + + concatOverlayPart(other: readonly CellOverlayPart[]): CellPartsCollection { + return new CellPartsCollection(this.contentParts, this.overlayParts.concat(other)); + } + + scheduleRenderCell(element: ICellViewModel): void { + // prepare model + for (const part of this.contentParts) { + part.prepareRenderCell(element); + } + + for (const part of this.overlayParts) { + part.prepareRenderCell(element); + } + + // render content parts + for (const part of this.contentParts) { part.renderCell(element); } + + // schedule overlay parts rendering + this._scheduledOverlayRendering?.dispose(); + + this._scheduledOverlayRendering = DOM.modify(() => { + for (const part of this.overlayParts) { + part.renderCell(element); + } + }); } unrenderCell(element: ICellViewModel): void { - for (const part of this.parts) { + for (const part of this.contentParts) { + part.unrenderCell(element); + } + + this._scheduledOverlayRendering?.dispose(); + this._scheduledOverlayUpdateState?.dispose(); + this._scheduledOverlayUpdateExecutionState?.dispose(); + + for (const part of this.overlayParts) { part.unrenderCell(element); } } updateInternalLayoutNow(viewCell: ICellViewModel) { - for (const part of this.parts) { + for (const part of this.contentParts) { part.updateInternalLayoutNow(viewCell); } } prepareLayout() { - for (const part of this.parts) { + for (const part of this.contentParts) { part.prepareLayout(); } } updateState(viewCell: ICellViewModel, e: CellViewModelStateChangeEvent) { - for (const part of this.parts) { + for (const part of this.contentParts) { part.updateState(viewCell, e); } + + this._scheduledOverlayUpdateState?.dispose(); + + this._scheduledOverlayUpdateState = DOM.modify(() => { + for (const part of this.overlayParts) { + part.updateState(viewCell, e); + } + }); } updateForExecutionState(viewCell: ICellViewModel, e: ICellExecutionStateChangedEvent) { - for (const part of this.parts) { + for (const part of this.contentParts) { part.updateForExecutionState(viewCell, e); } + + this._scheduledOverlayUpdateExecutionState?.dispose(); + this._scheduledOverlayUpdateExecutionState = DOM.modify(() => { + for (const part of this.overlayParts) { + part.updateForExecutionState(viewCell, e); + } + }); } } diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellComments.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellComments.ts index b4bc5a482a3..b8f33697d19 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellComments.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellComments.ts @@ -14,12 +14,12 @@ import { IThemeService } from 'vs/platform/theme/common/themeService'; import { ICommentService } from 'vs/workbench/contrib/comments/browser/commentService'; import { CommentThreadWidget } from 'vs/workbench/contrib/comments/browser/commentThreadWidget'; import { ICellViewModel, INotebookEditorDelegate } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; -import { CellPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; +import { CellContentPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel'; import { CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange'; -export class CellComments extends CellPart { +export class CellComments extends CellContentPart { private _initialized: boolean = false; private _commentThreadWidget: CommentThreadWidget | null = null; private currentElement: CodeCellViewModel | undefined; diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellContextKeys.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellContextKeys.ts index 364939e3456..7f4c8b9f5b4 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellContextKeys.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellContextKeys.ts @@ -8,14 +8,14 @@ import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/c import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { CellEditState, CellFocusMode, ICellViewModel, INotebookEditorDelegate } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellViewModelStateChangeEvent } from 'vs/workbench/contrib/notebook/browser/notebookViewEvents'; -import { CellPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; +import { CellContentPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel'; import { MarkupCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markupCellViewModel'; import { NotebookCellExecutionState } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { NotebookCellExecutionStateContext, NOTEBOOK_CELL_EDITABLE, NOTEBOOK_CELL_EDITOR_FOCUSED, NOTEBOOK_CELL_EXECUTING, NOTEBOOK_CELL_EXECUTION_STATE, NOTEBOOK_CELL_FOCUSED, NOTEBOOK_CELL_HAS_OUTPUTS, NOTEBOOK_CELL_INPUT_COLLAPSED, NOTEBOOK_CELL_LINE_NUMBERS, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE, NOTEBOOK_CELL_OUTPUT_COLLAPSED, NOTEBOOK_CELL_RESOURCE, NOTEBOOK_CELL_TYPE } from 'vs/workbench/contrib/notebook/common/notebookContextKeys'; import { INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService'; -export class CellContextKeyPart extends CellPart { +export class CellContextKeyPart extends CellContentPart { private cellContextKeyManager: CellContextKeyManager; constructor( diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellDecorations.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellDecorations.ts index 7aac88fa2dc..103b2371698 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellDecorations.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellDecorations.ts @@ -5,9 +5,9 @@ import * as DOM from 'vs/base/browser/dom'; import { ICellViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; -import { CellPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; +import { CellContentPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; -export class CellDecorations extends CellPart { +export class CellDecorations extends CellContentPart { constructor( readonly rootContainer: HTMLElement, readonly decorationContainer: HTMLElement, diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellDnd.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellDnd.ts index a5b951d33c9..007ed9dc801 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellDnd.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellDnd.ts @@ -9,7 +9,7 @@ import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; import * as platform from 'vs/base/common/platform'; import { expandCellRangesWithHiddenCells, ICellViewModel, INotebookEditorDelegate } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellViewModelStateChangeEvent } from 'vs/workbench/contrib/notebook/browser/notebookViewEvents'; -import { CellPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; +import { CellContentPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; import { BaseCellRenderTemplate, INotebookCellList } from 'vs/workbench/contrib/notebook/browser/view/notebookRenderingCommon'; import { cloneNotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import { CellEditType, ICellMoveEdit, SelectionStateType } from 'vs/workbench/contrib/notebook/common/notebookCommon'; @@ -30,7 +30,7 @@ interface CellDragEvent { dragPosRatio: number; } -export class CellDragAndDropPart extends CellPart { +export class CellDragAndDropPart extends CellContentPart { constructor( private readonly container: HTMLElement ) { diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellEditorOptions.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellEditorOptions.ts index f3751c8dbdf..70f65487c66 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellEditorOptions.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellEditorOptions.ts @@ -17,12 +17,12 @@ import { ActiveEditorContext } from 'vs/workbench/common/contextkeys'; import { INotebookCellToolbarActionContext, INotebookCommandContext, NotebookMultiCellAction, NOTEBOOK_ACTIONS_CATEGORY } from 'vs/workbench/contrib/notebook/browser/controller/coreActions'; import { IBaseCellEditorOptions, ICellViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { NOTEBOOK_CELL_LINE_NUMBERS, NOTEBOOK_EDITOR_FOCUSED } from 'vs/workbench/contrib/notebook/common/notebookContextKeys'; -import { CellPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; +import { CellContentPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; import { NotebookCellInternalMetadata, NOTEBOOK_EDITOR_ID } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { NotebookOptions } from 'vs/workbench/contrib/notebook/common/notebookOptions'; import { CellViewModelStateChangeEvent } from 'vs/workbench/contrib/notebook/browser/notebookViewEvents'; -export class CellEditorOptions extends CellPart { +export class CellEditorOptions extends CellContentPart { private _lineNumbers: 'on' | 'off' | 'inherit' = 'inherit'; private readonly _onDidChange = this._register(new Emitter()); readonly onDidChange: Event = this._onDidChange.event; diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellExecution.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellExecution.ts index bfcb770270e..d71a10c6212 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellExecution.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellExecution.ts @@ -8,13 +8,13 @@ import { disposableTimeout } from 'vs/base/common/async'; import { DisposableStore } from 'vs/base/common/lifecycle'; import { ICellViewModel, INotebookEditorDelegate } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellViewModelStateChangeEvent } from 'vs/workbench/contrib/notebook/browser/notebookViewEvents'; -import { CellPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; +import { CellContentPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; import { NotebookCellInternalMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService'; const UPDATE_EXECUTION_ORDER_GRACE_PERIOD = 200; -export class CellExecutionPart extends CellPart { +export class CellExecutionPart extends CellContentPart { private kernelDisposables = this._register(new DisposableStore()); constructor( diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellFocus.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellFocus.ts index 281116d7a00..f7df5d49e59 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellFocus.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellFocus.ts @@ -5,10 +5,10 @@ import * as DOM from 'vs/base/browser/dom'; import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; -import { CellPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; +import { CellContentPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel'; -export class CellFocusPart extends CellPart { +export class CellFocusPart extends CellContentPart { constructor( containerElement: HTMLElement, focusSinkElement: HTMLElement | undefined, diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellFocusIndicator.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellFocusIndicator.ts index 0b27d730a1d..51b7ba06f55 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellFocusIndicator.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellFocusIndicator.ts @@ -6,13 +6,13 @@ import * as DOM from 'vs/base/browser/dom'; import { FastDomNode } from 'vs/base/browser/fastDomNode'; import { CodeCellLayoutInfo, ICellViewModel, INotebookEditorDelegate } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; -import { CellPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; +import { CellContentPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; import { CellTitleToolbarPart } from 'vs/workbench/contrib/notebook/browser/view/cellParts/cellToolbars'; import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel'; import { MarkupCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markupCellViewModel'; import { CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon'; -export class CellFocusIndicator extends CellPart { +export class CellFocusIndicator extends CellContentPart { public codeFocusIndicator: FastDomNode; public outputFocusIndicator: FastDomNode; diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellOutput.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellOutput.ts index 69052c4576f..e2b8ea102ab 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellOutput.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellOutput.ts @@ -24,7 +24,7 @@ import { IExtensionsViewPaneContainer, VIEWLET_ID as EXTENSION_VIEWLET_ID } from import { INotebookCellActionContext } from 'vs/workbench/contrib/notebook/browser/controller/coreActions'; import { ICellOutputViewModel, ICellViewModel, IInsetRenderOutput, INotebookEditorDelegate, JUPYTER_EXTENSION_ID, RenderOutputType } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { mimetypeIcon } from 'vs/workbench/contrib/notebook/browser/notebookIcons'; -import { CellPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; +import { CellContentPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; import { CodeCellRenderTemplate } from 'vs/workbench/contrib/notebook/browser/view/notebookRenderingCommon'; import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel'; import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel'; @@ -427,7 +427,7 @@ class OutputEntryViewHandler { } } -export class CellOutputContainer extends CellPart { +export class CellOutputContainer extends CellContentPart { private _outputEntries: OutputEntryViewHandler[] = []; get renderedOutputEntries() { diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellProgressBar.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellProgressBar.ts index 655bffaa72f..df45ee5073b 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellProgressBar.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellProgressBar.ts @@ -7,11 +7,11 @@ import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar'; import { getProgressBarStyles } from 'vs/platform/theme/browser/defaultStyles'; import { ICellViewModel } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellViewModelStateChangeEvent } from 'vs/workbench/contrib/notebook/browser/notebookViewEvents'; -import { CellPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; +import { CellContentPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; import { NotebookCellExecutionState } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { ICellExecutionStateChangedEvent, INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService'; -export class CellProgressBar extends CellPart { +export class CellProgressBar extends CellContentPart { private readonly _progressBar: ProgressBar; private readonly _collapsedProgressBar: ProgressBar; diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellStatusPart.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellStatusPart.ts index 2234e5d3a15..9a7879ac1fe 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellStatusPart.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellStatusPart.ts @@ -22,7 +22,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IThemeService, ThemeColor } from 'vs/platform/theme/common/themeService'; import { INotebookCellActionContext } from 'vs/workbench/contrib/notebook/browser/controller/coreActions'; import { CellFocusMode, ICellViewModel, INotebookEditorDelegate } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; -import { CellPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; +import { CellContentPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; import { ClickTargetType, IClickTarget } from 'vs/workbench/contrib/notebook/browser/view/cellParts/cellWidgets'; import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel'; import { CellStatusbarAlignment, INotebookCellStatusBarItem } from 'vs/workbench/contrib/notebook/common/notebookCommon'; @@ -30,7 +30,7 @@ import { CellStatusbarAlignment, INotebookCellStatusBarItem } from 'vs/workbench const $ = DOM.$; -export class CellEditorStatusBar extends CellPart { +export class CellEditorStatusBar extends CellContentPart { readonly statusBarContainer: HTMLElement; private readonly leftItemsContainer: HTMLElement; diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellToolbars.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellToolbars.ts index 2ac050ea828..5e3018eec42 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellToolbars.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellToolbars.ts @@ -19,31 +19,37 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { INotebookCellActionContext } from 'vs/workbench/contrib/notebook/browser/controller/coreActions'; import { ICellViewModel, INotebookEditorDelegate } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CodiconActionViewItem } from 'vs/workbench/contrib/notebook/browser/view/cellParts/cellActionView'; -import { CellPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; +import { CellOverlayPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; import { registerStickyScroll } from 'vs/workbench/contrib/notebook/browser/view/cellParts/stickyScroll'; import { WorkbenchToolBar } from 'vs/platform/actions/browser/toolbar'; -export class BetweenCellToolbar extends CellPart { - private _betweenCellToolbar!: ToolBar; +export class BetweenCellToolbar extends CellOverlayPart { + private _betweenCellToolbar: ToolBar | undefined; constructor( private readonly _notebookEditor: INotebookEditorDelegate, _titleToolbarContainer: HTMLElement, private readonly _bottomCellToolbarContainer: HTMLElement, - @IInstantiationService instantiationService: IInstantiationService, - @IContextMenuService contextMenuService: IContextMenuService, - @IContextKeyService contextKeyService: IContextKeyService, - @IMenuService menuService: IMenuService + @IInstantiationService private readonly instantiationService: IInstantiationService, + @IContextMenuService private readonly contextMenuService: IContextMenuService, + @IContextKeyService private readonly contextKeyService: IContextKeyService, + @IMenuService private readonly menuService: IMenuService ) { super(); + } - this._betweenCellToolbar = this._register(new ToolBar(this._bottomCellToolbarContainer, contextMenuService, { + private _initialize(): ToolBar { + if (this._betweenCellToolbar) { + return this._betweenCellToolbar; + } + + const betweenCellToolbar = this._register(new ToolBar(this._bottomCellToolbarContainer, this.contextMenuService, { actionViewItemProvider: action => { if (action instanceof MenuItemAction) { if (this._notebookEditor.notebookOptions.getLayoutConfiguration().insertToolbarAlignment === 'center') { - return instantiationService.createInstance(CodiconActionViewItem, action, undefined); + return this.instantiationService.createInstance(CodiconActionViewItem, action, undefined); } else { - return instantiationService.createInstance(MenuEntryActionViewItem, action, undefined); + return this.instantiationService.createInstance(MenuEntryActionViewItem, action, undefined); } } @@ -51,10 +57,11 @@ export class BetweenCellToolbar extends CellPart { } })); - const menu = this._register(menuService.createMenu(this._notebookEditor.creationOptions.menuIds.cellInsertToolbar, contextKeyService)); + this._betweenCellToolbar = betweenCellToolbar; + const menu = this._register(this.menuService.createMenu(this._notebookEditor.creationOptions.menuIds.cellInsertToolbar, this.contextKeyService)); const updateActions = () => { const actions = getCellToolbarActions(menu); - this._betweenCellToolbar.setActions(actions.primary, actions.secondary); + betweenCellToolbar.setActions(actions.primary, actions.secondary); }; this._register(menu.onDidChange(() => updateActions())); @@ -63,15 +70,15 @@ export class BetweenCellToolbar extends CellPart { updateActions(); } })); - updateActions(); - } - updateContext(context: INotebookCellActionContext) { - this._betweenCellToolbar.context = context; + updateActions(); + + return betweenCellToolbar; } override didRenderCell(element: ICellViewModel): void { - this._betweenCellToolbar.context = { + const betweenCellToolbar = this._initialize(); + betweenCellToolbar.context = { ui: true, cell: element, notebookEditor: this._notebookEditor, @@ -90,53 +97,110 @@ export interface ICssClassDelegate { toggle: (className: string, force?: boolean) => void; } -export class CellTitleToolbarPart extends CellPart { - private _toolbar: ToolBar; - private _titleMenu: IMenu; - private _deleteToolbar: ToolBar; - private _deleteMenu: IMenu; +interface CellTitleToolbarModel { + titleMenu: IMenu; + actions: { primary: IAction[]; secondary: IAction[] }; + deleteMenu: IMenu; + deleteActions: { primary: IAction[]; secondary: IAction[] }; +} + +interface CellTitleToolbarView { + toolbar: ToolBar; + deleteToolbar: ToolBar; +} + +export class CellTitleToolbarPart extends CellOverlayPart { + private _model: CellTitleToolbarModel | undefined; + private _view: CellTitleToolbarView | undefined; private readonly _onDidUpdateActions: Emitter = this._register(new Emitter()); readonly onDidUpdateActions: Event = this._onDidUpdateActions.event; get hasActions(): boolean { - return this._toolbar.getItemsLength() + this._deleteToolbar.getItemsLength() > 0; + if (!this._model) { + return false; + } + + return this._model.actions.primary.length + + this._model.actions.secondary.length + + this._model.deleteActions.primary.length + + this._model.deleteActions.secondary.length + > 0; } constructor( private readonly toolbarContainer: HTMLElement, private readonly _rootClassDelegate: ICssClassDelegate, - toolbarId: MenuId, - deleteToolbarId: MenuId, + private readonly toolbarId: MenuId, + private readonly deleteToolbarId: MenuId, private readonly _notebookEditor: INotebookEditorDelegate, - @IContextKeyService contextKeyService: IContextKeyService, - @IMenuService menuService: IMenuService, - @IInstantiationService instantiationService: IInstantiationService, + @IContextKeyService private readonly contextKeyService: IContextKeyService, + @IMenuService private readonly menuService: IMenuService, + @IInstantiationService private readonly instantiationService: IInstantiationService, ) { super(); + } - this._toolbar = instantiationService.createInstance(WorkbenchToolBar, toolbarContainer, { + private _initializeModel(): CellTitleToolbarModel { + if (this._model) { + return this._model; + } + + const titleMenu = this._register(this.menuService.createMenu(this.toolbarId, this.contextKeyService)); + const deleteMenu = this._register(this.menuService.createMenu(this.deleteToolbarId, this.contextKeyService)); + const actions = getCellToolbarActions(titleMenu); + const deleteActions = !this._notebookEditor.creationOptions.isReadOnly ? getCellToolbarActions(deleteMenu) : { + primary: [], + secondary: [] + }; + + this._model = { + titleMenu, + actions, + deleteMenu, + deleteActions + }; + + return this._model; + } + + private _initialize(model: CellTitleToolbarModel): CellTitleToolbarView { + if (this._view) { + return this._view; + } + + const toolbar = this.instantiationService.createInstance(WorkbenchToolBar, this.toolbarContainer, { actionViewItemProvider: action => { - return createActionViewItem(instantiationService, action); + return createActionViewItem(this.instantiationService, action); }, renderDropdownAsChildElement: true }); - this._titleMenu = this._register(menuService.createMenu(toolbarId, contextKeyService)); - this._deleteToolbar = this._register(instantiationService.invokeFunction(accessor => createDeleteToolbar(accessor, toolbarContainer, 'cell-delete-toolbar'))); - this._deleteMenu = this._register(menuService.createMenu(deleteToolbarId, contextKeyService)); - if (!this._notebookEditor.creationOptions.isReadOnly) { - const deleteActions = getCellToolbarActions(this._deleteMenu); - this._deleteToolbar.setActions(deleteActions.primary, deleteActions.secondary); + const deleteToolbar = this._register(this.instantiationService.invokeFunction(accessor => createDeleteToolbar(accessor, this.toolbarContainer, 'cell-delete-toolbar'))); + if (model.deleteActions.primary.length !== 0 || model.deleteActions.secondary.length !== 0) { + deleteToolbar.setActions(model.deleteActions.primary, model.deleteActions.secondary); } - this.setupChangeListeners(this._toolbar, this._titleMenu); - this.setupChangeListeners(this._deleteToolbar, this._deleteMenu); + this.setupChangeListeners(toolbar, model.titleMenu); + this.setupChangeListeners(deleteToolbar, model.deleteMenu); + + this._view = { + toolbar, + deleteToolbar + }; + + return this._view; + } + + override prepareRenderCell(element: ICellViewModel): void { + this._initializeModel(); } override didRenderCell(element: ICellViewModel): void { + const model = this._initializeModel(); + const view = this._initialize(model); this.cellDisposables.add(registerStickyScroll(this._notebookEditor, element, this.toolbarContainer, { extraOffset: 4, min: -14 })); - this.updateContext({ + this.updateContext(view, { ui: true, cell: element, notebookEditor: this._notebookEditor, @@ -144,9 +208,9 @@ export class CellTitleToolbarPart extends CellPart { }); } - private updateContext(toolbarContext: INotebookCellActionContext) { - this._toolbar.context = toolbarContext; - this._deleteToolbar.context = toolbarContext; + private updateContext(view: CellTitleToolbarView, toolbarContext: INotebookCellActionContext) { + view.toolbar.context = toolbarContext; + view.deleteToolbar.context = toolbarContext; } private setupChangeListeners(toolbar: ToolBar, menu: IMenu): void { diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/codeCell.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/codeCell.ts index bc47297e810..c8f786c707e 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/codeCell.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/codeCell.ts @@ -55,7 +55,7 @@ export class CodeCell extends Disposable { const cellEditorOptions = this._register(new CellEditorOptions(this.notebookEditor.getBaseCellEditorOptions(viewCell.language), this.notebookEditor.notebookOptions, this.configurationService)); this._outputContainerRenderer = this.instantiationService.createInstance(CellOutputContainer, notebookEditor, viewCell, templateData, { limit: 500 }); - this.cellParts = templateData.cellParts.concat([cellEditorOptions, this._outputContainerRenderer]); + this.cellParts = templateData.cellParts.concatContentPart([cellEditorOptions, this._outputContainerRenderer]); const editorHeight = this.calculateInitEditorHeight(); this.initializeEditor(editorHeight); @@ -100,7 +100,7 @@ export class CodeCell extends Disposable { } })); - this.cellParts.renderCell(this.viewCell); + this.cellParts.scheduleRenderCell(this.viewCell); this._register(toDisposable(() => { this.cellParts.unrenderCell(this.viewCell); @@ -468,12 +468,14 @@ export class CodeCell extends Disposable { const viewLayout = this.templateData.editor.getLayoutInfo(); this.viewCell.editorHeight = newHeight; this.relayoutCell(); - this.layoutEditor( - { - width: viewLayout.width, - height: newHeight - } - ); + DOM.scheduleAtNextAnimationFrame(() => { + this.layoutEditor( + { + width: viewLayout.width, + height: newHeight + } + ); + }); } relayoutCell() { diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/codeCellRunToolbar.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/codeCellRunToolbar.ts index ab30afc1519..176621ea0c0 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/codeCellRunToolbar.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/codeCellRunToolbar.ts @@ -19,11 +19,11 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { INotebookCellActionContext } from 'vs/workbench/contrib/notebook/browser/controller/coreActions'; import { ICellViewModel, INotebookEditorDelegate } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; -import { CellPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; +import { CellContentPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; import { registerStickyScroll } from 'vs/workbench/contrib/notebook/browser/view/cellParts/stickyScroll'; import { NOTEBOOK_CELL_EXECUTION_STATE, NOTEBOOK_CELL_LIST_FOCUSED, NOTEBOOK_CELL_TYPE, NOTEBOOK_EDITOR_FOCUSED } from 'vs/workbench/contrib/notebook/common/notebookContextKeys'; -export class RunToolbar extends CellPart { +export class RunToolbar extends CellContentPart { private toolbar!: ToolBar; private primaryMenu: IMenu; diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/collapsedCellInput.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/collapsedCellInput.ts index 4d29d44bc05..ceee7ec9ff9 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/collapsedCellInput.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/collapsedCellInput.ts @@ -5,9 +5,9 @@ import * as DOM from 'vs/base/browser/dom'; import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; -import { CellPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; +import { CellContentPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; -export class CollapsedCellInput extends CellPart { +export class CollapsedCellInput extends CellContentPart { constructor( private readonly notebookEditor: INotebookEditor, cellInputCollapsedContainer: HTMLElement, diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/collapsedCellOutput.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/collapsedCellOutput.ts index 560a6f009a1..96cda1a0fcb 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/collapsedCellOutput.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/collapsedCellOutput.ts @@ -8,11 +8,11 @@ import { Codicon, CSSIcon } from 'vs/base/common/codicons'; import { localize } from 'vs/nls'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { EXPAND_CELL_OUTPUT_COMMAND_ID, INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; -import { CellPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; +import { CellContentPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; const $ = DOM.$; -export class CollapsedCellOutput extends CellPart { +export class CollapsedCellOutput extends CellContentPart { constructor( private readonly notebookEditor: INotebookEditor, cellOutputCollapseContainer: HTMLElement, diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/foldedCellHint.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/foldedCellHint.ts index 44d8f209cbe..84358d83847 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/foldedCellHint.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/foldedCellHint.ts @@ -8,10 +8,10 @@ import { Codicon, CSSIcon } from 'vs/base/common/codicons'; import { localize } from 'vs/nls'; import { FoldingController } from 'vs/workbench/contrib/notebook/browser/controller/foldingController'; import { CellEditState, CellFoldingState, INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; -import { CellPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; +import { CellContentPart } from 'vs/workbench/contrib/notebook/browser/view/cellPart'; import { MarkupCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markupCellViewModel'; -export class FoldedCellHint extends CellPart { +export class FoldedCellHint extends CellContentPart { constructor( private readonly _notebookEditor: INotebookEditor, diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/markupCell.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/markupCell.ts index 8dbe08da1df..368f20a9320 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/markupCell.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/markupCell.ts @@ -69,7 +69,7 @@ export class MarkupCell extends Disposable { this.registerListeners(); // update for init state - this.templateData.cellParts.renderCell(this.viewCell); + this.templateData.cellParts.scheduleRenderCell(this.viewCell); this._register(toDisposable(() => { this.templateData.cellParts.unrenderCell(this.viewCell); 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 7832f49b365..921e5795d2f 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts @@ -166,8 +166,6 @@ export class MarkupCellRenderer extends AbstractCellRenderer implements IListRen const focusIndicatorBottom = new FastDomNode(DOM.append(container, $('.cell-focus-indicator.cell-focus-indicator-bottom'))); const cellParts = new CellPartsCollection([ - titleToolbar, - templateDisposables.add(scopedInstaService.createInstance(BetweenCellToolbar, this.notebookEditor, titleToolbarContainer, bottomCellContainer)), templateDisposables.add(scopedInstaService.createInstance(CellEditorStatusBar, this.notebookEditor, container, editorPart, undefined)), templateDisposables.add(new CellFocusIndicator(this.notebookEditor, titleToolbar, focusIndicatorTop, focusIndicatorLeft, focusIndicatorRight, focusIndicatorBottom)), templateDisposables.add(new FoldedCellHint(this.notebookEditor, DOM.append(container, $('.notebook-folded-hint')))), @@ -177,6 +175,9 @@ export class MarkupCellRenderer extends AbstractCellRenderer implements IListRen templateDisposables.add(new CellFocusPart(container, undefined, this.notebookEditor)), templateDisposables.add(new CellDragAndDropPart(container)), templateDisposables.add(scopedInstaService.createInstance(CellContextKeyPart, this.notebookEditor)), + ], [ + titleToolbar, + templateDisposables.add(scopedInstaService.createInstance(BetweenCellToolbar, this.notebookEditor, titleToolbarContainer, bottomCellContainer)) ]); const templateData: MarkdownCellRenderTemplate = { @@ -307,8 +308,6 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende const focusIndicatorPart = templateDisposables.add(new CellFocusIndicator(this.notebookEditor, titleToolbar, focusIndicatorTop, focusIndicatorLeft, focusIndicatorRight, focusIndicatorBottom)); const cellParts = new CellPartsCollection([ focusIndicatorPart, - titleToolbar, - templateDisposables.add(scopedInstaService.createInstance(BetweenCellToolbar, this.notebookEditor, titleToolbarContainer, bottomCellToolbarContainer)), templateDisposables.add(scopedInstaService.createInstance(CellEditorStatusBar, this.notebookEditor, container, editorPart, editor)), templateDisposables.add(scopedInstaService.createInstance(CellProgressBar, editorPart, cellInputCollapsedContainer)), templateDisposables.add(scopedInstaService.createInstance(RunToolbar, this.notebookEditor, contextKeyService, container, runButtonContainer)), @@ -320,6 +319,9 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende templateDisposables.add(new CellFocusPart(container, focusSinkElement, this.notebookEditor)), templateDisposables.add(new CellDragAndDropPart(container)), templateDisposables.add(scopedInstaService.createInstance(CellContextKeyPart, this.notebookEditor)), + ], [ + titleToolbar, + templateDisposables.add(scopedInstaService.createInstance(BetweenCellToolbar, this.notebookEditor, titleToolbarContainer, bottomCellToolbarContainer)) ]); const templateData: CodeCellRenderTemplate = {