@theia/notebook 1.53.0-next.5 → 1.53.0-next.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/README.md +30 -30
  2. package/lib/browser/contributions/notebook-actions-contribution.d.ts +1 -0
  3. package/lib/browser/contributions/notebook-actions-contribution.d.ts.map +1 -1
  4. package/lib/browser/contributions/notebook-actions-contribution.js +31 -5
  5. package/lib/browser/contributions/notebook-actions-contribution.js.map +1 -1
  6. package/lib/browser/contributions/notebook-cell-actions-contribution.d.ts +2 -0
  7. package/lib/browser/contributions/notebook-cell-actions-contribution.d.ts.map +1 -1
  8. package/lib/browser/contributions/notebook-cell-actions-contribution.js +41 -7
  9. package/lib/browser/contributions/notebook-cell-actions-contribution.js.map +1 -1
  10. package/lib/browser/contributions/notebook-status-bar-contribution.d.ts +14 -0
  11. package/lib/browser/contributions/notebook-status-bar-contribution.d.ts.map +1 -0
  12. package/lib/browser/contributions/notebook-status-bar-contribution.js +75 -0
  13. package/lib/browser/contributions/notebook-status-bar-contribution.js.map +1 -0
  14. package/lib/browser/notebook-editor-widget.d.ts.map +1 -1
  15. package/lib/browser/notebook-editor-widget.js +3 -5
  16. package/lib/browser/notebook-editor-widget.js.map +1 -1
  17. package/lib/browser/notebook-frontend-module.d.ts.map +1 -1
  18. package/lib/browser/notebook-frontend-module.js +3 -0
  19. package/lib/browser/notebook-frontend-module.js.map +1 -1
  20. package/lib/browser/notebook-open-handler.d.ts +3 -2
  21. package/lib/browser/notebook-open-handler.d.ts.map +1 -1
  22. package/lib/browser/notebook-open-handler.js +12 -5
  23. package/lib/browser/notebook-open-handler.js.map +1 -1
  24. package/lib/browser/view/notebook-cell-editor.d.ts +1 -0
  25. package/lib/browser/view/notebook-cell-editor.d.ts.map +1 -1
  26. package/lib/browser/view/notebook-cell-editor.js +30 -16
  27. package/lib/browser/view/notebook-cell-editor.js.map +1 -1
  28. package/lib/browser/view/notebook-cell-list-view.d.ts +6 -4
  29. package/lib/browser/view/notebook-cell-list-view.d.ts.map +1 -1
  30. package/lib/browser/view/notebook-cell-list-view.js +20 -13
  31. package/lib/browser/view/notebook-cell-list-view.js.map +1 -1
  32. package/lib/browser/view-model/notebook-cell-model.d.ts +3 -0
  33. package/lib/browser/view-model/notebook-cell-model.d.ts.map +1 -1
  34. package/lib/browser/view-model/notebook-cell-model.js +5 -0
  35. package/lib/browser/view-model/notebook-cell-model.js.map +1 -1
  36. package/package.json +8 -8
  37. package/src/browser/contributions/cell-operations.ts +44 -44
  38. package/src/browser/contributions/notebook-actions-contribution.ts +379 -350
  39. package/src/browser/contributions/notebook-cell-actions-contribution.ts +525 -487
  40. package/src/browser/contributions/notebook-color-contribution.ts +268 -268
  41. package/src/browser/contributions/notebook-context-keys.ts +113 -113
  42. package/src/browser/contributions/notebook-label-provider-contribution.ts +85 -85
  43. package/src/browser/contributions/notebook-outline-contribution.ts +114 -114
  44. package/src/browser/contributions/notebook-output-action-contribution.ts +82 -82
  45. package/src/browser/contributions/notebook-preferences.ts +92 -92
  46. package/src/browser/contributions/notebook-status-bar-contribution.ts +77 -0
  47. package/src/browser/contributions/notebook-undo-redo-handler.ts +41 -41
  48. package/src/browser/index.ts +27 -27
  49. package/src/browser/notebook-cell-resource-resolver.ts +130 -130
  50. package/src/browser/notebook-editor-widget-factory.ts +82 -82
  51. package/src/browser/notebook-editor-widget.tsx +330 -331
  52. package/src/browser/notebook-frontend-module.ts +119 -115
  53. package/src/browser/notebook-open-handler.ts +120 -114
  54. package/src/browser/notebook-output-utils.ts +119 -119
  55. package/src/browser/notebook-renderer-registry.ts +85 -85
  56. package/src/browser/notebook-type-registry.ts +54 -54
  57. package/src/browser/notebook-types.ts +186 -186
  58. package/src/browser/renderers/cell-output-webview.ts +33 -33
  59. package/src/browser/service/notebook-clipboard-service.ts +43 -43
  60. package/src/browser/service/notebook-context-manager.ts +162 -162
  61. package/src/browser/service/notebook-editor-widget-service.ts +101 -101
  62. package/src/browser/service/notebook-execution-service.ts +139 -139
  63. package/src/browser/service/notebook-execution-state-service.ts +311 -311
  64. package/src/browser/service/notebook-kernel-history-service.ts +124 -124
  65. package/src/browser/service/notebook-kernel-quick-pick-service.ts +479 -479
  66. package/src/browser/service/notebook-kernel-service.ts +357 -357
  67. package/src/browser/service/notebook-model-resolver-service.ts +160 -160
  68. package/src/browser/service/notebook-monaco-text-model-service.ts +48 -48
  69. package/src/browser/service/notebook-options.ts +155 -155
  70. package/src/browser/service/notebook-renderer-messaging-service.ts +121 -121
  71. package/src/browser/service/notebook-service.ts +215 -215
  72. package/src/browser/style/index.css +483 -471
  73. package/src/browser/view/notebook-cell-editor.tsx +263 -247
  74. package/src/browser/view/notebook-cell-list-view.tsx +279 -262
  75. package/src/browser/view/notebook-cell-toolbar-factory.tsx +102 -102
  76. package/src/browser/view/notebook-cell-toolbar.tsx +74 -74
  77. package/src/browser/view/notebook-code-cell-view.tsx +350 -350
  78. package/src/browser/view/notebook-find-widget.tsx +335 -335
  79. package/src/browser/view/notebook-main-toolbar.tsx +235 -235
  80. package/src/browser/view/notebook-markdown-cell-view.tsx +208 -208
  81. package/src/browser/view/notebook-viewport-service.ts +61 -61
  82. package/src/browser/view-model/notebook-cell-model.ts +473 -466
  83. package/src/browser/view-model/notebook-cell-output-model.ts +100 -100
  84. package/src/browser/view-model/notebook-model.ts +550 -550
  85. package/src/common/index.ts +18 -18
  86. package/src/common/notebook-common.ts +337 -337
  87. package/src/common/notebook-protocol.ts +35 -35
  88. package/src/common/notebook-range.ts +30 -30
