Path: blob/main/src/vs/workbench/contrib/notebook/browser/viewModel/markupCellViewModel.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 { 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);129130this._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: 0145};146147this._register(this.onDidChangeState(e => {148this.viewContext.eventDispatcher.emit([new NotebookCellStateChangedEvent(e, this.model)]);149150if (e.foldingStateChanged) {151this._updateTotalHeight(this._computeTotalHeight(), CellLayoutContext.Fold);152}153}));154}155156private _computeTotalHeight(): number {157const layoutConfiguration = this.viewContext.notebookOptions.getLayoutConfiguration();158const { bottomToolbarGap } = this.viewContext.notebookOptions.computeBottomToolbarDimensions(this.viewType);159const foldHintHeight = this._computeFoldHintHeight();160161if (this.getEditState() === CellEditState.Editing) {162return this._editorHeight163+ layoutConfiguration.markdownCellTopMargin164+ layoutConfiguration.markdownCellBottomMargin165+ bottomToolbarGap166+ this._statusBarHeight167+ this._commentHeight;168} else {169// @rebornix170// On file open, the previewHeight + bottomToolbarGap for a cell out of viewport can be 0171// When it's 0, the list view will never try to render it anymore even if we scroll the cell into view.172// Thus we make sure it's greater than 0173return Math.max(1, this._previewHeight + bottomToolbarGap + foldHintHeight + this._commentHeight);174}175}176177private _computeFoldHintHeight(): number {178return (this.getEditState() === CellEditState.Editing || this.foldingState !== CellFoldingState.Collapsed) ?1790 : this.viewContext.notebookOptions.getLayoutConfiguration().markdownFoldHintHeight;180}181182override updateOptions(e: NotebookOptionsChangeEvent) {183super.updateOptions(e);184if (e.cellStatusBarVisibility || e.insertToolbarPosition || e.cellToolbarLocation) {185this._updateTotalHeight(this._computeTotalHeight());186}187}188189/**190* we put outputs stuff here to make compiler happy191*/192outputsViewModels: ICellOutputViewModel[] = [];193getOutputOffset(index: number): number {194// throw new Error('Method not implemented.');195return -1;196}197updateOutputHeight(index: number, height: number): void {198// throw new Error('Method not implemented.');199}200201triggerFoldingStateChange() {202this._onDidChangeState.fire({ foldingStateChanged: true });203}204205private _updateTotalHeight(newHeight: number, context?: CellLayoutContext) {206if (newHeight !== this.layoutInfo.totalHeight) {207this.layoutChange({ totalHeight: newHeight, context });208}209}210211layoutChange(state: MarkupCellLayoutChangeEvent) {212let totalHeight: number;213let foldHintHeight: number;214if (!this.isInputCollapsed) {215totalHeight = state.totalHeight === undefined ?216(this._layoutInfo.layoutState ===217CellLayoutState.Uninitialized ?218100 :219this._layoutInfo.totalHeight) :220state.totalHeight;221// recompute222foldHintHeight = this._computeFoldHintHeight();223} else {224totalHeight =225this.viewContext.notebookOptions226.computeCollapsedMarkdownCellHeight(this.viewType);227state.totalHeight = totalHeight;228229foldHintHeight = 0;230}231let commentOffset: number;232if (this.getEditState() === CellEditState.Editing) {233const notebookLayoutConfiguration = this.viewContext.notebookOptions.getLayoutConfiguration();234commentOffset = notebookLayoutConfiguration.editorToolbarHeight235+ notebookLayoutConfiguration.cellTopMargin // CELL_TOP_MARGIN236+ this._chatHeight237+ this._editorHeight238+ this._statusBarHeight;239} else {240commentOffset = this._previewHeight;241}242243this._layoutInfo = {244fontInfo: state.font || this._layoutInfo.fontInfo,245editorWidth: state.outerWidth !== undefined ?246this.viewContext.notebookOptions247.computeMarkdownCellEditorWidth(state.outerWidth) :248this._layoutInfo.editorWidth,249chatHeight: this._chatHeight,250editorHeight: this._editorHeight,251statusBarHeight: this._statusBarHeight,252previewHeight: this._previewHeight,253bottomToolbarOffset: this.viewContext.notebookOptions254.computeBottomToolbarOffset(255totalHeight, this.viewType),256totalHeight,257layoutState: CellLayoutState.Measured,258foldHintHeight,259commentOffset,260commentHeight: state.commentHeight ?261this._commentHeight :262this._layoutInfo.commentHeight,263};264265this._onDidChangeLayout.fire(state);266}267268override restoreEditorViewState(editorViewStates: editorCommon.ICodeEditorViewState | null, totalHeight?: number) {269super.restoreEditorViewState(editorViewStates);270// we might already warmup the viewport so the cell has a total height computed271if (totalHeight !== undefined && this.layoutInfo.layoutState === CellLayoutState.Uninitialized) {272this._layoutInfo = {273...this.layoutInfo,274totalHeight: totalHeight,275chatHeight: this._chatHeight,276editorHeight: this._editorHeight,277statusBarHeight: this._statusBarHeight,278layoutState: CellLayoutState.FromCache,279};280this.layoutChange({});281}282}283284getDynamicHeight() {285return null;286}287288getHeight(lineHeight: number) {289if (this._layoutInfo.layoutState === CellLayoutState.Uninitialized) {290return 100;291} else {292return this._layoutInfo.totalHeight;293}294}295296protected onDidChangeTextModelContent(): void {297this._onDidChangeState.fire({ contentChanged: true });298}299300onDeselect() {301}302303304private readonly _hasFindResult = this._register(new Emitter<boolean>());305public readonly hasFindResult: Event<boolean> = this._hasFindResult.event;306307startFind(value: string, options: INotebookFindOptions): CellFindMatch | null {308const matches = super.cellStartFind(value, options);309310if (matches === null) {311return null;312}313314return {315cell: this,316contentMatches: matches317};318}319320override dispose() {321super.dispose();322(this.foldingDelegate as any) = null;323}324}325326327