Path: blob/main/src/vs/workbench/contrib/notebook/browser/notebookCellLayoutManager.ts
5238 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)) {43const oldPendingLayout = this._pendingLayouts.get(cell)!;44oldPendingLayout.dispose();45this._layoutDisposables.delete(oldPendingLayout);46}4748const deferred = new DeferredPromise<void>();49const doLayout = () => {50const pendingLayout = this._pendingLayouts?.get(cell);51this._pendingLayouts?.delete(cell);5253this._layoutStack.push(layoutTag);54try {55if (this._isDisposed) {56return;57}5859if (!this.notebookWidget.viewModel?.hasCell(cell)) {60// Cell removed in the meantime?61return;62}6364if (this._list.getViewIndex(cell) === undefined) {65// Cell can be hidden66return;67}6869if (this._list.elementHeight(cell) === height) {70return;71}7273this.checkStackDepth();7475if (!this.notebookWidget.hasEditorFocus()) {76// Do not scroll inactive notebook77// https://github.com/microsoft/vscode/issues/14534078const cellIndex = this.notebookWidget.viewModel?.getCellIndex(cell);79const visibleRanges = this.notebookWidget.visibleRanges;80if (cellIndex !== undefined81&& visibleRanges && visibleRanges.length && visibleRanges[0].start === cellIndex82// cell is partially visible83&& this._list.scrollTop > this.notebookWidget.getAbsoluteTopOfElement(cell)84) {85return this._list.updateElementHeight2(cell, height, Math.min(cellIndex + 1, this.notebookWidget.getLength() - 1));86}87}8889this._list.updateElementHeight2(cell, height);90} finally {91this._layoutStack.pop();92deferred.complete(undefined);93if (pendingLayout) {94pendingLayout.dispose();95this._layoutDisposables.delete(pendingLayout);96}9798}99};100101if (this._list.inRenderingTransaction) {102const layoutDisposable = DOM.scheduleAtNextAnimationFrame(DOM.getWindow(this.notebookWidget.getDomNode()), doLayout);103104const disposable = toDisposable(() => {105layoutDisposable.dispose();106deferred.complete(undefined);107});108this._pendingLayouts?.set(cell, disposable);109this._layoutDisposables.add(disposable);110} else {111doLayout();112}113114return deferred.p;115}116117override dispose() {118super.dispose();119this._isDisposed = true;120this._layoutDisposables.forEach(d => d.dispose());121}122}123124125