@@ -1,466 +1,473 @@
1
- // *****************************************************************************
2
- // Copyright (C) 2023 TypeFox and others.
3
- //
4
- // This program and the accompanying materials are made available under the
5
- // terms of the Eclipse Public License v. 2.0 which is available at
6
- // http://www.eclipse.org/legal/epl-2.0.
7
- //
8
- // This Source Code may also be made available under the following Secondary
9
- // Licenses when the conditions for such availability set forth in the Eclipse
10
- // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
- // with the GNU Classpath Exception which is available at
12
- // https://www.gnu.org/software/classpath/license.html.
13
- //
14
- // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
- // *****************************************************************************
16
- /*---------------------------------------------------------------------------------------------
17
- * Copyright (c) Microsoft Corporation. All rights reserved.
18
- * Licensed under the MIT License. See License.txt in the project root for license information.
19
- *--------------------------------------------------------------------------------------------*/
20
-
21
- import { Disposable, DisposableCollection, Emitter, Event, URI } from '@theia/core';
22
- import { inject, injectable, interfaces, postConstruct } from '@theia/core/shared/inversify';
23
- import { MonacoEditorModel } from '@theia/monaco/lib/browser/monaco-editor-model';
24
- import { type MonacoEditor } from '@theia/monaco/lib/browser/monaco-editor';
25
- import {
26
- CellKind, NotebookCellCollapseState, NotebookCellInternalMetadata,
27
- NotebookCellMetadata, CellOutput, CellData, CellOutputItem
28
- } from '../../common';
29
- import { NotebookCellOutputsSplice } from '../notebook-types';
30
- import { NotebookMonacoTextModelService } from '../service/notebook-monaco-text-model-service';
31
- import { NotebookCellOutputModel } from './notebook-cell-output-model';
32
- import { PreferenceService } from '@theia/core/lib/browser';
33
- import { NotebookPreferences } from '../contributions/notebook-preferences';
34
- import { LanguageService } from '@theia/core/lib/browser/language-service';
35
- import { NotebookEditorFindMatch, NotebookEditorFindMatchOptions } from '../view/notebook-find-widget';
36
- import { Range } from '@theia/core/shared/vscode-languageserver-protocol';
37
-
38
- export const NotebookCellModelFactory = Symbol('NotebookModelFactory');
39
- export type NotebookCellModelFactory = (props: NotebookCellModelProps) => NotebookCellModel;
40
-
41
- export type CellEditorFocusRequest = number | 'lastLine' | undefined;
42
-
43
- export function createNotebookCellModelContainer(parent: interfaces.Container, props: NotebookCellModelProps): interfaces.Container {
44
- const child = parent.createChild();
45
-
46
- child.bind(NotebookCellModelProps).toConstantValue(props);
47
- child.bind(NotebookCellModel).toSelf();
48
-
49
- return child;
50
- }
51
-
52
- export interface CellInternalMetadataChangedEvent {
53
- readonly lastRunSuccessChanged?: boolean;
54
- }
55
-
56
- export interface NotebookCell {
57
- readonly uri: URI;
58
- handle: number;
59
- language: string;
60
- cellKind: CellKind;
61
- outputs: CellOutput[];
62
- metadata: NotebookCellMetadata;
63
- internalMetadata: NotebookCellInternalMetadata;
64
- text: string;
65
- onDidChangeOutputs?: Event<NotebookCellOutputsSplice>;
66
- onDidChangeOutputItems?: Event<CellOutput>;
67
- onDidChangeLanguage: Event<string>;
68
- onDidChangeMetadata: Event<void>;
69
- onDidChangeInternalMetadata: Event<CellInternalMetadataChangedEvent>;
70
-
71
- }
72
-
73
- const NotebookCellModelProps = Symbol('NotebookModelProps');
74
- export interface NotebookCellModelProps {
75
- readonly uri: URI,
76
- readonly handle: number,
77
- source: string,
78
- language: string,
79
- readonly cellKind: CellKind,
80
- outputs: CellOutput[],
81
- metadata?: NotebookCellMetadata | undefined,
82
- internalMetadata?: NotebookCellInternalMetadata | undefined,
83
- readonly collapseState?: NotebookCellCollapseState | undefined,
84
-
85
- }
86
-
87
- @injectable()
88
- export class NotebookCellModel implements NotebookCell, Disposable {
89
-
90
- protected readonly onDidChangeOutputsEmitter = new Emitter<NotebookCellOutputsSplice>();
91
- readonly onDidChangeOutputs = this.onDidChangeOutputsEmitter.event;
92
-
93
- protected readonly onDidChangeOutputItemsEmitter = new Emitter<CellOutput>();
94
- readonly onDidChangeOutputItems = this.onDidChangeOutputItemsEmitter.event;
95
-
96
- protected readonly onDidChangeContentEmitter = new Emitter<'content' | 'language' | 'mime'>();
97
- readonly onDidChangeContent = this.onDidChangeContentEmitter.event;
98
-
99
- protected readonly onDidChangeMetadataEmitter = new Emitter<void>();
100
- readonly onDidChangeMetadata = this.onDidChangeMetadataEmitter.event;
101
-
102
- protected readonly onDidChangeInternalMetadataEmitter = new Emitter<CellInternalMetadataChangedEvent>();
103
- readonly onDidChangeInternalMetadata = this.onDidChangeInternalMetadataEmitter.event;
104
-
105
- protected readonly onDidChangeLanguageEmitter = new Emitter<string>();
106
- readonly onDidChangeLanguage = this.onDidChangeLanguageEmitter.event;
107
-
108
- protected readonly onDidRequestCellEditChangeEmitter = new Emitter<boolean>();
109
- readonly onDidRequestCellEditChange = this.onDidRequestCellEditChangeEmitter.event;
110
-
111
- protected readonly onWillFocusCellEditorEmitter = new Emitter<CellEditorFocusRequest>();
112
- readonly onWillFocusCellEditor = this.onWillFocusCellEditorEmitter.event;
113
-
114
- protected readonly onWillBlurCellEditorEmitter = new Emitter<void>();
115
- readonly onWillBlurCellEditor = this.onWillBlurCellEditorEmitter.event;
116
-
117
- protected readonly onDidChangeEditorOptionsEmitter = new Emitter<MonacoEditor.IOptions>();
118
- readonly onDidChangeEditorOptions = this.onDidChangeEditorOptionsEmitter.event;
119
-
120
- protected readonly outputVisibilityChangeEmitter = new Emitter<boolean>();
121
- readonly onDidChangeOutputVisibility = this.outputVisibilityChangeEmitter.event;
122
-
123
- protected readonly onDidFindMatchesEmitter = new Emitter<NotebookCodeEditorFindMatch[]>();
124
- readonly onDidFindMatches: Event<NotebookCodeEditorFindMatch[]> = this.onDidFindMatchesEmitter.event;
125
-
126
- protected readonly onDidSelectFindMatchEmitter = new Emitter<NotebookCodeEditorFindMatch>();
127
- readonly onDidSelectFindMatch: Event<NotebookCodeEditorFindMatch> = this.onDidSelectFindMatchEmitter.event;
128
-
129
- @inject(NotebookCellModelProps)
130
- protected readonly props: NotebookCellModelProps;
131
-
132
- @inject(NotebookMonacoTextModelService)
133
- protected readonly textModelService: NotebookMonacoTextModelService;
134
-
135
- @inject(LanguageService)
136
- protected readonly languageService: LanguageService;
137
-
138
- @inject(PreferenceService)
139
- protected readonly preferenceService: PreferenceService;
140
-
141
- get outputs(): NotebookCellOutputModel[] {
142
- return this._outputs;
143
- }
144
-
145
- protected _outputs: NotebookCellOutputModel[];
146
-
147
- get metadata(): NotebookCellMetadata {
148
- return this._metadata;
149
- }
150
-
151
- set metadata(newMetadata: NotebookCellMetadata) {
152
- this._metadata = newMetadata;
153
- this.onDidChangeMetadataEmitter.fire();
154
- }
155
-
156
- protected _metadata: NotebookCellMetadata;
157
-
158
- protected toDispose = new DisposableCollection();
159
-
160
- protected _internalMetadata: NotebookCellInternalMetadata;
161
-
162
- get internalMetadata(): NotebookCellInternalMetadata {
163
- return this._internalMetadata;
164
- }
165
-
166
- set internalMetadata(newInternalMetadata: NotebookCellInternalMetadata) {
167
- const lastRunSuccessChanged = this._internalMetadata.lastRunSuccess !== newInternalMetadata.lastRunSuccess;
168
- newInternalMetadata = {
169
- ...newInternalMetadata,
170
- ...{ runStartTimeAdjustment: computeRunStartTimeAdjustment(this._internalMetadata, newInternalMetadata) }
171
- };
172
- this._internalMetadata = newInternalMetadata;
173
- this.onDidChangeInternalMetadataEmitter.fire({ lastRunSuccessChanged });
174
-
175
- }
176
-
177
- protected textModel?: MonacoEditorModel;
178
-
179
- get text(): string {
180
- return this.textModel && !this.textModel.isDisposed() ? this.textModel.getText() : this.source;
181
- }
182
-
183
- get source(): string {
184
- return this.props.source;
185
- }
186
-
187
- set source(source: string) {
188
- this.props.source = source;
189
- this.textModel?.textEditorModel.setValue(source);
190
- }
191
-
192
- get language(): string {
193
- return this.props.language;
194
- }
195
-
196
- set language(newLanguage: string) {
197
- if (this.language === newLanguage) {
198
- return;
199
- }
200
-
201
- if (this.textModel) {
202
- this.textModel.setLanguageId(newLanguage);
203
- }
204
-
205
- this.props.language = newLanguage;
206
- this.onDidChangeLanguageEmitter.fire(newLanguage);
207
- this.onDidChangeContentEmitter.fire('language');
208
- }
209
-
210
- get languageName(): string {
211
- return this.languageService.getLanguage(this.language)?.name ?? this.language;
212
- }
213
-
214
- get uri(): URI {
215
- return this.props.uri;
216
- }
217
- get handle(): number {
218
- return this.props.handle;
219
- }
220
- get cellKind(): CellKind {
221
- return this.props.cellKind;
222
- }
223
-
224
- protected _editing: boolean = false;
225
- get editing(): boolean {
226
- return this._editing;
227
- }
228
-
229
- protected _editorOptions: MonacoEditor.IOptions = {};
230
- get editorOptions(): Readonly<MonacoEditor.IOptions> {
231
- return this._editorOptions;
232
- }
233
-
234
- set editorOptions(options: MonacoEditor.IOptions) {
235
- this._editorOptions = options;
236
- this.onDidChangeEditorOptionsEmitter.fire(options);
237
- }
238
-
239
- protected _outputVisible: boolean = true;
240
- get outputVisible(): boolean {
241
- return this._outputVisible;
242
- }
243
-
244
- set outputVisible(visible: boolean) {
245
- if (this._outputVisible !== visible) {
246
- this._outputVisible = visible;
247
- this.outputVisibilityChangeEmitter.fire(visible);
248
- }
249
- }
250
-
251
- @postConstruct()
252
- protected init(): void {
253
- this._outputs = this.props.outputs.map(op => new NotebookCellOutputModel(op));
254
- this._metadata = this.props.metadata ?? {};
255
- this._internalMetadata = this.props.internalMetadata ?? {};
256
-
257
- this.editorOptions = {
258
- lineNumbers: this.preferenceService.get(NotebookPreferences.NOTEBOOK_LINE_NUMBERS)
259
- };
260
- this.toDispose.push(this.preferenceService.onPreferenceChanged(e => {
261
- if (e.preferenceName === NotebookPreferences.NOTEBOOK_LINE_NUMBERS) {
262
- this.editorOptions = {
263
- ...this.editorOptions,
264
- lineNumbers: this.preferenceService.get(NotebookPreferences.NOTEBOOK_LINE_NUMBERS)
265
- };
266
- }
267
- }));
268
- }
269
-
270
- dispose(): void {
271
- this.onDidChangeOutputsEmitter.dispose();
272
- this.onDidChangeOutputItemsEmitter.dispose();
273
- this.onDidChangeContentEmitter.dispose();
274
- this.onDidChangeMetadataEmitter.dispose();
275
- this.onDidChangeInternalMetadataEmitter.dispose();
276
- this.onDidChangeLanguageEmitter.dispose();
277
- this.toDispose.dispose();
278
- }
279
-
280
- requestEdit(): void {
281
- if (!this.textModel || !this.textModel.readOnly) {
282
- this._editing = true;
283
- this.onDidRequestCellEditChangeEmitter.fire(true);
284
- }
285
- }
286
-
287
- requestStopEdit(): void {
288
- this._editing = false;
289
- this.onDidRequestCellEditChangeEmitter.fire(false);
290
- }
291
-
292
- requestFocusEditor(focusRequest?: CellEditorFocusRequest): void {
293
- this.requestEdit();
294
- this.onWillFocusCellEditorEmitter.fire(focusRequest);
295
- }
296
-
297
- requestBlurEditor(): void {
298
- this.requestStopEdit();
299
- this.onWillBlurCellEditorEmitter.fire();
300
- }
301
-
302
- spliceNotebookCellOutputs(splice: NotebookCellOutputsSplice): void {
303
- if (splice.deleteCount > 0 && splice.newOutputs.length > 0) {
304
- const commonLen = Math.min(splice.deleteCount, splice.newOutputs.length);
305
- // update
306
- for (let i = 0; i < commonLen; i++) {
307
- const currentOutput = this.outputs[splice.start + i];
308
- const newOutput = splice.newOutputs[i];
309
-
310
- this.replaceOutputData(currentOutput.outputId, newOutput);
311
- }
312
-
313
- this.outputs.splice(splice.start + commonLen, splice.deleteCount - commonLen, ...splice.newOutputs.slice(commonLen).map(op => new NotebookCellOutputModel(op)));
314
- this.onDidChangeOutputsEmitter.fire({ start: splice.start + commonLen, deleteCount: splice.deleteCount - commonLen, newOutputs: splice.newOutputs.slice(commonLen) });
315
- } else {
316
- this.outputs.splice(splice.start, splice.deleteCount, ...splice.newOutputs.map(op => new NotebookCellOutputModel(op)));
317
- this.onDidChangeOutputsEmitter.fire(splice);
318
- }
319
- }
320
-
321
- replaceOutputData(outputId: string, newOutputData: CellOutput): boolean {
322
- const output = this.outputs.find(out => out.outputId === outputId);
323
-
324
- if (!output) {
325
- return false;
326
- }
327
-
328
- output.replaceData(newOutputData);
329
- this.onDidChangeOutputItemsEmitter.fire(output);
330
- return true;
331
- }
332
-
333
- changeOutputItems(outputId: string, append: boolean, items: CellOutputItem[]): boolean {
334
- const output = this.outputs.find(out => out.outputId === outputId);
335
-
336
- if (!output) {
337
- return false;
338
- }
339
-
340
- if (append) {
341
- output.appendData(items);
342
- } else {
343
- output.replaceData({ outputId: outputId, outputs: items, metadata: output.metadata });
344
- }
345
- this.onDidChangeOutputItemsEmitter.fire(output);
346
- return true;
347
- }
348
-
349
- getData(): CellData {
350
- return {
351
- cellKind: this.cellKind,
352
- language: this.language,
353
- outputs: this.outputs.map(output => output.getData()),
354
- source: this.text,
355
- collapseState: this.props.collapseState,
356
- internalMetadata: this.internalMetadata,
357
- metadata: this.metadata
358
- };
359
- }
360
-
361
- async resolveTextModel(): Promise<MonacoEditorModel> {
362
- if (this.textModel) {
363
- return this.textModel;
364
- }
365
-
366
- const ref = await this.textModelService.getOrCreateNotebookCellModelReference(this.uri);
367
- this.textModel = ref.object;
368
- this.toDispose.push(ref);
369
- this.toDispose.push(this.textModel.onDidChangeContent(e => {
370
- this.props.source = e.model.getText();
371
- }));
372
- return ref.object;
373
- }
374
-
375
- restartOutputRenderer(outputId: string): void {
376
- const output = this.outputs.find(out => out.outputId === outputId);
377
- if (output) {
378
- this.onDidChangeOutputItemsEmitter.fire(output);
379
- }
380
- }
381
-
382
- onMarkdownFind: ((options: NotebookEditorFindMatchOptions) => NotebookEditorFindMatch[]) | undefined;
383
-
384
- showMatch(selected: NotebookCodeEditorFindMatch): void {
385
- this.onDidSelectFindMatchEmitter.fire(selected);
386
- }
387
-
388
- findMatches(options: NotebookEditorFindMatchOptions): NotebookEditorFindMatch[] {
389
- if (this.cellKind === CellKind.Markup && !this.editing) {
390
- return this.onMarkdownFind?.(options) ?? [];
391
- }
392
- if (!this.textModel) {
393
- return [];
394
- }
395
- const matches = options.search ? this.textModel.findMatches({
396
- searchString: options.search,
397
- isRegex: options.regex,
398
- matchCase: options.matchCase,
399
- matchWholeWord: options.wholeWord
400
- }) : [];
401
- const editorFindMatches = matches.map(match => new NotebookCodeEditorFindMatch(this, match.range, this.textModel!));
402
- this.onDidFindMatchesEmitter.fire(editorFindMatches);
403
- return editorFindMatches;
404
- }
405
-
406
- replaceAll(matches: NotebookCodeEditorFindMatch[], value: string): void {
407
- const editOperations = matches.map(match => ({
408
- range: {
409
- startColumn: match.range.start.character,
410
- startLineNumber: match.range.start.line,
411
- endColumn: match.range.end.character,
412
- endLineNumber: match.range.end.line
413
- },
414
- text: value
415
- }));
416
- this.textModel?.textEditorModel.pushEditOperations(
417
- // eslint-disable-next-line no-null/no-null
418
- null,
419
- editOperations,
420
- // eslint-disable-next-line no-null/no-null
421
- () => null);
422
- }
423
- }
424
-
425
- export interface NotebookCellFindMatches {
426
- matches: NotebookEditorFindMatch[];
427
- selected: NotebookEditorFindMatch;
428
- }
429
-
430
- export class NotebookCodeEditorFindMatch implements NotebookEditorFindMatch {
431
-
432
- selected = false;
433
-
434
- constructor(readonly cell: NotebookCellModel, readonly range: Range, readonly textModel: MonacoEditorModel) {
435
- }
436
-
437
- show(): void {
438
- this.cell.showMatch(this);
439
- }
440
- replace(value: string): void {
441
- this.textModel.textEditorModel.pushEditOperations(
442
- // eslint-disable-next-line no-null/no-null
443
- null,
444
- [{
445
- range: {
446
- startColumn: this.range.start.character,
447
- startLineNumber: this.range.start.line,
448
- endColumn: this.range.end.character,
449
- endLineNumber: this.range.end.line
450
- },
451
- text: value
452
- }],
453
- // eslint-disable-next-line no-null/no-null
454
- () => null);
455
- }
456
-
457
- }
458
-
459
- function computeRunStartTimeAdjustment(oldMetadata: NotebookCellInternalMetadata, newMetadata: NotebookCellInternalMetadata): number | undefined {
460
- if (oldMetadata.runStartTime !== newMetadata.runStartTime && typeof newMetadata.runStartTime === 'number') {
461
- const offset = Date.now() - newMetadata.runStartTime;
462
- return offset < 0 ? Math.abs(offset) : 0;
463
- } else {
464
- return newMetadata.runStartTimeAdjustment;
465
- }
466
- }
1
+ // *****************************************************************************
2
+ // Copyright (C) 2023 TypeFox and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+ /*---------------------------------------------------------------------------------------------
17
+ * Copyright (c) Microsoft Corporation. All rights reserved.
18
+ * Licensed under the MIT License. See License.txt in the project root for license information.
19
+ *--------------------------------------------------------------------------------------------*/
20
+
21
+ import { Disposable, DisposableCollection, Emitter, Event, URI } from '@theia/core';
22
+ import { inject, injectable, interfaces, postConstruct } from '@theia/core/shared/inversify';
23
+ import { MonacoEditorModel } from '@theia/monaco/lib/browser/monaco-editor-model';
24
+ import { type MonacoEditor } from '@theia/monaco/lib/browser/monaco-editor';
25
+ import {
26
+ CellKind, NotebookCellCollapseState, NotebookCellInternalMetadata,
27
+ NotebookCellMetadata, CellOutput, CellData, CellOutputItem
28
+ } from '../../common';
29
+ import { NotebookCellOutputsSplice } from '../notebook-types';
30
+ import { NotebookMonacoTextModelService } from '../service/notebook-monaco-text-model-service';
31
+ import { NotebookCellOutputModel } from './notebook-cell-output-model';
32
+ import { PreferenceService } from '@theia/core/lib/browser';
33
+ import { NotebookPreferences } from '../contributions/notebook-preferences';
34
+ import { LanguageService } from '@theia/core/lib/browser/language-service';
35
+ import { NotebookEditorFindMatch, NotebookEditorFindMatchOptions } from '../view/notebook-find-widget';
36
+ import { Range } from '@theia/core/shared/vscode-languageserver-protocol';
37
+
38
+ export const NotebookCellModelFactory = Symbol('NotebookModelFactory');
39
+ export type NotebookCellModelFactory = (props: NotebookCellModelProps) => NotebookCellModel;
40
+
41
+ export type CellEditorFocusRequest = number | 'lastLine' | undefined;
42
+
43
+ export function createNotebookCellModelContainer(parent: interfaces.Container, props: NotebookCellModelProps): interfaces.Container {
44
+ const child = parent.createChild();
45
+
46
+ child.bind(NotebookCellModelProps).toConstantValue(props);
47
+ child.bind(NotebookCellModel).toSelf();
48
+
49
+ return child;
50
+ }
51
+
52
+ export interface CellInternalMetadataChangedEvent {
53
+ readonly lastRunSuccessChanged?: boolean;
54
+ }
55
+
56
+ export interface NotebookCell {
57
+ readonly uri: URI;
58
+ handle: number;
59
+ language: string;
60
+ cellKind: CellKind;
61
+ outputs: CellOutput[];
62
+ metadata: NotebookCellMetadata;
63
+ internalMetadata: NotebookCellInternalMetadata;
64
+ text: string;
65
+ onDidChangeOutputs?: Event<NotebookCellOutputsSplice>;
66
+ onDidChangeOutputItems?: Event<CellOutput>;
67
+ onDidChangeLanguage: Event<string>;
68
+ onDidChangeMetadata: Event<void>;
69
+ onDidChangeInternalMetadata: Event<CellInternalMetadataChangedEvent>;
70
+
71
+ }
72
+
73
+ const NotebookCellModelProps = Symbol('NotebookModelProps');
74
+ export interface NotebookCellModelProps {
75
+ readonly uri: URI,
76
+ readonly handle: number,
77
+ source: string,
78
+ language: string,
79
+ readonly cellKind: CellKind,
80
+ outputs: CellOutput[],
81
+ metadata?: NotebookCellMetadata | undefined,
82
+ internalMetadata?: NotebookCellInternalMetadata | undefined,
83
+ readonly collapseState?: NotebookCellCollapseState | undefined,
84
+
85
+ }
86
+
87
+ @injectable()
88
+ export class NotebookCellModel implements NotebookCell, Disposable {
89
+
90
+ protected readonly onDidChangeOutputsEmitter = new Emitter<NotebookCellOutputsSplice>();
91
+ readonly onDidChangeOutputs = this.onDidChangeOutputsEmitter.event;
92
+
93
+ protected readonly onDidChangeOutputItemsEmitter = new Emitter<CellOutput>();
94
+ readonly onDidChangeOutputItems = this.onDidChangeOutputItemsEmitter.event;
95
+
96
+ protected readonly onDidChangeContentEmitter = new Emitter<'content' | 'language' | 'mime'>();
97
+ readonly onDidChangeContent = this.onDidChangeContentEmitter.event;
98
+
99
+ protected readonly onDidChangeMetadataEmitter = new Emitter<void>();
100
+ readonly onDidChangeMetadata = this.onDidChangeMetadataEmitter.event;
101
+
102
+ protected readonly onDidChangeInternalMetadataEmitter = new Emitter<CellInternalMetadataChangedEvent>();
103
+ readonly onDidChangeInternalMetadata = this.onDidChangeInternalMetadataEmitter.event;
104
+
105
+ protected readonly onDidChangeLanguageEmitter = new Emitter<string>();
106
+ readonly onDidChangeLanguage = this.onDidChangeLanguageEmitter.event;
107
+
108
+ protected readonly onDidRequestCellEditChangeEmitter = new Emitter<boolean>();
109
+ readonly onDidRequestCellEditChange = this.onDidRequestCellEditChangeEmitter.event;
110
+
111
+ protected readonly onWillFocusCellEditorEmitter = new Emitter<CellEditorFocusRequest>();
112
+ readonly onWillFocusCellEditor = this.onWillFocusCellEditorEmitter.event;
113
+
114
+ protected readonly onWillBlurCellEditorEmitter = new Emitter<void>();
115
+ readonly onWillBlurCellEditor = this.onWillBlurCellEditorEmitter.event;
116
+
117
+ protected readonly onDidChangeEditorOptionsEmitter = new Emitter<MonacoEditor.IOptions>();
118
+ readonly onDidChangeEditorOptions = this.onDidChangeEditorOptionsEmitter.event;
119
+
120
+ protected readonly outputVisibilityChangeEmitter = new Emitter<boolean>();
121
+ readonly onDidChangeOutputVisibility = this.outputVisibilityChangeEmitter.event;
122
+
123
+ protected readonly onDidFindMatchesEmitter = new Emitter<NotebookCodeEditorFindMatch[]>();
124
+ readonly onDidFindMatches: Event<NotebookCodeEditorFindMatch[]> = this.onDidFindMatchesEmitter.event;
125
+
126
+ protected readonly onDidSelectFindMatchEmitter = new Emitter<NotebookCodeEditorFindMatch>();
127
+ readonly onDidSelectFindMatch: Event<NotebookCodeEditorFindMatch> = this.onDidSelectFindMatchEmitter.event;
128
+
129
+ protected onDidRequestCenterEditorEmitter = new Emitter<void>();
130
+ readonly onDidRequestCenterEditor = this.onDidRequestCenterEditorEmitter.event;
131
+
132
+ @inject(NotebookCellModelProps)
133
+ protected readonly props: NotebookCellModelProps;
134
+
135
+ @inject(NotebookMonacoTextModelService)
136
+ protected readonly textModelService: NotebookMonacoTextModelService;
137
+
138
+ @inject(LanguageService)
139
+ protected readonly languageService: LanguageService;
140
+
141
+ @inject(PreferenceService)
142
+ protected readonly preferenceService: PreferenceService;
143
+
144
+ get outputs(): NotebookCellOutputModel[] {
145
+ return this._outputs;
146
+ }
147
+
148
+ protected _outputs: NotebookCellOutputModel[];
149
+
150
+ get metadata(): NotebookCellMetadata {
151
+ return this._metadata;
152
+ }
153
+
154
+ set metadata(newMetadata: NotebookCellMetadata) {
155
+ this._metadata = newMetadata;
156
+ this.onDidChangeMetadataEmitter.fire();
157
+ }
158
+
159
+ protected _metadata: NotebookCellMetadata;
160
+
161
+ protected toDispose = new DisposableCollection();
162
+
163
+ protected _internalMetadata: NotebookCellInternalMetadata;
164
+
165
+ get internalMetadata(): NotebookCellInternalMetadata {
166
+ return this._internalMetadata;
167
+ }
168
+
169
+ set internalMetadata(newInternalMetadata: NotebookCellInternalMetadata) {
170
+ const lastRunSuccessChanged = this._internalMetadata.lastRunSuccess !== newInternalMetadata.lastRunSuccess;
171
+ newInternalMetadata = {
172
+ ...newInternalMetadata,
173
+ ...{ runStartTimeAdjustment: computeRunStartTimeAdjustment(this._internalMetadata, newInternalMetadata) }
174
+ };
175
+ this._internalMetadata = newInternalMetadata;
176
+ this.onDidChangeInternalMetadataEmitter.fire({ lastRunSuccessChanged });
177
+
178
+ }
179
+
180
+ protected textModel?: MonacoEditorModel;
181
+
182
+ get text(): string {
183
+ return this.textModel && !this.textModel.isDisposed() ? this.textModel.getText() : this.source;
184
+ }
185
+
186
+ get source(): string {
187
+ return this.props.source;
188
+ }
189
+
190
+ set source(source: string) {
191
+ this.props.source = source;
192
+ this.textModel?.textEditorModel.setValue(source);
193
+ }
194
+
195
+ get language(): string {
196
+ return this.props.language;
197
+ }
198
+
199
+ set language(newLanguage: string) {
200
+ if (this.language === newLanguage) {
201
+ return;
202
+ }
203
+
204
+ if (this.textModel) {
205
+ this.textModel.setLanguageId(newLanguage);
206
+ }
207
+
208
+ this.props.language = newLanguage;
209
+ this.onDidChangeLanguageEmitter.fire(newLanguage);
210
+ this.onDidChangeContentEmitter.fire('language');
211
+ }
212
+
213
+ get languageName(): string {
214
+ return this.languageService.getLanguage(this.language)?.name ?? this.language;
215
+ }
216
+
217
+ get uri(): URI {
218
+ return this.props.uri;
219
+ }
220
+ get handle(): number {
221
+ return this.props.handle;
222
+ }
223
+ get cellKind(): CellKind {
224
+ return this.props.cellKind;
225
+ }
226
+
227
+ protected _editing: boolean = false;
228
+ get editing(): boolean {
229
+ return this._editing;
230
+ }
231
+
232
+ protected _editorOptions: MonacoEditor.IOptions = {};
233
+ get editorOptions(): Readonly<MonacoEditor.IOptions> {
234
+ return this._editorOptions;
235
+ }
236
+
237
+ set editorOptions(options: MonacoEditor.IOptions) {
238
+ this._editorOptions = options;
239
+ this.onDidChangeEditorOptionsEmitter.fire(options);
240
+ }
241
+
242
+ protected _outputVisible: boolean = true;
243
+ get outputVisible(): boolean {
244
+ return this._outputVisible;
245
+ }
246
+
247
+ set outputVisible(visible: boolean) {
248
+ if (this._outputVisible !== visible) {
249
+ this._outputVisible = visible;
250
+ this.outputVisibilityChangeEmitter.fire(visible);
251
+ }
252
+ }
253
+
254
+ @postConstruct()
255
+ protected init(): void {
256
+ this._outputs = this.props.outputs.map(op => new NotebookCellOutputModel(op));
257
+ this._metadata = this.props.metadata ?? {};
258
+ this._internalMetadata = this.props.internalMetadata ?? {};
259
+
260
+ this.editorOptions = {
261
+ lineNumbers: this.preferenceService.get(NotebookPreferences.NOTEBOOK_LINE_NUMBERS)
262
+ };
263
+ this.toDispose.push(this.preferenceService.onPreferenceChanged(e => {
264
+ if (e.preferenceName === NotebookPreferences.NOTEBOOK_LINE_NUMBERS) {
265
+ this.editorOptions = {
266
+ ...this.editorOptions,
267
+ lineNumbers: this.preferenceService.get(NotebookPreferences.NOTEBOOK_LINE_NUMBERS)
268
+ };
269
+ }
270
+ }));
271
+ }
272
+
273
+ dispose(): void {
274
+ this.onDidChangeOutputsEmitter.dispose();
275
+ this.onDidChangeOutputItemsEmitter.dispose();
276
+ this.onDidChangeContentEmitter.dispose();
277
+ this.onDidChangeMetadataEmitter.dispose();
278
+ this.onDidChangeInternalMetadataEmitter.dispose();
279
+ this.onDidChangeLanguageEmitter.dispose();
280
+ this.toDispose.dispose();
281
+ }
282
+
283
+ requestEdit(): void {
284
+ if (!this.textModel || !this.textModel.readOnly) {
285
+ this._editing = true;
286
+ this.onDidRequestCellEditChangeEmitter.fire(true);
287
+ }
288
+ }
289
+
290
+ requestStopEdit(): void {
291
+ this._editing = false;
292
+ this.onDidRequestCellEditChangeEmitter.fire(false);
293
+ }
294
+
295
+ requestFocusEditor(focusRequest?: CellEditorFocusRequest): void {
296
+ this.requestEdit();
297
+ this.onWillFocusCellEditorEmitter.fire(focusRequest);
298
+ }
299
+
300
+ requestBlurEditor(): void {
301
+ this.requestStopEdit();
302
+ this.onWillBlurCellEditorEmitter.fire();
303
+ }
304
+
305
+ requestCenterEditor(): void {
306
+ this.onDidRequestCenterEditorEmitter.fire();
307
+ }
308
+
309
+ spliceNotebookCellOutputs(splice: NotebookCellOutputsSplice): void {
310
+ if (splice.deleteCount > 0 && splice.newOutputs.length > 0) {
311
+ const commonLen = Math.min(splice.deleteCount, splice.newOutputs.length);
312
+ // update
313
+ for (let i = 0; i < commonLen; i++) {
314
+ const currentOutput = this.outputs[splice.start + i];
315
+ const newOutput = splice.newOutputs[i];
316
+
317
+ this.replaceOutputData(currentOutput.outputId, newOutput);
318
+ }
319
+
320
+ this.outputs.splice(splice.start + commonLen, splice.deleteCount - commonLen, ...splice.newOutputs.slice(commonLen).map(op => new NotebookCellOutputModel(op)));
321
+ this.onDidChangeOutputsEmitter.fire({ start: splice.start + commonLen, deleteCount: splice.deleteCount - commonLen, newOutputs: splice.newOutputs.slice(commonLen) });
322
+ } else {
323
+ this.outputs.splice(splice.start, splice.deleteCount, ...splice.newOutputs.map(op => new NotebookCellOutputModel(op)));
324
+ this.onDidChangeOutputsEmitter.fire(splice);
325
+ }
326
+ }
327
+
328
+ replaceOutputData(outputId: string, newOutputData: CellOutput): boolean {
329
+ const output = this.outputs.find(out => out.outputId === outputId);
330
+
331
+ if (!output) {
332
+ return false;
333
+ }
334
+
335
+ output.replaceData(newOutputData);
336
+ this.onDidChangeOutputItemsEmitter.fire(output);
337
+ return true;
338
+ }
339
+
340
+ changeOutputItems(outputId: string, append: boolean, items: CellOutputItem[]): boolean {
341
+ const output = this.outputs.find(out => out.outputId === outputId);
342
+
343
+ if (!output) {
344
+ return false;
345
+ }
346
+
347
+ if (append) {
348
+ output.appendData(items);
349
+ } else {
350
+ output.replaceData({ outputId: outputId, outputs: items, metadata: output.metadata });
351
+ }
352
+ this.onDidChangeOutputItemsEmitter.fire(output);
353
+ return true;
354
+ }
355
+
356
+ getData(): CellData {
357
+ return {
358
+ cellKind: this.cellKind,
359
+ language: this.language,
360
+ outputs: this.outputs.map(output => output.getData()),
361
+ source: this.text,
362
+ collapseState: this.props.collapseState,
363
+ internalMetadata: this.internalMetadata,
364
+ metadata: this.metadata
365
+ };
366
+ }
367
+
368
+ async resolveTextModel(): Promise<MonacoEditorModel> {
369
+ if (this.textModel) {
370
+ return this.textModel;
371
+ }
372
+
373
+ const ref = await this.textModelService.getOrCreateNotebookCellModelReference(this.uri);
374
+ this.textModel = ref.object;
375
+ this.toDispose.push(ref);
376
+ this.toDispose.push(this.textModel.onDidChangeContent(e => {
377
+ this.props.source = e.model.getText();
378
+ }));
379
+ return ref.object;
380
+ }
381
+
382
+ restartOutputRenderer(outputId: string): void {
383
+ const output = this.outputs.find(out => out.outputId === outputId);
384
+ if (output) {
385
+ this.onDidChangeOutputItemsEmitter.fire(output);
386
+ }
387
+ }
388
+
389
+ onMarkdownFind: ((options: NotebookEditorFindMatchOptions) => NotebookEditorFindMatch[]) | undefined;
390
+
391
+ showMatch(selected: NotebookCodeEditorFindMatch): void {
392
+ this.onDidSelectFindMatchEmitter.fire(selected);
393
+ }
394
+
395
+ findMatches(options: NotebookEditorFindMatchOptions): NotebookEditorFindMatch[] {
396
+ if (this.cellKind === CellKind.Markup && !this.editing) {
397
+ return this.onMarkdownFind?.(options) ?? [];
398
+ }
399
+ if (!this.textModel) {
400
+ return [];
401
+ }
402
+ const matches = options.search ? this.textModel.findMatches({
403
+ searchString: options.search,
404
+ isRegex: options.regex,
405
+ matchCase: options.matchCase,
406
+ matchWholeWord: options.wholeWord
407
+ }) : [];
408
+ const editorFindMatches = matches.map(match => new NotebookCodeEditorFindMatch(this, match.range, this.textModel!));
409
+ this.onDidFindMatchesEmitter.fire(editorFindMatches);
410
+ return editorFindMatches;
411
+ }
412
+
413
+ replaceAll(matches: NotebookCodeEditorFindMatch[], value: string): void {
414
+ const editOperations = matches.map(match => ({
415
+ range: {
416
+ startColumn: match.range.start.character,
417
+ startLineNumber: match.range.start.line,
418
+ endColumn: match.range.end.character,
419
+ endLineNumber: match.range.end.line
420
+ },
421
+ text: value
422
+ }));
423
+ this.textModel?.textEditorModel.pushEditOperations(
424
+ // eslint-disable-next-line no-null/no-null
425
+ null,
426
+ editOperations,
427
+ // eslint-disable-next-line no-null/no-null
428
+ () => null);
429
+ }
430
+ }
431
+
432
+ export interface NotebookCellFindMatches {
433
+ matches: NotebookEditorFindMatch[];
434
+ selected: NotebookEditorFindMatch;
435
+ }
436
+
437
+ export class NotebookCodeEditorFindMatch implements NotebookEditorFindMatch {
438
+
439
+ selected = false;
440
+
441
+ constructor(readonly cell: NotebookCellModel, readonly range: Range, readonly textModel: MonacoEditorModel) {
442
+ }
443
+
444
+ show(): void {
445
+ this.cell.showMatch(this);
446
+ }
447
+ replace(value: string): void {
448
+ this.textModel.textEditorModel.pushEditOperations(
449
+ // eslint-disable-next-line no-null/no-null
450
+ null,
451
+ [{
452
+ range: {
453
+ startColumn: this.range.start.character,
454
+ startLineNumber: this.range.start.line,
455
+ endColumn: this.range.end.character,
456
+ endLineNumber: this.range.end.line
457
+ },
458
+ text: value
459
+ }],
460
+ // eslint-disable-next-line no-null/no-null
461
+ () => null);
462
+ }
463
+
464
+ }
465
+
466
+ function computeRunStartTimeAdjustment(oldMetadata: NotebookCellInternalMetadata, newMetadata: NotebookCellInternalMetadata): number | undefined {
467
+ if (oldMetadata.runStartTime !== newMetadata.runStartTime && typeof newMetadata.runStartTime === 'number') {
468
+ const offset = Date.now() - newMetadata.runStartTime;
469
+ return offset < 0 ? Math.abs(offset) : 0;
470
+ } else {
471
+ return newMetadata.runStartTimeAdjustment;
472
+ }
473
+ }