Path: blob/main/src/vs/workbench/contrib/notebook/browser/notebookCellLayoutManager.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { DeferredPromise } from '../../../../base/common/async.js';6import { Disposable, IDisposable, toDisposable } from '../../../../base/common/lifecycle.js';7import { ICellViewModel } from './notebookBrowser.js';8import { NotebookEditorWidget } from './notebookEditorWidget.js';9import { INotebookCellList } from './view/notebookRenderingCommon.js';10import * as DOM from '../../../../base/browser/dom.js';11import { INotebookLoggingService } from '../common/notebookLoggingService.js';1213export class NotebookCellLayoutManager extends Disposable {14private _pendingLayouts: WeakMap<ICellViewModel, IDisposable> | null = new WeakMap<ICellViewModel, IDisposable>();15private _layoutDisposables: Set<IDisposable> = new Set<IDisposable>();16private readonly _layoutStack: string[] = [];17private _isDisposed = false;18constructor(19private notebookWidget: NotebookEditorWidget,20private _list: INotebookCellList,21private loggingService: INotebookLoggingService22) {23super();24}2526private checkStackDepth() {27if (this._layoutStack.length > 30) {28const layoutTrace = this._layoutStack.join(' -> ');29throw new Error('NotebookCellLayoutManager: layout stack is too deep: ' + layoutTrace);30}31}3233async layoutNotebookCell(cell: ICellViewModel, height: number): Promise<void> {34const layoutTag = `cell:${cell.handle}, height:${height}`;35this.loggingService.debug('cell layout', layoutTag);36const viewIndex = this._list.getViewIndex(cell);37if (viewIndex === undefined) {38// the cell is hidden39return;40}4142if (this._pendingLayouts?.has(cell)) {43this._pendingLayouts?.get(cell)!.dispose();44}4546const deferred = new DeferredPromise<void>();47const doLayout = () => {48const pendingLayout = this._pendingLayouts?.get(cell);49this._pendingLayouts?.delete(cell);5051this._layoutStack.push(layoutTag);52try {53if (this._isDisposed) {54return;55}5657if (!this.notebookWidget.viewModel?.hasCell(cell)) {58// Cell removed in the meantime?59return;60}6162if (this._list.getViewIndex(cell) === undefined) {63// Cell can be hidden64return;65}6667if (this._list.elementHeight(cell) === height) {68return;69}7071this.checkStackDepth();7273if (!this.notebookWidget.hasEditorFocus()) {74// Do not scroll inactive notebook75// https://github.com/microsoft/vscode/issues/14534076const cellIndex = this.notebookWidget.viewModel?.getCellIndex(cell);77const visibleRanges = this.notebookWidget.visibleRanges;78if (cellIndex !== undefined79&& visibleRanges && visibleRanges.length && visibleRanges[0].start === cellIndex80// cell is partially visible81&& this._list.scrollTop > this.notebookWidget.getAbsoluteTopOfElement(cell)82) {83return this._list.updateElementHeight2(cell, height, Math.min(cellIndex + 1, this.notebookWidget.getLength() - 1));84}85}8687this._list.updateElementHeight2(cell, height);88} finally {89this._layoutStack.pop();90deferred.complete(undefined);91if (pendingLayout) {92pendingLayout.dispose();93this._layoutDisposables.delete(pendingLayout);94}9596}97};9899if (this._list.inRenderingTransaction) {100const layoutDisposable = DOM.scheduleAtNextAnimationFrame(DOM.getWindow(this.notebookWidget.getDomNode()), doLayout);101102const disposable = toDisposable(() => {103layoutDisposable.dispose();104deferred.complete(undefined);105});106this._pendingLayouts?.set(cell, disposable);107this._layoutDisposables.add(disposable);108} else {109doLayout();110}111112return deferred.p;113}114115override dispose() {116super.dispose();117this._isDisposed = true;118this._layoutDisposables.forEach(d => d.dispose());119}120}121122123