Path: blob/main/src/vs/workbench/contrib/notebook/browser/notebookOptions.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 { PixelRatio } from '../../../../base/browser/pixelRatio.js';6import { CodeWindow } from '../../../../base/browser/window.js';7import { Emitter } from '../../../../base/common/event.js';8import { Disposable } from '../../../../base/common/lifecycle.js';9import { observableValue } from '../../../../base/common/observable.js';10import { isObject } from '../../../../base/common/types.js';11import { URI } from '../../../../base/common/uri.js';12import { FontMeasurements } from '../../../../editor/browser/config/fontMeasurements.js';13import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js';14import { IEditorOptions } from '../../../../editor/common/config/editorOptions.js';15import { BareFontInfo } from '../../../../editor/common/config/fontInfo.js';16import { ConfigurationTarget, IConfigurationChangeEvent, IConfigurationService } from '../../../../platform/configuration/common/configuration.js';17import { NotebookTextModel } from '../common/model/notebookTextModel.js';18import { InteractiveWindowCollapseCodeCells, NotebookCellDefaultCollapseConfig, NotebookCellInternalMetadata, NotebookSetting, ShowCellStatusBarType } from '../common/notebookCommon.js';19import { INotebookExecutionStateService } from '../common/notebookExecutionStateService.js';2021const SCROLLABLE_ELEMENT_PADDING_TOP = 18;2223export const OutputInnerContainerTopPadding = 4;2425export interface NotebookDisplayOptions { // TODO @Yoyokrazy rename to a more generic name, not display26showCellStatusBar: ShowCellStatusBarType;27cellToolbarLocation: string | { [key: string]: string };28cellToolbarInteraction: string;29compactView: boolean;30focusIndicator: 'border' | 'gutter';31insertToolbarPosition: 'betweenCells' | 'notebookToolbar' | 'both' | 'hidden';32insertToolbarAlignment: 'left' | 'center';33globalToolbar: boolean;34stickyScrollEnabled: boolean;35stickyScrollMode: 'flat' | 'indented';36consolidatedOutputButton: boolean;37consolidatedRunButton: boolean;38showFoldingControls: 'always' | 'never' | 'mouseover';39dragAndDropEnabled: boolean;40interactiveWindowCollapseCodeCells: InteractiveWindowCollapseCodeCells;41outputScrolling: boolean;42outputWordWrap: boolean;43outputLineLimit: number;44outputLinkifyFilePaths: boolean;45outputMinimalError: boolean;46fontSize: number;47outputFontSize: number;48outputFontFamily: string;49outputLineHeight: number;50markupFontSize: number;51markdownLineHeight: number;52editorOptionsCustomizations: Partial<{53'editor.indentSize': 'tabSize' | number;54'editor.tabSize': number;55'editor.insertSpaces': boolean;56}> | undefined;57markupFontFamily: string;58disableRulers: boolean | undefined;59}6061export interface NotebookLayoutConfiguration {62cellRightMargin: number;63cellRunGutter: number;64cellTopMargin: number;65cellBottomMargin: number;66cellOutputPadding: number;67codeCellLeftMargin: number;68markdownCellLeftMargin: number;69markdownCellGutter: number;70markdownCellTopMargin: number;71markdownCellBottomMargin: number;72markdownPreviewPadding: number;73markdownFoldHintHeight: number;74editorToolbarHeight: number;75editorTopPadding: number;76editorBottomPadding: number;77editorBottomPaddingWithoutStatusBar: number;78collapsedIndicatorHeight: number;79cellStatusBarHeight: number;80focusIndicatorLeftMargin: number;81focusIndicatorGap: number;82}8384export interface NotebookOptionsChangeEvent {85readonly cellStatusBarVisibility?: boolean;86readonly cellToolbarLocation?: boolean;87readonly cellToolbarInteraction?: boolean;88readonly editorTopPadding?: boolean;89readonly compactView?: boolean;90readonly focusIndicator?: boolean;91readonly insertToolbarPosition?: boolean;92readonly insertToolbarAlignment?: boolean;93readonly globalToolbar?: boolean;94readonly stickyScrollEnabled?: boolean;95readonly stickyScrollMode?: boolean;96readonly showFoldingControls?: boolean;97readonly consolidatedOutputButton?: boolean;98readonly consolidatedRunButton?: boolean;99readonly dragAndDropEnabled?: boolean;100readonly fontSize?: boolean;101readonly outputFontSize?: boolean;102readonly markupFontSize?: boolean;103readonly markdownLineHeight?: boolean;104readonly fontFamily?: boolean;105readonly outputFontFamily?: boolean;106readonly editorOptionsCustomizations?: boolean;107readonly interactiveWindowCollapseCodeCells?: boolean;108readonly outputLineHeight?: boolean;109readonly outputWordWrap?: boolean;110readonly outputScrolling?: boolean;111readonly outputLinkifyFilePaths?: boolean;112readonly minimalError?: boolean;113readonly readonly?: boolean;114readonly markupFontFamily?: boolean;115}116117const defaultConfigConstants = Object.freeze({118codeCellLeftMargin: 28,119cellRunGutter: 32,120markdownCellTopMargin: 8,121markdownCellBottomMargin: 8,122markdownCellLeftMargin: 0,123markdownCellGutter: 32,124focusIndicatorLeftMargin: 4125});126127const compactConfigConstants = Object.freeze({128codeCellLeftMargin: 8,129cellRunGutter: 36,130markdownCellTopMargin: 6,131markdownCellBottomMargin: 6,132markdownCellLeftMargin: 8,133markdownCellGutter: 36,134focusIndicatorLeftMargin: 4135});136137export class NotebookOptions extends Disposable {138private _layoutConfiguration: NotebookLayoutConfiguration & NotebookDisplayOptions;139protected readonly _onDidChangeOptions = this._register(new Emitter<NotebookOptionsChangeEvent>());140readonly onDidChangeOptions = this._onDidChangeOptions.event;141private _editorTopPadding: number = 12;142143readonly previousModelToCompare = observableValue<NotebookTextModel | undefined>('previousModelToCompare', undefined);144145constructor(146readonly targetWindow: CodeWindow,147private isReadonly: boolean,148private readonly overrides: { cellToolbarInteraction: string; globalToolbar: boolean; stickyScrollEnabled: boolean; dragAndDropEnabled: boolean; disableRulers: boolean } | undefined,149@IConfigurationService private readonly configurationService: IConfigurationService,150@INotebookExecutionStateService private readonly notebookExecutionStateService: INotebookExecutionStateService,151@ICodeEditorService private readonly codeEditorService: ICodeEditorService,152) {153super();154const showCellStatusBar = this.configurationService.getValue<ShowCellStatusBarType>(NotebookSetting.showCellStatusBar);155const globalToolbar = overrides?.globalToolbar ?? this.configurationService.getValue<boolean | undefined>(NotebookSetting.globalToolbar) ?? true;156const stickyScrollEnabled = overrides?.stickyScrollEnabled ?? this.configurationService.getValue<boolean | undefined>(NotebookSetting.stickyScrollEnabled) ?? false;157const stickyScrollMode = this._computeStickyScrollModeOption();158const consolidatedOutputButton = this.configurationService.getValue<boolean | undefined>(NotebookSetting.consolidatedOutputButton) ?? true;159const consolidatedRunButton = this.configurationService.getValue<boolean | undefined>(NotebookSetting.consolidatedRunButton) ?? false;160const dragAndDropEnabled = overrides?.dragAndDropEnabled ?? this.configurationService.getValue<boolean | undefined>(NotebookSetting.dragAndDropEnabled) ?? true;161const cellToolbarLocation = this.configurationService.getValue<string | { [key: string]: string }>(NotebookSetting.cellToolbarLocation) ?? { 'default': 'right' };162const cellToolbarInteraction = overrides?.cellToolbarInteraction ?? this.configurationService.getValue<string>(NotebookSetting.cellToolbarVisibility);163const compactView = this.configurationService.getValue<boolean | undefined>(NotebookSetting.compactView) ?? true;164const focusIndicator = this._computeFocusIndicatorOption();165const insertToolbarPosition = this._computeInsertToolbarPositionOption(this.isReadonly);166const insertToolbarAlignment = this._computeInsertToolbarAlignmentOption();167const showFoldingControls = this._computeShowFoldingControlsOption();168// const { bottomToolbarGap, bottomToolbarHeight } = this._computeBottomToolbarDimensions(compactView, insertToolbarPosition, insertToolbarAlignment);169const fontSize = this.configurationService.getValue<number>('editor.fontSize');170const markupFontSize = this.configurationService.getValue<number>(NotebookSetting.markupFontSize);171const markdownLineHeight = this.configurationService.getValue<number>(NotebookSetting.markdownLineHeight);172let editorOptionsCustomizations = this.configurationService.getValue<Partial<{173'editor.indentSize': 'tabSize' | number;174'editor.tabSize': number;175'editor.insertSpaces': boolean;176}>>(NotebookSetting.cellEditorOptionsCustomizations) ?? {};177editorOptionsCustomizations = isObject(editorOptionsCustomizations) ? editorOptionsCustomizations : {};178const interactiveWindowCollapseCodeCells: InteractiveWindowCollapseCodeCells = this.configurationService.getValue(NotebookSetting.interactiveWindowCollapseCodeCells);179180// TOOD @rebornix remove after a few iterations of deprecated setting181let outputLineHeightSettingValue: number;182const deprecatedOutputLineHeightSetting = this.configurationService.getValue<number>(NotebookSetting.outputLineHeightDeprecated);183if (deprecatedOutputLineHeightSetting !== undefined) {184this._migrateDeprecatedSetting(NotebookSetting.outputLineHeightDeprecated, NotebookSetting.outputLineHeight);185outputLineHeightSettingValue = deprecatedOutputLineHeightSetting;186} else {187outputLineHeightSettingValue = this.configurationService.getValue<number>(NotebookSetting.outputLineHeight);188}189190let outputFontSize: number;191const deprecatedOutputFontSizeSetting = this.configurationService.getValue<number>(NotebookSetting.outputFontSizeDeprecated);192if (deprecatedOutputFontSizeSetting !== undefined) {193this._migrateDeprecatedSetting(NotebookSetting.outputFontSizeDeprecated, NotebookSetting.outputFontSize);194outputFontSize = deprecatedOutputFontSizeSetting;195} else {196outputFontSize = this.configurationService.getValue<number>(NotebookSetting.outputFontSize) || fontSize;197}198199let outputFontFamily: string;200const deprecatedOutputFontFamilySetting = this.configurationService.getValue<string>(NotebookSetting.outputFontFamilyDeprecated);201if (deprecatedOutputFontFamilySetting !== undefined) {202this._migrateDeprecatedSetting(NotebookSetting.outputFontFamilyDeprecated, NotebookSetting.outputFontFamily);203outputFontFamily = deprecatedOutputFontFamilySetting;204} else {205outputFontFamily = this.configurationService.getValue<string>(NotebookSetting.outputFontFamily);206}207208let outputScrolling: boolean;209const deprecatedOutputScrollingSetting = this.configurationService.getValue<boolean>(NotebookSetting.outputScrollingDeprecated);210if (deprecatedOutputScrollingSetting !== undefined) {211this._migrateDeprecatedSetting(NotebookSetting.outputScrollingDeprecated, NotebookSetting.outputScrolling);212outputScrolling = deprecatedOutputScrollingSetting;213} else {214outputScrolling = this.configurationService.getValue<boolean>(NotebookSetting.outputScrolling);215}216217const outputLineHeight = this._computeOutputLineHeight(outputLineHeightSettingValue, outputFontSize);218const outputWordWrap = this.configurationService.getValue<boolean>(NotebookSetting.outputWordWrap);219const outputLineLimit = this.configurationService.getValue<number>(NotebookSetting.textOutputLineLimit) ?? 30;220const linkifyFilePaths = this.configurationService.getValue<boolean>(NotebookSetting.LinkifyOutputFilePaths) ?? true;221const minimalErrors = this.configurationService.getValue<boolean>(NotebookSetting.minimalErrorRendering);222const markupFontFamily = this.configurationService.getValue<string>(NotebookSetting.markupFontFamily);223224const editorTopPadding = this._computeEditorTopPadding();225226this._layoutConfiguration = {227...(compactView ? compactConfigConstants : defaultConfigConstants),228cellTopMargin: 6,229cellBottomMargin: 6,230cellRightMargin: 16,231cellStatusBarHeight: 22,232cellOutputPadding: 8,233markdownPreviewPadding: 8,234// bottomToolbarHeight: bottomToolbarHeight,235// bottomToolbarGap: bottomToolbarGap,236editorToolbarHeight: 0,237editorTopPadding: editorTopPadding,238editorBottomPadding: 4,239editorBottomPaddingWithoutStatusBar: 12,240collapsedIndicatorHeight: 28,241showCellStatusBar,242globalToolbar,243stickyScrollEnabled,244stickyScrollMode,245consolidatedOutputButton,246consolidatedRunButton,247dragAndDropEnabled,248cellToolbarLocation,249cellToolbarInteraction,250compactView,251focusIndicator,252insertToolbarPosition,253insertToolbarAlignment,254showFoldingControls,255fontSize,256outputFontSize,257outputFontFamily,258outputLineHeight,259markupFontSize,260markdownLineHeight,261editorOptionsCustomizations,262focusIndicatorGap: 3,263interactiveWindowCollapseCodeCells,264markdownFoldHintHeight: 22,265outputScrolling: outputScrolling,266outputWordWrap: outputWordWrap,267outputLineLimit: outputLineLimit,268outputLinkifyFilePaths: linkifyFilePaths,269outputMinimalError: minimalErrors,270markupFontFamily,271disableRulers: overrides?.disableRulers,272};273274this._register(this.configurationService.onDidChangeConfiguration(e => {275this._updateConfiguration(e);276}));277}278279updateOptions(isReadonly: boolean) {280if (this.isReadonly !== isReadonly) {281this.isReadonly = isReadonly;282283this._updateConfiguration({284affectsConfiguration(configuration: string): boolean {285return configuration === NotebookSetting.insertToolbarLocation;286},287source: ConfigurationTarget.DEFAULT,288affectedKeys: new Set([NotebookSetting.insertToolbarLocation]),289change: { keys: [NotebookSetting.insertToolbarLocation], overrides: [] },290});291}292}293294private _computeEditorTopPadding(): number {295let decorationTriggeredAdjustment = false;296297const updateEditorTopPadding = (top: number) => {298this._editorTopPadding = top;299const configuration = Object.assign({}, this._layoutConfiguration);300configuration.editorTopPadding = this._editorTopPadding;301this._layoutConfiguration = configuration;302this._onDidChangeOptions.fire({ editorTopPadding: true });303};304305const decorationCheckSet = new Set<string>();306const onDidAddDecorationType = (e: string) => {307if (decorationTriggeredAdjustment) {308return;309}310311if (decorationCheckSet.has(e)) {312return;313}314315try {316const options = this.codeEditorService.resolveDecorationOptions(e, true);317if (options.afterContentClassName || options.beforeContentClassName) {318const cssRules = this.codeEditorService.resolveDecorationCSSRules(e);319if (cssRules !== null) {320for (let i = 0; i < cssRules.length; i++) {321// The following ways to index into the list are equivalent322if (323((cssRules[i] as CSSStyleRule).selectorText.endsWith('::after') || (cssRules[i] as CSSStyleRule).selectorText.endsWith('::after'))324&& (cssRules[i] as CSSStyleRule).cssText.indexOf('top:') > -1325) {326// there is a `::before` or `::after` text decoration whose position is above or below current line327// we at least make sure that the editor top padding is at least one line328const editorOptions = this.configurationService.getValue<IEditorOptions>('editor');329updateEditorTopPadding(BareFontInfo.createFromRawSettings(editorOptions, PixelRatio.getInstance(this.targetWindow).value).lineHeight + 2);330decorationTriggeredAdjustment = true;331break;332}333}334}335}336337decorationCheckSet.add(e);338} catch (_ex) {339// do not throw and break notebook340}341342};343this._register(this.codeEditorService.onDecorationTypeRegistered(onDidAddDecorationType));344this.codeEditorService.listDecorationTypes().forEach(onDidAddDecorationType);345346return this._editorTopPadding;347}348349private _migrateDeprecatedSetting(deprecatedKey: string, key: string): void {350const deprecatedSetting = this.configurationService.inspect(deprecatedKey);351352if (deprecatedSetting.application !== undefined) {353this.configurationService.updateValue(deprecatedKey, undefined, ConfigurationTarget.APPLICATION);354this.configurationService.updateValue(key, deprecatedSetting.application.value, ConfigurationTarget.APPLICATION);355}356357if (deprecatedSetting.user !== undefined) {358this.configurationService.updateValue(deprecatedKey, undefined, ConfigurationTarget.USER);359this.configurationService.updateValue(key, deprecatedSetting.user.value, ConfigurationTarget.USER);360}361362if (deprecatedSetting.userLocal !== undefined) {363this.configurationService.updateValue(deprecatedKey, undefined, ConfigurationTarget.USER_LOCAL);364this.configurationService.updateValue(key, deprecatedSetting.userLocal.value, ConfigurationTarget.USER_LOCAL);365}366367if (deprecatedSetting.userRemote !== undefined) {368this.configurationService.updateValue(deprecatedKey, undefined, ConfigurationTarget.USER_REMOTE);369this.configurationService.updateValue(key, deprecatedSetting.userRemote.value, ConfigurationTarget.USER_REMOTE);370}371372if (deprecatedSetting.workspace !== undefined) {373this.configurationService.updateValue(deprecatedKey, undefined, ConfigurationTarget.WORKSPACE);374this.configurationService.updateValue(key, deprecatedSetting.workspace.value, ConfigurationTarget.WORKSPACE);375}376377if (deprecatedSetting.workspaceFolder !== undefined) {378this.configurationService.updateValue(deprecatedKey, undefined, ConfigurationTarget.WORKSPACE_FOLDER);379this.configurationService.updateValue(key, deprecatedSetting.workspaceFolder.value, ConfigurationTarget.WORKSPACE_FOLDER);380}381}382383private _computeOutputLineHeight(lineHeight: number, outputFontSize: number): number {384const minimumLineHeight = 9;385386if (lineHeight === 0) {387// use editor line height388const editorOptions = this.configurationService.getValue<IEditorOptions>('editor');389const fontInfo = FontMeasurements.readFontInfo(this.targetWindow, BareFontInfo.createFromRawSettings(editorOptions, PixelRatio.getInstance(this.targetWindow).value));390lineHeight = fontInfo.lineHeight;391} else if (lineHeight < minimumLineHeight) {392// Values too small to be line heights in pixels are in ems.393let fontSize = outputFontSize;394if (fontSize === 0) {395fontSize = this.configurationService.getValue<number>('editor.fontSize');396}397398lineHeight = lineHeight * fontSize;399}400401// Enforce integer, minimum constraints402lineHeight = Math.round(lineHeight);403if (lineHeight < minimumLineHeight) {404lineHeight = minimumLineHeight;405}406407return lineHeight;408}409410private _updateConfiguration(e: IConfigurationChangeEvent) {411const cellStatusBarVisibility = e.affectsConfiguration(NotebookSetting.showCellStatusBar);412const cellToolbarLocation = e.affectsConfiguration(NotebookSetting.cellToolbarLocation);413const cellToolbarInteraction = e.affectsConfiguration(NotebookSetting.cellToolbarVisibility);414const compactView = e.affectsConfiguration(NotebookSetting.compactView);415const focusIndicator = e.affectsConfiguration(NotebookSetting.focusIndicator);416const insertToolbarPosition = e.affectsConfiguration(NotebookSetting.insertToolbarLocation);417const insertToolbarAlignment = e.affectsConfiguration(NotebookSetting.experimentalInsertToolbarAlignment);418const globalToolbar = e.affectsConfiguration(NotebookSetting.globalToolbar);419const stickyScrollEnabled = e.affectsConfiguration(NotebookSetting.stickyScrollEnabled);420const stickyScrollMode = e.affectsConfiguration(NotebookSetting.stickyScrollMode);421const consolidatedOutputButton = e.affectsConfiguration(NotebookSetting.consolidatedOutputButton);422const consolidatedRunButton = e.affectsConfiguration(NotebookSetting.consolidatedRunButton);423const showFoldingControls = e.affectsConfiguration(NotebookSetting.showFoldingControls);424const dragAndDropEnabled = e.affectsConfiguration(NotebookSetting.dragAndDropEnabled);425const fontSize = e.affectsConfiguration('editor.fontSize');426const outputFontSize = e.affectsConfiguration(NotebookSetting.outputFontSize);427const markupFontSize = e.affectsConfiguration(NotebookSetting.markupFontSize);428const markdownLineHeight = e.affectsConfiguration(NotebookSetting.markdownLineHeight);429const fontFamily = e.affectsConfiguration('editor.fontFamily');430const outputFontFamily = e.affectsConfiguration(NotebookSetting.outputFontFamily);431const editorOptionsCustomizations = e.affectsConfiguration(NotebookSetting.cellEditorOptionsCustomizations);432const interactiveWindowCollapseCodeCells = e.affectsConfiguration(NotebookSetting.interactiveWindowCollapseCodeCells);433const outputLineHeight = e.affectsConfiguration(NotebookSetting.outputLineHeight);434const outputScrolling = e.affectsConfiguration(NotebookSetting.outputScrolling);435const outputWordWrap = e.affectsConfiguration(NotebookSetting.outputWordWrap);436const outputLinkifyFilePaths = e.affectsConfiguration(NotebookSetting.LinkifyOutputFilePaths);437const minimalError = e.affectsConfiguration(NotebookSetting.minimalErrorRendering);438const markupFontFamily = e.affectsConfiguration(NotebookSetting.markupFontFamily);439440if (441!cellStatusBarVisibility442&& !cellToolbarLocation443&& !cellToolbarInteraction444&& !compactView445&& !focusIndicator446&& !insertToolbarPosition447&& !insertToolbarAlignment448&& !globalToolbar449&& !stickyScrollEnabled450&& !stickyScrollMode451&& !consolidatedOutputButton452&& !consolidatedRunButton453&& !showFoldingControls454&& !dragAndDropEnabled455&& !fontSize456&& !outputFontSize457&& !markupFontSize458&& !markdownLineHeight459&& !fontFamily460&& !outputFontFamily461&& !editorOptionsCustomizations462&& !interactiveWindowCollapseCodeCells463&& !outputLineHeight464&& !outputScrolling465&& !outputWordWrap466&& !outputLinkifyFilePaths467&& !minimalError468&& !markupFontFamily) {469return;470}471472let configuration = Object.assign({}, this._layoutConfiguration);473474if (cellStatusBarVisibility) {475configuration.showCellStatusBar = this.configurationService.getValue<ShowCellStatusBarType>(NotebookSetting.showCellStatusBar);476}477478if (cellToolbarLocation) {479configuration.cellToolbarLocation = this.configurationService.getValue<string | { [key: string]: string }>(NotebookSetting.cellToolbarLocation) ?? { 'default': 'right' };480}481482if (cellToolbarInteraction && !this.overrides?.cellToolbarInteraction) {483configuration.cellToolbarInteraction = this.configurationService.getValue<string>(NotebookSetting.cellToolbarVisibility);484}485486if (focusIndicator) {487configuration.focusIndicator = this._computeFocusIndicatorOption();488}489490if (compactView) {491const compactViewValue = this.configurationService.getValue<boolean | undefined>(NotebookSetting.compactView) ?? true;492configuration = Object.assign(configuration, {493...(compactViewValue ? compactConfigConstants : defaultConfigConstants),494});495configuration.compactView = compactViewValue;496}497498if (insertToolbarAlignment) {499configuration.insertToolbarAlignment = this._computeInsertToolbarAlignmentOption();500}501502if (insertToolbarPosition) {503configuration.insertToolbarPosition = this._computeInsertToolbarPositionOption(this.isReadonly);504}505506if (globalToolbar && this.overrides?.globalToolbar === undefined) {507configuration.globalToolbar = this.configurationService.getValue<boolean>(NotebookSetting.globalToolbar) ?? true;508}509510if (stickyScrollEnabled && this.overrides?.stickyScrollEnabled === undefined) {511configuration.stickyScrollEnabled = this.configurationService.getValue<boolean>(NotebookSetting.stickyScrollEnabled) ?? false;512}513514if (stickyScrollMode) {515configuration.stickyScrollMode = this.configurationService.getValue<'flat' | 'indented'>(NotebookSetting.stickyScrollMode) ?? 'flat';516}517518if (consolidatedOutputButton) {519configuration.consolidatedOutputButton = this.configurationService.getValue<boolean>(NotebookSetting.consolidatedOutputButton) ?? true;520}521522if (consolidatedRunButton) {523configuration.consolidatedRunButton = this.configurationService.getValue<boolean>(NotebookSetting.consolidatedRunButton) ?? true;524}525526if (showFoldingControls) {527configuration.showFoldingControls = this._computeShowFoldingControlsOption();528}529530if (dragAndDropEnabled) {531configuration.dragAndDropEnabled = this.configurationService.getValue<boolean>(NotebookSetting.dragAndDropEnabled) ?? true;532}533534if (fontSize) {535configuration.fontSize = this.configurationService.getValue<number>('editor.fontSize');536}537538if (outputFontSize || fontSize) {539configuration.outputFontSize = this.configurationService.getValue<number>(NotebookSetting.outputFontSize) || configuration.fontSize;540}541542if (markupFontSize) {543configuration.markupFontSize = this.configurationService.getValue<number>(NotebookSetting.markupFontSize);544}545546if (markdownLineHeight) {547configuration.markdownLineHeight = this.configurationService.getValue<number>(NotebookSetting.markdownLineHeight);548}549550if (outputFontFamily) {551configuration.outputFontFamily = this.configurationService.getValue<string>(NotebookSetting.outputFontFamily);552}553554if (editorOptionsCustomizations) {555configuration.editorOptionsCustomizations = this.configurationService.getValue(NotebookSetting.cellEditorOptionsCustomizations);556}557558if (interactiveWindowCollapseCodeCells) {559configuration.interactiveWindowCollapseCodeCells = this.configurationService.getValue(NotebookSetting.interactiveWindowCollapseCodeCells);560}561562if (outputLineHeight || fontSize || outputFontSize) {563const lineHeight = this.configurationService.getValue<number>(NotebookSetting.outputLineHeight);564configuration.outputLineHeight = this._computeOutputLineHeight(lineHeight, configuration.outputFontSize);565}566567if (outputWordWrap) {568configuration.outputWordWrap = this.configurationService.getValue<boolean>(NotebookSetting.outputWordWrap);569}570571if (outputScrolling) {572configuration.outputScrolling = this.configurationService.getValue<boolean>(NotebookSetting.outputScrolling);573}574575if (outputLinkifyFilePaths) {576configuration.outputLinkifyFilePaths = this.configurationService.getValue<boolean>(NotebookSetting.LinkifyOutputFilePaths);577}578579if (minimalError) {580configuration.outputMinimalError = this.configurationService.getValue<boolean>(NotebookSetting.minimalErrorRendering);581}582583if (markupFontFamily) {584configuration.markupFontFamily = this.configurationService.getValue<string>(NotebookSetting.markupFontFamily);585}586587this._layoutConfiguration = Object.freeze(configuration);588589// trigger event590this._onDidChangeOptions.fire({591cellStatusBarVisibility,592cellToolbarLocation,593cellToolbarInteraction,594compactView,595focusIndicator,596insertToolbarPosition,597insertToolbarAlignment,598globalToolbar,599stickyScrollEnabled,600stickyScrollMode,601showFoldingControls,602consolidatedOutputButton,603consolidatedRunButton,604dragAndDropEnabled,605fontSize,606outputFontSize,607markupFontSize,608markdownLineHeight,609fontFamily,610outputFontFamily,611editorOptionsCustomizations,612interactiveWindowCollapseCodeCells,613outputLineHeight,614outputScrolling,615outputWordWrap,616outputLinkifyFilePaths,617minimalError,618markupFontFamily619});620}621622private _computeInsertToolbarPositionOption(isReadOnly: boolean) {623return isReadOnly ? 'hidden' : this.configurationService.getValue<'betweenCells' | 'notebookToolbar' | 'both' | 'hidden'>(NotebookSetting.insertToolbarLocation) ?? 'both';624}625626private _computeInsertToolbarAlignmentOption() {627return this.configurationService.getValue<'left' | 'center'>(NotebookSetting.experimentalInsertToolbarAlignment) ?? 'center';628}629630private _computeShowFoldingControlsOption() {631return this.configurationService.getValue<'always' | 'never' | 'mouseover'>(NotebookSetting.showFoldingControls) ?? 'mouseover';632}633634private _computeFocusIndicatorOption() {635return this.configurationService.getValue<'border' | 'gutter'>(NotebookSetting.focusIndicator) ?? 'gutter';636}637638private _computeStickyScrollModeOption() {639return this.configurationService.getValue<'flat' | 'indented'>(NotebookSetting.stickyScrollMode) ?? 'flat';640}641642getCellCollapseDefault(): NotebookCellDefaultCollapseConfig {643return this._layoutConfiguration.interactiveWindowCollapseCodeCells === 'never' ?644{645codeCell: {646inputCollapsed: false647}648} : {649codeCell: {650inputCollapsed: true651}652};653}654655getLayoutConfiguration(): NotebookLayoutConfiguration & NotebookDisplayOptions {656return this._layoutConfiguration;657}658659getDisplayOptions(): NotebookDisplayOptions {660return this._layoutConfiguration;661}662663getCellEditorContainerLeftMargin() {664const {665codeCellLeftMargin,666cellRunGutter667} = this._layoutConfiguration;668return codeCellLeftMargin + cellRunGutter;669}670671computeCollapsedMarkdownCellHeight(viewType: string): number {672const { bottomToolbarGap } = this.computeBottomToolbarDimensions(viewType);673return this._layoutConfiguration.markdownCellTopMargin674+ this._layoutConfiguration.collapsedIndicatorHeight675+ bottomToolbarGap676+ this._layoutConfiguration.markdownCellBottomMargin;677}678679computeBottomToolbarOffset(totalHeight: number, viewType: string) {680const { bottomToolbarGap, bottomToolbarHeight } = this.computeBottomToolbarDimensions(viewType);681682return totalHeight683- bottomToolbarGap684- bottomToolbarHeight / 2;685}686687computeCodeCellEditorWidth(outerWidth: number): number {688return outerWidth - (689this._layoutConfiguration.codeCellLeftMargin690+ this._layoutConfiguration.cellRunGutter691+ this._layoutConfiguration.cellRightMargin692);693}694695computeMarkdownCellEditorWidth(outerWidth: number): number {696return outerWidth697- this._layoutConfiguration.markdownCellGutter698- this._layoutConfiguration.markdownCellLeftMargin699- this._layoutConfiguration.cellRightMargin;700}701702computeStatusBarHeight(): number {703return this._layoutConfiguration.cellStatusBarHeight;704}705706private _computeBottomToolbarDimensions(compactView: boolean, insertToolbarPosition: 'betweenCells' | 'notebookToolbar' | 'both' | 'hidden', insertToolbarAlignment: 'left' | 'center', cellToolbar: 'right' | 'left' | 'hidden'): { bottomToolbarGap: number; bottomToolbarHeight: number } {707if (insertToolbarAlignment === 'left' || cellToolbar !== 'hidden') {708return {709bottomToolbarGap: 18,710bottomToolbarHeight: 18711};712}713714if (insertToolbarPosition === 'betweenCells' || insertToolbarPosition === 'both') {715return compactView ? {716bottomToolbarGap: 12,717bottomToolbarHeight: 20718} : {719bottomToolbarGap: 20,720bottomToolbarHeight: 20721};722} else {723return {724bottomToolbarGap: 0,725bottomToolbarHeight: 0726};727}728}729730computeBottomToolbarDimensions(viewType?: string): { bottomToolbarGap: number; bottomToolbarHeight: number } {731const configuration = this._layoutConfiguration;732const cellToolbarPosition = this.computeCellToolbarLocation(viewType);733const { bottomToolbarGap, bottomToolbarHeight } = this._computeBottomToolbarDimensions(configuration.compactView, configuration.insertToolbarPosition, configuration.insertToolbarAlignment, cellToolbarPosition);734return {735bottomToolbarGap,736bottomToolbarHeight737};738}739740computeCellToolbarLocation(viewType?: string): 'right' | 'left' | 'hidden' {741const cellToolbarLocation = this._layoutConfiguration.cellToolbarLocation;742743if (typeof cellToolbarLocation === 'string') {744if (cellToolbarLocation === 'left' || cellToolbarLocation === 'right' || cellToolbarLocation === 'hidden') {745return cellToolbarLocation;746}747} else {748if (viewType) {749const notebookSpecificSetting = cellToolbarLocation[viewType] ?? cellToolbarLocation['default'];750let cellToolbarLocationForCurrentView: 'right' | 'left' | 'hidden' = 'right';751752switch (notebookSpecificSetting) {753case 'left':754cellToolbarLocationForCurrentView = 'left';755break;756case 'right':757cellToolbarLocationForCurrentView = 'right';758break;759case 'hidden':760cellToolbarLocationForCurrentView = 'hidden';761break;762default:763cellToolbarLocationForCurrentView = 'right';764break;765}766767return cellToolbarLocationForCurrentView;768}769}770771return 'right';772}773774computeTopInsertToolbarHeight(viewType?: string): number {775if (this._layoutConfiguration.insertToolbarPosition === 'betweenCells' || this._layoutConfiguration.insertToolbarPosition === 'both') {776return SCROLLABLE_ELEMENT_PADDING_TOP;777}778779const cellToolbarLocation = this.computeCellToolbarLocation(viewType);780781if (cellToolbarLocation === 'left' || cellToolbarLocation === 'right') {782return SCROLLABLE_ELEMENT_PADDING_TOP;783}784785return 0;786}787788computeEditorPadding(internalMetadata: NotebookCellInternalMetadata, cellUri: URI) {789return {790top: this._editorTopPadding,791bottom: this.statusBarIsVisible(internalMetadata, cellUri)792? this._layoutConfiguration.editorBottomPadding793: this._layoutConfiguration.editorBottomPaddingWithoutStatusBar794};795}796797798computeEditorStatusbarHeight(internalMetadata: NotebookCellInternalMetadata, cellUri: URI) {799return this.statusBarIsVisible(internalMetadata, cellUri) ? this.computeStatusBarHeight() : 0;800}801802private statusBarIsVisible(internalMetadata: NotebookCellInternalMetadata, cellUri: URI): boolean {803const exe = this.notebookExecutionStateService.getCellExecution(cellUri);804if (this._layoutConfiguration.showCellStatusBar === 'visible') {805return true;806} else if (this._layoutConfiguration.showCellStatusBar === 'visibleAfterExecute') {807return typeof internalMetadata.lastRunSuccess === 'boolean' || exe !== undefined;808} else {809return false;810}811}812813computeWebviewOptions() {814return {815outputNodePadding: this._layoutConfiguration.cellOutputPadding,816outputNodeLeftPadding: this._layoutConfiguration.cellOutputPadding,817previewNodePadding: this._layoutConfiguration.markdownPreviewPadding,818markdownLeftMargin: this._layoutConfiguration.markdownCellGutter + this._layoutConfiguration.markdownCellLeftMargin,819leftMargin: this._layoutConfiguration.codeCellLeftMargin,820rightMargin: this._layoutConfiguration.cellRightMargin,821runGutter: this._layoutConfiguration.cellRunGutter,822dragAndDropEnabled: this._layoutConfiguration.dragAndDropEnabled,823fontSize: this._layoutConfiguration.fontSize,824outputFontSize: this._layoutConfiguration.outputFontSize,825outputFontFamily: this._layoutConfiguration.outputFontFamily,826markupFontSize: this._layoutConfiguration.markupFontSize,827markdownLineHeight: this._layoutConfiguration.markdownLineHeight,828outputLineHeight: this._layoutConfiguration.outputLineHeight,829outputScrolling: this._layoutConfiguration.outputScrolling,830outputWordWrap: this._layoutConfiguration.outputWordWrap,831outputLineLimit: this._layoutConfiguration.outputLineLimit,832outputLinkifyFilePaths: this._layoutConfiguration.outputLinkifyFilePaths,833minimalError: this._layoutConfiguration.outputMinimalError,834markupFontFamily: this._layoutConfiguration.markupFontFamily835};836}837838computeDiffWebviewOptions() {839return {840outputNodePadding: this._layoutConfiguration.cellOutputPadding,841outputNodeLeftPadding: 0,842previewNodePadding: this._layoutConfiguration.markdownPreviewPadding,843markdownLeftMargin: 0,844leftMargin: 32,845rightMargin: 0,846runGutter: 0,847dragAndDropEnabled: false,848fontSize: this._layoutConfiguration.fontSize,849outputFontSize: this._layoutConfiguration.outputFontSize,850outputFontFamily: this._layoutConfiguration.outputFontFamily,851markupFontSize: this._layoutConfiguration.markupFontSize,852markdownLineHeight: this._layoutConfiguration.markdownLineHeight,853outputLineHeight: this._layoutConfiguration.outputLineHeight,854outputScrolling: this._layoutConfiguration.outputScrolling,855outputWordWrap: this._layoutConfiguration.outputWordWrap,856outputLineLimit: this._layoutConfiguration.outputLineLimit,857outputLinkifyFilePaths: false,858minimalError: false,859markupFontFamily: this._layoutConfiguration.markupFontFamily860};861}862863computeIndicatorPosition(totalHeight: number, foldHintHeight: number, viewType?: string) {864const { bottomToolbarGap } = this.computeBottomToolbarDimensions(viewType);865866return {867bottomIndicatorTop: totalHeight - bottomToolbarGap - this._layoutConfiguration.cellBottomMargin - foldHintHeight,868verticalIndicatorHeight: totalHeight - bottomToolbarGap - foldHintHeight869};870}871}872873874