Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/notebook/browser/notebookOptions.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { PixelRatio } from '../../../../base/browser/pixelRatio.js';
7
import { CodeWindow } from '../../../../base/browser/window.js';
8
import { Emitter } from '../../../../base/common/event.js';
9
import { Disposable } from '../../../../base/common/lifecycle.js';
10
import { observableValue } from '../../../../base/common/observable.js';
11
import { isObject } from '../../../../base/common/types.js';
12
import { URI } from '../../../../base/common/uri.js';
13
import { FontMeasurements } from '../../../../editor/browser/config/fontMeasurements.js';
14
import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js';
15
import { IEditorOptions } from '../../../../editor/common/config/editorOptions.js';
16
import { BareFontInfo } from '../../../../editor/common/config/fontInfo.js';
17
import { ConfigurationTarget, IConfigurationChangeEvent, IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
18
import { NotebookTextModel } from '../common/model/notebookTextModel.js';
19
import { InteractiveWindowCollapseCodeCells, NotebookCellDefaultCollapseConfig, NotebookCellInternalMetadata, NotebookSetting, ShowCellStatusBarType } from '../common/notebookCommon.js';
20
import { INotebookExecutionStateService } from '../common/notebookExecutionStateService.js';
21
22
const SCROLLABLE_ELEMENT_PADDING_TOP = 18;
23
24
export const OutputInnerContainerTopPadding = 4;
25
26
export interface NotebookDisplayOptions { // TODO @Yoyokrazy rename to a more generic name, not display
27
showCellStatusBar: ShowCellStatusBarType;
28
cellToolbarLocation: string | { [key: string]: string };
29
cellToolbarInteraction: string;
30
compactView: boolean;
31
focusIndicator: 'border' | 'gutter';
32
insertToolbarPosition: 'betweenCells' | 'notebookToolbar' | 'both' | 'hidden';
33
insertToolbarAlignment: 'left' | 'center';
34
globalToolbar: boolean;
35
stickyScrollEnabled: boolean;
36
stickyScrollMode: 'flat' | 'indented';
37
consolidatedOutputButton: boolean;
38
consolidatedRunButton: boolean;
39
showFoldingControls: 'always' | 'never' | 'mouseover';
40
dragAndDropEnabled: boolean;
41
interactiveWindowCollapseCodeCells: InteractiveWindowCollapseCodeCells;
42
outputScrolling: boolean;
43
outputWordWrap: boolean;
44
outputLineLimit: number;
45
outputLinkifyFilePaths: boolean;
46
outputMinimalError: boolean;
47
fontSize: number;
48
outputFontSize: number;
49
outputFontFamily: string;
50
outputLineHeight: number;
51
markupFontSize: number;
52
markdownLineHeight: number;
53
editorOptionsCustomizations: Partial<{
54
'editor.indentSize': 'tabSize' | number;
55
'editor.tabSize': number;
56
'editor.insertSpaces': boolean;
57
}> | undefined;
58
markupFontFamily: string;
59
disableRulers: boolean | undefined;
60
}
61
62
export interface NotebookLayoutConfiguration {
63
cellRightMargin: number;
64
cellRunGutter: number;
65
cellTopMargin: number;
66
cellBottomMargin: number;
67
cellOutputPadding: number;
68
codeCellLeftMargin: number;
69
markdownCellLeftMargin: number;
70
markdownCellGutter: number;
71
markdownCellTopMargin: number;
72
markdownCellBottomMargin: number;
73
markdownPreviewPadding: number;
74
markdownFoldHintHeight: number;
75
editorToolbarHeight: number;
76
editorTopPadding: number;
77
editorBottomPadding: number;
78
editorBottomPaddingWithoutStatusBar: number;
79
collapsedIndicatorHeight: number;
80
cellStatusBarHeight: number;
81
focusIndicatorLeftMargin: number;
82
focusIndicatorGap: number;
83
}
84
85
export interface NotebookOptionsChangeEvent {
86
readonly cellStatusBarVisibility?: boolean;
87
readonly cellToolbarLocation?: boolean;
88
readonly cellToolbarInteraction?: boolean;
89
readonly editorTopPadding?: boolean;
90
readonly compactView?: boolean;
91
readonly focusIndicator?: boolean;
92
readonly insertToolbarPosition?: boolean;
93
readonly insertToolbarAlignment?: boolean;
94
readonly globalToolbar?: boolean;
95
readonly stickyScrollEnabled?: boolean;
96
readonly stickyScrollMode?: boolean;
97
readonly showFoldingControls?: boolean;
98
readonly consolidatedOutputButton?: boolean;
99
readonly consolidatedRunButton?: boolean;
100
readonly dragAndDropEnabled?: boolean;
101
readonly fontSize?: boolean;
102
readonly outputFontSize?: boolean;
103
readonly markupFontSize?: boolean;
104
readonly markdownLineHeight?: boolean;
105
readonly fontFamily?: boolean;
106
readonly outputFontFamily?: boolean;
107
readonly editorOptionsCustomizations?: boolean;
108
readonly interactiveWindowCollapseCodeCells?: boolean;
109
readonly outputLineHeight?: boolean;
110
readonly outputWordWrap?: boolean;
111
readonly outputScrolling?: boolean;
112
readonly outputLinkifyFilePaths?: boolean;
113
readonly minimalError?: boolean;
114
readonly readonly?: boolean;
115
readonly markupFontFamily?: boolean;
116
}
117
118
const defaultConfigConstants = Object.freeze({
119
codeCellLeftMargin: 28,
120
cellRunGutter: 32,
121
markdownCellTopMargin: 8,
122
markdownCellBottomMargin: 8,
123
markdownCellLeftMargin: 0,
124
markdownCellGutter: 32,
125
focusIndicatorLeftMargin: 4
126
});
127
128
const compactConfigConstants = Object.freeze({
129
codeCellLeftMargin: 8,
130
cellRunGutter: 36,
131
markdownCellTopMargin: 6,
132
markdownCellBottomMargin: 6,
133
markdownCellLeftMargin: 8,
134
markdownCellGutter: 36,
135
focusIndicatorLeftMargin: 4
136
});
137
138
export class NotebookOptions extends Disposable {
139
private _layoutConfiguration: NotebookLayoutConfiguration & NotebookDisplayOptions;
140
protected readonly _onDidChangeOptions = this._register(new Emitter<NotebookOptionsChangeEvent>());
141
readonly onDidChangeOptions = this._onDidChangeOptions.event;
142
private _editorTopPadding: number = 12;
143
144
readonly previousModelToCompare = observableValue<NotebookTextModel | undefined>('previousModelToCompare', undefined);
145
146
constructor(
147
readonly targetWindow: CodeWindow,
148
private isReadonly: boolean,
149
private readonly overrides: { cellToolbarInteraction: string; globalToolbar: boolean; stickyScrollEnabled: boolean; dragAndDropEnabled: boolean; disableRulers: boolean } | undefined,
150
@IConfigurationService private readonly configurationService: IConfigurationService,
151
@INotebookExecutionStateService private readonly notebookExecutionStateService: INotebookExecutionStateService,
152
@ICodeEditorService private readonly codeEditorService: ICodeEditorService,
153
) {
154
super();
155
const showCellStatusBar = this.configurationService.getValue<ShowCellStatusBarType>(NotebookSetting.showCellStatusBar);
156
const globalToolbar = overrides?.globalToolbar ?? this.configurationService.getValue<boolean | undefined>(NotebookSetting.globalToolbar) ?? true;
157
const stickyScrollEnabled = overrides?.stickyScrollEnabled ?? this.configurationService.getValue<boolean | undefined>(NotebookSetting.stickyScrollEnabled) ?? false;
158
const stickyScrollMode = this._computeStickyScrollModeOption();
159
const consolidatedOutputButton = this.configurationService.getValue<boolean | undefined>(NotebookSetting.consolidatedOutputButton) ?? true;
160
const consolidatedRunButton = this.configurationService.getValue<boolean | undefined>(NotebookSetting.consolidatedRunButton) ?? false;
161
const dragAndDropEnabled = overrides?.dragAndDropEnabled ?? this.configurationService.getValue<boolean | undefined>(NotebookSetting.dragAndDropEnabled) ?? true;
162
const cellToolbarLocation = this.configurationService.getValue<string | { [key: string]: string }>(NotebookSetting.cellToolbarLocation) ?? { 'default': 'right' };
163
const cellToolbarInteraction = overrides?.cellToolbarInteraction ?? this.configurationService.getValue<string>(NotebookSetting.cellToolbarVisibility);
164
const compactView = this.configurationService.getValue<boolean | undefined>(NotebookSetting.compactView) ?? true;
165
const focusIndicator = this._computeFocusIndicatorOption();
166
const insertToolbarPosition = this._computeInsertToolbarPositionOption(this.isReadonly);
167
const insertToolbarAlignment = this._computeInsertToolbarAlignmentOption();
168
const showFoldingControls = this._computeShowFoldingControlsOption();
169
// const { bottomToolbarGap, bottomToolbarHeight } = this._computeBottomToolbarDimensions(compactView, insertToolbarPosition, insertToolbarAlignment);
170
const fontSize = this.configurationService.getValue<number>('editor.fontSize');
171
const markupFontSize = this.configurationService.getValue<number>(NotebookSetting.markupFontSize);
172
const markdownLineHeight = this.configurationService.getValue<number>(NotebookSetting.markdownLineHeight);
173
let editorOptionsCustomizations = this.configurationService.getValue<Partial<{
174
'editor.indentSize': 'tabSize' | number;
175
'editor.tabSize': number;
176
'editor.insertSpaces': boolean;
177
}>>(NotebookSetting.cellEditorOptionsCustomizations) ?? {};
178
editorOptionsCustomizations = isObject(editorOptionsCustomizations) ? editorOptionsCustomizations : {};
179
const interactiveWindowCollapseCodeCells: InteractiveWindowCollapseCodeCells = this.configurationService.getValue(NotebookSetting.interactiveWindowCollapseCodeCells);
180
181
// TOOD @rebornix remove after a few iterations of deprecated setting
182
let outputLineHeightSettingValue: number;
183
const deprecatedOutputLineHeightSetting = this.configurationService.getValue<number>(NotebookSetting.outputLineHeightDeprecated);
184
if (deprecatedOutputLineHeightSetting !== undefined) {
185
this._migrateDeprecatedSetting(NotebookSetting.outputLineHeightDeprecated, NotebookSetting.outputLineHeight);
186
outputLineHeightSettingValue = deprecatedOutputLineHeightSetting;
187
} else {
188
outputLineHeightSettingValue = this.configurationService.getValue<number>(NotebookSetting.outputLineHeight);
189
}
190
191
let outputFontSize: number;
192
const deprecatedOutputFontSizeSetting = this.configurationService.getValue<number>(NotebookSetting.outputFontSizeDeprecated);
193
if (deprecatedOutputFontSizeSetting !== undefined) {
194
this._migrateDeprecatedSetting(NotebookSetting.outputFontSizeDeprecated, NotebookSetting.outputFontSize);
195
outputFontSize = deprecatedOutputFontSizeSetting;
196
} else {
197
outputFontSize = this.configurationService.getValue<number>(NotebookSetting.outputFontSize) || fontSize;
198
}
199
200
let outputFontFamily: string;
201
const deprecatedOutputFontFamilySetting = this.configurationService.getValue<string>(NotebookSetting.outputFontFamilyDeprecated);
202
if (deprecatedOutputFontFamilySetting !== undefined) {
203
this._migrateDeprecatedSetting(NotebookSetting.outputFontFamilyDeprecated, NotebookSetting.outputFontFamily);
204
outputFontFamily = deprecatedOutputFontFamilySetting;
205
} else {
206
outputFontFamily = this.configurationService.getValue<string>(NotebookSetting.outputFontFamily);
207
}
208
209
let outputScrolling: boolean;
210
const deprecatedOutputScrollingSetting = this.configurationService.getValue<boolean>(NotebookSetting.outputScrollingDeprecated);
211
if (deprecatedOutputScrollingSetting !== undefined) {
212
this._migrateDeprecatedSetting(NotebookSetting.outputScrollingDeprecated, NotebookSetting.outputScrolling);
213
outputScrolling = deprecatedOutputScrollingSetting;
214
} else {
215
outputScrolling = this.configurationService.getValue<boolean>(NotebookSetting.outputScrolling);
216
}
217
218
const outputLineHeight = this._computeOutputLineHeight(outputLineHeightSettingValue, outputFontSize);
219
const outputWordWrap = this.configurationService.getValue<boolean>(NotebookSetting.outputWordWrap);
220
const outputLineLimit = this.configurationService.getValue<number>(NotebookSetting.textOutputLineLimit) ?? 30;
221
const linkifyFilePaths = this.configurationService.getValue<boolean>(NotebookSetting.LinkifyOutputFilePaths) ?? true;
222
const minimalErrors = this.configurationService.getValue<boolean>(NotebookSetting.minimalErrorRendering);
223
const markupFontFamily = this.configurationService.getValue<string>(NotebookSetting.markupFontFamily);
224
225
const editorTopPadding = this._computeEditorTopPadding();
226
227
this._layoutConfiguration = {
228
...(compactView ? compactConfigConstants : defaultConfigConstants),
229
cellTopMargin: 6,
230
cellBottomMargin: 6,
231
cellRightMargin: 16,
232
cellStatusBarHeight: 22,
233
cellOutputPadding: 8,
234
markdownPreviewPadding: 8,
235
// bottomToolbarHeight: bottomToolbarHeight,
236
// bottomToolbarGap: bottomToolbarGap,
237
editorToolbarHeight: 0,
238
editorTopPadding: editorTopPadding,
239
editorBottomPadding: 4,
240
editorBottomPaddingWithoutStatusBar: 12,
241
collapsedIndicatorHeight: 28,
242
showCellStatusBar,
243
globalToolbar,
244
stickyScrollEnabled,
245
stickyScrollMode,
246
consolidatedOutputButton,
247
consolidatedRunButton,
248
dragAndDropEnabled,
249
cellToolbarLocation,
250
cellToolbarInteraction,
251
compactView,
252
focusIndicator,
253
insertToolbarPosition,
254
insertToolbarAlignment,
255
showFoldingControls,
256
fontSize,
257
outputFontSize,
258
outputFontFamily,
259
outputLineHeight,
260
markupFontSize,
261
markdownLineHeight,
262
editorOptionsCustomizations,
263
focusIndicatorGap: 3,
264
interactiveWindowCollapseCodeCells,
265
markdownFoldHintHeight: 22,
266
outputScrolling: outputScrolling,
267
outputWordWrap: outputWordWrap,
268
outputLineLimit: outputLineLimit,
269
outputLinkifyFilePaths: linkifyFilePaths,
270
outputMinimalError: minimalErrors,
271
markupFontFamily,
272
disableRulers: overrides?.disableRulers,
273
};
274
275
this._register(this.configurationService.onDidChangeConfiguration(e => {
276
this._updateConfiguration(e);
277
}));
278
}
279
280
updateOptions(isReadonly: boolean) {
281
if (this.isReadonly !== isReadonly) {
282
this.isReadonly = isReadonly;
283
284
this._updateConfiguration({
285
affectsConfiguration(configuration: string): boolean {
286
return configuration === NotebookSetting.insertToolbarLocation;
287
},
288
source: ConfigurationTarget.DEFAULT,
289
affectedKeys: new Set([NotebookSetting.insertToolbarLocation]),
290
change: { keys: [NotebookSetting.insertToolbarLocation], overrides: [] },
291
});
292
}
293
}
294
295
private _computeEditorTopPadding(): number {
296
let decorationTriggeredAdjustment = false;
297
298
const updateEditorTopPadding = (top: number) => {
299
this._editorTopPadding = top;
300
const configuration = Object.assign({}, this._layoutConfiguration);
301
configuration.editorTopPadding = this._editorTopPadding;
302
this._layoutConfiguration = configuration;
303
this._onDidChangeOptions.fire({ editorTopPadding: true });
304
};
305
306
const decorationCheckSet = new Set<string>();
307
const onDidAddDecorationType = (e: string) => {
308
if (decorationTriggeredAdjustment) {
309
return;
310
}
311
312
if (decorationCheckSet.has(e)) {
313
return;
314
}
315
316
try {
317
const options = this.codeEditorService.resolveDecorationOptions(e, true);
318
if (options.afterContentClassName || options.beforeContentClassName) {
319
const cssRules = this.codeEditorService.resolveDecorationCSSRules(e);
320
if (cssRules !== null) {
321
for (let i = 0; i < cssRules.length; i++) {
322
// The following ways to index into the list are equivalent
323
if (
324
((cssRules[i] as CSSStyleRule).selectorText.endsWith('::after') || (cssRules[i] as CSSStyleRule).selectorText.endsWith('::after'))
325
&& (cssRules[i] as CSSStyleRule).cssText.indexOf('top:') > -1
326
) {
327
// there is a `::before` or `::after` text decoration whose position is above or below current line
328
// we at least make sure that the editor top padding is at least one line
329
const editorOptions = this.configurationService.getValue<IEditorOptions>('editor');
330
updateEditorTopPadding(BareFontInfo.createFromRawSettings(editorOptions, PixelRatio.getInstance(this.targetWindow).value).lineHeight + 2);
331
decorationTriggeredAdjustment = true;
332
break;
333
}
334
}
335
}
336
}
337
338
decorationCheckSet.add(e);
339
} catch (_ex) {
340
// do not throw and break notebook
341
}
342
343
};
344
this._register(this.codeEditorService.onDecorationTypeRegistered(onDidAddDecorationType));
345
this.codeEditorService.listDecorationTypes().forEach(onDidAddDecorationType);
346
347
return this._editorTopPadding;
348
}
349
350
private _migrateDeprecatedSetting(deprecatedKey: string, key: string): void {
351
const deprecatedSetting = this.configurationService.inspect(deprecatedKey);
352
353
if (deprecatedSetting.application !== undefined) {
354
this.configurationService.updateValue(deprecatedKey, undefined, ConfigurationTarget.APPLICATION);
355
this.configurationService.updateValue(key, deprecatedSetting.application.value, ConfigurationTarget.APPLICATION);
356
}
357
358
if (deprecatedSetting.user !== undefined) {
359
this.configurationService.updateValue(deprecatedKey, undefined, ConfigurationTarget.USER);
360
this.configurationService.updateValue(key, deprecatedSetting.user.value, ConfigurationTarget.USER);
361
}
362
363
if (deprecatedSetting.userLocal !== undefined) {
364
this.configurationService.updateValue(deprecatedKey, undefined, ConfigurationTarget.USER_LOCAL);
365
this.configurationService.updateValue(key, deprecatedSetting.userLocal.value, ConfigurationTarget.USER_LOCAL);
366
}
367
368
if (deprecatedSetting.userRemote !== undefined) {
369
this.configurationService.updateValue(deprecatedKey, undefined, ConfigurationTarget.USER_REMOTE);
370
this.configurationService.updateValue(key, deprecatedSetting.userRemote.value, ConfigurationTarget.USER_REMOTE);
371
}
372
373
if (deprecatedSetting.workspace !== undefined) {
374
this.configurationService.updateValue(deprecatedKey, undefined, ConfigurationTarget.WORKSPACE);
375
this.configurationService.updateValue(key, deprecatedSetting.workspace.value, ConfigurationTarget.WORKSPACE);
376
}
377
378
if (deprecatedSetting.workspaceFolder !== undefined) {
379
this.configurationService.updateValue(deprecatedKey, undefined, ConfigurationTarget.WORKSPACE_FOLDER);
380
this.configurationService.updateValue(key, deprecatedSetting.workspaceFolder.value, ConfigurationTarget.WORKSPACE_FOLDER);
381
}
382
}
383
384
private _computeOutputLineHeight(lineHeight: number, outputFontSize: number): number {
385
const minimumLineHeight = 9;
386
387
if (lineHeight === 0) {
388
// use editor line height
389
const editorOptions = this.configurationService.getValue<IEditorOptions>('editor');
390
const fontInfo = FontMeasurements.readFontInfo(this.targetWindow, BareFontInfo.createFromRawSettings(editorOptions, PixelRatio.getInstance(this.targetWindow).value));
391
lineHeight = fontInfo.lineHeight;
392
} else if (lineHeight < minimumLineHeight) {
393
// Values too small to be line heights in pixels are in ems.
394
let fontSize = outputFontSize;
395
if (fontSize === 0) {
396
fontSize = this.configurationService.getValue<number>('editor.fontSize');
397
}
398
399
lineHeight = lineHeight * fontSize;
400
}
401
402
// Enforce integer, minimum constraints
403
lineHeight = Math.round(lineHeight);
404
if (lineHeight < minimumLineHeight) {
405
lineHeight = minimumLineHeight;
406
}
407
408
return lineHeight;
409
}
410
411
private _updateConfiguration(e: IConfigurationChangeEvent) {
412
const cellStatusBarVisibility = e.affectsConfiguration(NotebookSetting.showCellStatusBar);
413
const cellToolbarLocation = e.affectsConfiguration(NotebookSetting.cellToolbarLocation);
414
const cellToolbarInteraction = e.affectsConfiguration(NotebookSetting.cellToolbarVisibility);
415
const compactView = e.affectsConfiguration(NotebookSetting.compactView);
416
const focusIndicator = e.affectsConfiguration(NotebookSetting.focusIndicator);
417
const insertToolbarPosition = e.affectsConfiguration(NotebookSetting.insertToolbarLocation);
418
const insertToolbarAlignment = e.affectsConfiguration(NotebookSetting.experimentalInsertToolbarAlignment);
419
const globalToolbar = e.affectsConfiguration(NotebookSetting.globalToolbar);
420
const stickyScrollEnabled = e.affectsConfiguration(NotebookSetting.stickyScrollEnabled);
421
const stickyScrollMode = e.affectsConfiguration(NotebookSetting.stickyScrollMode);
422
const consolidatedOutputButton = e.affectsConfiguration(NotebookSetting.consolidatedOutputButton);
423
const consolidatedRunButton = e.affectsConfiguration(NotebookSetting.consolidatedRunButton);
424
const showFoldingControls = e.affectsConfiguration(NotebookSetting.showFoldingControls);
425
const dragAndDropEnabled = e.affectsConfiguration(NotebookSetting.dragAndDropEnabled);
426
const fontSize = e.affectsConfiguration('editor.fontSize');
427
const outputFontSize = e.affectsConfiguration(NotebookSetting.outputFontSize);
428
const markupFontSize = e.affectsConfiguration(NotebookSetting.markupFontSize);
429
const markdownLineHeight = e.affectsConfiguration(NotebookSetting.markdownLineHeight);
430
const fontFamily = e.affectsConfiguration('editor.fontFamily');
431
const outputFontFamily = e.affectsConfiguration(NotebookSetting.outputFontFamily);
432
const editorOptionsCustomizations = e.affectsConfiguration(NotebookSetting.cellEditorOptionsCustomizations);
433
const interactiveWindowCollapseCodeCells = e.affectsConfiguration(NotebookSetting.interactiveWindowCollapseCodeCells);
434
const outputLineHeight = e.affectsConfiguration(NotebookSetting.outputLineHeight);
435
const outputScrolling = e.affectsConfiguration(NotebookSetting.outputScrolling);
436
const outputWordWrap = e.affectsConfiguration(NotebookSetting.outputWordWrap);
437
const outputLinkifyFilePaths = e.affectsConfiguration(NotebookSetting.LinkifyOutputFilePaths);
438
const minimalError = e.affectsConfiguration(NotebookSetting.minimalErrorRendering);
439
const markupFontFamily = e.affectsConfiguration(NotebookSetting.markupFontFamily);
440
441
if (
442
!cellStatusBarVisibility
443
&& !cellToolbarLocation
444
&& !cellToolbarInteraction
445
&& !compactView
446
&& !focusIndicator
447
&& !insertToolbarPosition
448
&& !insertToolbarAlignment
449
&& !globalToolbar
450
&& !stickyScrollEnabled
451
&& !stickyScrollMode
452
&& !consolidatedOutputButton
453
&& !consolidatedRunButton
454
&& !showFoldingControls
455
&& !dragAndDropEnabled
456
&& !fontSize
457
&& !outputFontSize
458
&& !markupFontSize
459
&& !markdownLineHeight
460
&& !fontFamily
461
&& !outputFontFamily
462
&& !editorOptionsCustomizations
463
&& !interactiveWindowCollapseCodeCells
464
&& !outputLineHeight
465
&& !outputScrolling
466
&& !outputWordWrap
467
&& !outputLinkifyFilePaths
468
&& !minimalError
469
&& !markupFontFamily) {
470
return;
471
}
472
473
let configuration = Object.assign({}, this._layoutConfiguration);
474
475
if (cellStatusBarVisibility) {
476
configuration.showCellStatusBar = this.configurationService.getValue<ShowCellStatusBarType>(NotebookSetting.showCellStatusBar);
477
}
478
479
if (cellToolbarLocation) {
480
configuration.cellToolbarLocation = this.configurationService.getValue<string | { [key: string]: string }>(NotebookSetting.cellToolbarLocation) ?? { 'default': 'right' };
481
}
482
483
if (cellToolbarInteraction && !this.overrides?.cellToolbarInteraction) {
484
configuration.cellToolbarInteraction = this.configurationService.getValue<string>(NotebookSetting.cellToolbarVisibility);
485
}
486
487
if (focusIndicator) {
488
configuration.focusIndicator = this._computeFocusIndicatorOption();
489
}
490
491
if (compactView) {
492
const compactViewValue = this.configurationService.getValue<boolean | undefined>(NotebookSetting.compactView) ?? true;
493
configuration = Object.assign(configuration, {
494
...(compactViewValue ? compactConfigConstants : defaultConfigConstants),
495
});
496
configuration.compactView = compactViewValue;
497
}
498
499
if (insertToolbarAlignment) {
500
configuration.insertToolbarAlignment = this._computeInsertToolbarAlignmentOption();
501
}
502
503
if (insertToolbarPosition) {
504
configuration.insertToolbarPosition = this._computeInsertToolbarPositionOption(this.isReadonly);
505
}
506
507
if (globalToolbar && this.overrides?.globalToolbar === undefined) {
508
configuration.globalToolbar = this.configurationService.getValue<boolean>(NotebookSetting.globalToolbar) ?? true;
509
}
510
511
if (stickyScrollEnabled && this.overrides?.stickyScrollEnabled === undefined) {
512
configuration.stickyScrollEnabled = this.configurationService.getValue<boolean>(NotebookSetting.stickyScrollEnabled) ?? false;
513
}
514
515
if (stickyScrollMode) {
516
configuration.stickyScrollMode = this.configurationService.getValue<'flat' | 'indented'>(NotebookSetting.stickyScrollMode) ?? 'flat';
517
}
518
519
if (consolidatedOutputButton) {
520
configuration.consolidatedOutputButton = this.configurationService.getValue<boolean>(NotebookSetting.consolidatedOutputButton) ?? true;
521
}
522
523
if (consolidatedRunButton) {
524
configuration.consolidatedRunButton = this.configurationService.getValue<boolean>(NotebookSetting.consolidatedRunButton) ?? true;
525
}
526
527
if (showFoldingControls) {
528
configuration.showFoldingControls = this._computeShowFoldingControlsOption();
529
}
530
531
if (dragAndDropEnabled) {
532
configuration.dragAndDropEnabled = this.configurationService.getValue<boolean>(NotebookSetting.dragAndDropEnabled) ?? true;
533
}
534
535
if (fontSize) {
536
configuration.fontSize = this.configurationService.getValue<number>('editor.fontSize');
537
}
538
539
if (outputFontSize || fontSize) {
540
configuration.outputFontSize = this.configurationService.getValue<number>(NotebookSetting.outputFontSize) || configuration.fontSize;
541
}
542
543
if (markupFontSize) {
544
configuration.markupFontSize = this.configurationService.getValue<number>(NotebookSetting.markupFontSize);
545
}
546
547
if (markdownLineHeight) {
548
configuration.markdownLineHeight = this.configurationService.getValue<number>(NotebookSetting.markdownLineHeight);
549
}
550
551
if (outputFontFamily) {
552
configuration.outputFontFamily = this.configurationService.getValue<string>(NotebookSetting.outputFontFamily);
553
}
554
555
if (editorOptionsCustomizations) {
556
configuration.editorOptionsCustomizations = this.configurationService.getValue(NotebookSetting.cellEditorOptionsCustomizations);
557
}
558
559
if (interactiveWindowCollapseCodeCells) {
560
configuration.interactiveWindowCollapseCodeCells = this.configurationService.getValue(NotebookSetting.interactiveWindowCollapseCodeCells);
561
}
562
563
if (outputLineHeight || fontSize || outputFontSize) {
564
const lineHeight = this.configurationService.getValue<number>(NotebookSetting.outputLineHeight);
565
configuration.outputLineHeight = this._computeOutputLineHeight(lineHeight, configuration.outputFontSize);
566
}
567
568
if (outputWordWrap) {
569
configuration.outputWordWrap = this.configurationService.getValue<boolean>(NotebookSetting.outputWordWrap);
570
}
571
572
if (outputScrolling) {
573
configuration.outputScrolling = this.configurationService.getValue<boolean>(NotebookSetting.outputScrolling);
574
}
575
576
if (outputLinkifyFilePaths) {
577
configuration.outputLinkifyFilePaths = this.configurationService.getValue<boolean>(NotebookSetting.LinkifyOutputFilePaths);
578
}
579
580
if (minimalError) {
581
configuration.outputMinimalError = this.configurationService.getValue<boolean>(NotebookSetting.minimalErrorRendering);
582
}
583
584
if (markupFontFamily) {
585
configuration.markupFontFamily = this.configurationService.getValue<string>(NotebookSetting.markupFontFamily);
586
}
587
588
this._layoutConfiguration = Object.freeze(configuration);
589
590
// trigger event
591
this._onDidChangeOptions.fire({
592
cellStatusBarVisibility,
593
cellToolbarLocation,
594
cellToolbarInteraction,
595
compactView,
596
focusIndicator,
597
insertToolbarPosition,
598
insertToolbarAlignment,
599
globalToolbar,
600
stickyScrollEnabled,
601
stickyScrollMode,
602
showFoldingControls,
603
consolidatedOutputButton,
604
consolidatedRunButton,
605
dragAndDropEnabled,
606
fontSize,
607
outputFontSize,
608
markupFontSize,
609
markdownLineHeight,
610
fontFamily,
611
outputFontFamily,
612
editorOptionsCustomizations,
613
interactiveWindowCollapseCodeCells,
614
outputLineHeight,
615
outputScrolling,
616
outputWordWrap,
617
outputLinkifyFilePaths,
618
minimalError,
619
markupFontFamily
620
});
621
}
622
623
private _computeInsertToolbarPositionOption(isReadOnly: boolean) {
624
return isReadOnly ? 'hidden' : this.configurationService.getValue<'betweenCells' | 'notebookToolbar' | 'both' | 'hidden'>(NotebookSetting.insertToolbarLocation) ?? 'both';
625
}
626
627
private _computeInsertToolbarAlignmentOption() {
628
return this.configurationService.getValue<'left' | 'center'>(NotebookSetting.experimentalInsertToolbarAlignment) ?? 'center';
629
}
630
631
private _computeShowFoldingControlsOption() {
632
return this.configurationService.getValue<'always' | 'never' | 'mouseover'>(NotebookSetting.showFoldingControls) ?? 'mouseover';
633
}
634
635
private _computeFocusIndicatorOption() {
636
return this.configurationService.getValue<'border' | 'gutter'>(NotebookSetting.focusIndicator) ?? 'gutter';
637
}
638
639
private _computeStickyScrollModeOption() {
640
return this.configurationService.getValue<'flat' | 'indented'>(NotebookSetting.stickyScrollMode) ?? 'flat';
641
}
642
643
getCellCollapseDefault(): NotebookCellDefaultCollapseConfig {
644
return this._layoutConfiguration.interactiveWindowCollapseCodeCells === 'never' ?
645
{
646
codeCell: {
647
inputCollapsed: false
648
}
649
} : {
650
codeCell: {
651
inputCollapsed: true
652
}
653
};
654
}
655
656
getLayoutConfiguration(): NotebookLayoutConfiguration & NotebookDisplayOptions {
657
return this._layoutConfiguration;
658
}
659
660
getDisplayOptions(): NotebookDisplayOptions {
661
return this._layoutConfiguration;
662
}
663
664
getCellEditorContainerLeftMargin() {
665
const {
666
codeCellLeftMargin,
667
cellRunGutter
668
} = this._layoutConfiguration;
669
return codeCellLeftMargin + cellRunGutter;
670
}
671
672
computeCollapsedMarkdownCellHeight(viewType: string): number {
673
const { bottomToolbarGap } = this.computeBottomToolbarDimensions(viewType);
674
return this._layoutConfiguration.markdownCellTopMargin
675
+ this._layoutConfiguration.collapsedIndicatorHeight
676
+ bottomToolbarGap
677
+ this._layoutConfiguration.markdownCellBottomMargin;
678
}
679
680
computeBottomToolbarOffset(totalHeight: number, viewType: string) {
681
const { bottomToolbarGap, bottomToolbarHeight } = this.computeBottomToolbarDimensions(viewType);
682
683
return totalHeight
684
- bottomToolbarGap
685
- bottomToolbarHeight / 2;
686
}
687
688
computeCodeCellEditorWidth(outerWidth: number): number {
689
return outerWidth - (
690
this._layoutConfiguration.codeCellLeftMargin
691
+ this._layoutConfiguration.cellRunGutter
692
+ this._layoutConfiguration.cellRightMargin
693
);
694
}
695
696
computeMarkdownCellEditorWidth(outerWidth: number): number {
697
return outerWidth
698
- this._layoutConfiguration.markdownCellGutter
699
- this._layoutConfiguration.markdownCellLeftMargin
700
- this._layoutConfiguration.cellRightMargin;
701
}
702
703
computeStatusBarHeight(): number {
704
return this._layoutConfiguration.cellStatusBarHeight;
705
}
706
707
private _computeBottomToolbarDimensions(compactView: boolean, insertToolbarPosition: 'betweenCells' | 'notebookToolbar' | 'both' | 'hidden', insertToolbarAlignment: 'left' | 'center', cellToolbar: 'right' | 'left' | 'hidden'): { bottomToolbarGap: number; bottomToolbarHeight: number } {
708
if (insertToolbarAlignment === 'left' || cellToolbar !== 'hidden') {
709
return {
710
bottomToolbarGap: 18,
711
bottomToolbarHeight: 18
712
};
713
}
714
715
if (insertToolbarPosition === 'betweenCells' || insertToolbarPosition === 'both') {
716
return compactView ? {
717
bottomToolbarGap: 12,
718
bottomToolbarHeight: 20
719
} : {
720
bottomToolbarGap: 20,
721
bottomToolbarHeight: 20
722
};
723
} else {
724
return {
725
bottomToolbarGap: 0,
726
bottomToolbarHeight: 0
727
};
728
}
729
}
730
731
computeBottomToolbarDimensions(viewType?: string): { bottomToolbarGap: number; bottomToolbarHeight: number } {
732
const configuration = this._layoutConfiguration;
733
const cellToolbarPosition = this.computeCellToolbarLocation(viewType);
734
const { bottomToolbarGap, bottomToolbarHeight } = this._computeBottomToolbarDimensions(configuration.compactView, configuration.insertToolbarPosition, configuration.insertToolbarAlignment, cellToolbarPosition);
735
return {
736
bottomToolbarGap,
737
bottomToolbarHeight
738
};
739
}
740
741
computeCellToolbarLocation(viewType?: string): 'right' | 'left' | 'hidden' {
742
const cellToolbarLocation = this._layoutConfiguration.cellToolbarLocation;
743
744
if (typeof cellToolbarLocation === 'string') {
745
if (cellToolbarLocation === 'left' || cellToolbarLocation === 'right' || cellToolbarLocation === 'hidden') {
746
return cellToolbarLocation;
747
}
748
} else {
749
if (viewType) {
750
const notebookSpecificSetting = cellToolbarLocation[viewType] ?? cellToolbarLocation['default'];
751
let cellToolbarLocationForCurrentView: 'right' | 'left' | 'hidden' = 'right';
752
753
switch (notebookSpecificSetting) {
754
case 'left':
755
cellToolbarLocationForCurrentView = 'left';
756
break;
757
case 'right':
758
cellToolbarLocationForCurrentView = 'right';
759
break;
760
case 'hidden':
761
cellToolbarLocationForCurrentView = 'hidden';
762
break;
763
default:
764
cellToolbarLocationForCurrentView = 'right';
765
break;
766
}
767
768
return cellToolbarLocationForCurrentView;
769
}
770
}
771
772
return 'right';
773
}
774
775
computeTopInsertToolbarHeight(viewType?: string): number {
776
if (this._layoutConfiguration.insertToolbarPosition === 'betweenCells' || this._layoutConfiguration.insertToolbarPosition === 'both') {
777
return SCROLLABLE_ELEMENT_PADDING_TOP;
778
}
779
780
const cellToolbarLocation = this.computeCellToolbarLocation(viewType);
781
782
if (cellToolbarLocation === 'left' || cellToolbarLocation === 'right') {
783
return SCROLLABLE_ELEMENT_PADDING_TOP;
784
}
785
786
return 0;
787
}
788
789
computeEditorPadding(internalMetadata: NotebookCellInternalMetadata, cellUri: URI) {
790
return {
791
top: this._editorTopPadding,
792
bottom: this.statusBarIsVisible(internalMetadata, cellUri)
793
? this._layoutConfiguration.editorBottomPadding
794
: this._layoutConfiguration.editorBottomPaddingWithoutStatusBar
795
};
796
}
797
798
799
computeEditorStatusbarHeight(internalMetadata: NotebookCellInternalMetadata, cellUri: URI) {
800
return this.statusBarIsVisible(internalMetadata, cellUri) ? this.computeStatusBarHeight() : 0;
801
}
802
803
private statusBarIsVisible(internalMetadata: NotebookCellInternalMetadata, cellUri: URI): boolean {
804
const exe = this.notebookExecutionStateService.getCellExecution(cellUri);
805
if (this._layoutConfiguration.showCellStatusBar === 'visible') {
806
return true;
807
} else if (this._layoutConfiguration.showCellStatusBar === 'visibleAfterExecute') {
808
return typeof internalMetadata.lastRunSuccess === 'boolean' || exe !== undefined;
809
} else {
810
return false;
811
}
812
}
813
814
computeWebviewOptions() {
815
return {
816
outputNodePadding: this._layoutConfiguration.cellOutputPadding,
817
outputNodeLeftPadding: this._layoutConfiguration.cellOutputPadding,
818
previewNodePadding: this._layoutConfiguration.markdownPreviewPadding,
819
markdownLeftMargin: this._layoutConfiguration.markdownCellGutter + this._layoutConfiguration.markdownCellLeftMargin,
820
leftMargin: this._layoutConfiguration.codeCellLeftMargin,
821
rightMargin: this._layoutConfiguration.cellRightMargin,
822
runGutter: this._layoutConfiguration.cellRunGutter,
823
dragAndDropEnabled: this._layoutConfiguration.dragAndDropEnabled,
824
fontSize: this._layoutConfiguration.fontSize,
825
outputFontSize: this._layoutConfiguration.outputFontSize,
826
outputFontFamily: this._layoutConfiguration.outputFontFamily,
827
markupFontSize: this._layoutConfiguration.markupFontSize,
828
markdownLineHeight: this._layoutConfiguration.markdownLineHeight,
829
outputLineHeight: this._layoutConfiguration.outputLineHeight,
830
outputScrolling: this._layoutConfiguration.outputScrolling,
831
outputWordWrap: this._layoutConfiguration.outputWordWrap,
832
outputLineLimit: this._layoutConfiguration.outputLineLimit,
833
outputLinkifyFilePaths: this._layoutConfiguration.outputLinkifyFilePaths,
834
minimalError: this._layoutConfiguration.outputMinimalError,
835
markupFontFamily: this._layoutConfiguration.markupFontFamily
836
};
837
}
838
839
computeDiffWebviewOptions() {
840
return {
841
outputNodePadding: this._layoutConfiguration.cellOutputPadding,
842
outputNodeLeftPadding: 0,
843
previewNodePadding: this._layoutConfiguration.markdownPreviewPadding,
844
markdownLeftMargin: 0,
845
leftMargin: 32,
846
rightMargin: 0,
847
runGutter: 0,
848
dragAndDropEnabled: false,
849
fontSize: this._layoutConfiguration.fontSize,
850
outputFontSize: this._layoutConfiguration.outputFontSize,
851
outputFontFamily: this._layoutConfiguration.outputFontFamily,
852
markupFontSize: this._layoutConfiguration.markupFontSize,
853
markdownLineHeight: this._layoutConfiguration.markdownLineHeight,
854
outputLineHeight: this._layoutConfiguration.outputLineHeight,
855
outputScrolling: this._layoutConfiguration.outputScrolling,
856
outputWordWrap: this._layoutConfiguration.outputWordWrap,
857
outputLineLimit: this._layoutConfiguration.outputLineLimit,
858
outputLinkifyFilePaths: false,
859
minimalError: false,
860
markupFontFamily: this._layoutConfiguration.markupFontFamily
861
};
862
}
863
864
computeIndicatorPosition(totalHeight: number, foldHintHeight: number, viewType?: string) {
865
const { bottomToolbarGap } = this.computeBottomToolbarDimensions(viewType);
866
867
return {
868
bottomIndicatorTop: totalHeight - bottomToolbarGap - this._layoutConfiguration.cellBottomMargin - foldHintHeight,
869
verticalIndicatorHeight: totalHeight - bottomToolbarGap - foldHintHeight
870
};
871
}
872
}
873
874