Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/notebook/browser/notebook.contribution.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 { Schemas } from '../../../../base/common/network.js';
7
import { IDisposable, Disposable, DisposableStore, dispose } from '../../../../base/common/lifecycle.js';
8
import { parse } from '../../../../base/common/marshalling.js';
9
import { extname, isEqual } from '../../../../base/common/resources.js';
10
import { assertType } from '../../../../base/common/types.js';
11
import { URI } from '../../../../base/common/uri.js';
12
import { toFormattedString } from '../../../../base/common/jsonFormatter.js';
13
import { ITextModel, ITextBufferFactory, ITextBuffer } from '../../../../editor/common/model.js';
14
import { IModelService } from '../../../../editor/common/services/model.js';
15
import { ILanguageSelection, ILanguageService } from '../../../../editor/common/languages/language.js';
16
import { ITextModelContentProvider, ITextModelService } from '../../../../editor/common/services/resolverService.js';
17
import * as nls from '../../../../nls.js';
18
import { Extensions, IConfigurationPropertySchema, IConfigurationRegistry } from '../../../../platform/configuration/common/configurationRegistry.js';
19
import { SyncDescriptor } from '../../../../platform/instantiation/common/descriptors.js';
20
import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';
21
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
22
import { LifecyclePhase } from '../../../services/lifecycle/common/lifecycle.js';
23
import { Registry } from '../../../../platform/registry/common/platform.js';
24
import { EditorPaneDescriptor, IEditorPaneRegistry } from '../../../browser/editor.js';
25
import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry, WorkbenchPhase, registerWorkbenchContribution2 } from '../../../common/contributions.js';
26
import { IEditorSerializer, IEditorFactoryRegistry, EditorExtensions } from '../../../common/editor.js';
27
import { EditorInput } from '../../../common/editor/editorInput.js';
28
import { NotebookEditor } from './notebookEditor.js';
29
import { NotebookEditorInput, NotebookEditorInputOptions } from '../common/notebookEditorInput.js';
30
import { INotebookService } from '../common/notebookService.js';
31
import { NotebookService } from './services/notebookServiceImpl.js';
32
import { CellKind, CellUri, IResolvedNotebookEditorModel, NotebookWorkingCopyTypeIdentifier, NotebookSetting, ICellOutput, ICell, NotebookCellsChangeType, NotebookMetadataUri } from '../common/notebookCommon.js';
33
import { IEditorService } from '../../../services/editor/common/editorService.js';
34
import { IUndoRedoService } from '../../../../platform/undoRedo/common/undoRedo.js';
35
import { INotebookEditorModelResolverService } from '../common/notebookEditorModelResolverService.js';
36
import { NotebookDiffEditorInput } from '../common/notebookDiffEditorInput.js';
37
import { NotebookTextDiffEditor } from './diff/notebookDiffEditor.js';
38
import { INotebookEditorWorkerService } from '../common/services/notebookWorkerService.js';
39
import { NotebookEditorWorkerServiceImpl } from './services/notebookWorkerServiceImpl.js';
40
import { INotebookCellStatusBarService } from '../common/notebookCellStatusBarService.js';
41
import { NotebookCellStatusBarService } from './services/notebookCellStatusBarServiceImpl.js';
42
import { INotebookEditorService } from './services/notebookEditorService.js';
43
import { NotebookEditorWidgetService } from './services/notebookEditorServiceImpl.js';
44
import { IJSONContributionRegistry, Extensions as JSONExtensions } from '../../../../platform/jsonschemas/common/jsonContributionRegistry.js';
45
import { IJSONSchema, IJSONSchemaMap } from '../../../../base/common/jsonSchema.js';
46
import { Event } from '../../../../base/common/event.js';
47
import { getFormattedOutputJSON, getStreamOutputData } from './diff/diffElementViewModel.js';
48
import { NotebookModelResolverServiceImpl } from '../common/notebookEditorModelResolverServiceImpl.js';
49
import { INotebookKernelHistoryService, INotebookKernelService } from '../common/notebookKernelService.js';
50
import { NotebookKernelService } from './services/notebookKernelServiceImpl.js';
51
import { IWorkingCopyIdentifier } from '../../../services/workingCopy/common/workingCopy.js';
52
import { IResourceEditorInput } from '../../../../platform/editor/common/editor.js';
53
import { IExtensionService } from '../../../services/extensions/common/extensions.js';
54
import { IWorkingCopyEditorHandler, IWorkingCopyEditorService } from '../../../services/workingCopy/common/workingCopyEditorService.js';
55
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
56
import { ILabelService } from '../../../../platform/label/common/label.js';
57
import { IEditorGroupsService } from '../../../services/editor/common/editorGroupsService.js';
58
import { NotebookRendererMessagingService } from './services/notebookRendererMessagingServiceImpl.js';
59
import { INotebookRendererMessagingService } from '../common/notebookRendererMessagingService.js';
60
import { INotebookCellOutlineDataSourceFactory, NotebookCellOutlineDataSourceFactory } from './viewModel/notebookOutlineDataSourceFactory.js';
61
62
// Editor Controller
63
import './controller/coreActions.js';
64
import './controller/insertCellActions.js';
65
import './controller/executeActions.js';
66
import './controller/sectionActions.js';
67
import './controller/layoutActions.js';
68
import './controller/editActions.js';
69
import './controller/cellOutputActions.js';
70
import './controller/apiActions.js';
71
import './controller/foldingController.js';
72
import './controller/chat/notebook.chat.contribution.js';
73
import './controller/variablesActions.js';
74
75
// Editor Contribution
76
import './contrib/editorHint/emptyCellEditorHint.js';
77
import './contrib/clipboard/notebookClipboard.js';
78
import './contrib/find/notebookFind.js';
79
import './contrib/format/formatting.js';
80
import './contrib/saveParticipants/saveParticipants.js';
81
import './contrib/gettingStarted/notebookGettingStarted.js';
82
import './contrib/layout/layoutActions.js';
83
import './contrib/marker/markerProvider.js';
84
import './contrib/navigation/arrow.js';
85
import './contrib/outline/notebookOutline.js';
86
import './contrib/profile/notebookProfile.js';
87
import './contrib/cellStatusBar/statusBarProviders.js';
88
import './contrib/cellStatusBar/contributedStatusBarItemController.js';
89
import './contrib/cellStatusBar/executionStatusBarItemController.js';
90
import './contrib/editorStatusBar/editorStatusBar.js';
91
import './contrib/undoRedo/notebookUndoRedo.js';
92
import './contrib/cellCommands/cellCommands.js';
93
import './contrib/viewportWarmup/viewportWarmup.js';
94
import './contrib/troubleshoot/layout.js';
95
import './contrib/debug/notebookBreakpoints.js';
96
import './contrib/debug/notebookCellPausing.js';
97
import './contrib/debug/notebookDebugDecorations.js';
98
import './contrib/execute/executionEditorProgress.js';
99
import './contrib/kernelDetection/notebookKernelDetection.js';
100
import './contrib/cellDiagnostics/cellDiagnostics.js';
101
import './contrib/multicursor/notebookMulticursor.js';
102
import './contrib/multicursor/notebookSelectionHighlight.js';
103
import './contrib/notebookVariables/notebookInlineVariables.js';
104
105
// Diff Editor Contribution
106
import './diff/notebookDiffActions.js';
107
108
// Services
109
import { editorOptionsRegistry } from '../../../../editor/common/config/editorOptions.js';
110
import { NotebookExecutionStateService } from './services/notebookExecutionStateServiceImpl.js';
111
import { NotebookExecutionService } from './services/notebookExecutionServiceImpl.js';
112
import { INotebookExecutionService } from '../common/notebookExecutionService.js';
113
import { INotebookKeymapService } from '../common/notebookKeymapService.js';
114
import { NotebookKeymapService } from './services/notebookKeymapServiceImpl.js';
115
import { PLAINTEXT_LANGUAGE_ID } from '../../../../editor/common/languages/modesRegistry.js';
116
import { INotebookExecutionStateService } from '../common/notebookExecutionStateService.js';
117
import { ILanguageFeaturesService } from '../../../../editor/common/services/languageFeatures.js';
118
import { NotebookInfo } from '../../../../editor/common/languageFeatureRegistry.js';
119
import { COMMENTEDITOR_DECORATION_KEY } from '../../comments/browser/commentReply.js';
120
import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js';
121
import { NotebookKernelHistoryService } from './services/notebookKernelHistoryServiceImpl.js';
122
import { INotebookLoggingService } from '../common/notebookLoggingService.js';
123
import { NotebookLoggingService } from './services/notebookLoggingServiceImpl.js';
124
import product from '../../../../platform/product/common/product.js';
125
import { NotebookVariables } from './contrib/notebookVariables/notebookVariables.js';
126
import { AccessibleViewRegistry } from '../../../../platform/accessibility/browser/accessibleViewRegistry.js';
127
import { NotebookAccessibilityHelp } from './notebookAccessibilityHelp.js';
128
import { NotebookAccessibleView } from './notebookAccessibleView.js';
129
import { DefaultFormatter } from '../../format/browser/formatActionsMultiple.js';
130
import { NotebookMultiTextDiffEditor } from './diff/notebookMultiDiffEditor.js';
131
import { NotebookMultiDiffEditorInput } from './diff/notebookMultiDiffEditorInput.js';
132
import { getFormattedMetadataJSON } from '../common/model/notebookCellTextModel.js';
133
import { INotebookOutlineEntryFactory, NotebookOutlineEntryFactory } from './viewModel/notebookOutlineEntryFactory.js';
134
import { getFormattedNotebookMetadataJSON } from '../common/model/notebookMetadataTextModel.js';
135
import { NotebookOutputEditor } from './outputEditor/notebookOutputEditor.js';
136
import { NotebookOutputEditorInput } from './outputEditor/notebookOutputEditorInput.js';
137
138
/*--------------------------------------------------------------------------------------------- */
139
140
Registry.as<IEditorPaneRegistry>(EditorExtensions.EditorPane).registerEditorPane(
141
EditorPaneDescriptor.create(
142
NotebookEditor,
143
NotebookEditor.ID,
144
'Notebook Editor'
145
),
146
[
147
new SyncDescriptor(NotebookEditorInput)
148
]
149
);
150
151
Registry.as<IEditorPaneRegistry>(EditorExtensions.EditorPane).registerEditorPane(
152
EditorPaneDescriptor.create(
153
NotebookTextDiffEditor,
154
NotebookTextDiffEditor.ID,
155
'Notebook Diff Editor'
156
),
157
[
158
new SyncDescriptor(NotebookDiffEditorInput)
159
]
160
);
161
162
Registry.as<IEditorPaneRegistry>(EditorExtensions.EditorPane).registerEditorPane(
163
EditorPaneDescriptor.create(
164
NotebookOutputEditor,
165
NotebookOutputEditor.ID,
166
'Notebook Output Editor'
167
),
168
[
169
new SyncDescriptor(NotebookOutputEditorInput)
170
]
171
);
172
173
Registry.as<IEditorPaneRegistry>(EditorExtensions.EditorPane).registerEditorPane(
174
EditorPaneDescriptor.create(
175
NotebookMultiTextDiffEditor,
176
NotebookMultiTextDiffEditor.ID,
177
'Notebook Diff Editor'
178
),
179
[
180
new SyncDescriptor(NotebookMultiDiffEditorInput)
181
]
182
);
183
184
class NotebookDiffEditorSerializer implements IEditorSerializer {
185
constructor(@IConfigurationService private readonly _configurationService: IConfigurationService) { }
186
canSerialize(): boolean {
187
return true;
188
}
189
190
serialize(input: EditorInput): string {
191
assertType(input instanceof NotebookDiffEditorInput);
192
return JSON.stringify({
193
resource: input.resource,
194
originalResource: input.original.resource,
195
name: input.getName(),
196
originalName: input.original.getName(),
197
textDiffName: input.getName(),
198
viewType: input.viewType,
199
});
200
}
201
202
deserialize(instantiationService: IInstantiationService, raw: string) {
203
type Data = { resource: URI; originalResource: URI; name: string; originalName: string; viewType: string; textDiffName: string | undefined; group: number };
204
const data = <Data>parse(raw);
205
if (!data) {
206
return undefined;
207
}
208
const { resource, originalResource, name, viewType } = data;
209
if (!data || !URI.isUri(resource) || !URI.isUri(originalResource) || typeof name !== 'string' || typeof viewType !== 'string') {
210
return undefined;
211
}
212
213
if (this._configurationService.getValue('notebook.experimental.enableNewDiffEditor')) {
214
return NotebookMultiDiffEditorInput.create(instantiationService, resource, name, undefined, originalResource, viewType);
215
} else {
216
return NotebookDiffEditorInput.create(instantiationService, resource, name, undefined, originalResource, viewType);
217
}
218
}
219
220
static canResolveBackup(editorInput: EditorInput, backupResource: URI): boolean {
221
return false;
222
}
223
224
}
225
type SerializedNotebookEditorData = { resource: URI; preferredResource: URI; viewType: string; options?: NotebookEditorInputOptions };
226
class NotebookEditorSerializer implements IEditorSerializer {
227
canSerialize(input: EditorInput): boolean {
228
return input.typeId === NotebookEditorInput.ID;
229
}
230
serialize(input: EditorInput): string {
231
assertType(input instanceof NotebookEditorInput);
232
const data: SerializedNotebookEditorData = {
233
resource: input.resource,
234
preferredResource: input.preferredResource,
235
viewType: input.viewType,
236
options: input.options
237
};
238
return JSON.stringify(data);
239
}
240
deserialize(instantiationService: IInstantiationService, raw: string) {
241
const data = <SerializedNotebookEditorData>parse(raw);
242
if (!data) {
243
return undefined;
244
}
245
const { resource, preferredResource, viewType, options } = data;
246
if (!data || !URI.isUri(resource) || typeof viewType !== 'string') {
247
return undefined;
248
}
249
250
const input = NotebookEditorInput.getOrCreate(instantiationService, resource, preferredResource, viewType, options);
251
return input;
252
}
253
}
254
255
export type SerializedNotebookOutputEditorData = { notebookUri: URI; cellIndex: number; outputIndex: number };
256
class NotebookOutputEditorSerializer implements IEditorSerializer {
257
canSerialize(input: EditorInput): boolean {
258
return input.typeId === NotebookOutputEditorInput.ID;
259
}
260
serialize(input: EditorInput): string | undefined {
261
assertType(input instanceof NotebookOutputEditorInput);
262
263
const data = input.getSerializedData(); // in case of cell movement etc get latest indices
264
if (!data) {
265
return undefined;
266
}
267
268
return JSON.stringify(data);
269
}
270
deserialize(instantiationService: IInstantiationService, raw: string): EditorInput | undefined {
271
const data = <SerializedNotebookOutputEditorData>parse(raw);
272
if (!data) {
273
return undefined;
274
}
275
276
const input = instantiationService.createInstance(NotebookOutputEditorInput, data.notebookUri, data.cellIndex, undefined, data.outputIndex);
277
return input;
278
}
279
}
280
281
Registry.as<IEditorFactoryRegistry>(EditorExtensions.EditorFactory).registerEditorSerializer(
282
NotebookEditorInput.ID,
283
NotebookEditorSerializer
284
);
285
286
Registry.as<IEditorFactoryRegistry>(EditorExtensions.EditorFactory).registerEditorSerializer(
287
NotebookDiffEditorInput.ID,
288
NotebookDiffEditorSerializer
289
);
290
291
Registry.as<IEditorFactoryRegistry>(EditorExtensions.EditorFactory).registerEditorSerializer(
292
NotebookOutputEditorInput.ID,
293
NotebookOutputEditorSerializer
294
);
295
296
export class NotebookContribution extends Disposable implements IWorkbenchContribution {
297
298
static readonly ID = 'workbench.contrib.notebook';
299
300
private _uriComparisonKeyComputer?: IDisposable;
301
302
constructor(
303
@IUndoRedoService undoRedoService: IUndoRedoService,
304
@IConfigurationService configurationService: IConfigurationService,
305
@ICodeEditorService private readonly codeEditorService: ICodeEditorService,
306
) {
307
super();
308
309
this.updateCellUndoRedoComparisonKey(configurationService, undoRedoService);
310
311
// Watch for changes to undoRedoPerCell setting
312
this._register(configurationService.onDidChangeConfiguration(e => {
313
if (e.affectsConfiguration(NotebookSetting.undoRedoPerCell)) {
314
this.updateCellUndoRedoComparisonKey(configurationService, undoRedoService);
315
}
316
}));
317
318
// register comment decoration
319
this.codeEditorService.registerDecorationType('comment-controller', COMMENTEDITOR_DECORATION_KEY, {});
320
}
321
322
// Add or remove the cell undo redo comparison key based on the user setting
323
private updateCellUndoRedoComparisonKey(configurationService: IConfigurationService, undoRedoService: IUndoRedoService) {
324
const undoRedoPerCell = configurationService.getValue<boolean>(NotebookSetting.undoRedoPerCell);
325
326
if (!undoRedoPerCell) {
327
// Add comparison key to map cell => main document
328
if (!this._uriComparisonKeyComputer) {
329
this._uriComparisonKeyComputer = undoRedoService.registerUriComparisonKeyComputer(CellUri.scheme, {
330
getComparisonKey: (uri: URI): string => {
331
if (undoRedoPerCell) {
332
return uri.toString();
333
}
334
return NotebookContribution._getCellUndoRedoComparisonKey(uri);
335
}
336
});
337
}
338
} else {
339
// Dispose comparison key
340
this._uriComparisonKeyComputer?.dispose();
341
this._uriComparisonKeyComputer = undefined;
342
}
343
}
344
345
private static _getCellUndoRedoComparisonKey(uri: URI) {
346
const data = CellUri.parse(uri);
347
if (!data) {
348
return uri.toString();
349
}
350
351
return data.notebook.toString();
352
}
353
354
override dispose(): void {
355
super.dispose();
356
this._uriComparisonKeyComputer?.dispose();
357
}
358
}
359
360
class CellContentProvider implements ITextModelContentProvider {
361
362
static readonly ID = 'workbench.contrib.cellContentProvider';
363
364
private readonly _registration: IDisposable;
365
366
constructor(
367
@ITextModelService textModelService: ITextModelService,
368
@IModelService private readonly _modelService: IModelService,
369
@ILanguageService private readonly _languageService: ILanguageService,
370
@INotebookEditorModelResolverService private readonly _notebookModelResolverService: INotebookEditorModelResolverService,
371
) {
372
this._registration = textModelService.registerTextModelContentProvider(CellUri.scheme, this);
373
}
374
375
dispose(): void {
376
this._registration.dispose();
377
}
378
379
async provideTextContent(resource: URI): Promise<ITextModel | null> {
380
const existing = this._modelService.getModel(resource);
381
if (existing) {
382
return existing;
383
}
384
const data = CellUri.parse(resource);
385
// const data = parseCellUri(resource);
386
if (!data) {
387
return null;
388
}
389
390
const ref = await this._notebookModelResolverService.resolve(data.notebook);
391
let result: ITextModel | null = null;
392
393
if (!ref.object.isResolved()) {
394
return null;
395
}
396
397
for (const cell of ref.object.notebook.cells) {
398
if (cell.uri.toString() === resource.toString()) {
399
const bufferFactory: ITextBufferFactory = {
400
create: (defaultEOL) => {
401
return { textBuffer: cell.textBuffer as ITextBuffer, disposable: Disposable.None };
402
},
403
getFirstLineText: (limit: number) => {
404
return cell.textBuffer.getLineContent(1).substring(0, limit);
405
}
406
};
407
const languageId = this._languageService.getLanguageIdByLanguageName(cell.language);
408
const languageSelection = languageId ? this._languageService.createById(languageId) : (cell.cellKind === CellKind.Markup ? this._languageService.createById('markdown') : this._languageService.createByFilepathOrFirstLine(resource, cell.textBuffer.getLineContent(1)));
409
result = this._modelService.createModel(
410
bufferFactory,
411
languageSelection,
412
resource
413
);
414
break;
415
}
416
}
417
418
if (!result) {
419
ref.dispose();
420
return null;
421
}
422
423
const once = Event.any(result.onWillDispose, ref.object.notebook.onWillDispose)(() => {
424
once.dispose();
425
ref.dispose();
426
});
427
428
return result;
429
}
430
}
431
432
class CellInfoContentProvider {
433
434
static readonly ID = 'workbench.contrib.cellInfoContentProvider';
435
436
private readonly _disposables: IDisposable[] = [];
437
438
constructor(
439
@ITextModelService textModelService: ITextModelService,
440
@IModelService private readonly _modelService: IModelService,
441
@ILanguageService private readonly _languageService: ILanguageService,
442
@ILabelService private readonly _labelService: ILabelService,
443
@INotebookEditorModelResolverService private readonly _notebookModelResolverService: INotebookEditorModelResolverService,
444
) {
445
this._disposables.push(textModelService.registerTextModelContentProvider(Schemas.vscodeNotebookCellMetadata, {
446
provideTextContent: this.provideMetadataTextContent.bind(this)
447
}));
448
449
this._disposables.push(textModelService.registerTextModelContentProvider(Schemas.vscodeNotebookCellOutput, {
450
provideTextContent: this.provideOutputTextContent.bind(this)
451
}));
452
453
this._disposables.push(this._labelService.registerFormatter({
454
scheme: Schemas.vscodeNotebookCellMetadata,
455
formatting: {
456
label: '${path} (metadata)',
457
separator: '/'
458
}
459
}));
460
461
this._disposables.push(this._labelService.registerFormatter({
462
scheme: Schemas.vscodeNotebookCellOutput,
463
formatting: {
464
label: '${path} (output)',
465
separator: '/'
466
}
467
}));
468
}
469
470
dispose(): void {
471
dispose(this._disposables);
472
}
473
474
async provideMetadataTextContent(resource: URI): Promise<ITextModel | null> {
475
const existing = this._modelService.getModel(resource);
476
if (existing) {
477
return existing;
478
}
479
480
const data = CellUri.parseCellPropertyUri(resource, Schemas.vscodeNotebookCellMetadata);
481
if (!data) {
482
return null;
483
}
484
485
const ref = await this._notebookModelResolverService.resolve(data.notebook);
486
let result: ITextModel | null = null;
487
488
const mode = this._languageService.createById('json');
489
const disposables = new DisposableStore();
490
for (const cell of ref.object.notebook.cells) {
491
if (cell.handle === data.handle) {
492
const cellIndex = ref.object.notebook.cells.indexOf(cell);
493
const metadataSource = getFormattedMetadataJSON(ref.object.notebook.transientOptions.transientCellMetadata, cell.metadata, cell.language, true);
494
result = this._modelService.createModel(
495
metadataSource,
496
mode,
497
resource
498
);
499
this._disposables.push(disposables.add(ref.object.notebook.onDidChangeContent(e => {
500
if (result && e.rawEvents.some(event => (event.kind === NotebookCellsChangeType.ChangeCellMetadata || event.kind === NotebookCellsChangeType.ChangeCellLanguage) && event.index === cellIndex)) {
501
const value = getFormattedMetadataJSON(ref.object.notebook.transientOptions.transientCellMetadata, cell.metadata, cell.language, true);
502
if (result.getValue() !== value) {
503
result.setValue(value);
504
}
505
}
506
})));
507
break;
508
}
509
}
510
511
if (!result) {
512
ref.dispose();
513
return null;
514
}
515
516
const once = result.onWillDispose(() => {
517
disposables.dispose();
518
once.dispose();
519
ref.dispose();
520
});
521
522
return result;
523
}
524
525
private parseStreamOutput(op?: ICellOutput): { content: string; mode: ILanguageSelection } | undefined {
526
if (!op) {
527
return;
528
}
529
530
const streamOutputData = getStreamOutputData(op.outputs);
531
if (streamOutputData) {
532
return {
533
content: streamOutputData,
534
mode: this._languageService.createById(PLAINTEXT_LANGUAGE_ID)
535
};
536
}
537
538
return;
539
}
540
541
private _getResult(data: {
542
notebook: URI;
543
outputId?: string | undefined;
544
}, cell: ICell) {
545
let result: { content: string; mode: ILanguageSelection } | undefined = undefined;
546
547
const mode = this._languageService.createById('json');
548
const op = cell.outputs.find(op => op.outputId === data.outputId || op.alternativeOutputId === data.outputId);
549
const streamOutputData = this.parseStreamOutput(op);
550
if (streamOutputData) {
551
result = streamOutputData;
552
return result;
553
}
554
555
const obj = cell.outputs.map(output => ({
556
metadata: output.metadata,
557
outputItems: output.outputs.map(opit => ({
558
mimeType: opit.mime,
559
data: opit.data.toString()
560
}))
561
}));
562
563
const outputSource = toFormattedString(obj, {});
564
result = {
565
content: outputSource,
566
mode
567
};
568
569
return result;
570
}
571
572
async provideOutputsTextContent(resource: URI): Promise<ITextModel | null> {
573
const existing = this._modelService.getModel(resource);
574
if (existing) {
575
return existing;
576
}
577
578
const data = CellUri.parseCellPropertyUri(resource, Schemas.vscodeNotebookCellOutput);
579
if (!data) {
580
return null;
581
}
582
583
const ref = await this._notebookModelResolverService.resolve(data.notebook);
584
const cell = ref.object.notebook.cells.find(cell => cell.handle === data.handle);
585
586
if (!cell) {
587
ref.dispose();
588
return null;
589
}
590
591
const mode = this._languageService.createById('json');
592
const model = this._modelService.createModel(getFormattedOutputJSON(cell.outputs || []), mode, resource, true);
593
const cellModelListener = Event.any(cell.onDidChangeOutputs ?? Event.None, cell.onDidChangeOutputItems ?? Event.None)(() => {
594
model.setValue(getFormattedOutputJSON(cell.outputs || []));
595
});
596
597
const once = model.onWillDispose(() => {
598
once.dispose();
599
cellModelListener.dispose();
600
ref.dispose();
601
});
602
603
return model;
604
}
605
606
async provideOutputTextContent(resource: URI): Promise<ITextModel | null> {
607
const existing = this._modelService.getModel(resource);
608
if (existing) {
609
return existing;
610
}
611
612
const data = CellUri.parseCellOutputUri(resource);
613
if (!data) {
614
return this.provideOutputsTextContent(resource);
615
}
616
617
const ref = await this._notebookModelResolverService.resolve(data.notebook);
618
const cell = ref.object.notebook.cells.find(cell => !!cell.outputs.find(op => op.outputId === data.outputId || op.alternativeOutputId === data.outputId));
619
620
if (!cell) {
621
ref.dispose();
622
return null;
623
}
624
625
const result = this._getResult(data, cell);
626
627
if (!result) {
628
ref.dispose();
629
return null;
630
}
631
632
const model = this._modelService.createModel(result.content, result.mode, resource);
633
const cellModelListener = Event.any(cell.onDidChangeOutputs ?? Event.None, cell.onDidChangeOutputItems ?? Event.None)(() => {
634
const newResult = this._getResult(data, cell);
635
636
if (!newResult) {
637
return;
638
}
639
640
model.setValue(newResult.content);
641
model.setLanguage(newResult.mode.languageId);
642
});
643
644
const once = model.onWillDispose(() => {
645
once.dispose();
646
cellModelListener.dispose();
647
ref.dispose();
648
});
649
650
return model;
651
}
652
}
653
654
class NotebookMetadataContentProvider {
655
static readonly ID = 'workbench.contrib.notebookMetadataContentProvider';
656
657
private readonly _disposables: IDisposable[] = [];
658
659
constructor(
660
@ITextModelService textModelService: ITextModelService,
661
@IModelService private readonly _modelService: IModelService,
662
@ILanguageService private readonly _languageService: ILanguageService,
663
@ILabelService private readonly _labelService: ILabelService,
664
@INotebookEditorModelResolverService private readonly _notebookModelResolverService: INotebookEditorModelResolverService,
665
) {
666
this._disposables.push(textModelService.registerTextModelContentProvider(Schemas.vscodeNotebookMetadata, {
667
provideTextContent: this.provideMetadataTextContent.bind(this)
668
}));
669
670
this._disposables.push(this._labelService.registerFormatter({
671
scheme: Schemas.vscodeNotebookMetadata,
672
formatting: {
673
label: '${path} (metadata)',
674
separator: '/'
675
}
676
}));
677
}
678
679
dispose(): void {
680
dispose(this._disposables);
681
}
682
683
async provideMetadataTextContent(resource: URI): Promise<ITextModel | null> {
684
const existing = this._modelService.getModel(resource);
685
if (existing) {
686
return existing;
687
}
688
689
const data = NotebookMetadataUri.parse(resource);
690
if (!data) {
691
return null;
692
}
693
694
const ref = await this._notebookModelResolverService.resolve(data);
695
let result: ITextModel | null = null;
696
697
const mode = this._languageService.createById('json');
698
const disposables = new DisposableStore();
699
const metadataSource = getFormattedNotebookMetadataJSON(ref.object.notebook.transientOptions.transientDocumentMetadata, ref.object.notebook.metadata);
700
result = this._modelService.createModel(
701
metadataSource,
702
mode,
703
resource
704
);
705
706
if (!result) {
707
ref.dispose();
708
return null;
709
}
710
711
this._disposables.push(disposables.add(ref.object.notebook.onDidChangeContent(e => {
712
if (result && e.rawEvents.some(event => (event.kind === NotebookCellsChangeType.ChangeCellContent || event.kind === NotebookCellsChangeType.ChangeDocumentMetadata || event.kind === NotebookCellsChangeType.ModelChange))) {
713
const value = getFormattedNotebookMetadataJSON(ref.object.notebook.transientOptions.transientDocumentMetadata, ref.object.notebook.metadata);
714
if (result.getValue() !== value) {
715
result.setValue(value);
716
}
717
}
718
})));
719
720
const once = result.onWillDispose(() => {
721
disposables.dispose();
722
once.dispose();
723
ref.dispose();
724
});
725
726
return result;
727
}
728
}
729
730
class RegisterSchemasContribution extends Disposable implements IWorkbenchContribution {
731
732
static readonly ID = 'workbench.contrib.registerCellSchemas';
733
734
constructor() {
735
super();
736
this.registerMetadataSchemas();
737
}
738
739
private registerMetadataSchemas(): void {
740
const jsonRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
741
const metadataSchema: IJSONSchema = {
742
properties: {
743
['language']: {
744
type: 'string',
745
description: 'The language for the cell'
746
}
747
},
748
// patternProperties: allSettings.patternProperties,
749
additionalProperties: true,
750
allowTrailingCommas: true,
751
allowComments: true
752
};
753
754
jsonRegistry.registerSchema('vscode://schemas/notebook/cellmetadata', metadataSchema);
755
}
756
}
757
758
class NotebookEditorManager implements IWorkbenchContribution {
759
760
static readonly ID = 'workbench.contrib.notebookEditorManager';
761
762
private readonly _disposables = new DisposableStore();
763
764
constructor(
765
@IEditorService private readonly _editorService: IEditorService,
766
@INotebookEditorModelResolverService private readonly _notebookEditorModelService: INotebookEditorModelResolverService,
767
@IEditorGroupsService editorGroups: IEditorGroupsService
768
) {
769
// OPEN notebook editor for models that have turned dirty without being visible in an editor
770
type E = IResolvedNotebookEditorModel;
771
this._disposables.add(Event.debounce<E, E[]>(
772
this._notebookEditorModelService.onDidChangeDirty,
773
(last, current) => !last ? [current] : [...last, current],
774
100
775
)(this._openMissingDirtyNotebookEditors, this));
776
777
// CLOSE editors when we are about to open conflicting notebooks
778
this._disposables.add(_notebookEditorModelService.onWillFailWithConflict(e => {
779
for (const group of editorGroups.groups) {
780
const conflictInputs = group.editors.filter(input => input instanceof NotebookEditorInput && input.viewType !== e.viewType && isEqual(input.resource, e.resource));
781
const p = group.closeEditors(conflictInputs);
782
e.waitUntil(p);
783
}
784
}));
785
}
786
787
dispose(): void {
788
this._disposables.dispose();
789
}
790
791
private _openMissingDirtyNotebookEditors(models: IResolvedNotebookEditorModel[]): void {
792
const result: IResourceEditorInput[] = [];
793
for (const model of models) {
794
if (model.isDirty() && !this._editorService.isOpened({ resource: model.resource, typeId: NotebookEditorInput.ID, editorId: model.viewType }) && extname(model.resource) !== '.interactive') {
795
result.push({
796
resource: model.resource,
797
options: { inactive: true, preserveFocus: true, pinned: true, override: model.viewType }
798
});
799
}
800
}
801
if (result.length > 0) {
802
this._editorService.openEditors(result);
803
}
804
}
805
}
806
807
class SimpleNotebookWorkingCopyEditorHandler extends Disposable implements IWorkbenchContribution, IWorkingCopyEditorHandler {
808
809
static readonly ID = 'workbench.contrib.simpleNotebookWorkingCopyEditorHandler';
810
811
constructor(
812
@IInstantiationService private readonly _instantiationService: IInstantiationService,
813
@IWorkingCopyEditorService private readonly _workingCopyEditorService: IWorkingCopyEditorService,
814
@IExtensionService private readonly _extensionService: IExtensionService,
815
@INotebookService private readonly _notebookService: INotebookService
816
) {
817
super();
818
819
this._installHandler();
820
}
821
822
async handles(workingCopy: IWorkingCopyIdentifier): Promise<boolean> {
823
const viewType = this.handlesSync(workingCopy);
824
if (!viewType) {
825
return false;
826
}
827
828
return this._notebookService.canResolve(viewType);
829
}
830
831
private handlesSync(workingCopy: IWorkingCopyIdentifier): string /* viewType */ | undefined {
832
const viewType = this._getViewType(workingCopy);
833
if (!viewType || viewType === 'interactive') {
834
return undefined;
835
}
836
837
return viewType;
838
}
839
840
isOpen(workingCopy: IWorkingCopyIdentifier, editor: EditorInput): boolean {
841
if (!this.handlesSync(workingCopy)) {
842
return false;
843
}
844
845
return editor instanceof NotebookEditorInput && editor.viewType === this._getViewType(workingCopy) && isEqual(workingCopy.resource, editor.resource);
846
}
847
848
createEditor(workingCopy: IWorkingCopyIdentifier): EditorInput {
849
return NotebookEditorInput.getOrCreate(this._instantiationService, workingCopy.resource, undefined, this._getViewType(workingCopy)!);
850
}
851
852
private async _installHandler(): Promise<void> {
853
await this._extensionService.whenInstalledExtensionsRegistered();
854
855
this._register(this._workingCopyEditorService.registerHandler(this));
856
}
857
858
private _getViewType(workingCopy: IWorkingCopyIdentifier) {
859
const notebookType = NotebookWorkingCopyTypeIdentifier.parse(workingCopy.typeId);
860
if (notebookType && notebookType.viewType === notebookType.notebookType) {
861
return notebookType?.viewType;
862
}
863
return undefined;
864
}
865
}
866
867
class NotebookLanguageSelectorScoreRefine {
868
869
static readonly ID = 'workbench.contrib.notebookLanguageSelectorScoreRefine';
870
871
constructor(
872
@INotebookService private readonly _notebookService: INotebookService,
873
@ILanguageFeaturesService languageFeaturesService: ILanguageFeaturesService,
874
) {
875
languageFeaturesService.setNotebookTypeResolver(this._getNotebookInfo.bind(this));
876
}
877
878
private _getNotebookInfo(uri: URI): NotebookInfo | undefined {
879
const cellUri = CellUri.parse(uri);
880
if (!cellUri) {
881
return undefined;
882
}
883
const notebook = this._notebookService.getNotebookTextModel(cellUri.notebook);
884
if (!notebook) {
885
return undefined;
886
}
887
return {
888
uri: notebook.uri,
889
type: notebook.viewType
890
};
891
}
892
}
893
894
const workbenchContributionsRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
895
registerWorkbenchContribution2(NotebookContribution.ID, NotebookContribution, WorkbenchPhase.BlockStartup);
896
registerWorkbenchContribution2(CellContentProvider.ID, CellContentProvider, WorkbenchPhase.BlockStartup);
897
registerWorkbenchContribution2(CellInfoContentProvider.ID, CellInfoContentProvider, WorkbenchPhase.BlockStartup);
898
registerWorkbenchContribution2(NotebookMetadataContentProvider.ID, NotebookMetadataContentProvider, WorkbenchPhase.BlockStartup);
899
registerWorkbenchContribution2(RegisterSchemasContribution.ID, RegisterSchemasContribution, WorkbenchPhase.BlockStartup);
900
registerWorkbenchContribution2(NotebookEditorManager.ID, NotebookEditorManager, WorkbenchPhase.BlockRestore);
901
registerWorkbenchContribution2(NotebookLanguageSelectorScoreRefine.ID, NotebookLanguageSelectorScoreRefine, WorkbenchPhase.BlockRestore);
902
registerWorkbenchContribution2(SimpleNotebookWorkingCopyEditorHandler.ID, SimpleNotebookWorkingCopyEditorHandler, WorkbenchPhase.BlockRestore);
903
workbenchContributionsRegistry.registerWorkbenchContribution(NotebookVariables, LifecyclePhase.Eventually);
904
905
AccessibleViewRegistry.register(new NotebookAccessibleView());
906
AccessibleViewRegistry.register(new NotebookAccessibilityHelp());
907
908
registerSingleton(INotebookService, NotebookService, InstantiationType.Delayed);
909
registerSingleton(INotebookEditorWorkerService, NotebookEditorWorkerServiceImpl, InstantiationType.Delayed);
910
registerSingleton(INotebookEditorModelResolverService, NotebookModelResolverServiceImpl, InstantiationType.Delayed);
911
registerSingleton(INotebookCellStatusBarService, NotebookCellStatusBarService, InstantiationType.Delayed);
912
registerSingleton(INotebookEditorService, NotebookEditorWidgetService, InstantiationType.Delayed);
913
registerSingleton(INotebookKernelService, NotebookKernelService, InstantiationType.Delayed);
914
registerSingleton(INotebookKernelHistoryService, NotebookKernelHistoryService, InstantiationType.Delayed);
915
registerSingleton(INotebookExecutionService, NotebookExecutionService, InstantiationType.Delayed);
916
registerSingleton(INotebookExecutionStateService, NotebookExecutionStateService, InstantiationType.Delayed);
917
registerSingleton(INotebookRendererMessagingService, NotebookRendererMessagingService, InstantiationType.Delayed);
918
registerSingleton(INotebookKeymapService, NotebookKeymapService, InstantiationType.Delayed);
919
registerSingleton(INotebookLoggingService, NotebookLoggingService, InstantiationType.Delayed);
920
registerSingleton(INotebookCellOutlineDataSourceFactory, NotebookCellOutlineDataSourceFactory, InstantiationType.Delayed);
921
registerSingleton(INotebookOutlineEntryFactory, NotebookOutlineEntryFactory, InstantiationType.Delayed);
922
923
const schemas: IJSONSchemaMap = {};
924
function isConfigurationPropertySchema(x: IConfigurationPropertySchema | { [path: string]: IConfigurationPropertySchema }): x is IConfigurationPropertySchema {
925
return (typeof x.type !== 'undefined' || typeof x.anyOf !== 'undefined');
926
}
927
for (const editorOption of editorOptionsRegistry) {
928
const schema = editorOption.schema;
929
if (schema) {
930
if (isConfigurationPropertySchema(schema)) {
931
schemas[`editor.${editorOption.name}`] = schema;
932
} else {
933
for (const key in schema) {
934
if (Object.hasOwnProperty.call(schema, key)) {
935
schemas[key] = schema[key];
936
}
937
}
938
}
939
}
940
}
941
942
const editorOptionsCustomizationSchema: IConfigurationPropertySchema = {
943
description: nls.localize('notebook.editorOptions.experimentalCustomization', 'Settings for code editors used in notebooks. This can be used to customize most editor.* settings.'),
944
default: {},
945
allOf: [
946
{
947
properties: schemas,
948
}
949
// , {
950
// patternProperties: {
951
// '^\\[.*\\]$': {
952
// type: 'object',
953
// default: {},
954
// properties: schemas
955
// }
956
// }
957
// }
958
],
959
tags: ['notebookLayout']
960
};
961
962
const configurationRegistry = Registry.as<IConfigurationRegistry>(Extensions.Configuration);
963
configurationRegistry.registerConfiguration({
964
id: 'notebook',
965
order: 100,
966
title: nls.localize('notebookConfigurationTitle', "Notebook"),
967
type: 'object',
968
properties: {
969
[NotebookSetting.displayOrder]: {
970
description: nls.localize('notebook.displayOrder.description', "Priority list for output mime types"),
971
type: 'array',
972
items: {
973
type: 'string'
974
},
975
default: []
976
},
977
[NotebookSetting.cellToolbarLocation]: {
978
description: nls.localize('notebook.cellToolbarLocation.description', "Where the cell toolbar should be shown, or whether it should be hidden."),
979
type: 'object',
980
additionalProperties: {
981
markdownDescription: nls.localize('notebook.cellToolbarLocation.viewType', "Configure the cell toolbar position for for specific file types"),
982
type: 'string',
983
enum: ['left', 'right', 'hidden']
984
},
985
default: {
986
'default': 'right'
987
},
988
tags: ['notebookLayout']
989
},
990
[NotebookSetting.showCellStatusBar]: {
991
description: nls.localize('notebook.showCellStatusbar.description', "Whether the cell status bar should be shown."),
992
type: 'string',
993
enum: ['hidden', 'visible', 'visibleAfterExecute'],
994
enumDescriptions: [
995
nls.localize('notebook.showCellStatusbar.hidden.description', "The cell Status bar is always hidden."),
996
nls.localize('notebook.showCellStatusbar.visible.description', "The cell Status bar is always visible."),
997
nls.localize('notebook.showCellStatusbar.visibleAfterExecute.description', "The cell Status bar is hidden until the cell has executed. Then it becomes visible to show the execution status.")],
998
default: 'visible',
999
tags: ['notebookLayout']
1000
},
1001
[NotebookSetting.cellExecutionTimeVerbosity]: {
1002
description: nls.localize('notebook.cellExecutionTimeVerbosity.description', "Controls the verbosity of the cell execution time in the cell status bar."),
1003
type: 'string',
1004
enum: ['default', 'verbose'],
1005
enumDescriptions: [
1006
nls.localize('notebook.cellExecutionTimeVerbosity.default.description', "The cell execution duration is visible, with advanced information in the hover tooltip."),
1007
nls.localize('notebook.cellExecutionTimeVerbosity.verbose.description', "The cell last execution timestamp and duration are visible, with advanced information in the hover tooltip.")],
1008
default: 'default',
1009
tags: ['notebookLayout']
1010
},
1011
[NotebookSetting.textDiffEditorPreview]: {
1012
description: nls.localize('notebook.diff.enablePreview.description', "Whether to use the enhanced text diff editor for notebook."),
1013
type: 'boolean',
1014
default: true,
1015
tags: ['notebookLayout']
1016
},
1017
[NotebookSetting.diffOverviewRuler]: {
1018
description: nls.localize('notebook.diff.enableOverviewRuler.description', "Whether to render the overview ruler in the diff editor for notebook."),
1019
type: 'boolean',
1020
default: false,
1021
tags: ['notebookLayout']
1022
},
1023
[NotebookSetting.cellToolbarVisibility]: {
1024
markdownDescription: nls.localize('notebook.cellToolbarVisibility.description', "Whether the cell toolbar should appear on hover or click."),
1025
type: 'string',
1026
enum: ['hover', 'click'],
1027
default: 'click',
1028
tags: ['notebookLayout']
1029
},
1030
[NotebookSetting.undoRedoPerCell]: {
1031
description: nls.localize('notebook.undoRedoPerCell.description', "Whether to use separate undo/redo stack for each cell."),
1032
type: 'boolean',
1033
default: true,
1034
tags: ['notebookLayout']
1035
},
1036
[NotebookSetting.compactView]: {
1037
description: nls.localize('notebook.compactView.description', "Control whether the notebook editor should be rendered in a compact form. For example, when turned on, it will decrease the left margin width."),
1038
type: 'boolean',
1039
default: true,
1040
tags: ['notebookLayout']
1041
},
1042
[NotebookSetting.focusIndicator]: {
1043
description: nls.localize('notebook.focusIndicator.description', "Controls where the focus indicator is rendered, either along the cell borders or on the left gutter."),
1044
type: 'string',
1045
enum: ['border', 'gutter'],
1046
default: 'gutter',
1047
tags: ['notebookLayout']
1048
},
1049
[NotebookSetting.insertToolbarLocation]: {
1050
description: nls.localize('notebook.insertToolbarPosition.description', "Control where the insert cell actions should appear."),
1051
type: 'string',
1052
enum: ['betweenCells', 'notebookToolbar', 'both', 'hidden'],
1053
enumDescriptions: [
1054
nls.localize('insertToolbarLocation.betweenCells', "A toolbar that appears on hover between cells."),
1055
nls.localize('insertToolbarLocation.notebookToolbar', "The toolbar at the top of the notebook editor."),
1056
nls.localize('insertToolbarLocation.both', "Both toolbars."),
1057
nls.localize('insertToolbarLocation.hidden', "The insert actions don't appear anywhere."),
1058
],
1059
default: 'both',
1060
tags: ['notebookLayout']
1061
},
1062
[NotebookSetting.globalToolbar]: {
1063
description: nls.localize('notebook.globalToolbar.description', "Control whether to render a global toolbar inside the notebook editor."),
1064
type: 'boolean',
1065
default: true,
1066
tags: ['notebookLayout']
1067
},
1068
[NotebookSetting.stickyScrollEnabled]: {
1069
description: nls.localize('notebook.stickyScrollEnabled.description', "Experimental. Control whether to render notebook Sticky Scroll headers in the notebook editor."),
1070
type: 'boolean',
1071
default: false,
1072
tags: ['notebookLayout']
1073
},
1074
[NotebookSetting.stickyScrollMode]: {
1075
description: nls.localize('notebook.stickyScrollMode.description', "Control whether nested sticky lines appear to stack flat or indented."),
1076
type: 'string',
1077
enum: ['flat', 'indented'],
1078
enumDescriptions: [
1079
nls.localize('notebook.stickyScrollMode.flat', "Nested sticky lines appear flat."),
1080
nls.localize('notebook.stickyScrollMode.indented', "Nested sticky lines appear indented."),
1081
],
1082
default: 'indented',
1083
tags: ['notebookLayout']
1084
},
1085
[NotebookSetting.consolidatedOutputButton]: {
1086
description: nls.localize('notebook.consolidatedOutputButton.description', "Control whether outputs action should be rendered in the output toolbar."),
1087
type: 'boolean',
1088
default: true,
1089
tags: ['notebookLayout']
1090
},
1091
// [NotebookSetting.openOutputInPreviewEditor]: {
1092
// description: nls.localize('notebook.output.openInPreviewEditor.description', "Controls whether or not the action to open a cell output in a preview editor is enabled. This action can be used via the cell output menu."),
1093
// type: 'boolean',
1094
// default: false,
1095
// tags: ['preview']
1096
// },
1097
[NotebookSetting.showFoldingControls]: {
1098
description: nls.localize('notebook.showFoldingControls.description', "Controls when the Markdown header folding arrow is shown."),
1099
type: 'string',
1100
enum: ['always', 'never', 'mouseover'],
1101
enumDescriptions: [
1102
nls.localize('showFoldingControls.always', "The folding controls are always visible."),
1103
nls.localize('showFoldingControls.never', "Never show the folding controls and reduce the gutter size."),
1104
nls.localize('showFoldingControls.mouseover', "The folding controls are visible only on mouseover."),
1105
],
1106
default: 'mouseover',
1107
tags: ['notebookLayout']
1108
},
1109
[NotebookSetting.dragAndDropEnabled]: {
1110
description: nls.localize('notebook.dragAndDrop.description', "Control whether the notebook editor should allow moving cells through drag and drop."),
1111
type: 'boolean',
1112
default: true,
1113
tags: ['notebookLayout']
1114
},
1115
[NotebookSetting.consolidatedRunButton]: {
1116
description: nls.localize('notebook.consolidatedRunButton.description', "Control whether extra actions are shown in a dropdown next to the run button."),
1117
type: 'boolean',
1118
default: false,
1119
tags: ['notebookLayout']
1120
},
1121
[NotebookSetting.globalToolbarShowLabel]: {
1122
description: nls.localize('notebook.globalToolbarShowLabel', "Control whether the actions on the notebook toolbar should render label or not."),
1123
type: 'string',
1124
enum: ['always', 'never', 'dynamic'],
1125
default: 'always',
1126
tags: ['notebookLayout']
1127
},
1128
[NotebookSetting.textOutputLineLimit]: {
1129
markdownDescription: nls.localize('notebook.textOutputLineLimit', "Controls how many lines of text are displayed in a text output. If {0} is enabled, this setting is used to determine the scroll height of the output.", '`#notebook.output.scrolling#`'),
1130
type: 'number',
1131
default: 30,
1132
tags: ['notebookLayout', 'notebookOutputLayout'],
1133
minimum: 1,
1134
},
1135
[NotebookSetting.LinkifyOutputFilePaths]: {
1136
description: nls.localize('notebook.disableOutputFilePathLinks', "Control whether to disable filepath links in the output of notebook cells."),
1137
type: 'boolean',
1138
default: true,
1139
tags: ['notebookOutputLayout']
1140
},
1141
[NotebookSetting.minimalErrorRendering]: {
1142
description: nls.localize('notebook.minimalErrorRendering', "Control whether to render error output in a minimal style."),
1143
type: 'boolean',
1144
default: false,
1145
tags: ['notebookOutputLayout']
1146
},
1147
[NotebookSetting.markupFontSize]: {
1148
markdownDescription: nls.localize('notebook.markup.fontSize', "Controls the font size in pixels of rendered markup in notebooks. When set to {0}, 120% of {1} is used.", '`0`', '`#editor.fontSize#`'),
1149
type: 'number',
1150
default: 0,
1151
tags: ['notebookLayout']
1152
},
1153
[NotebookSetting.markdownLineHeight]: {
1154
markdownDescription: nls.localize('notebook.markdown.lineHeight', "Controls the line height in pixels of markdown cells in notebooks. When set to {0}, {1} will be used", '`0`', '`normal`'),
1155
type: 'number',
1156
default: 0,
1157
tags: ['notebookLayout']
1158
},
1159
[NotebookSetting.cellEditorOptionsCustomizations]: editorOptionsCustomizationSchema,
1160
[NotebookSetting.interactiveWindowCollapseCodeCells]: {
1161
markdownDescription: nls.localize('notebook.interactiveWindow.collapseCodeCells', "Controls whether code cells in the interactive window are collapsed by default."),
1162
type: 'string',
1163
enum: ['always', 'never', 'fromEditor'],
1164
default: 'fromEditor'
1165
},
1166
[NotebookSetting.outputLineHeight]: {
1167
markdownDescription: nls.localize('notebook.outputLineHeight', "Line height of the output text within notebook cells.\n - When set to 0, editor line height is used.\n - Values between 0 and 8 will be used as a multiplier with the font size.\n - Values greater than or equal to 8 will be used as effective values."),
1168
type: 'number',
1169
default: 0,
1170
tags: ['notebookLayout', 'notebookOutputLayout']
1171
},
1172
[NotebookSetting.outputFontSize]: {
1173
markdownDescription: nls.localize('notebook.outputFontSize', "Font size for the output text within notebook cells. When set to 0, {0} is used.", '`#editor.fontSize#`'),
1174
type: 'number',
1175
default: 0,
1176
tags: ['notebookLayout', 'notebookOutputLayout']
1177
},
1178
[NotebookSetting.outputFontFamily]: {
1179
markdownDescription: nls.localize('notebook.outputFontFamily', "The font family of the output text within notebook cells. When set to empty, the {0} is used.", '`#editor.fontFamily#`'),
1180
type: 'string',
1181
tags: ['notebookLayout', 'notebookOutputLayout']
1182
},
1183
[NotebookSetting.outputScrolling]: {
1184
markdownDescription: nls.localize('notebook.outputScrolling', "Initially render notebook outputs in a scrollable region when longer than the limit."),
1185
type: 'boolean',
1186
tags: ['notebookLayout', 'notebookOutputLayout'],
1187
default: typeof product.quality === 'string' && product.quality !== 'stable' // only enable as default in insiders
1188
},
1189
[NotebookSetting.outputWordWrap]: {
1190
markdownDescription: nls.localize('notebook.outputWordWrap', "Controls whether the lines in output should wrap."),
1191
type: 'boolean',
1192
tags: ['notebookLayout', 'notebookOutputLayout'],
1193
default: false
1194
},
1195
[NotebookSetting.defaultFormatter]: {
1196
description: nls.localize('notebookFormatter.default', "Defines a default notebook formatter which takes precedence over all other formatter settings. Must be the identifier of an extension contributing a formatter."),
1197
type: ['string', 'null'],
1198
default: null,
1199
enum: DefaultFormatter.extensionIds,
1200
enumItemLabels: DefaultFormatter.extensionItemLabels,
1201
markdownEnumDescriptions: DefaultFormatter.extensionDescriptions
1202
},
1203
[NotebookSetting.formatOnSave]: {
1204
markdownDescription: nls.localize('notebook.formatOnSave', "Format a notebook on save. A formatter must be available and the editor must not be shutting down. When {0} is set to `afterDelay`, the file will only be formatted when saved explicitly.", '`#files.autoSave#`'),
1205
type: 'boolean',
1206
tags: ['notebookLayout'],
1207
default: false
1208
},
1209
[NotebookSetting.insertFinalNewline]: {
1210
markdownDescription: nls.localize('notebook.insertFinalNewline', "When enabled, insert a final new line into the end of code cells when saving a notebook."),
1211
type: 'boolean',
1212
tags: ['notebookLayout'],
1213
default: false
1214
},
1215
[NotebookSetting.formatOnCellExecution]: {
1216
markdownDescription: nls.localize('notebook.formatOnCellExecution', "Format a notebook cell upon execution. A formatter must be available."),
1217
type: 'boolean',
1218
default: false
1219
},
1220
[NotebookSetting.confirmDeleteRunningCell]: {
1221
markdownDescription: nls.localize('notebook.confirmDeleteRunningCell', "Control whether a confirmation prompt is required to delete a running cell."),
1222
type: 'boolean',
1223
default: true
1224
},
1225
[NotebookSetting.findFilters]: {
1226
markdownDescription: nls.localize('notebook.findFilters', "Customize the Find Widget behavior for searching within notebook cells. When both markup source and markup preview are enabled, the Find Widget will search either the source code or preview based on the current state of the cell."),
1227
type: 'object',
1228
properties: {
1229
markupSource: {
1230
type: 'boolean',
1231
default: true
1232
},
1233
markupPreview: {
1234
type: 'boolean',
1235
default: true
1236
},
1237
codeSource: {
1238
type: 'boolean',
1239
default: true
1240
},
1241
codeOutput: {
1242
type: 'boolean',
1243
default: true
1244
}
1245
},
1246
default: {
1247
markupSource: true,
1248
markupPreview: true,
1249
codeSource: true,
1250
codeOutput: true
1251
},
1252
tags: ['notebookLayout']
1253
},
1254
[NotebookSetting.remoteSaving]: {
1255
markdownDescription: nls.localize('notebook.remoteSaving', "Enables the incremental saving of notebooks between processes and across Remote connections. When enabled, only the changes to the notebook are sent to the extension host, improving performance for large notebooks and slow network connections."),
1256
type: 'boolean',
1257
default: typeof product.quality === 'string' && product.quality !== 'stable', // only enable as default in insiders
1258
tags: ['experimental']
1259
},
1260
[NotebookSetting.scrollToRevealCell]: {
1261
markdownDescription: nls.localize('notebook.scrolling.revealNextCellOnExecute.description', "How far to scroll when revealing the next cell upon running {0}.", 'notebook.cell.executeAndSelectBelow'),
1262
type: 'string',
1263
enum: ['fullCell', 'firstLine', 'none'],
1264
markdownEnumDescriptions: [
1265
nls.localize('notebook.scrolling.revealNextCellOnExecute.fullCell.description', 'Scroll to fully reveal the next cell.'),
1266
nls.localize('notebook.scrolling.revealNextCellOnExecute.firstLine.description', 'Scroll to reveal the first line of the next cell.'),
1267
nls.localize('notebook.scrolling.revealNextCellOnExecute.none.description', 'Do not scroll.'),
1268
],
1269
default: 'fullCell'
1270
},
1271
[NotebookSetting.cellGenerate]: {
1272
markdownDescription: nls.localize('notebook.cellGenerate', "Enable experimental generate action to create code cell with inline chat enabled."),
1273
type: 'boolean',
1274
default: true
1275
},
1276
[NotebookSetting.notebookVariablesView]: {
1277
markdownDescription: nls.localize('notebook.VariablesView.description', "Enable the experimental notebook variables view within the debug panel."),
1278
type: 'boolean',
1279
default: false
1280
},
1281
[NotebookSetting.notebookInlineValues]: {
1282
markdownDescription: nls.localize('notebook.inlineValues.description', "Control whether to show inline values within notebook code cells after cell execution. Values will remain until the cell is edited, re-executed, or explicitly cleared via the Clear All Outputs toolbar button or the `Notebook: Clear Inline Values` command."),
1283
type: 'string',
1284
enum: ['on', 'auto', 'off'],
1285
enumDescriptions: [
1286
nls.localize('notebook.inlineValues.on', "Always show inline values, with a regex fallback if no inline value provider is registered. Note: There may be a performance impact in larger cells if the fallback is used."),
1287
nls.localize('notebook.inlineValues.auto', "Show inline values only when an inline value provider is registered."),
1288
nls.localize('notebook.inlineValues.off', "Never show inline values."),
1289
],
1290
default: 'off'
1291
},
1292
[NotebookSetting.cellFailureDiagnostics]: {
1293
markdownDescription: nls.localize('notebook.cellFailureDiagnostics', "Show available diagnostics for cell failures."),
1294
type: 'boolean',
1295
default: true
1296
},
1297
[NotebookSetting.outputBackupSizeLimit]: {
1298
markdownDescription: nls.localize('notebook.backup.sizeLimit', "The limit of notebook output size in kilobytes (KB) where notebook files will no longer be backed up for hot reload. Use 0 for unlimited."),
1299
type: 'number',
1300
default: 10000
1301
},
1302
[NotebookSetting.multiCursor]: {
1303
markdownDescription: nls.localize('notebook.multiCursor.enabled', "Experimental. Enables a limited set of multi cursor controls across multiple cells in the notebook editor. Currently supported are core editor actions (typing/cut/copy/paste/composition) and a limited subset of editor commands."),
1304
type: 'boolean',
1305
default: false
1306
},
1307
[NotebookSetting.markupFontFamily]: {
1308
markdownDescription: nls.localize('notebook.markup.fontFamily', "Controls the font family of rendered markup in notebooks. When left blank, this will fall back to the default workbench font family."),
1309
type: 'string',
1310
default: '',
1311
tags: ['notebookLayout']
1312
}
1313
}
1314
});
1315
1316