Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/notebook/browser/notebookCellLayoutManager.ts
5238 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 { DeferredPromise } from '../../../../base/common/async.js';
7
import { Disposable, IDisposable, toDisposable } from '../../../../base/common/lifecycle.js';
8
import { ICellViewModel } from './notebookBrowser.js';
9
import { NotebookEditorWidget } from './notebookEditorWidget.js';
10
import { INotebookCellList } from './view/notebookRenderingCommon.js';
11
import * as DOM from '../../../../base/browser/dom.js';
12
import { INotebookLoggingService } from '../common/notebookLoggingService.js';
13
14
export class NotebookCellLayoutManager extends Disposable {
15
private _pendingLayouts: WeakMap<ICellViewModel, IDisposable> | null = new WeakMap<ICellViewModel, IDisposable>();
16
private _layoutDisposables: Set<IDisposable> = new Set<IDisposable>();
17
private readonly _layoutStack: string[] = [];
18
private _isDisposed = false;
19
constructor(
20
private notebookWidget: NotebookEditorWidget,
21
private _list: INotebookCellList,
22
private loggingService: INotebookLoggingService
23
) {
24
super();
25
}
26
27
private checkStackDepth() {
28
if (this._layoutStack.length > 30) {
29
const layoutTrace = this._layoutStack.join(' -> ');
30
throw new Error('NotebookCellLayoutManager: layout stack is too deep: ' + layoutTrace);
31
}
32
}
33
34
async layoutNotebookCell(cell: ICellViewModel, height: number): Promise<void> {
35
const layoutTag = `cell:${cell.handle}, height:${height}`;
36
this.loggingService.debug('cell layout', layoutTag);
37
const viewIndex = this._list.getViewIndex(cell);
38
if (viewIndex === undefined) {
39
// the cell is hidden
40
return;
41
}
42
43
if (this._pendingLayouts?.has(cell)) {
44
const oldPendingLayout = this._pendingLayouts.get(cell)!;
45
oldPendingLayout.dispose();
46
this._layoutDisposables.delete(oldPendingLayout);
47
}
48
49
const deferred = new DeferredPromise<void>();
50
const doLayout = () => {
51
const pendingLayout = this._pendingLayouts?.get(cell);
52
this._pendingLayouts?.delete(cell);
53
54
this._layoutStack.push(layoutTag);
55
try {
56
if (this._isDisposed) {
57
return;
58
}
59
60
if (!this.notebookWidget.viewModel?.hasCell(cell)) {
61
// Cell removed in the meantime?
62
return;
63
}
64
65
if (this._list.getViewIndex(cell) === undefined) {
66
// Cell can be hidden
67
return;
68
}
69
70
if (this._list.elementHeight(cell) === height) {
71
return;
72
}
73
74
this.checkStackDepth();
75
76
if (!this.notebookWidget.hasEditorFocus()) {
77
// Do not scroll inactive notebook
78
// https://github.com/microsoft/vscode/issues/145340
79
const cellIndex = this.notebookWidget.viewModel?.getCellIndex(cell);
80
const visibleRanges = this.notebookWidget.visibleRanges;
81
if (cellIndex !== undefined
82
&& visibleRanges && visibleRanges.length && visibleRanges[0].start === cellIndex
83
// cell is partially visible
84
&& this._list.scrollTop > this.notebookWidget.getAbsoluteTopOfElement(cell)
85
) {
86
return this._list.updateElementHeight2(cell, height, Math.min(cellIndex + 1, this.notebookWidget.getLength() - 1));
87
}
88
}
89
90
this._list.updateElementHeight2(cell, height);
91
} finally {
92
this._layoutStack.pop();
93
deferred.complete(undefined);
94
if (pendingLayout) {
95
pendingLayout.dispose();
96
this._layoutDisposables.delete(pendingLayout);
97
}
98
99
}
100
};
101
102
if (this._list.inRenderingTransaction) {
103
const layoutDisposable = DOM.scheduleAtNextAnimationFrame(DOM.getWindow(this.notebookWidget.getDomNode()), doLayout);
104
105
const disposable = toDisposable(() => {
106
layoutDisposable.dispose();
107
deferred.complete(undefined);
108
});
109
this._pendingLayouts?.set(cell, disposable);
110
this._layoutDisposables.add(disposable);
111
} else {
112
doLayout();
113
}
114
115
return deferred.p;
116
}
117
118
override dispose() {
119
super.dispose();
120
this._isDisposed = true;
121
this._layoutDisposables.forEach(d => d.dispose());
122
}
123
}
124
125