@theia/notebook 1.44.0 → 1.45.1
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.
- package/lib/browser/contributions/notebook-actions-contribution.d.ts +2 -2
- package/lib/browser/contributions/notebook-actions-contribution.d.ts.map +1 -1
- package/lib/browser/contributions/notebook-actions-contribution.js +1 -1
- package/lib/browser/contributions/notebook-actions-contribution.js.map +1 -1
- package/lib/browser/index.d.ts +1 -0
- package/lib/browser/index.d.ts.map +1 -1
- package/lib/browser/index.js +1 -0
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/notebook-editor-widget.d.ts +4 -1
- package/lib/browser/notebook-editor-widget.d.ts.map +1 -1
- package/lib/browser/notebook-editor-widget.js +9 -3
- package/lib/browser/notebook-editor-widget.js.map +1 -1
- package/lib/browser/notebook-frontend-module.js +1 -1
- package/lib/browser/notebook-frontend-module.js.map +1 -1
- package/lib/browser/notebook-output-utils.d.ts +13 -0
- package/lib/browser/notebook-output-utils.d.ts.map +1 -0
- package/lib/browser/notebook-output-utils.js +112 -0
- package/lib/browser/notebook-output-utils.js.map +1 -0
- package/lib/browser/notebook-types.d.ts +120 -0
- package/lib/browser/notebook-types.d.ts.map +1 -0
- package/lib/browser/notebook-types.js +28 -0
- package/lib/browser/notebook-types.js.map +1 -0
- package/lib/browser/service/notebook-cell-context-manager.d.ts +5 -4
- package/lib/browser/service/notebook-cell-context-manager.d.ts.map +1 -1
- package/lib/browser/service/notebook-cell-context-manager.js +15 -10
- package/lib/browser/service/notebook-cell-context-manager.js.map +1 -1
- package/lib/browser/service/notebook-editor-widget-service.d.ts +2 -5
- package/lib/browser/service/notebook-editor-widget-service.d.ts.map +1 -1
- package/lib/browser/service/notebook-editor-widget-service.js +12 -15
- package/lib/browser/service/notebook-editor-widget-service.js.map +1 -1
- package/lib/browser/service/notebook-execution-service.d.ts +3 -4
- package/lib/browser/service/notebook-execution-service.d.ts.map +1 -1
- package/lib/browser/service/notebook-execution-service.js +2 -12
- package/lib/browser/service/notebook-execution-service.js.map +1 -1
- package/lib/browser/service/notebook-execution-state-service.d.ts +2 -5
- package/lib/browser/service/notebook-execution-state-service.d.ts.map +1 -1
- package/lib/browser/service/notebook-execution-state-service.js.map +1 -1
- package/lib/browser/service/notebook-kernel-history-service.d.ts +4 -1
- package/lib/browser/service/notebook-kernel-history-service.d.ts.map +1 -1
- package/lib/browser/service/notebook-kernel-history-service.js +15 -0
- package/lib/browser/service/notebook-kernel-history-service.js.map +1 -1
- package/lib/browser/service/notebook-kernel-quick-pick-service.d.ts +5 -11
- package/lib/browser/service/notebook-kernel-quick-pick-service.d.ts.map +1 -1
- package/lib/browser/service/notebook-kernel-quick-pick-service.js +33 -48
- package/lib/browser/service/notebook-kernel-quick-pick-service.js.map +1 -1
- package/lib/browser/view/notebook-cell-editor.d.ts +1 -1
- package/lib/browser/view/notebook-cell-editor.d.ts.map +1 -1
- package/lib/browser/view/notebook-cell-editor.js +5 -5
- package/lib/browser/view/notebook-cell-editor.js.map +1 -1
- package/lib/browser/view/notebook-cell-list-view.d.ts.map +1 -1
- package/lib/browser/view/notebook-cell-list-view.js +9 -3
- package/lib/browser/view/notebook-cell-list-view.js.map +1 -1
- package/lib/browser/view/notebook-cell-toolbar-factory.d.ts +1 -0
- package/lib/browser/view/notebook-cell-toolbar-factory.d.ts.map +1 -1
- package/lib/browser/view/notebook-cell-toolbar-factory.js +2 -1
- package/lib/browser/view/notebook-cell-toolbar-factory.js.map +1 -1
- package/lib/browser/view/notebook-cell-toolbar.d.ts +5 -4
- package/lib/browser/view/notebook-cell-toolbar.d.ts.map +1 -1
- package/lib/browser/view/notebook-cell-toolbar.js +6 -4
- package/lib/browser/view/notebook-cell-toolbar.js.map +1 -1
- package/lib/browser/view/notebook-main-toolbar.d.ts.map +1 -1
- package/lib/browser/view/notebook-main-toolbar.js +8 -0
- package/lib/browser/view/notebook-main-toolbar.js.map +1 -1
- package/lib/browser/view-model/notebook-cell-model.d.ts +22 -2
- package/lib/browser/view-model/notebook-cell-model.d.ts.map +1 -1
- package/lib/browser/view-model/notebook-cell-model.js +5 -0
- package/lib/browser/view-model/notebook-cell-model.js.map +1 -1
- package/lib/browser/view-model/notebook-cell-output-model.d.ts.map +1 -1
- package/lib/browser/view-model/notebook-cell-output-model.js +4 -3
- package/lib/browser/view-model/notebook-cell-output-model.js.map +1 -1
- package/lib/browser/view-model/notebook-model.d.ts +9 -7
- package/lib/browser/view-model/notebook-model.d.ts.map +1 -1
- package/lib/browser/view-model/notebook-model.js +42 -36
- package/lib/browser/view-model/notebook-model.js.map +1 -1
- package/lib/common/notebook-common.d.ts +14 -146
- package/lib/common/notebook-common.d.ts.map +1 -1
- package/lib/common/notebook-common.js +13 -9
- package/lib/common/notebook-common.js.map +1 -1
- package/package.json +7 -7
- package/src/browser/contributions/notebook-actions-contribution.ts +2 -2
- package/src/browser/index.ts +1 -0
- package/src/browser/notebook-editor-widget.tsx +11 -5
- package/src/browser/notebook-frontend-module.ts +2 -2
- package/src/browser/notebook-output-utils.ts +119 -0
- package/src/browser/notebook-types.ts +172 -0
- package/src/browser/service/notebook-cell-context-manager.ts +17 -12
- package/src/browser/service/notebook-editor-widget-service.ts +14 -19
- package/src/browser/service/notebook-execution-service.ts +4 -16
- package/src/browser/service/notebook-execution-state-service.ts +2 -5
- package/src/browser/service/notebook-kernel-history-service.ts +18 -1
- package/src/browser/service/notebook-kernel-quick-pick-service.ts +29 -49
- package/src/browser/view/notebook-cell-editor.tsx +7 -5
- package/src/browser/view/notebook-cell-list-view.tsx +8 -3
- package/src/browser/view/notebook-cell-toolbar-factory.tsx +3 -1
- package/src/browser/view/notebook-cell-toolbar.tsx +8 -5
- package/src/browser/view/notebook-main-toolbar.tsx +9 -0
- package/src/browser/view-model/notebook-cell-model.ts +30 -3
- package/src/browser/view-model/notebook-cell-output-model.ts +6 -5
- package/src/browser/view-model/notebook-model.ts +52 -45
- package/src/common/notebook-common.ts +22 -181
|
@@ -18,19 +18,18 @@
|
|
|
18
18
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
19
19
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
20
20
|
*--------------------------------------------------------------------------------------------*/
|
|
21
|
-
import { ArrayUtils,
|
|
21
|
+
import { ArrayUtils, CommandService, DisposableCollection, Event, nls, QuickInputButton, QuickInputService, QuickPickInput, QuickPickItem, URI, } from '@theia/core';
|
|
22
22
|
import { inject, injectable } from '@theia/core/shared/inversify';
|
|
23
23
|
import { NotebookKernelService, NotebookKernel, NotebookKernelMatchResult, SourceCommand } from './notebook-kernel-service';
|
|
24
24
|
import { NotebookModel } from '../view-model/notebook-model';
|
|
25
25
|
import { NotebookEditorWidget } from '../notebook-editor-widget';
|
|
26
26
|
import { codicon, OpenerService } from '@theia/core/lib/browser';
|
|
27
27
|
import { NotebookKernelHistoryService } from './notebook-kernel-history-service';
|
|
28
|
+
import { NotebookCommand, NotebookModelResource } from '../../common';
|
|
28
29
|
import debounce = require('@theia/core/shared/lodash.debounce');
|
|
29
30
|
|
|
30
31
|
export const JUPYTER_EXTENSION_ID = 'ms-toolsai.jupyter';
|
|
31
32
|
|
|
32
|
-
export const NotebookKernelQuickPickService = Symbol('NotebookKernelQuickPickService');
|
|
33
|
-
|
|
34
33
|
type KernelPick = QuickPickItem & { kernel: NotebookKernel };
|
|
35
34
|
function isKernelPick(item: QuickPickInput<QuickPickItem>): item is KernelPick {
|
|
36
35
|
return 'kernel' in item;
|
|
@@ -45,7 +44,7 @@ function isSourcePick(item: QuickPickInput<QuickPickItem>): item is SourcePick {
|
|
|
45
44
|
}
|
|
46
45
|
type InstallExtensionPick = QuickPickItem & { extensionIds: string[] };
|
|
47
46
|
|
|
48
|
-
type KernelSourceQuickPickItem = QuickPickItem & { command:
|
|
47
|
+
type KernelSourceQuickPickItem = QuickPickItem & { command: NotebookCommand; documentation?: string };
|
|
49
48
|
function isKernelSourceQuickPickItem(item: QuickPickItem): item is KernelSourceQuickPickItem {
|
|
50
49
|
return 'command' in item;
|
|
51
50
|
}
|
|
@@ -82,7 +81,7 @@ function toKernelQuickPick(kernel: NotebookKernel, selected: NotebookKernel | un
|
|
|
82
81
|
}
|
|
83
82
|
|
|
84
83
|
@injectable()
|
|
85
|
-
export
|
|
84
|
+
export class NotebookKernelQuickPickService {
|
|
86
85
|
|
|
87
86
|
@inject(NotebookKernelService)
|
|
88
87
|
protected readonly notebookKernelService: NotebookKernelService;
|
|
@@ -91,6 +90,12 @@ export abstract class NotebookKernelQuickPickServiceImpl {
|
|
|
91
90
|
@inject(CommandService)
|
|
92
91
|
protected readonly commandService: CommandService;
|
|
93
92
|
|
|
93
|
+
@inject(OpenerService)
|
|
94
|
+
protected openerService: OpenerService;
|
|
95
|
+
|
|
96
|
+
@inject(NotebookKernelHistoryService)
|
|
97
|
+
protected notebookKernelHistoryService: NotebookKernelHistoryService;
|
|
98
|
+
|
|
94
99
|
async showQuickPick(editor: NotebookModel, wantedId?: string, skipAutoRun?: boolean): Promise<boolean> {
|
|
95
100
|
const notebook = editor;
|
|
96
101
|
const matchResult = this.getMatchingResult(notebook);
|
|
@@ -200,40 +205,6 @@ export abstract class NotebookKernelQuickPickServiceImpl {
|
|
|
200
205
|
return false;
|
|
201
206
|
}
|
|
202
207
|
|
|
203
|
-
protected getMatchingResult(notebook: NotebookModel): NotebookKernelMatchResult {
|
|
204
|
-
return this.notebookKernelService.getMatchingKernel(notebook);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
protected abstract getKernelPickerQuickPickItems(matchResult: NotebookKernelMatchResult): QuickPickInput<KernelQuickPickItem>[];
|
|
208
|
-
|
|
209
|
-
protected async handleQuickPick(editor: NotebookModel, pick: KernelQuickPickItem, quickPickItems: KernelQuickPickItem[]): Promise<boolean> {
|
|
210
|
-
if (isKernelPick(pick)) {
|
|
211
|
-
const newKernel = pick.kernel;
|
|
212
|
-
this.selectKernel(editor, newKernel);
|
|
213
|
-
return true;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if (isSourcePick(pick)) {
|
|
217
|
-
// selected explicitly, it should trigger the execution?
|
|
218
|
-
pick.action.run(this.commandService);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
return true;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
protected selectKernel(notebook: NotebookModel, kernel: NotebookKernel): void {
|
|
225
|
-
this.notebookKernelService.selectKernelForNotebook(kernel, notebook);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
@injectable()
|
|
229
|
-
export class KernelPickerMRUStrategy extends NotebookKernelQuickPickServiceImpl {
|
|
230
|
-
|
|
231
|
-
@inject(OpenerService)
|
|
232
|
-
protected openerService: OpenerService;
|
|
233
|
-
|
|
234
|
-
@inject(NotebookKernelHistoryService)
|
|
235
|
-
protected notebookKernelHistoryService: NotebookKernelHistoryService;
|
|
236
|
-
|
|
237
208
|
protected getKernelPickerQuickPickItems(matchResult: NotebookKernelMatchResult): QuickPickInput<KernelQuickPickItem>[] {
|
|
238
209
|
const quickPickItems: QuickPickInput<KernelQuickPickItem>[] = [];
|
|
239
210
|
|
|
@@ -266,17 +237,17 @@ export class KernelPickerMRUStrategy extends NotebookKernelQuickPickServiceImpl
|
|
|
266
237
|
return quickPickItems;
|
|
267
238
|
}
|
|
268
239
|
|
|
269
|
-
protected
|
|
240
|
+
protected selectKernel(notebook: NotebookModel, kernel: NotebookKernel): void {
|
|
270
241
|
const currentInfo = this.notebookKernelService.getMatchingKernel(notebook);
|
|
271
242
|
if (currentInfo.selected) {
|
|
272
243
|
// there is already a selected kernel
|
|
273
244
|
this.notebookKernelHistoryService.addMostRecentKernel(currentInfo.selected);
|
|
274
245
|
}
|
|
275
|
-
|
|
246
|
+
this.notebookKernelService.selectKernelForNotebook(kernel, notebook);
|
|
276
247
|
this.notebookKernelHistoryService.addMostRecentKernel(kernel);
|
|
277
248
|
}
|
|
278
249
|
|
|
279
|
-
protected
|
|
250
|
+
protected getMatchingResult(notebook: NotebookModel): NotebookKernelMatchResult {
|
|
280
251
|
const { selected, all } = this.notebookKernelHistoryService.getKernels(notebook);
|
|
281
252
|
const matchingResult = this.notebookKernelService.getMatchingKernel(notebook);
|
|
282
253
|
return {
|
|
@@ -287,12 +258,23 @@ export class KernelPickerMRUStrategy extends NotebookKernelQuickPickServiceImpl
|
|
|
287
258
|
};
|
|
288
259
|
}
|
|
289
260
|
|
|
290
|
-
protected
|
|
261
|
+
protected async handleQuickPick(editor: NotebookModel, pick: KernelQuickPickItem, items: KernelQuickPickItem[]): Promise<boolean> {
|
|
291
262
|
if (pick.id === 'selectAnother') {
|
|
292
263
|
return this.displaySelectAnotherQuickPick(editor, items.length === 1 && items[0] === pick);
|
|
293
264
|
}
|
|
294
265
|
|
|
295
|
-
|
|
266
|
+
if (isKernelPick(pick)) {
|
|
267
|
+
const newKernel = pick.kernel;
|
|
268
|
+
this.selectKernel(editor, newKernel);
|
|
269
|
+
return true;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (isSourcePick(pick)) {
|
|
273
|
+
// selected explicitly, it should trigger the execution?
|
|
274
|
+
pick.action.run(this.commandService);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return true;
|
|
296
278
|
}
|
|
297
279
|
|
|
298
280
|
private async displaySelectAnotherQuickPick(editor: NotebookModel, kernelListEmpty: boolean): Promise<boolean> {
|
|
@@ -488,10 +470,8 @@ export class KernelPickerMRUStrategy extends NotebookKernelQuickPickServiceImpl
|
|
|
488
470
|
quickPick.show();
|
|
489
471
|
}
|
|
490
472
|
|
|
491
|
-
private async executeCommand<T>(notebook: NotebookModel, command:
|
|
492
|
-
const
|
|
493
|
-
|
|
494
|
-
return this.commandService.executeCommand(id, { uri: notebook.uri });
|
|
495
|
-
|
|
473
|
+
private async executeCommand<T>(notebook: NotebookModel, command: NotebookCommand): Promise<T | undefined | void> {
|
|
474
|
+
const args = (command.arguments || []).concat([NotebookModelResource.create(notebook.uri)]);
|
|
475
|
+
return this.commandService.executeCommand(command.id, ...args);
|
|
496
476
|
}
|
|
497
477
|
}
|
|
@@ -77,13 +77,12 @@ export class CellEditor extends React.Component<CellEditorProps, {}> {
|
|
|
77
77
|
}));
|
|
78
78
|
this.toDispose.push(this.editor.onDocumentContentChanged(e => {
|
|
79
79
|
notebookModel.cellDirtyChanged(cell, true);
|
|
80
|
-
cell.source = e.document.getText();
|
|
81
80
|
}));
|
|
82
81
|
}
|
|
83
82
|
}
|
|
84
83
|
|
|
85
|
-
protected
|
|
86
|
-
this.container = component;
|
|
84
|
+
protected setContainer(component: HTMLDivElement | null): void {
|
|
85
|
+
this.container = component ?? undefined;
|
|
87
86
|
};
|
|
88
87
|
|
|
89
88
|
protected handleResize = () => {
|
|
@@ -91,7 +90,10 @@ export class CellEditor extends React.Component<CellEditorProps, {}> {
|
|
|
91
90
|
};
|
|
92
91
|
|
|
93
92
|
override render(): React.ReactNode {
|
|
94
|
-
return <div className='theia-notebook-cell-editor' onResize={this.handleResize} id={this.props.cell.uri.toString()}
|
|
95
|
-
|
|
93
|
+
return <div className='theia-notebook-cell-editor' onResize={this.handleResize} id={this.props.cell.uri.toString()}
|
|
94
|
+
ref={container => this.setContainer(container)}>
|
|
95
|
+
|
|
96
|
+
</div>;
|
|
97
|
+
}
|
|
96
98
|
|
|
97
99
|
}
|
|
@@ -47,7 +47,11 @@ export class NotebookCellListView extends React.Component<CellListProps, Noteboo
|
|
|
47
47
|
super(props);
|
|
48
48
|
this.state = { selectedCell: undefined, dragOverIndicator: undefined };
|
|
49
49
|
this.toDispose.push(props.notebookModel.onDidAddOrRemoveCell(e => {
|
|
50
|
-
|
|
50
|
+
if (e.newCellIds && e.newCellIds.length > 0) {
|
|
51
|
+
this.setState({ ...this.state, selectedCell: this.props.notebookModel.cells.find(model => model.handle === e.newCellIds![e.newCellIds!.length - 1]) });
|
|
52
|
+
} else {
|
|
53
|
+
this.setState({ ...this.state, selectedCell: this.props.notebookModel.cells.find(cell => cell === this.state.selectedCell)});
|
|
54
|
+
}
|
|
51
55
|
}));
|
|
52
56
|
}
|
|
53
57
|
|
|
@@ -101,7 +105,8 @@ export class NotebookCellListView extends React.Component<CellListProps, Noteboo
|
|
|
101
105
|
|
|
102
106
|
protected onDragStart(event: React.DragEvent<HTMLLIElement>, index: number): void {
|
|
103
107
|
event.stopPropagation();
|
|
104
|
-
event.dataTransfer.setData('text/notebook-cell-index', index.toString());
|
|
108
|
+
event.dataTransfer.setData('text/theia-notebook-cell-index', index.toString());
|
|
109
|
+
event.dataTransfer.setData('text/plain', this.props.notebookModel.cells[index].source);
|
|
105
110
|
}
|
|
106
111
|
|
|
107
112
|
protected onDragOver(event: React.DragEvent<HTMLLIElement>, cell: NotebookCellModel, position?: 'top' | 'bottom'): void {
|
|
@@ -112,7 +117,7 @@ export class NotebookCellListView extends React.Component<CellListProps, Noteboo
|
|
|
112
117
|
}
|
|
113
118
|
|
|
114
119
|
protected onDrop(event: React.DragEvent<HTMLLIElement>, dropElementIndex: number): void {
|
|
115
|
-
const index = parseInt(event.dataTransfer.getData('text/notebook-cell-index'));
|
|
120
|
+
const index = parseInt(event.dataTransfer.getData('text/theia-notebook-cell-index'));
|
|
116
121
|
const isTargetBelow = index < dropElementIndex;
|
|
117
122
|
let newIdx = this.state.dragOverIndicator?.position === 'top' ? dropElementIndex : dropElementIndex + 1;
|
|
118
123
|
newIdx = isTargetBelow ? newIdx - 1 : newIdx;
|
|
@@ -29,6 +29,7 @@ export interface NotebookCellToolbarItem {
|
|
|
29
29
|
icon?: string;
|
|
30
30
|
label?: string;
|
|
31
31
|
onClick: (e: React.MouseEvent) => void;
|
|
32
|
+
contextKeys?: Set<string>
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
@injectable()
|
|
@@ -85,7 +86,8 @@ export class NotebookCellToolbarFactory {
|
|
|
85
86
|
includeAnchorArg: false,
|
|
86
87
|
args: [notebookModel, cell, output]
|
|
87
88
|
}) :
|
|
88
|
-
() => this.commandRegistry.executeCommand(menuNode.command!, notebookModel, cell, output)
|
|
89
|
+
() => this.commandRegistry.executeCommand(menuNode.command!, notebookModel, cell, output),
|
|
90
|
+
contextKeys: menuNode.when ? this.contextKeyService.parseKeys(menuNode.when) : undefined
|
|
89
91
|
};
|
|
90
92
|
}
|
|
91
93
|
}
|
|
@@ -17,24 +17,27 @@ import * as React from '@theia/core/shared/react';
|
|
|
17
17
|
import { ACTION_ITEM } from '@theia/core/lib/browser';
|
|
18
18
|
import { NotebookCellToolbarItem } from './notebook-cell-toolbar-factory';
|
|
19
19
|
import { DisposableCollection, Event } from '@theia/core';
|
|
20
|
+
import { ContextKeyChangeEvent } from '@theia/core/lib/browser/context-key-service';
|
|
20
21
|
|
|
21
22
|
export interface NotebookCellToolbarProps {
|
|
22
23
|
getMenuItems: () => NotebookCellToolbarItem[];
|
|
23
|
-
onContextKeysChanged: Event<
|
|
24
|
+
onContextKeysChanged: Event<ContextKeyChangeEvent>;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
interface NotebookCellToolbarState {
|
|
27
28
|
inlineItems: NotebookCellToolbarItem[];
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
abstract class
|
|
31
|
+
abstract class NotebookCellActionBar extends React.Component<NotebookCellToolbarProps, NotebookCellToolbarState> {
|
|
31
32
|
|
|
32
33
|
protected toDispose = new DisposableCollection();
|
|
33
34
|
|
|
34
35
|
constructor(props: NotebookCellToolbarProps) {
|
|
35
36
|
super(props);
|
|
36
37
|
this.toDispose.push(props.onContextKeysChanged(e => {
|
|
37
|
-
this.
|
|
38
|
+
if (this.props.getMenuItems().some(item => item.contextKeys ? e.affects(item.contextKeys) : false)) {
|
|
39
|
+
this.setState({ inlineItems: this.props.getMenuItems() });
|
|
40
|
+
}
|
|
38
41
|
}));
|
|
39
42
|
this.state = { inlineItems: this.props.getMenuItems() };
|
|
40
43
|
}
|
|
@@ -49,7 +52,7 @@ abstract class NotebookCellActionItems extends React.Component<NotebookCellToolb
|
|
|
49
52
|
|
|
50
53
|
}
|
|
51
54
|
|
|
52
|
-
export class NotebookCellToolbar extends
|
|
55
|
+
export class NotebookCellToolbar extends NotebookCellActionBar {
|
|
53
56
|
|
|
54
57
|
override render(): React.ReactNode {
|
|
55
58
|
return <div className='theia-notebook-cell-toolbar'>
|
|
@@ -59,7 +62,7 @@ export class NotebookCellToolbar extends NotebookCellActionItems {
|
|
|
59
62
|
|
|
60
63
|
}
|
|
61
64
|
|
|
62
|
-
export class NotebookCellSidebar extends
|
|
65
|
+
export class NotebookCellSidebar extends NotebookCellActionBar {
|
|
63
66
|
|
|
64
67
|
override render(): React.ReactNode {
|
|
65
68
|
return <div className='theia-notebook-cell-sidebar'>
|
|
@@ -66,6 +66,15 @@ export class NotebookMainToolbar extends React.Component<NotebookMainToolbarProp
|
|
|
66
66
|
this.setState({ selectedKernelLabel: props.notebookKernelService.getSelectedOrSuggestedKernel(props.notebookModel)?.label });
|
|
67
67
|
}
|
|
68
68
|
}));
|
|
69
|
+
|
|
70
|
+
// TODO maybe we need a mechanism to check for changes in the menu to update this toolbar
|
|
71
|
+
const contextKeys = new Set<string>();
|
|
72
|
+
this.getMenuItems().filter(item => item.when).forEach(item => props.contextKeyService.parseKeys(item.when!)?.forEach(key => contextKeys.add(key)));
|
|
73
|
+
props.contextKeyService.onDidChange(e => {
|
|
74
|
+
if (e.affects(contextKeys)) {
|
|
75
|
+
this.forceUpdate();
|
|
76
|
+
}
|
|
77
|
+
});
|
|
69
78
|
}
|
|
70
79
|
|
|
71
80
|
override componentWillUnmount(): void {
|
|
@@ -20,12 +20,14 @@
|
|
|
20
20
|
|
|
21
21
|
import { Disposable, DisposableCollection, Emitter, Event, URI } from '@theia/core';
|
|
22
22
|
import { inject, injectable, interfaces, postConstruct } from '@theia/core/shared/inversify';
|
|
23
|
+
import { ContextKeyChangeEvent } from '@theia/core/lib/browser/context-key-service';
|
|
23
24
|
import { MonacoEditorModel } from '@theia/monaco/lib/browser/monaco-editor-model';
|
|
24
25
|
import { MonacoTextModelService } from '@theia/monaco/lib/browser/monaco-text-model-service';
|
|
25
26
|
import {
|
|
26
|
-
|
|
27
|
-
NotebookCellMetadata,
|
|
27
|
+
CellKind, NotebookCellCollapseState, NotebookCellInternalMetadata,
|
|
28
|
+
NotebookCellMetadata, CellOutput, CellData, CellOutputItem
|
|
28
29
|
} from '../../common';
|
|
30
|
+
import { NotebookCellOutputsSplice } from '../notebook-types';
|
|
29
31
|
import { NotebookCellOutputModel } from './notebook-cell-output-model';
|
|
30
32
|
|
|
31
33
|
export const NotebookCellModelFactory = Symbol('NotebookModelFactory');
|
|
@@ -47,7 +49,28 @@ const NotebookCellContextManager = Symbol('NotebookCellContextManager');
|
|
|
47
49
|
interface NotebookCellContextManager {
|
|
48
50
|
updateCellContext(cell: NotebookCellModel, context: HTMLElement): void;
|
|
49
51
|
dispose(): void;
|
|
50
|
-
onDidChangeContext: Event<
|
|
52
|
+
onDidChangeContext: Event<ContextKeyChangeEvent>;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface CellInternalMetadataChangedEvent {
|
|
56
|
+
readonly lastRunSuccessChanged?: boolean;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface NotebookCell {
|
|
60
|
+
readonly uri: URI;
|
|
61
|
+
handle: number;
|
|
62
|
+
language: string;
|
|
63
|
+
cellKind: CellKind;
|
|
64
|
+
outputs: CellOutput[];
|
|
65
|
+
metadata: NotebookCellMetadata;
|
|
66
|
+
internalMetadata: NotebookCellInternalMetadata;
|
|
67
|
+
text: string;
|
|
68
|
+
onDidChangeOutputs?: Event<NotebookCellOutputsSplice>;
|
|
69
|
+
onDidChangeOutputItems?: Event<CellOutput>;
|
|
70
|
+
onDidChangeLanguage: Event<string>;
|
|
71
|
+
onDidChangeMetadata: Event<void>;
|
|
72
|
+
onDidChangeInternalMetadata: Event<CellInternalMetadataChangedEvent>;
|
|
73
|
+
|
|
51
74
|
}
|
|
52
75
|
|
|
53
76
|
const NotebookCellModelProps = Symbol('NotebookModelProps');
|
|
@@ -144,6 +167,7 @@ export class NotebookCellModel implements NotebookCell, Disposable {
|
|
|
144
167
|
}
|
|
145
168
|
set source(source: string) {
|
|
146
169
|
this.props.source = source;
|
|
170
|
+
this.textModel?.textEditorModel.setValue(source);
|
|
147
171
|
}
|
|
148
172
|
get language(): string {
|
|
149
173
|
return this.props.language;
|
|
@@ -274,6 +298,9 @@ export class NotebookCellModel implements NotebookCell, Disposable {
|
|
|
274
298
|
|
|
275
299
|
const ref = await this.textModelService.createModelReference(this.uri);
|
|
276
300
|
this.textModel = ref.object;
|
|
301
|
+
this.textModel.onDidChangeContent(e => {
|
|
302
|
+
this.props.source = e.model.getText();
|
|
303
|
+
});
|
|
277
304
|
return ref.object;
|
|
278
305
|
}
|
|
279
306
|
}
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
17
|
import { Disposable, Emitter } from '@theia/core';
|
|
18
|
-
import { BinaryBuffer } from '@theia/core/lib/common/buffer';
|
|
19
18
|
import { CellOutput, CellOutputItem, isTextStreamMime } from '../../common';
|
|
19
|
+
import { compressOutputItemStreams } from '../notebook-output-utils';
|
|
20
20
|
|
|
21
21
|
export class NotebookCellOutputModel implements Disposable {
|
|
22
22
|
|
|
@@ -73,10 +73,10 @@ export class NotebookCellOutputModel implements Disposable {
|
|
|
73
73
|
if (this.outputs.length > 1 && this.outputs.every(item => isTextStreamMime(item.mime))) {
|
|
74
74
|
// Look for the mimes in the items, and keep track of their order.
|
|
75
75
|
// Merge the streams into one output item, per mime type.
|
|
76
|
-
const mimeOutputs = new Map<string,
|
|
76
|
+
const mimeOutputs = new Map<string, Uint8Array[]>();
|
|
77
77
|
const mimeTypes: string[] = [];
|
|
78
78
|
this.outputs.forEach(item => {
|
|
79
|
-
let items:
|
|
79
|
+
let items: Uint8Array[];
|
|
80
80
|
if (mimeOutputs.has(item.mime)) {
|
|
81
81
|
items = mimeOutputs.get(item.mime)!;
|
|
82
82
|
} else {
|
|
@@ -84,13 +84,14 @@ export class NotebookCellOutputModel implements Disposable {
|
|
|
84
84
|
mimeOutputs.set(item.mime, items);
|
|
85
85
|
mimeTypes.push(item.mime);
|
|
86
86
|
}
|
|
87
|
-
items.push(item.data);
|
|
87
|
+
items.push(item.data.buffer);
|
|
88
88
|
});
|
|
89
89
|
this.outputs.length = 0;
|
|
90
90
|
mimeTypes.forEach(mime => {
|
|
91
|
+
const compressionResult = compressOutputItemStreams(mimeOutputs.get(mime)!);
|
|
91
92
|
this.outputs.push({
|
|
92
93
|
mime,
|
|
93
|
-
data:
|
|
94
|
+
data: compressionResult.data
|
|
94
95
|
});
|
|
95
96
|
});
|
|
96
97
|
}
|
|
@@ -17,18 +17,16 @@
|
|
|
17
17
|
import { Disposable, Emitter, URI } from '@theia/core';
|
|
18
18
|
import { Saveable, SaveOptions } from '@theia/core/lib/browser';
|
|
19
19
|
import {
|
|
20
|
-
CellData,
|
|
21
|
-
CellEditOperation, CellEditType, CellUri, NotebookCellInternalMetadata,
|
|
20
|
+
CellData, CellEditType, CellUri, NotebookCellInternalMetadata,
|
|
22
21
|
NotebookCellsChangeType, NotebookCellTextModelSplice, NotebookData,
|
|
23
|
-
NotebookDocumentMetadata,
|
|
24
|
-
NotebookTextModelChangedEvent, NullablePartialNotebookCellInternalMetadata
|
|
22
|
+
NotebookDocumentMetadata,
|
|
25
23
|
} from '../../common';
|
|
24
|
+
import { NotebookContentChangedEvent, NotebookModelWillAddRemoveEvent, CellEditOperation, NullablePartialNotebookCellInternalMetadata } from '../notebook-types';
|
|
26
25
|
import { NotebookSerializer } from '../service/notebook-service';
|
|
27
26
|
import { FileService } from '@theia/filesystem/lib/browser/file-service';
|
|
28
27
|
import { NotebookCellModel, NotebookCellModelFactory } from './notebook-cell-model';
|
|
29
28
|
import { MonacoTextModelService } from '@theia/monaco/lib/browser/monaco-text-model-service';
|
|
30
29
|
import { inject, injectable, interfaces, postConstruct } from '@theia/core/shared/inversify';
|
|
31
|
-
import { NotebookKernel } from '../service/notebook-kernel-service';
|
|
32
30
|
import { UndoRedoService } from '@theia/editor/lib/browser/undo-redo-service';
|
|
33
31
|
|
|
34
32
|
export const NotebookModelFactory = Symbol('NotebookModelFactory');
|
|
@@ -62,7 +60,7 @@ export class NotebookModel implements Saveable, Disposable {
|
|
|
62
60
|
protected readonly onDidAddOrRemoveCellEmitter = new Emitter<NotebookModelWillAddRemoveEvent>();
|
|
63
61
|
readonly onDidAddOrRemoveCell = this.onDidAddOrRemoveCellEmitter.event;
|
|
64
62
|
|
|
65
|
-
protected readonly onDidChangeContentEmitter = new Emitter<
|
|
63
|
+
protected readonly onDidChangeContentEmitter = new Emitter<NotebookContentChangedEvent[]>();
|
|
66
64
|
readonly onDidChangeContent = this.onDidChangeContentEmitter.event;
|
|
67
65
|
|
|
68
66
|
@inject(FileService)
|
|
@@ -81,11 +79,19 @@ export class NotebookModel implements Saveable, Disposable {
|
|
|
81
79
|
protected cellModelFactory: NotebookCellModelFactory;
|
|
82
80
|
readonly autoSave: 'off' | 'afterDelay' | 'onFocusChange' | 'onWindowChange';
|
|
83
81
|
|
|
84
|
-
nextHandle: number = 0;
|
|
82
|
+
protected nextHandle: number = 0;
|
|
85
83
|
|
|
86
|
-
|
|
84
|
+
protected _dirty: boolean = false;
|
|
85
|
+
|
|
86
|
+
set dirty(dirty: boolean) {
|
|
87
|
+
this._dirty = dirty;
|
|
88
|
+
this.onDirtyChangedEmitter.fire();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
get dirty(): boolean {
|
|
92
|
+
return this._dirty;
|
|
93
|
+
}
|
|
87
94
|
|
|
88
|
-
dirty: boolean;
|
|
89
95
|
selectedCell?: NotebookCellModel;
|
|
90
96
|
protected dirtyCells: NotebookCellModel[] = [];
|
|
91
97
|
|
|
@@ -121,18 +127,6 @@ export class NotebookModel implements Saveable, Disposable {
|
|
|
121
127
|
|
|
122
128
|
this.metadata = this.metadata;
|
|
123
129
|
|
|
124
|
-
this.modelService.onDidCreate(editorModel => {
|
|
125
|
-
const modelUri = new URI(editorModel.uri);
|
|
126
|
-
if (modelUri.scheme === CellUri.scheme) {
|
|
127
|
-
const cellUri = CellUri.parse(modelUri);
|
|
128
|
-
if (cellUri && cellUri.notebook.isEqual(this.uri)) {
|
|
129
|
-
const cell = this.cells.find(c => c.handle === cellUri.handle);
|
|
130
|
-
if (cell) {
|
|
131
|
-
cell.textModel = editorModel;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
});
|
|
136
130
|
this.nextHandle = this.cells.length;
|
|
137
131
|
}
|
|
138
132
|
|
|
@@ -147,7 +141,6 @@ export class NotebookModel implements Saveable, Disposable {
|
|
|
147
141
|
async save(options: SaveOptions): Promise<void> {
|
|
148
142
|
this.dirtyCells = [];
|
|
149
143
|
this.dirty = false;
|
|
150
|
-
this.onDirtyChangedEmitter.fire();
|
|
151
144
|
|
|
152
145
|
const serializedNotebook = await this.props.serializer.fromNotebook({
|
|
153
146
|
cells: this.cells.map(cell => cell.getData()),
|
|
@@ -170,9 +163,34 @@ export class NotebookModel implements Saveable, Disposable {
|
|
|
170
163
|
};
|
|
171
164
|
}
|
|
172
165
|
|
|
166
|
+
async applySnapshot(snapshot: Saveable.Snapshot): Promise<void> {
|
|
167
|
+
const rawData = 'read' in snapshot ? snapshot.read() : snapshot.value;
|
|
168
|
+
if (!rawData) {
|
|
169
|
+
throw new Error('could not read notebook snapshot');
|
|
170
|
+
}
|
|
171
|
+
const data = JSON.parse(rawData);
|
|
172
|
+
const cells = data.cells.map((cell: CellData, index: number) => {
|
|
173
|
+
const handle = this.nextHandle++;
|
|
174
|
+
return this.cellModelFactory({
|
|
175
|
+
uri: CellUri.generate(this.uri, handle),
|
|
176
|
+
handle: handle,
|
|
177
|
+
source: cell.source,
|
|
178
|
+
language: cell.language,
|
|
179
|
+
cellKind: cell.cellKind,
|
|
180
|
+
outputs: cell.outputs,
|
|
181
|
+
metadata: cell.metadata,
|
|
182
|
+
internalMetadata: cell.internalMetadata,
|
|
183
|
+
collapseState: cell.collapseState
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
this.addCellOutputListeners(cells);
|
|
187
|
+
|
|
188
|
+
this.metadata = data.metadata;
|
|
189
|
+
|
|
190
|
+
}
|
|
191
|
+
|
|
173
192
|
async revert(options?: Saveable.RevertOptions): Promise<void> {
|
|
174
193
|
this.dirty = false;
|
|
175
|
-
this.onDirtyChangedEmitter.fire();
|
|
176
194
|
}
|
|
177
195
|
|
|
178
196
|
isDirty(): boolean {
|
|
@@ -186,8 +204,8 @@ export class NotebookModel implements Saveable, Disposable {
|
|
|
186
204
|
this.dirtyCells.splice(this.dirtyCells.indexOf(cell), 1);
|
|
187
205
|
}
|
|
188
206
|
|
|
189
|
-
const oldDirtyState = this.
|
|
190
|
-
this.
|
|
207
|
+
const oldDirtyState = this._dirty;
|
|
208
|
+
this._dirty = this.dirtyCells.length > 0;
|
|
191
209
|
if (this.dirty !== oldDirtyState) {
|
|
192
210
|
this.onDirtyChangedEmitter.fire();
|
|
193
211
|
}
|
|
@@ -211,7 +229,6 @@ export class NotebookModel implements Saveable, Disposable {
|
|
|
211
229
|
for (const cell of cells) {
|
|
212
230
|
cell.onDidChangeOutputs(() => {
|
|
213
231
|
this.dirty = true;
|
|
214
|
-
this.onDirtyChangedEmitter.fire();
|
|
215
232
|
});
|
|
216
233
|
}
|
|
217
234
|
}
|
|
@@ -294,7 +311,7 @@ export class NotebookModel implements Saveable, Disposable {
|
|
|
294
311
|
});
|
|
295
312
|
this.addCellOutputListeners(cells);
|
|
296
313
|
|
|
297
|
-
const changes: NotebookCellTextModelSplice<NotebookCellModel>[] = [
|
|
314
|
+
const changes: NotebookCellTextModelSplice<NotebookCellModel>[] = [{ start, deleteCount, newItems: cells }];
|
|
298
315
|
|
|
299
316
|
const deletedCells = this.cells.splice(start, deleteCount, ...cells);
|
|
300
317
|
|
|
@@ -308,8 +325,8 @@ export class NotebookModel implements Saveable, Disposable {
|
|
|
308
325
|
async () => this.replaceCells(start, deleteCount, newCells, false));
|
|
309
326
|
}
|
|
310
327
|
|
|
311
|
-
this.onDidAddOrRemoveCellEmitter.fire({ rawEvent: { kind: NotebookCellsChangeType.ModelChange, changes } });
|
|
312
|
-
this.onDidChangeContentEmitter.fire(
|
|
328
|
+
this.onDidAddOrRemoveCellEmitter.fire({ rawEvent: { kind: NotebookCellsChangeType.ModelChange, changes }, newCellIds: cells.map(cell => cell.handle) });
|
|
329
|
+
this.onDidChangeContentEmitter.fire([{ kind: NotebookCellsChangeType.ModelChange, changes }]);
|
|
313
330
|
}
|
|
314
331
|
|
|
315
332
|
private changeCellInternalMetadataPartial(cell: NotebookCellModel, internalMetadata: NullablePartialNotebookCellInternalMetadata): void {
|
|
@@ -323,11 +340,9 @@ export class NotebookModel implements Saveable, Disposable {
|
|
|
323
340
|
}
|
|
324
341
|
|
|
325
342
|
cell.internalMetadata = newInternalMetadata;
|
|
326
|
-
this.onDidChangeContentEmitter.fire(
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
]
|
|
330
|
-
});
|
|
343
|
+
this.onDidChangeContentEmitter.fire([
|
|
344
|
+
{ kind: NotebookCellsChangeType.ChangeCellInternalMetadata, index: this.cells.indexOf(cell), internalMetadata: newInternalMetadata }
|
|
345
|
+
]);
|
|
331
346
|
}
|
|
332
347
|
|
|
333
348
|
private updateNotebookMetadata(metadata: NotebookDocumentMetadata, computeUndoRedo: boolean): void {
|
|
@@ -340,10 +355,7 @@ export class NotebookModel implements Saveable, Disposable {
|
|
|
340
355
|
}
|
|
341
356
|
|
|
342
357
|
this.metadata = metadata;
|
|
343
|
-
this.onDidChangeContentEmitter.fire({
|
|
344
|
-
rawEvents: [{ kind: NotebookCellsChangeType.ChangeDocumentMetadata, metadata: this.metadata }],
|
|
345
|
-
synchronous: true,
|
|
346
|
-
});
|
|
358
|
+
this.onDidChangeContentEmitter.fire([{ kind: NotebookCellsChangeType.ChangeDocumentMetadata, metadata: this.metadata }]);
|
|
347
359
|
}
|
|
348
360
|
|
|
349
361
|
private changeCellLanguage(cell: NotebookCellModel, languageId: string, computeUndoRedo: boolean): void {
|
|
@@ -353,10 +365,7 @@ export class NotebookModel implements Saveable, Disposable {
|
|
|
353
365
|
|
|
354
366
|
cell.language = languageId;
|
|
355
367
|
|
|
356
|
-
this.onDidChangeContentEmitter.fire({
|
|
357
|
-
rawEvents: [{ kind: NotebookCellsChangeType.ChangeCellLanguage, index: this.cells.indexOf(cell), language: languageId }],
|
|
358
|
-
synchronous: true,
|
|
359
|
-
});
|
|
368
|
+
this.onDidChangeContentEmitter.fire([{ kind: NotebookCellsChangeType.ChangeCellLanguage, index: this.cells.indexOf(cell), language: languageId }]);
|
|
360
369
|
}
|
|
361
370
|
|
|
362
371
|
private moveCellToIndex(fromIndex: number, length: number, toIndex: number, computeUndoRedo: boolean): boolean {
|
|
@@ -369,9 +378,7 @@ export class NotebookModel implements Saveable, Disposable {
|
|
|
369
378
|
|
|
370
379
|
const cells = this.cells.splice(fromIndex, length);
|
|
371
380
|
this.cells.splice(toIndex, 0, ...cells);
|
|
372
|
-
this.onDidChangeContentEmitter.fire({
|
|
373
|
-
rawEvents: [{ kind: NotebookCellsChangeType.Move, index: fromIndex, length, newIdx: toIndex, cells }],
|
|
374
|
-
});
|
|
381
|
+
this.onDidChangeContentEmitter.fire([{ kind: NotebookCellsChangeType.Move, index: fromIndex, length, newIdx: toIndex, cells }]);
|
|
375
382
|
|
|
376
383
|
return true;
|
|
377
384
|
}
|