@theia/notebook 1.42.1 → 1.43.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.
Files changed (119) hide show
  1. package/lib/browser/contributions/notebook-cell-actions-contribution.d.ts +8 -0
  2. package/lib/browser/contributions/notebook-cell-actions-contribution.d.ts.map +1 -1
  3. package/lib/browser/contributions/notebook-cell-actions-contribution.js +9 -1
  4. package/lib/browser/contributions/notebook-cell-actions-contribution.js.map +1 -1
  5. package/lib/browser/contributions/notebook-context-keys.d.ts +3 -0
  6. package/lib/browser/contributions/notebook-context-keys.d.ts.map +1 -1
  7. package/lib/browser/contributions/notebook-context-keys.js +7 -0
  8. package/lib/browser/contributions/notebook-context-keys.js.map +1 -1
  9. package/lib/browser/index.d.ts +1 -1
  10. package/lib/browser/index.d.ts.map +1 -1
  11. package/lib/browser/index.js +1 -1
  12. package/lib/browser/index.js.map +1 -1
  13. package/lib/browser/notebook-cell-resource-resolver.d.ts +1 -4
  14. package/lib/browser/notebook-cell-resource-resolver.d.ts.map +1 -1
  15. package/lib/browser/notebook-cell-resource-resolver.js.map +1 -1
  16. package/lib/browser/notebook-editor-widget-factory.d.ts.map +1 -1
  17. package/lib/browser/notebook-editor-widget-factory.js +1 -1
  18. package/lib/browser/notebook-editor-widget-factory.js.map +1 -1
  19. package/lib/browser/notebook-editor-widget.d.ts +8 -6
  20. package/lib/browser/notebook-editor-widget.d.ts.map +1 -1
  21. package/lib/browser/notebook-editor-widget.js +38 -27
  22. package/lib/browser/notebook-editor-widget.js.map +1 -1
  23. package/lib/browser/notebook-frontend-module.js +3 -3
  24. package/lib/browser/notebook-frontend-module.js.map +1 -1
  25. package/lib/browser/notebook-open-handler.d.ts +1 -2
  26. package/lib/browser/notebook-open-handler.d.ts.map +1 -1
  27. package/lib/browser/notebook-open-handler.js +8 -10
  28. package/lib/browser/notebook-open-handler.js.map +1 -1
  29. package/lib/browser/notebook-renderer-registry.d.ts +2 -1
  30. package/lib/browser/notebook-renderer-registry.d.ts.map +1 -1
  31. package/lib/browser/notebook-renderer-registry.js +6 -3
  32. package/lib/browser/notebook-renderer-registry.js.map +1 -1
  33. package/lib/browser/notebook-type-registry.d.ts +2 -1
  34. package/lib/browser/notebook-type-registry.d.ts.map +1 -1
  35. package/lib/browser/notebook-type-registry.js +6 -3
  36. package/lib/browser/notebook-type-registry.js.map +1 -1
  37. package/lib/browser/renderers/cell-output-webview.d.ts +1 -1
  38. package/lib/browser/renderers/cell-output-webview.d.ts.map +1 -1
  39. package/lib/browser/service/notebook-cell-context-manager.d.ts +1 -2
  40. package/lib/browser/service/notebook-cell-context-manager.d.ts.map +1 -1
  41. package/lib/browser/service/notebook-cell-context-manager.js +7 -11
  42. package/lib/browser/service/notebook-cell-context-manager.js.map +1 -1
  43. package/lib/browser/service/{notebook-editor-service.d.ts → notebook-editor-widget-service.d.ts} +5 -5
  44. package/lib/browser/service/notebook-editor-widget-service.d.ts.map +1 -0
  45. package/lib/browser/service/{notebook-editor-service.js → notebook-editor-widget-service.js} +21 -13
  46. package/lib/browser/service/notebook-editor-widget-service.js.map +1 -0
  47. package/lib/browser/service/notebook-execution-service.js +1 -1
  48. package/lib/browser/service/notebook-execution-service.js.map +1 -1
  49. package/lib/browser/service/notebook-execution-state-service.d.ts +6 -18
  50. package/lib/browser/service/notebook-execution-state-service.d.ts.map +1 -1
  51. package/lib/browser/service/notebook-execution-state-service.js +24 -14
  52. package/lib/browser/service/notebook-execution-state-service.js.map +1 -1
  53. package/lib/browser/service/notebook-kernel-quick-pick-service.d.ts +1 -0
  54. package/lib/browser/service/notebook-kernel-quick-pick-service.d.ts.map +1 -1
  55. package/lib/browser/service/notebook-kernel-quick-pick-service.js +20 -17
  56. package/lib/browser/service/notebook-kernel-quick-pick-service.js.map +1 -1
  57. package/lib/browser/service/notebook-kernel-service.d.ts +15 -14
  58. package/lib/browser/service/notebook-kernel-service.d.ts.map +1 -1
  59. package/lib/browser/service/notebook-kernel-service.js +24 -18
  60. package/lib/browser/service/notebook-kernel-service.js.map +1 -1
  61. package/lib/browser/service/notebook-model-resolver-service.d.ts +3 -2
  62. package/lib/browser/service/notebook-model-resolver-service.d.ts.map +1 -1
  63. package/lib/browser/service/notebook-model-resolver-service.js +53 -35
  64. package/lib/browser/service/notebook-model-resolver-service.js.map +1 -1
  65. package/lib/browser/service/notebook-renderer-messaging-service.d.ts +7 -5
  66. package/lib/browser/service/notebook-renderer-messaging-service.d.ts.map +1 -1
  67. package/lib/browser/service/notebook-renderer-messaging-service.js +11 -10
  68. package/lib/browser/service/notebook-renderer-messaging-service.js.map +1 -1
  69. package/lib/browser/service/notebook-service.d.ts +12 -17
  70. package/lib/browser/service/notebook-service.d.ts.map +1 -1
  71. package/lib/browser/service/notebook-service.js +13 -18
  72. package/lib/browser/service/notebook-service.js.map +1 -1
  73. package/lib/browser/view/notebook-cell-editor.d.ts +2 -2
  74. package/lib/browser/view/notebook-cell-editor.d.ts.map +1 -1
  75. package/lib/browser/view/notebook-cell-editor.js +2 -2
  76. package/lib/browser/view/notebook-cell-editor.js.map +1 -1
  77. package/lib/browser/view-model/notebook-cell-model.d.ts +7 -5
  78. package/lib/browser/view-model/notebook-cell-model.d.ts.map +1 -1
  79. package/lib/browser/view-model/notebook-cell-model.js +20 -6
  80. package/lib/browser/view-model/notebook-cell-model.js.map +1 -1
  81. package/lib/browser/view-model/notebook-cell-output-model.d.ts +1 -0
  82. package/lib/browser/view-model/notebook-cell-output-model.d.ts.map +1 -1
  83. package/lib/browser/view-model/notebook-cell-output-model.js +31 -0
  84. package/lib/browser/view-model/notebook-cell-output-model.js.map +1 -1
  85. package/lib/browser/view-model/notebook-model.d.ts +15 -12
  86. package/lib/browser/view-model/notebook-model.d.ts.map +1 -1
  87. package/lib/browser/view-model/notebook-model.js +36 -21
  88. package/lib/browser/view-model/notebook-model.js.map +1 -1
  89. package/lib/common/notebook-common.d.ts +4 -6
  90. package/lib/common/notebook-common.d.ts.map +1 -1
  91. package/lib/common/notebook-common.js.map +1 -1
  92. package/package.json +7 -7
  93. package/src/browser/contributions/notebook-cell-actions-contribution.ts +9 -2
  94. package/src/browser/contributions/notebook-context-keys.ts +7 -0
  95. package/src/browser/index.ts +1 -1
  96. package/src/browser/notebook-cell-resource-resolver.ts +1 -5
  97. package/src/browser/notebook-editor-widget-factory.ts +2 -2
  98. package/src/browser/notebook-editor-widget.tsx +18 -13
  99. package/src/browser/notebook-frontend-module.ts +3 -3
  100. package/src/browser/notebook-open-handler.ts +3 -4
  101. package/src/browser/notebook-renderer-registry.ts +7 -3
  102. package/src/browser/notebook-type-registry.ts +7 -3
  103. package/src/browser/renderers/cell-output-webview.ts +1 -1
  104. package/src/browser/service/notebook-cell-context-manager.ts +7 -9
  105. package/src/browser/service/{notebook-editor-service.ts → notebook-editor-widget-service.ts} +19 -12
  106. package/src/browser/service/notebook-execution-service.ts +1 -1
  107. package/src/browser/service/notebook-execution-state-service.ts +26 -33
  108. package/src/browser/service/notebook-kernel-quick-pick-service.ts +10 -7
  109. package/src/browser/service/notebook-kernel-service.ts +29 -30
  110. package/src/browser/service/notebook-model-resolver-service.ts +56 -35
  111. package/src/browser/service/notebook-renderer-messaging-service.ts +21 -19
  112. package/src/browser/service/notebook-service.ts +21 -27
  113. package/src/browser/view/notebook-cell-editor.tsx +3 -3
  114. package/src/browser/view-model/notebook-cell-model.ts +26 -9
  115. package/src/browser/view-model/notebook-cell-output-model.ts +31 -1
  116. package/src/browser/view-model/notebook-model.ts +26 -16
  117. package/src/common/notebook-common.ts +4 -7
  118. package/lib/browser/service/notebook-editor-service.d.ts.map +0 -1
  119. package/lib/browser/service/notebook-editor-service.js.map +0 -1
