Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/notebook/browser/view/cellPart.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import * as DOM from '../../../../../base/browser/dom.js';
7
import { onUnexpectedError } from '../../../../../base/common/errors.js';
8
import { Disposable, DisposableStore, MutableDisposable } from '../../../../../base/common/lifecycle.js';
9
import { ICellViewModel } from '../notebookBrowser.js';
10
import { CellViewModelStateChangeEvent } from '../notebookViewEvents.js';
11
import { ICellExecutionStateChangedEvent } from '../../common/notebookExecutionStateService.js';
12
13
/**
14
* A content part is a non-floating element that is rendered inside a cell.
15
* The rendering of the content part is synchronous to avoid flickering.
16
*/
17
export abstract class CellContentPart extends Disposable {
18
protected currentCell: ICellViewModel | undefined;
19
protected readonly cellDisposables = this._register(new DisposableStore());
20
21
constructor() {
22
super();
23
}
24
25
/**
26
* Prepare model for cell part rendering
27
* No DOM operations recommended within this operation
28
*/
29
prepareRenderCell(element: ICellViewModel): void { }
30
31
/**
32
* Update the DOM for the cell `element`
33
*/
34
renderCell(element: ICellViewModel): void {
35
this.currentCell = element;
36
safeInvokeNoArg(() => this.didRenderCell(element));
37
}
38
39
didRenderCell(element: ICellViewModel): void { }
40
41
/**
42
* Dispose any disposables generated from `didRenderCell`
43
*/
44
unrenderCell(element: ICellViewModel): void {
45
this.currentCell = undefined;
46
this.cellDisposables.clear();
47
}
48
49
/**
50
* Perform DOM read operations to prepare for the list/cell layout update.
51
*/
52
prepareLayout(): void { }
53
54
/**
55
* Update internal DOM (top positions) per cell layout info change
56
* Note that a cell part doesn't need to call `DOM.scheduleNextFrame`,
57
* the list view will ensure that layout call is invoked in the right frame
58
*/
59
updateInternalLayoutNow(element: ICellViewModel): void { }
60
61
/**
62
* Update per cell state change
63
*/
64
updateState(element: ICellViewModel, e: CellViewModelStateChangeEvent): void { }
65
66
/**
67
* Update per execution state change.
68
*/
69
updateForExecutionState(element: ICellViewModel, e: ICellExecutionStateChangedEvent): void { }
70
}
71
72
/**
73
* An overlay part renders on top of other components.
74
* The rendering of the overlay part might be postponed to the next animation frame to avoid forced reflow.
75
*/
76
export abstract class CellOverlayPart extends Disposable {
77
protected currentCell: ICellViewModel | undefined;
78
protected readonly cellDisposables = this._register(new DisposableStore());
79
80
constructor() {
81
super();
82
}
83
84
/**
85
* Prepare model for cell part rendering
86
* No DOM operations recommended within this operation
87
*/
88
prepareRenderCell(element: ICellViewModel): void { }
89
90
/**
91
* Update the DOM for the cell `element`
92
*/
93
renderCell(element: ICellViewModel): void {
94
this.currentCell = element;
95
this.didRenderCell(element);
96
}
97
98
didRenderCell(element: ICellViewModel): void { }
99
100
/**
101
* Dispose any disposables generated from `didRenderCell`
102
*/
103
unrenderCell(element: ICellViewModel): void {
104
this.currentCell = undefined;
105
this.cellDisposables.clear();
106
}
107
108
/**
109
* Update internal DOM (top positions) per cell layout info change
110
* Note that a cell part doesn't need to call `DOM.scheduleNextFrame`,
111
* the list view will ensure that layout call is invoked in the right frame
112
*/
113
updateInternalLayoutNow(element: ICellViewModel): void { }
114
115
/**
116
* Update per cell state change
117
*/
118
updateState(element: ICellViewModel, e: CellViewModelStateChangeEvent): void { }
119
120
/**
121
* Update per execution state change.
122
*/
123
updateForExecutionState(element: ICellViewModel, e: ICellExecutionStateChangedEvent): void { }
124
}
125
126
function safeInvokeNoArg<T>(func: () => T): T | null {
127
try {
128
return func();
129
} catch (e) {
130
onUnexpectedError(e);
131
return null;
132
}
133
}
134
135
export class CellPartsCollection extends Disposable {
136
private readonly _scheduledOverlayRendering = this._register(new MutableDisposable());
137
private readonly _scheduledOverlayUpdateState = this._register(new MutableDisposable());
138
private readonly _scheduledOverlayUpdateExecutionState = this._register(new MutableDisposable());
139
140
constructor(
141
private readonly targetWindow: Window,
142
private readonly contentParts: readonly CellContentPart[],
143
private readonly overlayParts: readonly CellOverlayPart[]
144
) {
145
super();
146
}
147
148
concatContentPart(other: readonly CellContentPart[], targetWindow: Window): CellPartsCollection {
149
return new CellPartsCollection(targetWindow, this.contentParts.concat(other), this.overlayParts);
150
}
151
152
concatOverlayPart(other: readonly CellOverlayPart[], targetWindow: Window): CellPartsCollection {
153
return new CellPartsCollection(targetWindow, this.contentParts, this.overlayParts.concat(other));
154
}
155
156
scheduleRenderCell(element: ICellViewModel): void {
157
// prepare model
158
for (const part of this.contentParts) {
159
safeInvokeNoArg(() => part.prepareRenderCell(element));
160
}
161
162
for (const part of this.overlayParts) {
163
safeInvokeNoArg(() => part.prepareRenderCell(element));
164
}
165
166
// render content parts
167
for (const part of this.contentParts) {
168
safeInvokeNoArg(() => part.renderCell(element));
169
}
170
171
this._scheduledOverlayRendering.value = DOM.modify(this.targetWindow, () => {
172
for (const part of this.overlayParts) {
173
safeInvokeNoArg(() => part.renderCell(element));
174
}
175
});
176
}
177
178
unrenderCell(element: ICellViewModel): void {
179
for (const part of this.contentParts) {
180
safeInvokeNoArg(() => part.unrenderCell(element));
181
}
182
183
this._scheduledOverlayRendering.value = undefined;
184
this._scheduledOverlayUpdateState.value = undefined;
185
this._scheduledOverlayUpdateExecutionState.value = undefined;
186
187
for (const part of this.overlayParts) {
188
safeInvokeNoArg(() => part.unrenderCell(element));
189
}
190
}
191
192
updateInternalLayoutNow(viewCell: ICellViewModel) {
193
for (const part of this.contentParts) {
194
safeInvokeNoArg(() => part.updateInternalLayoutNow(viewCell));
195
}
196
197
for (const part of this.overlayParts) {
198
safeInvokeNoArg(() => part.updateInternalLayoutNow(viewCell));
199
}
200
}
201
202
prepareLayout() {
203
for (const part of this.contentParts) {
204
safeInvokeNoArg(() => part.prepareLayout());
205
}
206
}
207
208
updateState(viewCell: ICellViewModel, e: CellViewModelStateChangeEvent) {
209
for (const part of this.contentParts) {
210
safeInvokeNoArg(() => part.updateState(viewCell, e));
211
}
212
213
this._scheduledOverlayUpdateState.value = DOM.modify(this.targetWindow, () => {
214
for (const part of this.overlayParts) {
215
safeInvokeNoArg(() => part.updateState(viewCell, e));
216
}
217
});
218
}
219
220
updateForExecutionState(viewCell: ICellViewModel, e: ICellExecutionStateChangedEvent) {
221
for (const part of this.contentParts) {
222
safeInvokeNoArg(() => part.updateForExecutionState(viewCell, e));
223
}
224
225
this._scheduledOverlayUpdateExecutionState.value = DOM.modify(this.targetWindow, () => {
226
for (const part of this.overlayParts) {
227
safeInvokeNoArg(() => part.updateForExecutionState(viewCell, e));
228
}
229
});
230
}
231
}
232
233