Path: blob/main/src/vs/workbench/contrib/notebook/browser/viewModel/markupCellViewModel.ts
5240 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 { Emitter, Event } from '../../../../../base/common/event.js';6import * as UUID from '../../../../../base/common/uuid.js';7import * as editorCommon from '../../../../../editor/common/editorCommon.js';8import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js';9import { CellEditState, CellFindMatch, CellFoldingState, CellLayoutContext, CellLayoutState, EditorFoldingStateDelegate, ICellOutputViewModel, ICellViewModel, MarkupCellLayoutChangeEvent, MarkupCellLayoutInfo } from '../notebookBrowser.js';10import { BaseCellViewModel } from './baseCellViewModel.js';11import { NotebookCellTextModel } from '../../common/model/notebookCellTextModel.js';12import { CellKind, INotebookFindOptions } from '../../common/notebookCommon.js';13import { ITextModelService } from '../../../../../editor/common/services/resolverService.js';14import { ViewContext } from './viewContext.js';15import { IUndoRedoService } from '../../../../../platform/undoRedo/common/undoRedo.js';16import { NotebookOptionsChangeEvent } from '../notebookOptions.js';17import { ICodeEditorService } from '../../../../../editor/browser/services/codeEditorService.js';18import { NotebookCellStateChangedEvent, NotebookLayoutInfo } from '../notebookViewEvents.js';19import { IInlineChatSessionService } from '../../../inlineChat/browser/inlineChatSessionService.js';2021export class MarkupCellViewModel extends BaseCellViewModel implements ICellViewModel {2223readonly cellKind = CellKind.Markup;2425private _layoutInfo: MarkupCellLayoutInfo;2627private _renderedHtml?: string;2829public get renderedHtml(): string | undefined { return this._renderedHtml; }30public set renderedHtml(value: string | undefined) {31if (this._renderedHtml !== value) {32this._renderedHtml = value;33this._onDidChangeState.fire({ contentChanged: true });34}35}3637get layoutInfo() {38return this._layoutInfo;39}4041private _previewHeight = 0;4243set renderedMarkdownHeight(newHeight: number) {44this._previewHeight = newHeight;45this._updateTotalHeight(this._computeTotalHeight());46}4748private _chatHeight = 0;4950set chatHeight(newHeight: number) {51this._chatHeight = newHeight;52this._updateTotalHeight(this._computeTotalHeight());53}5455get chatHeight() {56return this._chatHeight;57}5859private _editorHeight = 0;60private _statusBarHeight = 0;61set editorHeight(newHeight: number) {62this._editorHeight = newHeight;63this._statusBarHeight = this.viewContext.notebookOptions.computeStatusBarHeight();64this._updateTotalHeight(this._computeTotalHeight());65}6667get editorHeight() {68throw new Error('MarkdownCellViewModel.editorHeight is write only');69}7071protected readonly _onDidChangeLayout = this._register(new Emitter<MarkupCellLayoutChangeEvent>());72readonly onDidChangeLayout = this._onDidChangeLayout.event;7374get foldingState() {75return this.foldingDelegate.getFoldingState(this.foldingDelegate.getCellIndex(this));76}7778private _hoveringOutput: boolean = false;79public get outputIsHovered(): boolean {80return this._hoveringOutput;81}8283public set outputIsHovered(v: boolean) {84this._hoveringOutput = v;85}8687private _focusOnOutput: boolean = false;88public get outputIsFocused(): boolean {89return this._focusOnOutput;90}9192public set outputIsFocused(v: boolean) {93this._focusOnOutput = v;94}9596public get inputInOutputIsFocused(): boolean {97return false;98}99100public set inputInOutputIsFocused(_: boolean) {101//102}103104private _hoveringCell = false;105public get cellIsHovered(): boolean {106return this._hoveringCell;107}108109public set cellIsHovered(v: boolean) {110this._hoveringCell = v;111this._onDidChangeState.fire({ cellIsHoveredChanged: true });112}113114constructor(115viewType: string,116model: NotebookCellTextModel,117initialNotebookLayoutInfo: NotebookLayoutInfo | null,118readonly foldingDelegate: EditorFoldingStateDelegate,119readonly viewContext: ViewContext,120@IConfigurationService configurationService: IConfigurationService,121@ITextModelService textModelService: ITextModelService,122@IUndoRedoService undoRedoService: IUndoRedoService,123@ICodeEditorService codeEditorService: ICodeEditorService,124@IInlineChatSessionService inlineChatSessionService: IInlineChatSessionService125) {126super(viewType, model, UUID.generateUuid(), viewContext, configurationService, textModelService, undoRedoService, codeEditorService, inlineChatSessionService);127128const { bottomToolbarGap } = this.viewContext.notebookOptions.computeBottomToolbarDimensions(this.viewType);129const layoutConfiguration = this.viewContext.notebookOptions.getLayoutConfiguration();130this._layoutInfo = {131chatHeight: 0,132editorHeight: 0,133previewHeight: 0,134fontInfo: initialNotebookLayoutInfo?.fontInfo || null,135editorWidth: initialNotebookLayoutInfo?.width136? this.viewContext.notebookOptions.computeMarkdownCellEditorWidth(initialNotebookLayoutInfo.width)137: 0,138commentOffset: 0,139commentHeight: 0,140bottomToolbarOffset: bottomToolbarGap,141totalHeight: 100,142layoutState: CellLayoutState.Uninitialized,143foldHintHeight: 0,144statusBarHeight: 0,145outlineWidth: 1,146bottomMargin: layoutConfiguration.markdownCellBottomMargin,147topMargin: layoutConfiguration.markdownCellTopMargin,148};149150this._register(this.onDidChangeState(e => {151this.viewContext.eventDispatcher.emit([new NotebookCellStateChangedEvent(e, this.model)]);152153if (e.foldingStateChanged) {154this._updateTotalHeight(this._computeTotalHeight(), CellLayoutContext.Fold);155}156}));157}158159private _computeTotalHeight(): number {160const layoutConfiguration = this.viewContext.notebookOptions.getLayoutConfiguration();161const { bottomToolbarGap } = this.viewContext.notebookOptions.computeBottomToolbarDimensions(this.viewType);162const foldHintHeight = this._computeFoldHintHeight();163164if (this.getEditState() === CellEditState.Editing) {165return this._editorHeight166+ layoutConfiguration.markdownCellTopMargin167+ layoutConfiguration.markdownCellBottomMargin168+ bottomToolbarGap169+ this._statusBarHeight170+ this._commentHeight;171} else {172// @rebornix173// On file open, the previewHeight + bottomToolbarGap for a cell out of viewport can be 0174// When it's 0, the list view will never try to render it anymore even if we scroll the cell into view.175// Thus we make sure it's greater than 0176return Math.max(1, this._previewHeight + bottomToolbarGap + foldHintHeight + this._commentHeight);177}178}179180private _computeFoldHintHeight(): number {181return (this.getEditState() === CellEditState.Editing || this.foldingState !== CellFoldingState.Collapsed) ?1820 : this.viewContext.notebookOptions.getLayoutConfiguration().markdownFoldHintHeight;183}184185override updateOptions(e: NotebookOptionsChangeEvent) {186super.updateOptions(e);187if (e.cellStatusBarVisibility || e.insertToolbarPosition || e.cellToolbarLocation) {188this._updateTotalHeight(this._computeTotalHeight());189}190}191192/**193* we put outputs stuff here to make compiler happy194*/195outputsViewModels: ICellOutputViewModel[] = [];196getOutputOffset(index: number): number {197// throw new Error('Method not implemented.');198return -1;199}200updateOutputHeight(index: number, height: number): void {201// throw new Error('Method not implemented.');202}203204triggerFoldingStateChange() {205this._onDidChangeState.fire({ foldingStateChanged: true });206}207208private _updateTotalHeight(newHeight: number, context?: CellLayoutContext) {209if (newHeight !== this.layoutInfo.totalHeight) {210this.layoutChange({ totalHeight: newHeight, context });211}212}213214layoutChange(state: MarkupCellLayoutChangeEvent) {215let totalHeight: number;216let foldHintHeight: number;217if (!this.isInputCollapsed) {218totalHeight = state.totalHeight === undefined ?219(this._layoutInfo.layoutState ===220CellLayoutState.Uninitialized ?221100 :222this._layoutInfo.totalHeight) :223state.totalHeight;224// recompute225foldHintHeight = this._computeFoldHintHeight();226} else {227totalHeight =228this.viewContext.notebookOptions229.computeCollapsedMarkdownCellHeight(this.viewType);230state.totalHeight = totalHeight;231232foldHintHeight = 0;233}234let commentOffset: number;235const notebookLayoutConfiguration = this.viewContext.notebookOptions.getLayoutConfiguration();236if (this.getEditState() === CellEditState.Editing) {237commentOffset = notebookLayoutConfiguration.editorToolbarHeight238+ notebookLayoutConfiguration.cellTopMargin // CELL_TOP_MARGIN239+ this._chatHeight240+ this._editorHeight241+ this._statusBarHeight;242} else {243commentOffset = this._previewHeight;244}245246this._layoutInfo = {247fontInfo: state.font || this._layoutInfo.fontInfo,248editorWidth: state.outerWidth !== undefined ?249this.viewContext.notebookOptions250.computeMarkdownCellEditorWidth(state.outerWidth) :251this._layoutInfo.editorWidth,252chatHeight: this._chatHeight,253editorHeight: this._editorHeight,254statusBarHeight: this._statusBarHeight,255previewHeight: this._previewHeight,256bottomToolbarOffset: this.viewContext.notebookOptions257.computeBottomToolbarOffset(258totalHeight, this.viewType),259totalHeight,260layoutState: CellLayoutState.Measured,261foldHintHeight,262commentOffset,263commentHeight: state.commentHeight ?264this._commentHeight :265this._layoutInfo.commentHeight,266outlineWidth: 1,267bottomMargin: notebookLayoutConfiguration.markdownCellBottomMargin,268topMargin: notebookLayoutConfiguration.markdownCellTopMargin,269};270271this._onDidChangeLayout.fire(state);272}273274override restoreEditorViewState(editorViewStates: editorCommon.ICodeEditorViewState | null, totalHeight?: number) {275super.restoreEditorViewState(editorViewStates);276// we might already warmup the viewport so the cell has a total height computed277if (totalHeight !== undefined && this.layoutInfo.layoutState === CellLayoutState.Uninitialized) {278this._layoutInfo = {279...this.layoutInfo,280totalHeight: totalHeight,281chatHeight: this._chatHeight,282editorHeight: this._editorHeight,283statusBarHeight: this._statusBarHeight,284layoutState: CellLayoutState.FromCache,285};286this.layoutChange({});287}288}289290getDynamicHeight() {291return null;292}293294getHeight(lineHeight: number) {295if (this._layoutInfo.layoutState === CellLayoutState.Uninitialized) {296return 100;297} else {298return this._layoutInfo.totalHeight;299}300}301302protected onDidChangeTextModelContent(): void {303this._onDidChangeState.fire({ contentChanged: true });304}305306onDeselect() {307}308309310private readonly _hasFindResult = this._register(new Emitter<boolean>());311public readonly hasFindResult: Event<boolean> = this._hasFindResult.event;312313startFind(value: string, options: INotebookFindOptions): CellFindMatch | null {314const matches = super.cellStartFind(value, options);315316if (matches === null) {317return null;318}319320return {321cell: this,322contentMatches: matches323};324}325326override dispose() {327super.dispose();328(this.foldingDelegate as unknown) = null;329}330}331332333