@@ -28,9 +28,8 @@ export class NotebookOpenHandler extends NavigatableWidgetOpenHandler<NotebookEd
28
28
 
29
29
  id: string = 'notebook';
30
30
 
31
- constructor(@inject(NotebookTypeRegistry) private notebookTypeRegistry: NotebookTypeRegistry) {
32
- super();
33
- }
31
+ @inject(NotebookTypeRegistry)
32
+ protected notebookTypeRegistry: NotebookTypeRegistry;
34
33
 
35
34
  canHandle(uri: URI, options?: WidgetOpenerOptions | undefined): MaybePromise<number> {
36
35
  const priorities = this.notebookTypeRegistry.notebookTypes
@@ -59,7 +58,7 @@ export class NotebookOpenHandler extends NavigatableWidgetOpenHandler<NotebookEd
59
58
 
60
59
  protected calculatePriority(notebookType: NotebookTypeDescriptor | undefined): number {
61
60
  if (!notebookType) {
62
- return -1;
61
+ return 0;
63
62
  }
64
63
  return notebookType.priority === 'option' ? 100 : 200;
65
64
  }
@@ -33,7 +33,11 @@ export interface NotebookRendererInfo {
33
33
  @injectable()
34
34
  export class NotebookRendererRegistry {
35
35
 
36
- readonly notebookRenderers: NotebookRendererInfo[] = [];
36
+ private readonly _notebookRenderers: NotebookRendererInfo[] = [];
37
+
38
+ get notebookRenderers(): readonly NotebookRendererInfo[] {
39
+ return this._notebookRenderers;
40
+ }
37
41
 
38
42
  registerNotebookRenderer(type: NotebookRendererDescriptor, basePath: string): Disposable {
39
43
  let entrypoint;
@@ -48,14 +52,14 @@ export class NotebookRendererRegistry {
48
52
  };
49
53
  }
50
54
 
51
- this.notebookRenderers.push({
55
+ this._notebookRenderers.push({
52
56
  ...type,
53
57
  mimeTypes: type.mimeTypes || [],
54
58
  requiresMessaging: type.requiresMessaging === 'always' || type.requiresMessaging === 'optional',
55
59
  entrypoint
56
60
  });
57
61
  return Disposable.create(() => {
58
- this.notebookRenderers.splice(this.notebookRenderers.findIndex(renderer => renderer.id === type.id), 1);
62
+ this._notebookRenderers.splice(this._notebookRenderers.findIndex(renderer => renderer.id === type.id), 1);
59
63
  });
60
64
  }
61
65
  }
@@ -19,12 +19,16 @@ import { NotebookTypeDescriptor } from '../common/notebook-protocol';
19
19
 
20
20
  @injectable()
21
21
  export class NotebookTypeRegistry {
22
- readonly notebookTypes: NotebookTypeDescriptor[] = [];
22
+ private readonly _notebookTypes: NotebookTypeDescriptor[] = [];
23
+
24
+ get notebookTypes(): readonly NotebookTypeDescriptor[] {
25
+ return this._notebookTypes;
26
+ }
23
27
 
24
28
  registerNotebookType(type: NotebookTypeDescriptor): Disposable {
25
- this.notebookTypes.push(type);
29
+ this._notebookTypes.push(type);
26
30
  return Disposable.create(() => {
27
- this.notebookTypes.splice(this.notebookTypes.indexOf(type), 1);
31
+ this._notebookTypes.splice(this._notebookTypes.indexOf(type), 1);
28
32
  });
29
33
  }
30
34
  }
@@ -25,7 +25,7 @@ export interface CellOutputWebview extends Disposable {
25
25
 
26
26
  readonly id: string;
27
27
 
28
- render(): React.JSX.Element;
28
+ render(): React.ReactNode;
29
29
 
30
30
  attachWebview(): void;
31
31
  isAttached(): boolean
@@ -15,7 +15,7 @@
15
15
  // *****************************************************************************
16
16
 
17
17
  import { inject, injectable } from '@theia/core/shared/inversify';
18
- import { ContextKeyService, ScopedValueStore } from '@theia/core/lib/browser/context-key-service';
18
+ import { ContextKeyService } from '@theia/core/lib/browser/context-key-service';
19
19
  import { NotebookCellModel } from '../view-model/notebook-cell-model';
20
20
  import { NOTEBOOK_CELL_EXECUTING, NOTEBOOK_CELL_EXECUTION_STATE, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE, NOTEBOOK_CELL_TYPE } from '../contributions/notebook-context-keys';
21
21
  import { Disposable, DisposableCollection, Emitter } from '@theia/core';
@@ -31,7 +31,6 @@ export class NotebookCellContextManager implements Disposable {
31
31
 
32
32
  protected readonly toDispose = new DisposableCollection();
33
33
 
34
- protected currentStore: ScopedValueStore;
35
34
  protected currentContext: HTMLLIElement;
36
35
 
37
36
  protected readonly onDidChangeContextEmitter = new Emitter<void>();
@@ -40,21 +39,21 @@ export class NotebookCellContextManager implements Disposable {
40
39
  updateCellContext(cell: NotebookCellModel, newHtmlContext: HTMLLIElement): void {
41
40
  if (newHtmlContext !== this.currentContext) {
42
41
  this.toDispose.dispose();
43
- this.currentStore?.dispose();
44
42
 
45
43
  this.currentContext = newHtmlContext;
46
- this.currentStore = this.contextKeyService.createScoped(newHtmlContext);
44
+ const currentStore = this.contextKeyService.createScoped(newHtmlContext);
45
+ this.toDispose.push(currentStore);
47
46
 
48
- this.currentStore.setContext(NOTEBOOK_CELL_TYPE, cell.cellKind === CellKind.Code ? 'code' : 'markdown');
47
+ currentStore.setContext(NOTEBOOK_CELL_TYPE, cell.cellKind === CellKind.Code ? 'code' : 'markdown');
49
48
 
50
49
  this.toDispose.push(cell.onDidRequestCellEditChange(cellEdit => {
51
- this.currentStore?.setContext(NOTEBOOK_CELL_MARKDOWN_EDIT_MODE, cellEdit);
50
+ currentStore?.setContext(NOTEBOOK_CELL_MARKDOWN_EDIT_MODE, cellEdit);
52
51
  this.onDidChangeContextEmitter.fire();
53
52
  }));
54
53
  this.toDispose.push(this.executionStateService.onDidChangeExecution(e => {
55
54
  if (e.affectsCell(cell.uri)) {
56
- this.currentStore?.setContext(NOTEBOOK_CELL_EXECUTING, !!e.changed);
57
- this.currentStore?.setContext(NOTEBOOK_CELL_EXECUTION_STATE, e.changed?.state ?? 'idle');
55
+ currentStore?.setContext(NOTEBOOK_CELL_EXECUTING, !!e.changed);
56
+ currentStore?.setContext(NOTEBOOK_CELL_EXECUTION_STATE, e.changed?.state ?? 'idle');
58
57
  this.onDidChangeContextEmitter.fire();
59
58
  }
60
59
  }));
@@ -64,7 +63,6 @@ export class NotebookCellContextManager implements Disposable {
64
63
 
65
64
  dispose(): void {
66
65
  this.toDispose.dispose();
67
- this.currentStore?.dispose();
68
66
  this.onDidChangeContextEmitter.dispose();
69
67
  }
70
68
  }
@@ -22,7 +22,7 @@
22
22
  import { Disposable, DisposableCollection, Emitter } from '@theia/core';
23
23
  import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
24
24
  import { ApplicationShell } from '@theia/core/lib/browser';
25
- import { NotebookEditorWidget, NOTEBOOK_EDITOR_ID_PREFIX } from '../notebook-editor-widget';
25
+ import { NotebookEditorWidget } from '../notebook-editor-widget';
26
26
 
27
27
  @injectable()
28
28
  export class NotebookEditorWidgetService implements Disposable {
@@ -33,37 +33,42 @@ export class NotebookEditorWidgetService implements Disposable {
33
33
  private readonly notebookEditors = new Map<string, NotebookEditorWidget>();
34
34
 
35
35
  private readonly onNotebookEditorAddEmitter = new Emitter<NotebookEditorWidget>();
36
- private readonly onNotebookEditorsRemoveEmitter = new Emitter<NotebookEditorWidget>();
36
+ private readonly onNotebookEditorRemoveEmitter = new Emitter<NotebookEditorWidget>();
37
37
  readonly onDidAddNotebookEditor = this.onNotebookEditorAddEmitter.event;
38
- readonly onDidRemoveNotebookEditor = this.onNotebookEditorsRemoveEmitter.event;
38
+ readonly onDidRemoveNotebookEditor = this.onNotebookEditorRemoveEmitter.event;
39
39
 
40
- private readonly onFocusedEditorChangedEmitter = new Emitter<NotebookEditorWidget>();
41
- readonly onFocusedEditorChanged = this.onFocusedEditorChangedEmitter.event;
40
+ private readonly onDidChangeFocusedEditorEmitter = new Emitter<NotebookEditorWidget | undefined>();
41
+ readonly onDidChangeFocusedEditor = this.onDidChangeFocusedEditorEmitter.event;
42
42
 
43
43
  private readonly toDispose = new DisposableCollection();
44
44
 
45
- currentFocusedEditor?: NotebookEditorWidget = undefined;
45
+ focusedEditor?: NotebookEditorWidget = undefined;
46
46
 
47
47
  @postConstruct()
48
48
  protected init(): void {
49
49
  this.toDispose.push(this.applicationShell.onDidChangeActiveWidget(event => {
50
- if (event.newValue?.id.startsWith(NOTEBOOK_EDITOR_ID_PREFIX) && event.newValue !== this.currentFocusedEditor) {
51
- this.currentFocusedEditor = event.newValue as NotebookEditorWidget;
52
- this.onFocusedEditorChangedEmitter.fire(this.currentFocusedEditor);
50
+ if (event.newValue instanceof NotebookEditorWidget && event.newValue !== this.focusedEditor) {
51
+ this.focusedEditor = event.newValue;
52
+ this.onDidChangeFocusedEditorEmitter.fire(this.focusedEditor);
53
+ } else {
54
+ this.onDidChangeFocusedEditorEmitter.fire(undefined);
53
55
  }
54
56
  }));
55
57
  }
56
58
 
57
59
  dispose(): void {
58
60
  this.onNotebookEditorAddEmitter.dispose();
59
- this.onNotebookEditorsRemoveEmitter.dispose();
60
- this.onFocusedEditorChangedEmitter.dispose();
61
+ this.onNotebookEditorRemoveEmitter.dispose();
62
+ this.onDidChangeFocusedEditorEmitter.dispose();
61
63
  this.toDispose.dispose();
62
64
  }
63
65
 
64
66
  // --- editor management
65
67
 
66
68
  addNotebookEditor(editor: NotebookEditorWidget): void {
69
+ if (this.notebookEditors.has(editor.id)) {
70
+ console.warn('Attempting to add duplicated notebook editor: ' + editor.id);
71
+ }
67
72
  this.notebookEditors.set(editor.id, editor);
68
73
  this.onNotebookEditorAddEmitter.fire(editor);
69
74
  }
@@ -71,7 +76,9 @@ export class NotebookEditorWidgetService implements Disposable {
71
76
  removeNotebookEditor(editor: NotebookEditorWidget): void {
72
77
  if (this.notebookEditors.has(editor.id)) {
73
78
  this.notebookEditors.delete(editor.id);
74
- this.onNotebookEditorsRemoveEmitter.fire(editor);
79
+ this.onNotebookEditorRemoveEmitter.fire(editor);
80
+ } else {
81
+ console.warn('Attempting to remove not registered editor: ' + editor.id);
75
82
  }
76
83
  }
77
84
 
@@ -65,7 +65,7 @@ export class NotebookExecutionService {
65
65
  for (const cell of cellsArr) {
66
66
  const cellExe = this.notebookExecutionStateService.getCellExecution(cell.uri);
67
67
  if (!cellExe) {
68
- cellExecutions.push([cell, this.notebookExecutionStateService.createCellExecution(notebook.uri, cell.handle)]);
68
+ cellExecutions.push([cell, this.notebookExecutionStateService.getOrCreateCellExecution(notebook.uri, cell.handle)]);
69
69
  }
70
70
  }
71
71
 
@@ -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, Emitter, URI } from '@theia/core';
21
+ import { Disposable, DisposableCollection, Emitter, URI } from '@theia/core';
22
22
  import { inject, injectable } from '@theia/core/shared/inversify';
23
23
  import { NotebookService } from './notebook-service';
24
24
  import {
@@ -43,22 +43,6 @@ export interface CellExecutionStateUpdate {
43
43
  isPaused?: boolean;
44
44
  }
45
45
 
46
- export interface ICellExecutionStateUpdate {
47
- editType: CellExecutionUpdateType.ExecutionState;
48
- executionOrder?: number;
49
- runStartTime?: number;
50
- didPause?: boolean;
51
- isPaused?: boolean;
52
- }
53
-
54
- export interface ICellExecutionStateUpdate {
55
- editType: CellExecutionUpdateType.ExecutionState;
56
- executionOrder?: number;
57
- runStartTime?: number;
58
- didPause?: boolean;
59
- isPaused?: boolean;
60
- }
61
-
62
46
  export interface ICellExecutionComplete {
63
47
  runEndTime?: number;
64
48
  lastRunSuccess?: boolean;
@@ -85,7 +69,9 @@ export class NotebookExecutionStateService implements Disposable {
85
69
  @inject(NotebookService)
86
70
  protected notebookService: NotebookService;
87
71
 
88
- protected readonly executions = new Map<string, CellExecution>();
72
+ protected toDispose: DisposableCollection = new DisposableCollection();
73
+
74
+ protected readonly executions = new Map<string, Map<number, CellExecution>>();
89
75
 
90
76
  private readonly onDidChangeExecutionEmitter = new Emitter<CellExecutionStateChangedEvent>();
91
77
  onDidChangeExecution = this.onDidChangeExecutionEmitter.event;
@@ -93,18 +79,21 @@ export class NotebookExecutionStateService implements Disposable {
93
79
  private readonly onDidChangeLastRunFailStateEmitter = new Emitter<NotebookFailStateChangedEvent>();
94
80
  onDidChangeLastRunFailState = this.onDidChangeLastRunFailStateEmitter.event;
95
81
 
96
- createCellExecution(notebookUri: URI, cellHandle: number): CellExecution {
82
+ getOrCreateCellExecution(notebookUri: URI, cellHandle: number): CellExecution {
97
83
  const notebook = this.notebookService.getNotebookEditorModel(notebookUri);
98
84
 
99
85
  if (!notebook) {
100
86
  throw new Error(`Notebook not found: ${notebookUri.toString()}`);
101
87
  }
102
88
 
103
- let execution = this.executions.get(`${notebookUri}/${cellHandle}`);
89
+ let execution = this.executions.get(notebookUri.toString())?.get(cellHandle);
104
90
 
105
91
  if (!execution) {
106
92
  execution = this.createNotebookCellExecution(notebook, cellHandle);
107
- this.executions.set(`${notebookUri}/${cellHandle}`, execution);
93
+ if (!this.executions.has(notebookUri.toString())) {
94
+ this.executions.set(notebookUri.toString(), new Map());
95
+ }
96
+ this.executions.get(notebookUri.toString())?.set(cellHandle, execution);
108
97
  execution.initialize();
109
98
  this.onDidChangeExecutionEmitter.fire(new CellExecutionStateChangedEvent(notebookUri, cellHandle, execution));
110
99
  }
@@ -116,20 +105,20 @@ export class NotebookExecutionStateService implements Disposable {
116
105
  private createNotebookCellExecution(notebook: NotebookModel, cellHandle: number): CellExecution {
117
106
  const notebookUri = notebook.uri;
118
107
  const execution = new CellExecution(cellHandle, notebook);
119
- execution.onDidUpdate(() => this.onDidChangeExecutionEmitter.fire(new CellExecutionStateChangedEvent(notebookUri, cellHandle, execution)));
120
- execution.onDidComplete(lastRunSuccess => this.onCellExecutionDidComplete(notebookUri, cellHandle, execution, lastRunSuccess));
108
+ execution.toDispose.push(execution.onDidUpdate(() => this.onDidChangeExecutionEmitter.fire(new CellExecutionStateChangedEvent(notebookUri, cellHandle, execution))));
109
+ execution.toDispose.push(execution.onDidComplete(lastRunSuccess => this.onCellExecutionDidComplete(notebookUri, cellHandle, execution, lastRunSuccess)));
121
110
 
122
111
  return execution;
123
112
  }
124
113
 
125
114
  private onCellExecutionDidComplete(notebookUri: URI, cellHandle: number, exe: CellExecution, lastRunSuccess?: boolean): void {
126
- const notebookExecutions = this.executions.get(`${notebookUri}/${cellHandle}`);
115
+ const notebookExecutions = this.executions.get(notebookUri.toString())?.get(cellHandle);
127
116
  if (!notebookExecutions) {
128
- return;
117
+ throw new Error('Notebook Cell Execution not found while trying to complete it');
129
118
  }
130
119
 
131
120
  exe.dispose();
132
- this.executions.delete(`${notebookUri}/${cellHandle}`);
121
+ this.executions.get(notebookUri.toString())?.delete(cellHandle);
133
122
 
134
123
  this.onDidChangeExecutionEmitter.fire(new CellExecutionStateChangedEvent(notebookUri, cellHandle));
135
124
  }
@@ -140,14 +129,14 @@ export class NotebookExecutionStateService implements Disposable {
140
129
  throw new Error(`Not a cell URI: ${cellUri}`);
141
130
  }
142
131
 
143
- return this.executions.get(`${parsed.notebook.toString()}/${parsed.handle}`);
132
+ return this.executions.get(parsed.notebook.toString())?.get(parsed.handle);
144
133
  }
145
134
 
146
135
  dispose(): void {
147
136
  this.onDidChangeExecutionEmitter.dispose();
148
137
  this.onDidChangeLastRunFailStateEmitter.dispose();
149
138
 
150
- this.executions.forEach(cellExecution => cellExecution.dispose());
139
+ this.executions.forEach(notebookExecutions => notebookExecutions.forEach(execution => execution.dispose()));
151
140
  }
152
141
 
153
142
  }
@@ -159,6 +148,8 @@ export class CellExecution implements Disposable {
159
148
  private readonly onDidCompleteEmitter = new Emitter<boolean | undefined>();
160
149
  readonly onDidComplete = this.onDidCompleteEmitter.event;
161
150
 
151
+ toDispose = new DisposableCollection();
152
+
162
153
  private _state: NotebookCellExecutionState = NotebookCellExecutionState.Unconfirmed;
163
154
  get state(): NotebookCellExecutionState {
164
155
  return this._state;
@@ -198,7 +189,7 @@ export class CellExecution implements Disposable {
198
189
  renderDuration: undefined,
199
190
  }
200
191
  };
201
- this.applyExecutionEdits([startExecuteEdit]);
192
+ this.applyCellExecutionEditsToNotebook([startExecuteEdit]);
202
193
  }
203
194
 
204
195
  private getCellLog(): string {
@@ -221,7 +212,7 @@ export class CellExecution implements Disposable {
221
212
 
222
213
  const lastIsPausedUpdate = [...updates].reverse().find(u => u.editType === CellExecutionUpdateType.ExecutionState && typeof u.isPaused === 'boolean');
223
214
  if (lastIsPausedUpdate) {
224
- this._isPaused = (lastIsPausedUpdate as ICellExecutionStateUpdate).isPaused!;
215
+ this._isPaused = (lastIsPausedUpdate as CellExecutionStateUpdate).isPaused!;
225
216
  }
226
217
 
227
218
  const cellModel = this.notebook.cells.find(c => c.handle === this.cellHandle);
@@ -229,7 +220,7 @@ export class CellExecution implements Disposable {
229
220
  console.debug(`CellExecution#update, updating cell not in notebook: ${this.notebook.uri.toString()}, ${this.cellHandle}`);
230
221
  } else {
231
222
  const edits = updates.map(update => updateToEdit(update, this.cellHandle));
232
- this.applyExecutionEdits(edits);
223
+ this.applyCellExecutionEditsToNotebook(edits);
233
224
  }
234
225
 
235
226
  if (updates.some(u => u.editType === CellExecutionUpdateType.ExecutionState)) {
@@ -254,7 +245,7 @@ export class CellExecution implements Disposable {
254
245
  runEndTime: this._didPause ? null : completionData.runEndTime,
255
246
  }
256
247
  };
257
- this.applyExecutionEdits([edit]);
248
+ this.applyCellExecutionEditsToNotebook([edit]);
258
249
  }
259
250
 
260
251
  this.onDidCompleteEmitter.fire(completionData.lastRunSuccess);
@@ -264,9 +255,10 @@ export class CellExecution implements Disposable {
264
255
  dispose(): void {
265
256
  this.onDidUpdateEmitter.dispose();
266
257
  this.onDidCompleteEmitter.dispose();
258
+ this.toDispose.dispose();
267
259
  }
268
260
 
269
- private applyExecutionEdits(edits: CellEditOperation[]): void {
261
+ private applyCellExecutionEditsToNotebook(edits: CellEditOperation[]): void {
270
262
  this.notebook.applyEdits(edits, false);
271
263
  }
272
264
  }
@@ -301,6 +293,7 @@ export function updateToEdit(update: CellExecuteUpdate, cellHandle: number): Cel
301
293
  return {
302
294
  editType: CellEditType.OutputItems,
303
295
  items: update.items,
296
+ outputId: update.outputId,
304
297
  append: update.append,
305
298
  };
306
299
  } else if (update.editType === CellExecutionUpdateType.ExecutionState) {
@@ -18,7 +18,6 @@
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
-
22
21
  import { ArrayUtils, Command, CommandService, DisposableCollection, Event, nls, QuickInputButton, QuickInputService, QuickPickInput, QuickPickItem, URI, } from '@theia/core';
23
22
  import { inject, injectable } from '@theia/core/shared/inversify';
24
23
  import { NotebookKernelService, NotebookKernel, NotebookKernelMatchResult, SourceCommand } from './notebook-kernel-service';
@@ -216,7 +215,7 @@ export abstract class NotebookKernelQuickPickServiceImpl {
216
215
 
217
216
  if (isSourcePick(pick)) {
218
217
  // selected explicitly, it should trigger the execution?
219
- pick.action.run();
218
+ pick.action.run(this.commandService);
220
219
  }
221
220
 
222
221
  return true;
@@ -316,7 +315,7 @@ export class KernelPickerMRUStrategy extends NotebookKernelQuickPickServiceImpl
316
315
  quickPick.onDidTriggerItemButton(async e => {
317
316
 
318
317
  if (isKernelSourceQuickPickItem(e.item) && e.item.documentation !== undefined) {
319
- const uri: URI | undefined = URI.isUri(e.item.documentation) ? new URI(e.item.documentation) : await this.commandService.executeCommand(e.item.documentation);
318
+ const uri: URI | undefined = this.isUri(e.item.documentation) ? new URI(e.item.documentation) : await this.commandService.executeCommand(e.item.documentation);
320
319
  if (uri) {
321
320
  (await this.openerService.getOpener(uri, { openExternal: true })).open(uri, { openExternal: true });
322
321
  }
@@ -386,7 +385,7 @@ export class KernelPickerMRUStrategy extends NotebookKernelQuickPickServiceImpl
386
385
  } else if (isSourcePick(selectedKernelPickItem)) {
387
386
  // selected explicitly, it should trigger the execution?
388
387
  try {
389
- await selectedKernelPickItem.action.run();
388
+ await selectedKernelPickItem.action.run(this.commandService);
390
389
  return true;
391
390
  } catch (ex) {
392
391
  return false;
@@ -416,18 +415,22 @@ export class KernelPickerMRUStrategy extends NotebookKernelQuickPickServiceImpl
416
415
  return false;
417
416
  }
418
417
 
418
+ private isUri(value: string): boolean {
419
+ return /^(?<scheme>\w[\w\d+.-]*):/.test(value);
420
+ }
421
+
419
422
  private async calculateKernelSources(editor: NotebookModel): Promise<QuickPickInput<KernelQuickPickItem>[]> {
420
423
  const notebook: NotebookModel = editor;
421
424
 
422
425
  const actions = await this.notebookKernelService.getKernelSourceActionsFromProviders(notebook);
423
426
  const matchResult = this.getMatchingResult(notebook);
424
427
 
425
- const others = matchResult.all.filter(item => item.extension !== JUPYTER_EXTENSION_ID);
428
+ const others = matchResult.all.filter(item => item.extensionId !== JUPYTER_EXTENSION_ID);
426
429
  const quickPickItems: QuickPickInput<KernelQuickPickItem>[] = [];
427
430
 
428
431
  // group controllers by extension
429
- for (const group of ArrayUtils.groupBy(others, (a, b) => a.extension === b.extension ? 0 : 1)) {
430
- const source = group[0].extension;
432
+ for (const group of ArrayUtils.groupBy(others, (a, b) => a.extensionId === b.extensionId ? 0 : 1)) {
433
+ const source = group[0].extensionId;
431
434
  if (group.length > 1) {
432
435
  quickPickItems.push({
433
436
  label: source,
@@ -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 { Command, CommandRegistry, Disposable, Emitter, Event, URI } from '@theia/core';
21
+ import { Command, CommandService, Disposable, Emitter, Event, URI } from '@theia/core';
22
22
  import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
23
23
  import { StorageService } from '@theia/core/lib/browser';
24
24
  import { NotebookKernelSourceAction } from '../../common';
@@ -51,11 +51,8 @@ export interface NotebookKernel {
51
51
  readonly id: string;
52
52
  readonly viewType: string;
53
53
  readonly onDidChange: Event<Readonly<NotebookKernelChangeEvent>>;
54
- readonly extension: string;
55
-
56
- readonly localResourceRoot: URI;
57
- readonly preloadUris: URI[];
58
- readonly preloadProvides: string[];
54
+ // ID of the extension providing this kernel
55
+ readonly extensionId: string;
59
56
 
60
57
  label: string;
61
58
  description?: string;
@@ -78,24 +75,20 @@ export interface INotebookProxyKernelChangeEvent extends NotebookKernelChangeEve
78
75
  connectionState?: true;
79
76
  }
80
77
 
81
- export interface NotebookKernelDetectionTask {
82
- readonly notebookType: string;
83
- }
84
-
85
78
  export interface NotebookTextModelLike { uri: URI; viewType: string }
86
79
 
87
80
  class KernelInfo {
88
81
 
89
- private static logicClock = 0;
82
+ private static instanceCounter = 0;
90
83
 
84
+ score: number;
91
85
  readonly kernel: NotebookKernel;
92
- public score: number;
93
- readonly time: number;
86
+ readonly handle: number;
94
87
 
95
88
  constructor(kernel: NotebookKernel) {
96
89
  this.kernel = kernel;
97
90
  this.score = -1;
98
- this.time = KernelInfo.logicClock++;
91
+ this.handle = KernelInfo.instanceCounter++;
99
92
  }
100
93
  }
101
94
 
@@ -116,27 +109,25 @@ export class SourceCommand implements Disposable {
116
109
  readonly onDidChangeState = this.onDidChangeStateEmitter.event;
117
110
 
118
111
  constructor(
119
- readonly commandRegistry: CommandRegistry,
120
112
  readonly command: Command,
121
113
  readonly model: NotebookTextModelLike,
122
- readonly isPrimary: boolean
123
114
  ) { }
124
115
 
125
- async run(): Promise<void> {
116
+ async run(commandService: CommandService): Promise<void> {
126
117
  if (this.execution) {
127
118
  return this.execution;
128
119
  }
129
120
 
130
- this.execution = this.runCommand();
121
+ this.execution = this.runCommand(commandService);
131
122
  this.onDidChangeStateEmitter.fire();
132
123
  await this.execution;
133
124
  this.execution = undefined;
134
125
  this.onDidChangeStateEmitter.fire();
135
126
  }
136
127
 
137
- private async runCommand(): Promise<void> {
128
+ private async runCommand(commandService: CommandService): Promise<void> {
138
129
  try {
139
- await this.commandRegistry.executeCommand(this.command.id, {
130
+ await commandService.executeCommand(this.command.id, {
140
131
  uri: this.model.uri,
141
132
  });
142
133
 
@@ -165,7 +156,7 @@ export class NotebookKernelService implements Disposable {
165
156
 
166
157
  private notebookBindings: { [key: string]: string } = {};
167
158
 
168
- private readonly kernelDetectionTasks = new Map<string, NotebookKernelDetectionTask[]>();
159
+ private readonly kernelDetectionTasks = new Map<string, string[]>();
169
160
  private readonly onDidChangeKernelDetectionTasksEmitter = new Emitter<string>();
170
161
  readonly onDidChangeKernelDetectionTasks = this.onDidChangeKernelDetectionTasksEmitter.event;
171
162
 
@@ -196,7 +187,7 @@ export class NotebookKernelService implements Disposable {
196
187
 
197
188
  registerKernel(kernel: NotebookKernel): Disposable {
198
189
  if (this.kernels.has(kernel.id)) {
199
- throw new Error(`NOTEBOOK CONTROLLER with id '${kernel.id}' already exists`);
190
+ throw new Error(`Notebook Controller with id '${kernel.id}' already exists`);
200
191
  }
201
192
 
202
193
  this.kernels.set(kernel.id, new KernelInfo(kernel));
@@ -215,6 +206,15 @@ export class NotebookKernelService implements Disposable {
215
206
  });
216
207
  }
217
208
 
209
+ /**
210
+ * Helps to find the best matching kernel for a notebook.
211
+ * @param notebook notebook to get the matching kernel for
212
+ * @returns and object containing:
213
+ * all kernels sorted to match the notebook best first (affinity ascending, score descending, label))
214
+ * the selected kernel (if any)
215
+ * specific suggested kernels (if any)
216
+ * hidden kernels (if any)
217
+ */
218
218
  getMatchingKernel(notebook: NotebookTextModelLike): NotebookKernelMatchResult {
219
219
  const kernels: { kernel: NotebookKernel; instanceAffinity: number; score: number }[] = [];
220
220
  for (const info of this.kernels.values()) {
@@ -269,10 +269,10 @@ export class NotebookKernelService implements Disposable {
269
269
  }
270
270
 
271
271
  private static score(kernel: NotebookKernel, notebook: NotebookTextModelLike): number {
272
- if (kernel.viewType === '*') {
273
- return 5;
274
- } else if (kernel.viewType === notebook.viewType) {
272
+ if (kernel.viewType === notebook.viewType) {
275
273
  return 10;
274
+ } else if (kernel.viewType === '*') {
275
+ return 5;
276
276
  } else {
277
277
  return 0;
278
278
  }
@@ -295,15 +295,14 @@ export class NotebookKernelService implements Disposable {
295
295
  }
296
296
  }
297
297
 
298
- registerNotebookKernelDetectionTask(task: NotebookKernelDetectionTask): Disposable {
299
- const notebookType = task.notebookType;
298
+ registerNotebookKernelDetectionTask(notebookType: string): Disposable {
300
299
  const all = this.kernelDetectionTasks.get(notebookType) ?? [];
301
- all.push(task);
300
+ all.push(notebookType);
302
301
  this.kernelDetectionTasks.set(notebookType, all);
303
302
  this.onDidChangeKernelDetectionTasksEmitter.fire(notebookType);
304
303
  return Disposable.create(() => {
305
304
  const allTasks = this.kernelDetectionTasks.get(notebookType) ?? [];
306
- const taskIndex = allTasks.indexOf(task);
305
+ const taskIndex = allTasks.indexOf(notebookType);
307
306
  if (taskIndex >= 0) {
308
307
  allTasks.splice(taskIndex, 1);
309
308
  this.kernelDetectionTasks.set(notebookType, allTasks);
@@ -312,7 +311,7 @@ export class NotebookKernelService implements Disposable {
312
311
  });
313
312
  }
314
313
 
315
- getKernelDetectionTasks(notebook: NotebookTextModelLike): NotebookKernelDetectionTask[] {
314
+ getKernelDetectionTasks(notebook: NotebookTextModelLike): string[] {
316
315
  return this.kernelDetectionTasks.get(notebook.viewType) ?? [];
317
316
  }
318
317