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
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 { 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
this._pendingLayouts?.get(cell)!.dispose();
45
}
46
47
const deferred = new DeferredPromise<void>();
48
const doLayout = () => {
49
const pendingLayout = this._pendingLayouts?.get(cell);
50
this._pendingLayouts?.delete(cell);
51
52
this._layoutStack.push(layoutTag);
53
try {
54
if (this._isDisposed) {
55
return;
56
}
57
58
if (!this.notebookWidget.viewModel?.hasCell(cell)) {
59
// Cell removed in the meantime?
60
return;
61
}
62
63
if (this._list.getViewIndex(cell) === undefined) {
64
// Cell can be hidden
65
return;
66
}
67
68
if (this._list.elementHeight(cell) === height) {
69
return;
70
}
71
72
this.checkStackDepth();
73
74
if (!this.notebookWidget.hasEditorFocus()) {
75
// Do not scroll inactive notebook
76
// https://github.com/microsoft/vscode/issues/145340
77
const cellIndex = this.notebookWidget.viewModel?.getCellIndex(cell);
78
const visibleRanges = this.notebookWidget.visibleRanges;
79
if (cellIndex !== undefined
80
&& visibleRanges && visibleRanges.length && visibleRanges[0].start === cellIndex
81
// cell is partially visible
82
&& this._list.scrollTop > this.notebookWidget.getAbsoluteTopOfElement(cell)
83
) {
84
return this._list.updateElementHeight2(cell, height, Math.min(cellIndex + 1, this.notebookWidget.getLength() - 1));
85
}
86
}
87
88
this._list.updateElementHeight2(cell, height);
89
} finally {
90
this._layoutStack.pop();
91
deferred.complete(undefined);
92
if (pendingLayout) {
93
pendingLayout.dispose();
94
this._layoutDisposables.delete(pendingLayout);
95
}
96
97
}
98
};
99
100
if (this._list.inRenderingTransaction) {
101
const layoutDisposable = DOM.scheduleAtNextAnimationFrame(DOM.getWindow(this.notebookWidget.getDomNode()), doLayout);
102
103
const disposable = toDisposable(() => {
104
layoutDisposable.dispose();
105
deferred.complete(undefined);
106
});
107
this._pendingLayouts?.set(cell, disposable);
108
this._layoutDisposables.add(disposable);
109
} else {
110
doLayout();
111
}
112
113
return deferred.p;
114
}
115
116
override dispose() {
117
super.dispose();
118
this._isDisposed = true;
119
this._layoutDisposables.forEach(d => d.dispose());
120
}
121
}
122
123