@theia/notebook 1.47.0-next.0 → 1.47.0
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 +3 -1
- package/lib/browser/contributions/notebook-actions-contribution.d.ts.map +1 -1
- package/lib/browser/contributions/notebook-actions-contribution.js +34 -35
- package/lib/browser/contributions/notebook-actions-contribution.js.map +1 -1
- package/lib/browser/contributions/notebook-cell-actions-contribution.d.ts +5 -1
- package/lib/browser/contributions/notebook-cell-actions-contribution.d.ts.map +1 -1
- package/lib/browser/contributions/notebook-cell-actions-contribution.js +29 -36
- package/lib/browser/contributions/notebook-cell-actions-contribution.js.map +1 -1
- package/lib/browser/contributions/notebook-color-contribution.js +2 -7
- package/lib/browser/contributions/notebook-color-contribution.js.map +1 -1
- package/lib/browser/index.js +12 -21
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/notebook-cell-resource-resolver.d.ts +10 -5
- package/lib/browser/notebook-cell-resource-resolver.d.ts.map +1 -1
- package/lib/browser/notebook-cell-resource-resolver.js +18 -17
- package/lib/browser/notebook-cell-resource-resolver.js.map +1 -1
- package/lib/browser/notebook-editor-widget-factory.js +10 -18
- package/lib/browser/notebook-editor-widget-factory.js.map +1 -1
- package/lib/browser/notebook-editor-widget.d.ts +20 -0
- package/lib/browser/notebook-editor-widget.d.ts.map +1 -1
- package/lib/browser/notebook-editor-widget.js +69 -32
- package/lib/browser/notebook-editor-widget.js.map +1 -1
- package/lib/browser/notebook-open-handler.js +4 -12
- package/lib/browser/notebook-open-handler.js.map +1 -1
- package/lib/browser/notebook-renderer-registry.d.ts +7 -0
- package/lib/browser/notebook-renderer-registry.d.ts.map +1 -1
- package/lib/browser/notebook-renderer-registry.js +13 -7
- package/lib/browser/notebook-renderer-registry.js.map +1 -1
- package/lib/browser/notebook-type-registry.js +2 -7
- package/lib/browser/notebook-type-registry.js.map +1 -1
- package/lib/browser/renderers/cell-output-webview.d.ts +2 -1
- package/lib/browser/renderers/cell-output-webview.d.ts.map +1 -1
- package/lib/browser/renderers/cell-output-webview.js.map +1 -1
- package/lib/browser/service/notebook-cell-context-manager.d.ts.map +1 -1
- package/lib/browser/service/notebook-cell-context-manager.js +6 -16
- package/lib/browser/service/notebook-cell-context-manager.js.map +1 -1
- package/lib/browser/service/notebook-editor-widget-service.js +8 -16
- package/lib/browser/service/notebook-editor-widget-service.js.map +1 -1
- package/lib/browser/service/notebook-execution-service.js +12 -20
- package/lib/browser/service/notebook-execution-service.js.map +1 -1
- package/lib/browser/service/notebook-execution-state-service.d.ts.map +1 -1
- package/lib/browser/service/notebook-execution-state-service.js +5 -14
- package/lib/browser/service/notebook-execution-state-service.js.map +1 -1
- package/lib/browser/service/notebook-kernel-history-service.js +12 -20
- package/lib/browser/service/notebook-kernel-history-service.js.map +1 -1
- package/lib/browser/service/notebook-kernel-quick-pick-service.js +12 -20
- package/lib/browser/service/notebook-kernel-quick-pick-service.js.map +1 -1
- package/lib/browser/service/notebook-kernel-service.d.ts +4 -0
- package/lib/browser/service/notebook-kernel-service.d.ts.map +1 -1
- package/lib/browser/service/notebook-kernel-service.js +10 -18
- package/lib/browser/service/notebook-kernel-service.js.map +1 -1
- package/lib/browser/service/notebook-model-resolver-service.d.ts +3 -2
- package/lib/browser/service/notebook-model-resolver-service.d.ts.map +1 -1
- package/lib/browser/service/notebook-model-resolver-service.js +21 -22
- package/lib/browser/service/notebook-model-resolver-service.js.map +1 -1
- package/lib/browser/service/notebook-renderer-messaging-service.d.ts +1 -0
- package/lib/browser/service/notebook-renderer-messaging-service.d.ts.map +1 -1
- package/lib/browser/service/notebook-renderer-messaging-service.js +12 -7
- package/lib/browser/service/notebook-renderer-messaging-service.js.map +1 -1
- package/lib/browser/service/notebook-service.d.ts +2 -2
- package/lib/browser/service/notebook-service.d.ts.map +1 -1
- package/lib/browser/service/notebook-service.js +13 -21
- package/lib/browser/service/notebook-service.js.map +1 -1
- package/lib/browser/view/notebook-cell-list-view.d.ts +3 -1
- package/lib/browser/view/notebook-cell-list-view.d.ts.map +1 -1
- package/lib/browser/view/notebook-cell-list-view.js +24 -7
- 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 +11 -18
- package/lib/browser/view/notebook-cell-toolbar-factory.js.map +1 -1
- package/lib/browser/view/notebook-cell-toolbar.js +2 -2
- package/lib/browser/view/notebook-cell-toolbar.js.map +1 -1
- package/lib/browser/view/notebook-code-cell-view.d.ts +1 -0
- package/lib/browser/view/notebook-code-cell-view.d.ts.map +1 -1
- package/lib/browser/view/notebook-code-cell-view.js +16 -24
- package/lib/browser/view/notebook-code-cell-view.js.map +1 -1
- package/lib/browser/view/notebook-main-toolbar.d.ts.map +1 -1
- package/lib/browser/view/notebook-main-toolbar.js +17 -21
- package/lib/browser/view/notebook-main-toolbar.js.map +1 -1
- package/lib/browser/view/notebook-markdown-cell-view.js +6 -14
- package/lib/browser/view/notebook-markdown-cell-view.js.map +1 -1
- package/lib/browser/view-model/notebook-cell-model.d.ts +1 -1
- package/lib/browser/view-model/notebook-cell-model.d.ts.map +1 -1
- package/lib/browser/view-model/notebook-cell-model.js +17 -22
- package/lib/browser/view-model/notebook-cell-model.js.map +1 -1
- package/lib/browser/view-model/notebook-model.d.ts +17 -14
- package/lib/browser/view-model/notebook-model.d.ts.map +1 -1
- package/lib/browser/view-model/notebook-model.js +30 -27
- package/lib/browser/view-model/notebook-model.js.map +1 -1
- package/lib/common/index.js +3 -12
- package/lib/common/index.js.map +1 -1
- package/package.json +9 -8
- package/src/browser/contributions/notebook-actions-contribution.ts +34 -19
- package/src/browser/contributions/notebook-cell-actions-contribution.ts +24 -15
- package/src/browser/notebook-cell-resource-resolver.ts +24 -7
- package/src/browser/notebook-editor-widget.tsx +68 -6
- package/src/browser/notebook-renderer-registry.ts +19 -0
- package/src/browser/renderers/cell-output-webview.ts +2 -1
- package/src/browser/service/notebook-cell-context-manager.ts +0 -1
- package/src/browser/service/notebook-execution-state-service.ts +2 -3
- package/src/browser/service/notebook-kernel-service.ts +5 -0
- package/src/browser/service/notebook-model-resolver-service.ts +14 -10
- package/src/browser/service/notebook-renderer-messaging-service.ts +9 -1
- package/src/browser/service/notebook-service.ts +4 -4
- package/src/browser/style/index.css +17 -3
- package/src/browser/view/notebook-cell-list-view.tsx +34 -11
- package/src/browser/view/notebook-cell-toolbar-factory.tsx +2 -0
- package/src/browser/view/notebook-cell-toolbar.tsx +2 -2
- package/src/browser/view/notebook-code-cell-view.tsx +6 -5
- package/src/browser/view/notebook-main-toolbar.tsx +6 -2
- package/src/browser/view-model/notebook-cell-model.ts +5 -3
- package/src/browser/view-model/notebook-model.ts +27 -14
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
19
19
|
*--------------------------------------------------------------------------------------------*/
|
|
20
20
|
|
|
21
|
-
import { Disposable, DisposableCollection, Emitter, URI } from '@theia/core';
|
|
21
|
+
import { Disposable, DisposableCollection, Emitter, URI, generateUuid } from '@theia/core';
|
|
22
22
|
import { inject, injectable } from '@theia/core/shared/inversify';
|
|
23
23
|
import { NotebookService } from './notebook-service';
|
|
24
24
|
import {
|
|
@@ -27,7 +27,6 @@ import {
|
|
|
27
27
|
} from '../../common';
|
|
28
28
|
import { CellPartialInternalMetadataEditByHandle, CellEditOperation } from '../notebook-types';
|
|
29
29
|
import { NotebookModel } from '../view-model/notebook-model';
|
|
30
|
-
import { v4 } from 'uuid';
|
|
31
30
|
|
|
32
31
|
export type CellExecuteUpdate = CellExecuteOutputEdit | CellExecuteOutputItemEdit | CellExecutionStateUpdate;
|
|
33
32
|
|
|
@@ -178,7 +177,7 @@ export class CellExecution implements Disposable {
|
|
|
178
177
|
editType: CellEditType.PartialInternalMetadata,
|
|
179
178
|
handle: this.cellHandle,
|
|
180
179
|
internalMetadata: {
|
|
181
|
-
executionId:
|
|
180
|
+
executionId: generateUuid(),
|
|
182
181
|
runStartTime: undefined,
|
|
183
182
|
runEndTime: undefined,
|
|
184
183
|
lastRunSuccess: undefined,
|
|
@@ -54,6 +54,11 @@ export interface NotebookKernel {
|
|
|
54
54
|
// ID of the extension providing this kernel
|
|
55
55
|
readonly extensionId: string;
|
|
56
56
|
|
|
57
|
+
readonly localResourceRoot: URI;
|
|
58
|
+
readonly preloadUris: URI[];
|
|
59
|
+
readonly preloadProvides: string[];
|
|
60
|
+
|
|
61
|
+
readonly handle: number;
|
|
57
62
|
label: string;
|
|
58
63
|
description?: string;
|
|
59
64
|
detail?: string;
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
|
-
import { Emitter, URI } from '@theia/core';
|
|
17
|
+
import { Emitter, Resource, ResourceProvider, URI } from '@theia/core';
|
|
18
18
|
import { inject, injectable } from '@theia/core/shared/inversify';
|
|
19
19
|
import { UriComponents } from '@theia/core/lib/common/uri';
|
|
20
20
|
import { FileService } from '@theia/filesystem/lib/browser/file-service';
|
|
@@ -34,6 +34,9 @@ export class NotebookModelResolverService {
|
|
|
34
34
|
@inject(FileService)
|
|
35
35
|
protected fileService: FileService;
|
|
36
36
|
|
|
37
|
+
@inject(ResourceProvider)
|
|
38
|
+
protected resourceProvider: ResourceProvider;
|
|
39
|
+
|
|
37
40
|
@inject(NotebookService)
|
|
38
41
|
protected notebookService: NotebookService;
|
|
39
42
|
|
|
@@ -60,9 +63,9 @@ export class NotebookModelResolverService {
|
|
|
60
63
|
throw new Error(`Missing viewType for '${resource}'`);
|
|
61
64
|
}
|
|
62
65
|
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
const notebookModel = await this.notebookService.createNotebookModel(notebookData, viewType,
|
|
66
|
+
const actualResource = await this.resourceProvider(resource);
|
|
67
|
+
const notebookData = await this.resolveExistingNotebookData(actualResource, viewType!);
|
|
68
|
+
const notebookModel = await this.notebookService.createNotebookModel(notebookData, viewType, actualResource);
|
|
66
69
|
|
|
67
70
|
notebookModel.onDirtyChanged(() => this.onDidChangeDirtyEmitter.fire(notebookModel));
|
|
68
71
|
notebookModel.onDidSaveNotebook(() => this.onDidSaveNotebookEmitter.fire(notebookModel.uri.toComponents()));
|
|
@@ -103,8 +106,8 @@ export class NotebookModelResolverService {
|
|
|
103
106
|
return this.resolve(resource, viewType);
|
|
104
107
|
}
|
|
105
108
|
|
|
106
|
-
protected async resolveExistingNotebookData(resource:
|
|
107
|
-
if (resource.scheme === 'untitled') {
|
|
109
|
+
protected async resolveExistingNotebookData(resource: Resource, viewType: string): Promise<NotebookData> {
|
|
110
|
+
if (resource.uri.scheme === 'untitled') {
|
|
108
111
|
|
|
109
112
|
return {
|
|
110
113
|
cells: [
|
|
@@ -118,10 +121,11 @@ export class NotebookModelResolverService {
|
|
|
118
121
|
metadata: {}
|
|
119
122
|
};
|
|
120
123
|
} else {
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
124
|
+
const [dataProvider, contents] = await Promise.all([
|
|
125
|
+
this.notebookService.getNotebookDataProvider(viewType),
|
|
126
|
+
this.fileService.readFile(resource.uri)
|
|
127
|
+
]);
|
|
128
|
+
const notebook = await dataProvider.serializer.toNotebook(contents.value);
|
|
125
129
|
|
|
126
130
|
return notebook;
|
|
127
131
|
}
|
|
@@ -19,8 +19,9 @@
|
|
|
19
19
|
*--------------------------------------------------------------------------------------------*/
|
|
20
20
|
|
|
21
21
|
import { Emitter } from '@theia/core';
|
|
22
|
-
import { injectable } from '@theia/core/shared/inversify';
|
|
22
|
+
import { inject, injectable } from '@theia/core/shared/inversify';
|
|
23
23
|
import { Disposable } from '@theia/core/shared/vscode-languageserver-protocol';
|
|
24
|
+
import { NotebookEditorWidgetService } from './notebook-editor-widget-service';
|
|
24
25
|
|
|
25
26
|
interface RendererMessage {
|
|
26
27
|
editorId: string;
|
|
@@ -50,6 +51,9 @@ export class NotebookRendererMessagingService implements Disposable {
|
|
|
50
51
|
private readonly willActivateRendererEmitter = new Emitter<string>();
|
|
51
52
|
readonly onWillActivateRenderer = this.willActivateRendererEmitter.event;
|
|
52
53
|
|
|
54
|
+
@inject(NotebookEditorWidgetService)
|
|
55
|
+
private readonly editorWidgetService: NotebookEditorWidgetService;
|
|
56
|
+
|
|
53
57
|
private readonly activations = new Map<string /* rendererId */, undefined | RendererMessage[]>();
|
|
54
58
|
private readonly scopedMessaging = new Map<string /* editorId */, RendererMessaging>();
|
|
55
59
|
|
|
@@ -86,6 +90,10 @@ export class NotebookRendererMessagingService implements Disposable {
|
|
|
86
90
|
|
|
87
91
|
const messaging: RendererMessaging = {
|
|
88
92
|
postMessage: (rendererId, message) => this.postMessage(editorId, rendererId, message),
|
|
93
|
+
receiveMessage: async (rendererId, message) => {
|
|
94
|
+
this.editorWidgetService.getNotebookEditor(editorId)?.postRendererMessage(rendererId, message);
|
|
95
|
+
return true;
|
|
96
|
+
},
|
|
89
97
|
dispose: () => this.scopedMessaging.delete(editorId),
|
|
90
98
|
};
|
|
91
99
|
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
|
-
import { Disposable, DisposableCollection, Emitter, URI } from '@theia/core';
|
|
17
|
+
import { Disposable, DisposableCollection, Emitter, Resource, URI } from '@theia/core';
|
|
18
18
|
import { inject, injectable } from '@theia/core/shared/inversify';
|
|
19
19
|
import { BinaryBuffer } from '@theia/core/lib/common/buffer';
|
|
20
20
|
import { NotebookData, TransientOptions } from '../../common';
|
|
@@ -101,14 +101,14 @@ export class NotebookService implements Disposable {
|
|
|
101
101
|
});
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
async createNotebookModel(data: NotebookData, viewType: string,
|
|
104
|
+
async createNotebookModel(data: NotebookData, viewType: string, resource: Resource): Promise<NotebookModel> {
|
|
105
105
|
const serializer = this.notebookProviders.get(viewType)?.serializer;
|
|
106
106
|
if (!serializer) {
|
|
107
107
|
throw new Error('no notebook serializer for ' + viewType);
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
const model = this.notebookModelFactory({ data,
|
|
111
|
-
this.notebookModels.set(uri.toString(), model);
|
|
110
|
+
const model = this.notebookModelFactory({ data, resource, viewType, serializer });
|
|
111
|
+
this.notebookModels.set(resource.uri.toString(), model);
|
|
112
112
|
// Resolve cell text models right after creating the notebook model
|
|
113
113
|
// This ensures that all text models are available in the plugin host
|
|
114
114
|
await Promise.all(model.cells.map(e => e.resolveTextModel()));
|
|
@@ -26,11 +26,14 @@
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
.theia-notebook-cell {
|
|
29
|
-
cursor: grab;
|
|
30
29
|
display: flex;
|
|
31
30
|
margin: 10px 0px;
|
|
32
31
|
}
|
|
33
32
|
|
|
33
|
+
.theia-notebook-cell.draggable {
|
|
34
|
+
cursor: grab;
|
|
35
|
+
}
|
|
36
|
+
|
|
34
37
|
.theia-notebook-cell:hover .theia-notebook-cell-marker {
|
|
35
38
|
visibility: visible;
|
|
36
39
|
}
|
|
@@ -161,9 +164,20 @@
|
|
|
161
164
|
flex-direction: column;
|
|
162
165
|
}
|
|
163
166
|
|
|
167
|
+
.theia-notebook-main-container {
|
|
168
|
+
display: flex;
|
|
169
|
+
flex-direction: column;
|
|
170
|
+
height: 100%;
|
|
171
|
+
overflow: hidden;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.theia-notebook-scroll-container {
|
|
175
|
+
flex: 1;
|
|
176
|
+
overflow: hidden;
|
|
177
|
+
position: relative;
|
|
178
|
+
}
|
|
179
|
+
|
|
164
180
|
.theia-notebook-main-toolbar {
|
|
165
|
-
position: sticky;
|
|
166
|
-
top: 0;
|
|
167
181
|
background: var(--theia-editor-background);
|
|
168
182
|
display: flex;
|
|
169
183
|
flex-direction: row;
|
|
@@ -64,11 +64,13 @@ export class NotebookCellListView extends React.Component<CellListProps, Noteboo
|
|
|
64
64
|
{this.props.notebookModel.cells
|
|
65
65
|
.map((cell, index) =>
|
|
66
66
|
<React.Fragment key={'cell-' + cell.handle}>
|
|
67
|
-
<NotebookCellDivider
|
|
67
|
+
<NotebookCellDivider
|
|
68
|
+
isVisible={() => this.isEnabled()}
|
|
69
|
+
onAddNewCell={(kind: CellKind) => this.onAddNewCell(kind, index)}
|
|
68
70
|
onDrop={e => this.onDrop(e, index)}
|
|
69
71
|
onDragOver={e => this.onDragOver(e, cell, 'top')} />
|
|
70
72
|
{this.shouldRenderDragOverIndicator(cell, 'top') && <CellDropIndicator />}
|
|
71
|
-
<li className={'theia-notebook-cell' + (this.state.selectedCell === cell ? ' focused' : '')}
|
|
73
|
+
<li className={'theia-notebook-cell' + (this.state.selectedCell === cell ? ' focused' : '') + (this.isEnabled() ? ' draggable' : '')}
|
|
72
74
|
onClick={() => {
|
|
73
75
|
this.setState({ selectedCell: cell });
|
|
74
76
|
this.props.notebookModel.setSelectedCell(cell);
|
|
@@ -89,7 +91,9 @@ export class NotebookCellListView extends React.Component<CellListProps, Noteboo
|
|
|
89
91
|
</React.Fragment>
|
|
90
92
|
)
|
|
91
93
|
}
|
|
92
|
-
<NotebookCellDivider
|
|
94
|
+
<NotebookCellDivider
|
|
95
|
+
isVisible={() => this.isEnabled()}
|
|
96
|
+
onAddNewCell={(kind: CellKind) => this.onAddNewCell(kind, this.props.notebookModel.cells.length)}
|
|
93
97
|
onDrop={e => this.onDrop(e, this.props.notebookModel.cells.length - 1)}
|
|
94
98
|
onDragOver={e => this.onDragOver(e, this.props.notebookModel.cells[this.props.notebookModel.cells.length - 1], 'bottom')} />
|
|
95
99
|
</ul>;
|
|
@@ -105,18 +109,33 @@ export class NotebookCellListView extends React.Component<CellListProps, Noteboo
|
|
|
105
109
|
|
|
106
110
|
protected onDragStart(event: React.DragEvent<HTMLLIElement>, index: number): void {
|
|
107
111
|
event.stopPropagation();
|
|
112
|
+
if (!this.isEnabled()) {
|
|
113
|
+
event.preventDefault();
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
108
116
|
event.dataTransfer.setData('text/theia-notebook-cell-index', index.toString());
|
|
109
117
|
event.dataTransfer.setData('text/plain', this.props.notebookModel.cells[index].source);
|
|
110
118
|
}
|
|
111
119
|
|
|
112
120
|
protected onDragOver(event: React.DragEvent<HTMLLIElement>, cell: NotebookCellModel, position?: 'top' | 'bottom'): void {
|
|
121
|
+
if (!this.isEnabled()) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
113
124
|
event.preventDefault();
|
|
114
125
|
event.stopPropagation();
|
|
115
126
|
// show indicator
|
|
116
127
|
this.setState({ ...this.state, dragOverIndicator: { cell, position: position ?? event.nativeEvent.offsetY < event.currentTarget.clientHeight / 2 ? 'top' : 'bottom' } });
|
|
117
128
|
}
|
|
118
129
|
|
|
130
|
+
protected isEnabled(): boolean {
|
|
131
|
+
return !Boolean(this.props.notebookModel.readOnly);
|
|
132
|
+
}
|
|
133
|
+
|
|
119
134
|
protected onDrop(event: React.DragEvent<HTMLLIElement>, dropElementIndex: number): void {
|
|
135
|
+
if (!this.isEnabled()) {
|
|
136
|
+
this.setState({ dragOverIndicator: undefined });
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
120
139
|
const index = parseInt(event.dataTransfer.getData('text/theia-notebook-cell-index'));
|
|
121
140
|
const isTargetBelow = index < dropElementIndex;
|
|
122
141
|
let newIdx = this.state.dragOverIndicator?.position === 'top' ? dropElementIndex : dropElementIndex + 1;
|
|
@@ -133,15 +152,18 @@ export class NotebookCellListView extends React.Component<CellListProps, Noteboo
|
|
|
133
152
|
}
|
|
134
153
|
|
|
135
154
|
protected onAddNewCell(kind: CellKind, index: number): void {
|
|
136
|
-
this.
|
|
137
|
-
this.props.
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
155
|
+
if (this.isEnabled()) {
|
|
156
|
+
this.props.commandRegistry.executeCommand(NotebookCommands.ADD_NEW_CELL_COMMAND.id,
|
|
157
|
+
this.props.notebookModel,
|
|
158
|
+
kind,
|
|
159
|
+
index
|
|
160
|
+
);
|
|
161
|
+
}
|
|
141
162
|
}
|
|
142
163
|
|
|
143
164
|
protected shouldRenderDragOverIndicator(cell: NotebookCellModel, position: 'top' | 'bottom'): boolean {
|
|
144
|
-
return this.
|
|
165
|
+
return this.isEnabled() &&
|
|
166
|
+
this.state.dragOverIndicator !== undefined &&
|
|
145
167
|
this.state.dragOverIndicator.cell === cell &&
|
|
146
168
|
this.state.dragOverIndicator.position === position;
|
|
147
169
|
}
|
|
@@ -149,16 +171,17 @@ export class NotebookCellListView extends React.Component<CellListProps, Noteboo
|
|
|
149
171
|
}
|
|
150
172
|
|
|
151
173
|
export interface NotebookCellDividerProps {
|
|
174
|
+
isVisible: () => boolean;
|
|
152
175
|
onAddNewCell: (type: CellKind) => void;
|
|
153
176
|
onDrop: (event: React.DragEvent<HTMLLIElement>) => void;
|
|
154
177
|
onDragOver: (event: React.DragEvent<HTMLLIElement>) => void;
|
|
155
178
|
}
|
|
156
179
|
|
|
157
|
-
export function NotebookCellDivider({ onAddNewCell, onDrop, onDragOver }: NotebookCellDividerProps): React.JSX.Element {
|
|
180
|
+
export function NotebookCellDivider({ isVisible, onAddNewCell, onDrop, onDragOver }: NotebookCellDividerProps): React.JSX.Element {
|
|
158
181
|
const [hover, setHover] = React.useState(false);
|
|
159
182
|
|
|
160
183
|
return <li className='theia-notebook-cell-divider' onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)} onDrop={onDrop} onDragOver={onDragOver}>
|
|
161
|
-
{hover && <div className='theia-notebook-add-cell-buttons'>
|
|
184
|
+
{hover && isVisible() && <div className='theia-notebook-add-cell-buttons'>
|
|
162
185
|
<button className='theia-notebook-add-cell-button' onClick={() => onAddNewCell(CellKind.Code)} title={nls.localizeByDefault('Add Code Cell')}>
|
|
163
186
|
<div className={codicon('add') + ' theia-notebook-add-cell-button-icon'} />
|
|
164
187
|
{nls.localizeByDefault('Code')}
|
|
@@ -29,6 +29,7 @@ export interface NotebookCellToolbarItem {
|
|
|
29
29
|
icon?: string;
|
|
30
30
|
label?: string;
|
|
31
31
|
onClick: (e: React.MouseEvent) => void;
|
|
32
|
+
isVisible: () => boolean;
|
|
32
33
|
contextKeys?: Set<string>
|
|
33
34
|
}
|
|
34
35
|
|
|
@@ -87,6 +88,7 @@ export class NotebookCellToolbarFactory {
|
|
|
87
88
|
args: [notebookModel, cell, output]
|
|
88
89
|
}) :
|
|
89
90
|
() => this.commandRegistry.executeCommand(menuNode.command!, notebookModel, cell, output),
|
|
91
|
+
isVisible: () => menuPath ? true : Boolean(this.commandRegistry.getVisibleHandler(menuNode.command!, notebookModel, cell, output)),
|
|
90
92
|
contextKeys: menuNode.when ? this.contextKeyService.parseKeys(menuNode.when) : undefined
|
|
91
93
|
};
|
|
92
94
|
}
|
|
@@ -56,7 +56,7 @@ export class NotebookCellToolbar extends NotebookCellActionBar {
|
|
|
56
56
|
|
|
57
57
|
override render(): React.ReactNode {
|
|
58
58
|
return <div className='theia-notebook-cell-toolbar'>
|
|
59
|
-
{this.state.inlineItems.map(item => this.renderItem(item))}
|
|
59
|
+
{this.state.inlineItems.filter(e => e.isVisible()).map(item => this.renderItem(item))}
|
|
60
60
|
</div>;
|
|
61
61
|
}
|
|
62
62
|
|
|
@@ -66,7 +66,7 @@ export class NotebookCellSidebar extends NotebookCellActionBar {
|
|
|
66
66
|
|
|
67
67
|
override render(): React.ReactNode {
|
|
68
68
|
return <div className='theia-notebook-cell-sidebar'>
|
|
69
|
-
{this.state.inlineItems.map(item => this.renderItem(item))}
|
|
69
|
+
{this.state.inlineItems.filter(e => e.isVisible()).map(item => this.renderItem(item))}
|
|
70
70
|
</div>;
|
|
71
71
|
}
|
|
72
72
|
}
|
|
@@ -61,7 +61,7 @@ export class NotebookCodeCellRenderer implements CellRenderer {
|
|
|
61
61
|
</div>
|
|
62
62
|
</div>
|
|
63
63
|
<div className='theia-notebook-cell-with-sidebar'>
|
|
64
|
-
<NotebookCodeCellOutputs cell={cell} outputWebviewFactory={this.cellOutputWebviewFactory}
|
|
64
|
+
<NotebookCodeCellOutputs cell={cell} notebook={notebookModel} outputWebviewFactory={this.cellOutputWebviewFactory}
|
|
65
65
|
renderSidebar={() =>
|
|
66
66
|
this.notebookCellToolbarFactory.renderSidebar(NotebookCellActionContribution.OUTPUT_SIDEBAR_MENU, notebookModel, cell, cell.outputs[0])} />
|
|
67
67
|
</div>
|
|
@@ -166,6 +166,7 @@ export class NotebookCodeCellStatus extends React.Component<NotebookCodeCellStat
|
|
|
166
166
|
|
|
167
167
|
interface NotebookCellOutputProps {
|
|
168
168
|
cell: NotebookCellModel;
|
|
169
|
+
notebook: NotebookModel;
|
|
169
170
|
outputWebviewFactory: CellOutputWebviewFactory;
|
|
170
171
|
renderSidebar: () => React.ReactNode;
|
|
171
172
|
}
|
|
@@ -182,14 +183,14 @@ export class NotebookCodeCellOutputs extends React.Component<NotebookCellOutputP
|
|
|
182
183
|
}
|
|
183
184
|
|
|
184
185
|
override async componentDidMount(): Promise<void> {
|
|
185
|
-
const { cell, outputWebviewFactory } = this.props;
|
|
186
|
+
const { cell, notebook, outputWebviewFactory } = this.props;
|
|
186
187
|
this.toDispose.push(cell.onDidChangeOutputs(async () => {
|
|
187
188
|
if (!this.outputsWebviewPromise && cell.outputs.length > 0) {
|
|
188
|
-
this.outputsWebviewPromise = outputWebviewFactory(cell).then(webview => {
|
|
189
|
+
this.outputsWebviewPromise = outputWebviewFactory(cell, notebook).then(webview => {
|
|
189
190
|
this.outputsWebview = webview;
|
|
190
191
|
this.forceUpdate();
|
|
191
192
|
return webview;
|
|
192
|
-
|
|
193
|
+
});
|
|
193
194
|
this.forceUpdate();
|
|
194
195
|
} else if (this.outputsWebviewPromise && cell.outputs.length === 0 && cell.internalMetadata.runEndTime) {
|
|
195
196
|
(await this.outputsWebviewPromise).dispose();
|
|
@@ -199,7 +200,7 @@ export class NotebookCodeCellOutputs extends React.Component<NotebookCellOutputP
|
|
|
199
200
|
}
|
|
200
201
|
}));
|
|
201
202
|
if (cell.outputs.length > 0) {
|
|
202
|
-
this.outputsWebviewPromise = outputWebviewFactory(cell).then(webview => {
|
|
203
|
+
this.outputsWebviewPromise = outputWebviewFactory(cell, notebook).then(webview => {
|
|
203
204
|
this.outputsWebview = webview;
|
|
204
205
|
this.forceUpdate();
|
|
205
206
|
return webview;
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
//
|
|
14
14
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
15
|
// *****************************************************************************
|
|
16
|
-
import { CommandRegistry, CompoundMenuNodeRole, DisposableCollection, MenuModelRegistry, MenuNode, nls } from '@theia/core';
|
|
16
|
+
import { ArrayUtils, CommandRegistry, CompoundMenuNodeRole, DisposableCollection, MenuModelRegistry, MenuNode, nls } from '@theia/core';
|
|
17
17
|
import * as React from '@theia/core/shared/react';
|
|
18
18
|
import { codicon } from '@theia/core/lib/browser';
|
|
19
19
|
import { NotebookCommands, NotebookMenus } from '../contributions/notebook-actions-contribution';
|
|
@@ -98,12 +98,16 @@ export class NotebookMainToolbar extends React.Component<NotebookMainToolbarProp
|
|
|
98
98
|
|
|
99
99
|
protected renderMenuItem(item: MenuNode): React.ReactNode {
|
|
100
100
|
if (item.role === CompoundMenuNodeRole.Group) {
|
|
101
|
-
const itemNodes = item.children?.map(child => this.renderMenuItem(child))
|
|
101
|
+
const itemNodes = ArrayUtils.coalesce(item.children?.map(child => this.renderMenuItem(child)) ?? []);
|
|
102
102
|
return <React.Fragment key={item.id}>
|
|
103
103
|
{itemNodes}
|
|
104
104
|
{itemNodes && itemNodes.length > 0 && <span key={`${item.id}-separator`} className='theia-notebook-toolbar-separator'></span>}
|
|
105
105
|
</React.Fragment>;
|
|
106
106
|
} else if (!item.when || this.props.contextKeyService.match(item.when)) {
|
|
107
|
+
const visibleCommand = Boolean(this.props.commandRegistry.getVisibleHandler(item.command ?? '', this.props.notebookModel));
|
|
108
|
+
if (!visibleCommand) {
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
107
111
|
const title = (this.props.commandRegistry.getCommand(item.command ?? '') as NotebookCommand)?.tooltip ?? item.label;
|
|
108
112
|
return <div key={item.id} title={title} className='theia-notebook-main-toolbar-item action-label'
|
|
109
113
|
onClick={() => {
|
|
@@ -150,7 +150,7 @@ export class NotebookCellModel implements NotebookCell, Disposable {
|
|
|
150
150
|
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
-
textModel
|
|
153
|
+
protected textModel?: MonacoEditorModel;
|
|
154
154
|
|
|
155
155
|
protected htmlContext: HTMLLIElement;
|
|
156
156
|
|
|
@@ -220,12 +220,14 @@ export class NotebookCellModel implements NotebookCell, Disposable {
|
|
|
220
220
|
this.onDidChangeInternalMetadataEmitter.dispose();
|
|
221
221
|
this.onDidChangeLanguageEmitter.dispose();
|
|
222
222
|
this.notebookCellContextManager.dispose();
|
|
223
|
-
this.textModel
|
|
223
|
+
this.textModel?.dispose();
|
|
224
224
|
this.toDispose.dispose();
|
|
225
225
|
}
|
|
226
226
|
|
|
227
227
|
requestEdit(): void {
|
|
228
|
-
this.
|
|
228
|
+
if (!this.textModel || !this.textModel.readOnly) {
|
|
229
|
+
this.onDidRequestCellEditChangeEmitter.fire(true);
|
|
230
|
+
}
|
|
229
231
|
}
|
|
230
232
|
|
|
231
233
|
requestStopEdit(): void {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
15
|
// *****************************************************************************
|
|
16
16
|
|
|
17
|
-
import { Disposable, Emitter, URI } from '@theia/core';
|
|
17
|
+
import { Disposable, Emitter, Event, Resource, URI } from '@theia/core';
|
|
18
18
|
import { Saveable, SaveOptions } from '@theia/core/lib/browser';
|
|
19
19
|
import {
|
|
20
20
|
CellData, CellEditType, CellUri, NotebookCellInternalMetadata,
|
|
@@ -28,6 +28,7 @@ import { NotebookCellModel, NotebookCellModelFactory } from './notebook-cell-mod
|
|
|
28
28
|
import { MonacoTextModelService } from '@theia/monaco/lib/browser/monaco-text-model-service';
|
|
29
29
|
import { inject, injectable, interfaces, postConstruct } from '@theia/core/shared/inversify';
|
|
30
30
|
import { UndoRedoService } from '@theia/editor/lib/browser/undo-redo-service';
|
|
31
|
+
import { MarkdownString } from '@theia/core/lib/common/markdown-rendering';
|
|
31
32
|
|
|
32
33
|
export const NotebookModelFactory = Symbol('NotebookModelFactory');
|
|
33
34
|
|
|
@@ -42,10 +43,10 @@ export function createNotebookModelContainer(parent: interfaces.Container, props
|
|
|
42
43
|
|
|
43
44
|
const NotebookModelProps = Symbol('NotebookModelProps');
|
|
44
45
|
export interface NotebookModelProps {
|
|
45
|
-
data: NotebookData
|
|
46
|
-
|
|
47
|
-
viewType: string
|
|
48
|
-
serializer: NotebookSerializer
|
|
46
|
+
data: NotebookData;
|
|
47
|
+
resource: Resource;
|
|
48
|
+
viewType: string;
|
|
49
|
+
serializer: NotebookSerializer;
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
@injectable()
|
|
@@ -63,6 +64,10 @@ export class NotebookModel implements Saveable, Disposable {
|
|
|
63
64
|
protected readonly onDidChangeContentEmitter = new Emitter<NotebookContentChangedEvent[]>();
|
|
64
65
|
readonly onDidChangeContent = this.onDidChangeContentEmitter.event;
|
|
65
66
|
|
|
67
|
+
get onDidChangeReadOnly(): Event<boolean | MarkdownString> {
|
|
68
|
+
return this.props.resource.onDidChangeReadOnly ?? Event.None;
|
|
69
|
+
}
|
|
70
|
+
|
|
66
71
|
@inject(FileService)
|
|
67
72
|
protected readonly fileService: FileService;
|
|
68
73
|
|
|
@@ -81,7 +86,7 @@ export class NotebookModel implements Saveable, Disposable {
|
|
|
81
86
|
|
|
82
87
|
protected nextHandle: number = 0;
|
|
83
88
|
|
|
84
|
-
protected _dirty
|
|
89
|
+
protected _dirty = false;
|
|
85
90
|
|
|
86
91
|
set dirty(dirty: boolean) {
|
|
87
92
|
this._dirty = dirty;
|
|
@@ -92,13 +97,17 @@ export class NotebookModel implements Saveable, Disposable {
|
|
|
92
97
|
return this._dirty;
|
|
93
98
|
}
|
|
94
99
|
|
|
100
|
+
get readOnly(): boolean | MarkdownString {
|
|
101
|
+
return this.props.resource.readOnly ?? false;
|
|
102
|
+
}
|
|
103
|
+
|
|
95
104
|
selectedCell?: NotebookCellModel;
|
|
96
105
|
protected dirtyCells: NotebookCellModel[] = [];
|
|
97
106
|
|
|
98
107
|
cells: NotebookCellModel[];
|
|
99
108
|
|
|
100
109
|
get uri(): URI {
|
|
101
|
-
return this.props.uri;
|
|
110
|
+
return this.props.resource.uri;
|
|
102
111
|
}
|
|
103
112
|
|
|
104
113
|
get viewType(): string {
|
|
@@ -112,7 +121,7 @@ export class NotebookModel implements Saveable, Disposable {
|
|
|
112
121
|
this.dirty = false;
|
|
113
122
|
|
|
114
123
|
this.cells = this.props.data.cells.map((cell, index) => this.cellModelFactory({
|
|
115
|
-
uri: CellUri.generate(this.props.uri, index),
|
|
124
|
+
uri: CellUri.generate(this.props.resource.uri, index),
|
|
116
125
|
handle: index,
|
|
117
126
|
source: cell.source,
|
|
118
127
|
language: cell.language,
|
|
@@ -294,7 +303,7 @@ export class NotebookModel implements Saveable, Disposable {
|
|
|
294
303
|
}
|
|
295
304
|
}
|
|
296
305
|
|
|
297
|
-
|
|
306
|
+
protected async replaceCells(start: number, deleteCount: number, newCells: CellData[], computeUndoRedo: boolean): Promise<void> {
|
|
298
307
|
const cells = newCells.map(cell => {
|
|
299
308
|
const handle = this.nextHandle++;
|
|
300
309
|
return this.cellModelFactory({
|
|
@@ -325,11 +334,15 @@ export class NotebookModel implements Saveable, Disposable {
|
|
|
325
334
|
async () => this.replaceCells(start, deleteCount, newCells, false));
|
|
326
335
|
}
|
|
327
336
|
|
|
337
|
+
// Ensure that all text model have been created
|
|
338
|
+
// Otherwise we run into a race condition once we fire `onDidChangeContent`
|
|
339
|
+
await Promise.all(cells.map(cell => cell.resolveTextModel()));
|
|
340
|
+
|
|
328
341
|
this.onDidAddOrRemoveCellEmitter.fire({ rawEvent: { kind: NotebookCellsChangeType.ModelChange, changes }, newCellIds: cells.map(cell => cell.handle) });
|
|
329
342
|
this.onDidChangeContentEmitter.fire([{ kind: NotebookCellsChangeType.ModelChange, changes }]);
|
|
330
343
|
}
|
|
331
344
|
|
|
332
|
-
|
|
345
|
+
protected changeCellInternalMetadataPartial(cell: NotebookCellModel, internalMetadata: NullablePartialNotebookCellInternalMetadata): void {
|
|
333
346
|
const newInternalMetadata: NotebookCellInternalMetadata = {
|
|
334
347
|
...cell.internalMetadata
|
|
335
348
|
};
|
|
@@ -345,7 +358,7 @@ export class NotebookModel implements Saveable, Disposable {
|
|
|
345
358
|
]);
|
|
346
359
|
}
|
|
347
360
|
|
|
348
|
-
|
|
361
|
+
protected updateNotebookMetadata(metadata: NotebookDocumentMetadata, computeUndoRedo: boolean): void {
|
|
349
362
|
const oldMetadata = this.metadata;
|
|
350
363
|
if (computeUndoRedo) {
|
|
351
364
|
this.undoRedoService.pushElement(this.uri,
|
|
@@ -358,7 +371,7 @@ export class NotebookModel implements Saveable, Disposable {
|
|
|
358
371
|
this.onDidChangeContentEmitter.fire([{ kind: NotebookCellsChangeType.ChangeDocumentMetadata, metadata: this.metadata }]);
|
|
359
372
|
}
|
|
360
373
|
|
|
361
|
-
|
|
374
|
+
protected changeCellLanguage(cell: NotebookCellModel, languageId: string, computeUndoRedo: boolean): void {
|
|
362
375
|
if (cell.language === languageId) {
|
|
363
376
|
return;
|
|
364
377
|
}
|
|
@@ -368,7 +381,7 @@ export class NotebookModel implements Saveable, Disposable {
|
|
|
368
381
|
this.onDidChangeContentEmitter.fire([{ kind: NotebookCellsChangeType.ChangeCellLanguage, index: this.cells.indexOf(cell), language: languageId }]);
|
|
369
382
|
}
|
|
370
383
|
|
|
371
|
-
|
|
384
|
+
protected moveCellToIndex(fromIndex: number, length: number, toIndex: number, computeUndoRedo: boolean): boolean {
|
|
372
385
|
if (computeUndoRedo) {
|
|
373
386
|
this.undoRedoService.pushElement(this.uri,
|
|
374
387
|
async () => { this.moveCellToIndex(toIndex, length, fromIndex, false); },
|
|
@@ -383,7 +396,7 @@ export class NotebookModel implements Saveable, Disposable {
|
|
|
383
396
|
return true;
|
|
384
397
|
}
|
|
385
398
|
|
|
386
|
-
|
|
399
|
+
protected getCellIndexByHandle(handle: number): number {
|
|
387
400
|
return this.cells.findIndex(c => c.handle === handle);
|
|
388
401
|
}
|
|
389
402
|
}
|