@theia/notebook 1.49.1 → 1.50.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.
Files changed (151) hide show
  1. package/lib/browser/contributions/cell-operations.js +1 -1
  2. package/lib/browser/contributions/cell-operations.js.map +1 -1
  3. package/lib/browser/contributions/notebook-actions-contribution.d.ts +3 -0
  4. package/lib/browser/contributions/notebook-actions-contribution.d.ts.map +1 -1
  5. package/lib/browser/contributions/notebook-actions-contribution.js +54 -34
  6. package/lib/browser/contributions/notebook-actions-contribution.js.map +1 -1
  7. package/lib/browser/contributions/notebook-cell-actions-contribution.d.ts +2 -2
  8. package/lib/browser/contributions/notebook-cell-actions-contribution.d.ts.map +1 -1
  9. package/lib/browser/contributions/notebook-cell-actions-contribution.js +42 -42
  10. package/lib/browser/contributions/notebook-cell-actions-contribution.js.map +1 -1
  11. package/lib/browser/contributions/notebook-color-contribution.js +2 -2
  12. package/lib/browser/contributions/notebook-color-contribution.js.map +1 -1
  13. package/lib/browser/contributions/notebook-context-keys.d.ts +4 -1
  14. package/lib/browser/contributions/notebook-context-keys.d.ts.map +1 -1
  15. package/lib/browser/contributions/notebook-context-keys.js +8 -2
  16. package/lib/browser/contributions/notebook-context-keys.js.map +1 -1
  17. package/lib/browser/contributions/notebook-label-provider-contribution.d.ts +3 -0
  18. package/lib/browser/contributions/notebook-label-provider-contribution.d.ts.map +1 -1
  19. package/lib/browser/contributions/notebook-label-provider-contribution.js +33 -13
  20. package/lib/browser/contributions/notebook-label-provider-contribution.js.map +1 -1
  21. package/lib/browser/contributions/notebook-outline-contribution.d.ts +0 -2
  22. package/lib/browser/contributions/notebook-outline-contribution.d.ts.map +1 -1
  23. package/lib/browser/contributions/notebook-outline-contribution.js +21 -17
  24. package/lib/browser/contributions/notebook-outline-contribution.js.map +1 -1
  25. package/lib/browser/contributions/notebook-output-action-contribution.js +7 -7
  26. package/lib/browser/contributions/notebook-output-action-contribution.js.map +1 -1
  27. package/lib/browser/index.js +11 -11
  28. package/lib/browser/index.js.map +1 -1
  29. package/lib/browser/notebook-cell-resource-resolver.js +14 -14
  30. package/lib/browser/notebook-cell-resource-resolver.js.map +1 -1
  31. package/lib/browser/notebook-editor-widget-factory.d.ts +3 -2
  32. package/lib/browser/notebook-editor-widget-factory.d.ts.map +1 -1
  33. package/lib/browser/notebook-editor-widget-factory.js +10 -10
  34. package/lib/browser/notebook-editor-widget-factory.js.map +1 -1
  35. package/lib/browser/notebook-editor-widget.d.ts +3 -0
  36. package/lib/browser/notebook-editor-widget.d.ts.map +1 -1
  37. package/lib/browser/notebook-editor-widget.js +32 -26
  38. package/lib/browser/notebook-editor-widget.js.map +1 -1
  39. package/lib/browser/notebook-frontend-module.d.ts.map +1 -1
  40. package/lib/browser/notebook-frontend-module.js +1 -0
  41. package/lib/browser/notebook-frontend-module.js.map +1 -1
  42. package/lib/browser/notebook-open-handler.js +2 -2
  43. package/lib/browser/notebook-open-handler.js.map +1 -1
  44. package/lib/browser/notebook-output-utils.js.map +1 -1
  45. package/lib/browser/notebook-renderer-registry.js +2 -2
  46. package/lib/browser/notebook-renderer-registry.js.map +1 -1
  47. package/lib/browser/notebook-type-registry.js +6 -6
  48. package/lib/browser/notebook-type-registry.js.map +1 -1
  49. package/lib/browser/notebook-types.d.ts +6 -6
  50. package/lib/browser/notebook-types.d.ts.map +1 -1
  51. package/lib/browser/notebook-types.js +1 -1
  52. package/lib/browser/notebook-types.js.map +1 -1
  53. package/lib/browser/renderers/cell-output-webview.d.ts +1 -1
  54. package/lib/browser/renderers/cell-output-webview.d.ts.map +1 -1
  55. package/lib/browser/service/notebook-clipboard-service.js +4 -4
  56. package/lib/browser/service/notebook-clipboard-service.js.map +1 -1
  57. package/lib/browser/service/notebook-context-manager.d.ts.map +1 -1
  58. package/lib/browser/service/notebook-context-manager.js +14 -10
  59. package/lib/browser/service/notebook-context-manager.js.map +1 -1
  60. package/lib/browser/service/notebook-editor-widget-service.js +10 -10
  61. package/lib/browser/service/notebook-editor-widget-service.js.map +1 -1
  62. package/lib/browser/service/notebook-execution-service.d.ts.map +1 -1
  63. package/lib/browser/service/notebook-execution-service.js +22 -12
  64. package/lib/browser/service/notebook-execution-service.js.map +1 -1
  65. package/lib/browser/service/notebook-execution-state-service.d.ts +1 -1
  66. package/lib/browser/service/notebook-execution-state-service.d.ts.map +1 -1
  67. package/lib/browser/service/notebook-execution-state-service.js +22 -22
  68. package/lib/browser/service/notebook-execution-state-service.js.map +1 -1
  69. package/lib/browser/service/notebook-kernel-history-service.js +12 -12
  70. package/lib/browser/service/notebook-kernel-history-service.js.map +1 -1
  71. package/lib/browser/service/notebook-kernel-quick-pick-service.d.ts +7 -7
  72. package/lib/browser/service/notebook-kernel-quick-pick-service.d.ts.map +1 -1
  73. package/lib/browser/service/notebook-kernel-quick-pick-service.js +12 -12
  74. package/lib/browser/service/notebook-kernel-quick-pick-service.js.map +1 -1
  75. package/lib/browser/service/notebook-kernel-service.js +10 -10
  76. package/lib/browser/service/notebook-kernel-service.js.map +1 -1
  77. package/lib/browser/service/notebook-model-resolver-service.d.ts +1 -1
  78. package/lib/browser/service/notebook-model-resolver-service.d.ts.map +1 -1
  79. package/lib/browser/service/notebook-model-resolver-service.js +19 -25
  80. package/lib/browser/service/notebook-model-resolver-service.js.map +1 -1
  81. package/lib/browser/service/notebook-monaco-text-model-service.js +6 -6
  82. package/lib/browser/service/notebook-monaco-text-model-service.js.map +1 -1
  83. package/lib/browser/service/notebook-renderer-messaging-service.js +4 -4
  84. package/lib/browser/service/notebook-renderer-messaging-service.js.map +1 -1
  85. package/lib/browser/service/notebook-service.d.ts +1 -1
  86. package/lib/browser/service/notebook-service.d.ts.map +1 -1
  87. package/lib/browser/service/notebook-service.js +31 -25
  88. package/lib/browser/service/notebook-service.js.map +1 -1
  89. package/lib/browser/view/notebook-cell-editor.d.ts.map +1 -1
  90. package/lib/browser/view/notebook-cell-editor.js +27 -8
  91. package/lib/browser/view/notebook-cell-editor.js.map +1 -1
  92. package/lib/browser/view/notebook-cell-list-view.d.ts +4 -1
  93. package/lib/browser/view/notebook-cell-list-view.d.ts.map +1 -1
  94. package/lib/browser/view/notebook-cell-list-view.js +30 -9
  95. package/lib/browser/view/notebook-cell-list-view.js.map +1 -1
  96. package/lib/browser/view/notebook-cell-toolbar-factory.js +14 -14
  97. package/lib/browser/view/notebook-cell-toolbar-factory.js.map +1 -1
  98. package/lib/browser/view/notebook-cell-toolbar.js.map +1 -1
  99. package/lib/browser/view/notebook-code-cell-view.d.ts +1 -0
  100. package/lib/browser/view/notebook-code-cell-view.d.ts.map +1 -1
  101. package/lib/browser/view/notebook-code-cell-view.js +26 -20
  102. package/lib/browser/view/notebook-code-cell-view.js.map +1 -1
  103. package/lib/browser/view/notebook-main-toolbar.d.ts +18 -2
  104. package/lib/browser/view/notebook-main-toolbar.d.ts.map +1 -1
  105. package/lib/browser/view/notebook-main-toolbar.js +75 -17
  106. package/lib/browser/view/notebook-main-toolbar.js.map +1 -1
  107. package/lib/browser/view/notebook-markdown-cell-view.d.ts +1 -0
  108. package/lib/browser/view/notebook-markdown-cell-view.d.ts.map +1 -1
  109. package/lib/browser/view/notebook-markdown-cell-view.js +14 -8
  110. package/lib/browser/view/notebook-markdown-cell-view.js.map +1 -1
  111. package/lib/browser/view/notebook-viewport-service.js +2 -2
  112. package/lib/browser/view/notebook-viewport-service.js.map +1 -1
  113. package/lib/browser/view-model/notebook-cell-model.d.ts +5 -4
  114. package/lib/browser/view-model/notebook-cell-model.d.ts.map +1 -1
  115. package/lib/browser/view-model/notebook-cell-model.js +19 -20
  116. package/lib/browser/view-model/notebook-cell-model.js.map +1 -1
  117. package/lib/browser/view-model/notebook-cell-output-model.js +7 -7
  118. package/lib/browser/view-model/notebook-cell-output-model.js.map +1 -1
  119. package/lib/browser/view-model/notebook-model.d.ts +16 -6
  120. package/lib/browser/view-model/notebook-model.d.ts.map +1 -1
  121. package/lib/browser/view-model/notebook-model.js +73 -66
  122. package/lib/browser/view-model/notebook-model.js.map +1 -1
  123. package/lib/common/index.js +2 -2
  124. package/lib/common/index.js.map +1 -1
  125. package/lib/common/notebook-common.d.ts +4 -4
  126. package/lib/common/notebook-common.d.ts.map +1 -1
  127. package/lib/common/notebook-common.js +8 -8
  128. package/lib/common/notebook-common.js.map +1 -1
  129. package/package.json +8 -8
  130. package/src/browser/contributions/notebook-actions-contribution.ts +34 -12
  131. package/src/browser/contributions/notebook-cell-actions-contribution.ts +20 -19
  132. package/src/browser/contributions/notebook-context-keys.ts +7 -0
  133. package/src/browser/contributions/notebook-label-provider-contribution.ts +30 -8
  134. package/src/browser/contributions/notebook-outline-contribution.ts +11 -9
  135. package/src/browser/notebook-editor-widget-factory.ts +2 -3
  136. package/src/browser/notebook-editor-widget.tsx +8 -0
  137. package/src/browser/notebook-frontend-module.ts +2 -1
  138. package/src/browser/service/notebook-context-manager.ts +6 -1
  139. package/src/browser/service/notebook-execution-service.ts +12 -0
  140. package/src/browser/service/notebook-model-resolver-service.ts +12 -18
  141. package/src/browser/service/notebook-monaco-text-model-service.ts +2 -2
  142. package/src/browser/service/notebook-service.ts +20 -17
  143. package/src/browser/style/index.css +10 -1
  144. package/src/browser/view/notebook-cell-editor.tsx +27 -6
  145. package/src/browser/view/notebook-cell-list-view.tsx +35 -9
  146. package/src/browser/view/notebook-code-cell-view.tsx +7 -0
  147. package/src/browser/view/notebook-main-toolbar.tsx +82 -7
  148. package/src/browser/view/notebook-markdown-cell-view.tsx +6 -0
  149. package/src/browser/view-model/notebook-cell-model.ts +8 -6
  150. package/src/browser/view-model/notebook-model.ts +60 -49
  151. package/src/common/notebook-common.ts +1 -1
@@ -24,8 +24,9 @@ import { NotebookKernelQuickPickService } from '../service/notebook-kernel-quick
24
24
  import { NotebookExecutionService } from '../service/notebook-execution-service';
25
25
  import { NotebookEditorWidget } from '../notebook-editor-widget';
26
26
  import { NotebookEditorWidgetService } from '../service/notebook-editor-widget-service';
27
- import { NOTEBOOK_CELL_FOCUSED, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_HAS_OUTPUTS } from './notebook-context-keys';
27
+ import { NOTEBOOK_CELL_CURSOR_FIRST_LINE, NOTEBOOK_CELL_CURSOR_LAST_LINE, NOTEBOOK_CELL_FOCUSED, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_HAS_OUTPUTS } from './notebook-context-keys';
28
28
  import { NotebookClipboardService } from '../service/notebook-clipboard-service';
29
+ import { ContextKeyService } from '@theia/core/lib/browser/context-key-service';
29
30
 
30
31
  export namespace NotebookCommands {
31
32
  export const ADD_NEW_CELL_COMMAND = Command.toDefaultLocalizedCommand({
@@ -69,17 +70,17 @@ export namespace NotebookCommands {
69
70
  });
70
71
 
71
72
  export const CUT_SELECTED_CELL = Command.toDefaultLocalizedCommand({
72
- id: 'notebook.cut-selected-cell',
73
+ id: 'notebook.cell.cut',
73
74
  category: 'Notebook',
74
75
  });
75
76
 
76
77
  export const COPY_SELECTED_CELL = Command.toDefaultLocalizedCommand({
77
- id: 'notebook.copy-selected-cell',
78
+ id: 'notebook.cell.copy',
78
79
  category: 'Notebook',
79
80
  });
80
81
 
81
82
  export const PASTE_CELL = Command.toDefaultLocalizedCommand({
82
- id: 'notebook.paste-cell',
83
+ id: 'notebook.cell.paste',
83
84
  category: 'Notebook',
84
85
  });
85
86
  }
@@ -110,22 +111,26 @@ export class NotebookActionsContribution implements CommandContribution, MenuCon
110
111
  @inject(NotebookClipboardService)
111
112
  protected notebookClipboardService: NotebookClipboardService;
112
113
 
114
+ @inject(ContextKeyService)
115
+ protected contextKeyService: ContextKeyService;
116
+
113
117
  registerCommands(commands: CommandRegistry): void {
114
118
  commands.registerCommand(NotebookCommands.ADD_NEW_CELL_COMMAND, {
115
119
  execute: (notebookModel: NotebookModel, cellKind: CellKind = CellKind.Markup, index?: number | 'above' | 'below') => {
116
120
  notebookModel = notebookModel ?? this.notebookEditorWidgetService.focusedEditor?.model;
117
121
 
118
122
  let insertIndex: number = 0;
119
- if (index && index >= 0) {
120
- insertIndex = index as number;
123
+ if (typeof index === 'number' && index >= 0) {
124
+ insertIndex = index;
121
125
  } else if (notebookModel.selectedCell && typeof index === 'string') {
122
126
  // if index is -1 insert below otherwise at the index of the selected cell which is above the selected.
123
127
  insertIndex = notebookModel.cells.indexOf(notebookModel.selectedCell) + (index === 'below' ? 1 : 0);
124
128
  }
125
129
 
126
- let firstCodeCell;
130
+ let cellLanguage: string = 'markdown';
127
131
  if (cellKind === CellKind.Code) {
128
- firstCodeCell = notebookModel.cells.find(cell => cell.cellKind === CellKind.Code);
132
+ const firstCodeCell = notebookModel.cells.find(cell => cell.cellKind === CellKind.Code);
133
+ cellLanguage = firstCodeCell?.language ?? 'plaintext';
129
134
  }
130
135
 
131
136
  notebookModel.applyEdits([{
@@ -134,7 +139,7 @@ export class NotebookActionsContribution implements CommandContribution, MenuCon
134
139
  count: 0,
135
140
  cells: [{
136
141
  cellKind,
137
- language: firstCodeCell?.language ?? 'markdown',
142
+ language: cellLanguage,
138
143
  source: '',
139
144
  outputs: [],
140
145
  metadata: {},
@@ -169,15 +174,29 @@ export class NotebookActionsContribution implements CommandContribution, MenuCon
169
174
  commands.registerCommand(NotebookCommands.CHANGE_SELECTED_CELL,
170
175
  {
171
176
  execute: (change: number | CellChangeDirection) => {
172
- const model = this.notebookEditorWidgetService.focusedEditor?.model;
177
+ const focusedEditor = this.notebookEditorWidgetService.focusedEditor;
178
+ const model = focusedEditor?.model;
173
179
  if (model && typeof change === 'number') {
174
180
  model.setSelectedCell(model.cells[change]);
175
181
  } else if (model && model.selectedCell) {
176
182
  const currentIndex = model.cells.indexOf(model.selectedCell);
183
+ const shouldFocusEditor = this.contextKeyService.match('editorTextFocus');
184
+
177
185
  if (change === CellChangeDirection.Up && currentIndex > 0) {
178
186
  model.setSelectedCell(model.cells[currentIndex - 1]);
187
+ if (model.selectedCell?.cellKind === CellKind.Code && shouldFocusEditor) {
188
+ model.selectedCell.requestFocusEditor('lastLine');
189
+ }
179
190
  } else if (change === CellChangeDirection.Down && currentIndex < model.cells.length - 1) {
180
191
  model.setSelectedCell(model.cells[currentIndex + 1]);
192
+ if (model.selectedCell?.cellKind === CellKind.Code && shouldFocusEditor) {
193
+ model.selectedCell.requestFocusEditor();
194
+ }
195
+ }
196
+
197
+ if (model.selectedCell.cellKind === CellKind.Markup) {
198
+ // since were losing focus from the cell editor, we need to focus the notebook editor again
199
+ focusedEditor?.node.focus();
181
200
  }
182
201
  }
183
202
  }
@@ -286,6 +305,8 @@ export class NotebookActionsContribution implements CommandContribution, MenuCon
286
305
  order: '30',
287
306
  when: NOTEBOOK_HAS_OUTPUTS
288
307
  });
308
+
309
+ menus.registerIndependentSubmenu(NotebookMenus.NOTEBOOK_MAIN_TOOLBAR_HIDDEN_ITEMS_CONTEXT_MENU, '');
289
310
  }
290
311
 
291
312
  registerKeybindings(keybindings: KeybindingRegistry): void {
@@ -294,13 +315,13 @@ export class NotebookActionsContribution implements CommandContribution, MenuCon
294
315
  command: NotebookCommands.CHANGE_SELECTED_CELL.id,
295
316
  keybinding: 'up',
296
317
  args: CellChangeDirection.Up,
297
- when: `!editorTextFocus && ${NOTEBOOK_EDITOR_FOCUSED} && ${NOTEBOOK_CELL_FOCUSED}`
318
+ when: `(!editorTextFocus || ${NOTEBOOK_CELL_CURSOR_FIRST_LINE}) && ${NOTEBOOK_EDITOR_FOCUSED} && ${NOTEBOOK_CELL_FOCUSED}`
298
319
  },
299
320
  {
300
321
  command: NotebookCommands.CHANGE_SELECTED_CELL.id,
301
322
  keybinding: 'down',
302
323
  args: CellChangeDirection.Down,
303
- when: `!editorTextFocus && ${NOTEBOOK_EDITOR_FOCUSED} && ${NOTEBOOK_CELL_FOCUSED}`
324
+ when: `(!editorTextFocus || ${NOTEBOOK_CELL_CURSOR_LAST_LINE}) && ${NOTEBOOK_EDITOR_FOCUSED} && ${NOTEBOOK_CELL_FOCUSED}`
304
325
  },
305
326
  {
306
327
  command: NotebookCommands.CUT_SELECTED_CELL.id,
@@ -326,4 +347,5 @@ export namespace NotebookMenus {
326
347
  export const NOTEBOOK_MAIN_TOOLBAR = 'notebook/toolbar';
327
348
  export const NOTEBOOK_MAIN_TOOLBAR_CELL_ADD_GROUP = [NOTEBOOK_MAIN_TOOLBAR, 'cell-add-group'];
328
349
  export const NOTEBOOK_MAIN_TOOLBAR_EXECUTION_GROUP = [NOTEBOOK_MAIN_TOOLBAR, 'cell-execution-group'];
350
+ export const NOTEBOOK_MAIN_TOOLBAR_HIDDEN_ITEMS_CONTEXT_MENU = 'notebook-main-toolbar-hidden-items-context-menu';
329
351
  }
@@ -120,24 +120,24 @@ export namespace NotebookCellCommands {
120
120
  label: 'Change Cell to Mardown'
121
121
  });
122
122
 
123
- export const COLLAPSE_CELL_OUTPUT = Command.toDefaultLocalizedCommand({
124
- id: 'notebook.cell.collapseCellOutput',
123
+ export const TOGGLE_CELL_OUTPUT = Command.toDefaultLocalizedCommand({
124
+ id: 'notebook.cell.toggleOutputs',
125
125
  category: 'Notebook',
126
126
  label: 'Collapse Cell Output',
127
127
  });
128
128
 
129
- export const EXPAND_CELL_OUTPUT = Command.toDefaultLocalizedCommand({
130
- id: 'notebook.cell.expandCellOutput',
131
- category: 'Notebook',
132
- label: 'Expand Cell Output',
133
- });
134
-
135
129
  export const CHANGE_CELL_LANGUAGE = Command.toDefaultLocalizedCommand({
136
130
  id: 'notebook.cell.changeLanguage',
137
131
  category: 'Notebook',
138
132
  label: 'Change Cell Language',
139
133
  });
140
134
 
135
+ export const TOGGLE_LINE_NUMBERS = Command.toDefaultLocalizedCommand({
136
+ id: 'notebook.cell.toggleLineNumbers',
137
+ category: 'Notebook',
138
+ label: 'Show Cell Line Numbers',
139
+ });
140
+
141
141
  }
142
142
 
143
143
  @injectable()
@@ -351,20 +351,11 @@ export class NotebookCellActionContribution implements MenuContribution, Command
351
351
  changeCellType(notebookModel, cell, CellKind.Markup);
352
352
  }));
353
353
 
354
- commands.registerCommand(NotebookCellCommands.COLLAPSE_CELL_OUTPUT, {
355
- execute: () => {
356
- const selectedCell = this.notebookEditorWidgetService.focusedEditor?.model?.selectedCell;
357
- if (selectedCell) {
358
- selectedCell.outputVisible = false;
359
- }
360
- }
361
- });
362
-
363
- commands.registerCommand(NotebookCellCommands.EXPAND_CELL_OUTPUT, {
354
+ commands.registerCommand(NotebookCellCommands.TOGGLE_CELL_OUTPUT, {
364
355
  execute: () => {
365
356
  const selectedCell = this.notebookEditorWidgetService.focusedEditor?.model?.selectedCell;
366
357
  if (selectedCell) {
367
- selectedCell.outputVisible = true;
358
+ selectedCell.outputVisible = !selectedCell.outputVisible;
368
359
  }
369
360
  }
370
361
  });
@@ -387,6 +378,16 @@ export class NotebookCellActionContribution implements MenuContribution, Command
387
378
  }
388
379
  });
389
380
 
381
+ commands.registerCommand(NotebookCellCommands.TOGGLE_LINE_NUMBERS, {
382
+ execute: () => {
383
+ const selectedCell = this.notebookEditorWidgetService.focusedEditor?.model?.selectedCell;
384
+ if (selectedCell) {
385
+ const currentLineNumber = selectedCell.editorOptions?.lineNumbers;
386
+ selectedCell.editorOptions = { ...selectedCell.editorOptions, lineNumbers: !currentLineNumber || currentLineNumber === 'off' ? 'on' : 'off' };
387
+ }
388
+ }
389
+ });
390
+
390
391
  }
391
392
 
392
393
  protected editableCellCommandHandler(execute: (notebookModel: NotebookModel, cell: NotebookCellModel, output?: NotebookCellOutputModel) => void): CommandHandler {
@@ -30,6 +30,7 @@ export const KEYBINDING_CONTEXT_NOTEBOOK_FIND_WIDGET_FOCUSED = 'notebookFindWidg
30
30
  export const NOTEBOOK_EDITOR_FOCUSED = 'notebookEditorFocused';
31
31
  export const NOTEBOOK_CELL_LIST_FOCUSED = 'notebookCellListFocused';
32
32
  export const NOTEBOOK_OUTPUT_FOCUSED = 'notebookOutputFocused';
33
+ export const NOTEBOOK_OUTPUT_INPUT_FOCUSED = 'notebookOutputInputFocused';
33
34
  export const NOTEBOOK_EDITOR_EDITABLE = 'notebookEditable';
34
35
  export const NOTEBOOK_HAS_RUNNING_CELL = 'notebookHasRunningCell';
35
36
  export const NOTEBOOK_USE_CONSOLIDATED_OUTPUT_BUTTON = 'notebookUseConsolidatedOutputButton';
@@ -58,6 +59,9 @@ export const NOTEBOOK_INTERRUPTIBLE_KERNEL = 'notebookInterruptibleKernel';
58
59
  export const NOTEBOOK_MISSING_KERNEL_EXTENSION = 'notebookMissingKernelExtension';
59
60
  export const NOTEBOOK_HAS_OUTPUTS = 'notebookHasOutputs';
60
61
 
62
+ export const NOTEBOOK_CELL_CURSOR_FIRST_LINE = 'cellEditorCursorPositionFirstLine';
63
+ export const NOTEBOOK_CELL_CURSOR_LAST_LINE = 'cellEditorCursorPositionLastLine';
64
+
61
65
  export namespace NotebookContextKeys {
62
66
  export function initNotebookContextKeys(service: ContextKeyService): void {
63
67
  service.createKey(HAS_OPENED_NOTEBOOK, false);
@@ -71,6 +75,7 @@ export namespace NotebookContextKeys {
71
75
  service.createKey(NOTEBOOK_EDITOR_FOCUSED, false);
72
76
  service.createKey(NOTEBOOK_CELL_LIST_FOCUSED, false);
73
77
  service.createKey(NOTEBOOK_OUTPUT_FOCUSED, false);
78
+ service.createKey(NOTEBOOK_OUTPUT_INPUT_FOCUSED, false);
74
79
  service.createKey(NOTEBOOK_EDITOR_EDITABLE, true);
75
80
  service.createKey(NOTEBOOK_HAS_RUNNING_CELL, false);
76
81
  service.createKey(NOTEBOOK_USE_CONSOLIDATED_OUTPUT_BUTTON, false);
@@ -93,6 +98,8 @@ export namespace NotebookContextKeys {
93
98
  service.createKey(NOTEBOOK_CELL_INPUT_COLLAPSED, false);
94
99
  service.createKey(NOTEBOOK_CELL_OUTPUT_COLLAPSED, false);
95
100
  service.createKey(NOTEBOOK_CELL_RESOURCE, '');
101
+ service.createKey(NOTEBOOK_CELL_CURSOR_FIRST_LINE, false);
102
+ service.createKey(NOTEBOOK_CELL_CURSOR_LAST_LINE, false);
96
103
 
97
104
  // Kernels
98
105
  service.createKey(NOTEBOOK_KERNEL, undefined);
@@ -16,11 +16,13 @@
16
16
 
17
17
  import { codicon, LabelProvider, LabelProviderContribution } from '@theia/core/lib/browser';
18
18
  import { inject, injectable } from '@theia/core/shared/inversify';
19
- import { CellKind } from '../../common';
19
+ import { CellKind, CellUri } from '../../common';
20
20
  import { NotebookService } from '../service/notebook-service';
21
21
  import { NotebookCellOutlineNode } from './notebook-outline-contribution';
22
22
  import type Token = require('markdown-it/lib/token');
23
23
  import markdownit = require('@theia/core/shared/markdown-it');
24
+ import { NotebookCellModel } from '../view-model/notebook-cell-model';
25
+ import { URI } from '@theia/core';
24
26
 
25
27
  @injectable()
26
28
  export class NotebookLabelProviderContribution implements LabelProviderContribution {
@@ -41,23 +43,43 @@ export class NotebookLabelProviderContribution implements LabelProviderContribut
41
43
  }
42
44
 
43
45
  getIcon(element: NotebookCellOutlineNode): string {
44
- return element.notebookCell.cellKind === CellKind.Markup ? codicon('markdown') : codicon('code');
46
+ const cell = this.findCellByUri(element.uri);
47
+ if (cell) {
48
+ return cell.cellKind === CellKind.Markup ? codicon('markdown') : codicon('code');
49
+ }
50
+ return '';
45
51
  }
46
52
 
47
53
  getName(element: NotebookCellOutlineNode): string {
48
- return element.notebookCell.cellKind === CellKind.Code ?
49
- element.notebookCell.text.split('\n')[0] :
50
- this.extractPlaintext(this.markdownIt.parse(element.notebookCell.text.split('\n')[0], {}));
54
+ const cell = this.findCellByUri(element.uri);
55
+ if (cell) {
56
+ return cell.cellKind === CellKind.Code ?
57
+ cell.text.split('\n')[0] :
58
+ this.extractPlaintext(this.markdownIt.parse(cell.text.split('\n')[0], {}));
59
+ }
60
+ return '';
51
61
  }
52
62
 
53
63
  getLongName(element: NotebookCellOutlineNode): string {
54
- return element.notebookCell.cellKind === CellKind.Code ?
55
- element.notebookCell.text.split('\n')[0] :
56
- this.extractPlaintext(this.markdownIt.parse(element.notebookCell.text.split('\n')[0], {}));
64
+ const cell = this.findCellByUri(element.uri);
65
+ if (cell) {
66
+ return cell.cellKind === CellKind.Code ?
67
+ cell.text.split('\n')[0] :
68
+ this.extractPlaintext(this.markdownIt.parse(cell.text.split('\n')[0], {}));
69
+ }
70
+ return '';
57
71
  }
58
72
 
59
73
  extractPlaintext(parsedMarkdown: Token[]): string {
60
74
  return parsedMarkdown.map(token => token.children ? this.extractPlaintext(token.children) : token.content).join('');
61
75
  }
62
76
 
77
+ findCellByUri(uri: URI): NotebookCellModel | undefined {
78
+ const parsed = CellUri.parse(uri);
79
+ if (parsed) {
80
+ return this.notebookService.getNotebookEditorModel(parsed.notebook)?.cells.find(cell => cell.handle === parsed?.handle);
81
+ }
82
+ return undefined;
83
+ }
84
+
63
85
  }
@@ -21,18 +21,20 @@ import { OutlineViewService } from '@theia/outline-view/lib/browser/outline-view
21
21
  import { NotebookModel } from '../view-model/notebook-model';
22
22
  import { OutlineSymbolInformationNode } from '@theia/outline-view/lib/browser/outline-view-widget';
23
23
  import { NotebookEditorWidget } from '../notebook-editor-widget';
24
- import { NotebookCellModel } from '../view-model/notebook-cell-model';
25
- import { DisposableCollection, URI } from '@theia/core';
24
+ import { DisposableCollection, isObject, URI } from '@theia/core';
26
25
  import { CellKind, CellUri } from '../../common';
27
26
  import { NotebookService } from '../service/notebook-service';
28
27
  export interface NotebookCellOutlineNode extends OutlineSymbolInformationNode {
29
- notebookCell: NotebookCellModel;
30
28
  uri: URI;
31
29
  }
32
30
 
33
31
  export namespace NotebookCellOutlineNode {
34
32
  export function is(element: object): element is NotebookCellOutlineNode {
35
- return TreeNode.is(element) && OutlineSymbolInformationNode.is(element) && 'notebookCell' in element;
33
+ return TreeNode.is(element)
34
+ && OutlineSymbolInformationNode.is(element)
35
+ && isObject<NotebookCellOutlineNode>(element)
36
+ && element.uri instanceof URI
37
+ && element.uri.scheme === CellUri.cellUriScheme;
36
38
  }
37
39
  }
38
40
 
@@ -94,17 +96,17 @@ export class NotebookOutlineContribution implements FrontendApplicationContribut
94
96
  children: [],
95
97
  selected: model.selectedCell === cell,
96
98
  expanded: false,
97
- notebookCell: cell,
98
- uri: model.uri,
99
+ uri: cell.uri,
99
100
  } as NotebookCellOutlineNode));
100
101
  }
101
102
 
102
103
  selectCell(node: object): void {
103
104
  if (NotebookCellOutlineNode.is(node)) {
104
- const parsed = CellUri.parse(node.notebookCell.uri);
105
+ const parsed = CellUri.parse(node.uri);
105
106
  const model = parsed && this.notebookService.getNotebookEditorModel(parsed.notebook);
106
- if (model) {
107
- model.setSelectedCell(node.notebookCell);
107
+ const cell = model?.cells.find(c => c.handle === parsed?.handle);
108
+ if (model && cell) {
109
+ model.setSelectedCell(cell);
108
110
  }
109
111
  }
110
112
  }
@@ -61,8 +61,7 @@ export class NotebookEditorWidgetFactory implements WidgetFactory {
61
61
  return editor;
62
62
  }
63
63
 
64
- private async createEditor(uri: URI, notebookType: string): Promise<NotebookEditorWidget> {
65
-
64
+ protected async createEditor(uri: URI, notebookType: string): Promise<NotebookEditorWidget> {
66
65
  return this.createNotebookEditorWidget({
67
66
  uri,
68
67
  notebookType,
@@ -70,7 +69,7 @@ export class NotebookEditorWidgetFactory implements WidgetFactory {
70
69
  });
71
70
  }
72
71
 
73
- private setLabels(editor: NotebookEditorWidget, uri: URI): void {
72
+ protected setLabels(editor: NotebookEditorWidget, uri: URI): void {
74
73
  editor.title.caption = uri.path.fsPath();
75
74
  if (editor.model?.readOnly) {
76
75
  editor.title.caption += ` • ${nls.localizeByDefault('Read-only')}`;
@@ -120,6 +120,9 @@ export class NotebookEditorWidget extends ReactWidget implements Navigatable, Sa
120
120
  protected readonly onDidReceiveKernelMessageEmitter = new Emitter<unknown>();
121
121
  readonly onDidReceiveKernelMessage = this.onDidReceiveKernelMessageEmitter.event;
122
122
 
123
+ protected readonly onDidChangeOutputInputFocusEmitter = new Emitter<boolean>();
124
+ readonly onDidChangeOutputInputFocus = this.onDidChangeOutputInputFocusEmitter.event;
125
+
123
126
  protected readonly renderers = new Map<CellKind, CellRenderer>();
124
127
  protected _model?: NotebookModel;
125
128
  protected _ready: Deferred<NotebookModel> = new Deferred();
@@ -251,12 +254,17 @@ export class NotebookEditorWidget extends ReactWidget implements Navigatable, Sa
251
254
  this.onDidReceiveKernelMessageEmitter.fire(message);
252
255
  }
253
256
 
257
+ outputInputFocusChanged(focused: boolean): void {
258
+ this.onDidChangeOutputInputFocusEmitter.fire(focused);
259
+ }
260
+
254
261
  override dispose(): void {
255
262
  this.notebookContextManager.dispose();
256
263
  this.onDidChangeModelEmitter.dispose();
257
264
  this.onDidPostKernelMessageEmitter.dispose();
258
265
  this.onDidReceiveKernelMessageEmitter.dispose();
259
266
  this.onPostRendererMessageEmitter.dispose();
267
+ this.onDidChangeOutputInputFocusEmitter.dispose();
260
268
  this.viewportService.dispose();
261
269
  this._model?.dispose();
262
270
  super.dispose();
@@ -27,7 +27,7 @@ import { NotebookEditorWidgetFactory } from './notebook-editor-widget-factory';
27
27
  import { NotebookCellResourceResolver, NotebookOutputResourceResolver } from './notebook-cell-resource-resolver';
28
28
  import { NotebookModelResolverService } from './service/notebook-model-resolver-service';
29
29
  import { NotebookCellActionContribution } from './contributions/notebook-cell-actions-contribution';
30
- import { createNotebookModelContainer, NotebookModel, NotebookModelFactory, NotebookModelProps } from './view-model/notebook-model';
30
+ import { createNotebookModelContainer, NotebookModel, NotebookModelFactory, NotebookModelProps, NotebookModelResolverServiceProxy } from './view-model/notebook-model';
31
31
  import { createNotebookCellModelContainer, NotebookCellModel, NotebookCellModelFactory, NotebookCellModelProps } from './view-model/notebook-cell-model';
32
32
  import { createNotebookEditorWidgetContainer, NotebookEditorWidgetContainerFactory, NotebookEditorProps, NotebookEditorWidget } from './notebook-editor-widget';
33
33
  import { NotebookActionsContribution } from './contributions/notebook-actions-contribution';
@@ -71,6 +71,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
71
71
  bind(NotebookCellResourceResolver).toSelf().inSingletonScope();
72
72
  bind(ResourceResolver).toService(NotebookCellResourceResolver);
73
73
  bind(NotebookModelResolverService).toSelf().inSingletonScope();
74
+ bind(NotebookModelResolverServiceProxy).toService(NotebookModelResolverService);
74
75
  bind(NotebookOutputResourceResolver).toSelf().inSingletonScope();
75
76
  bind(ResourceResolver).toService(NotebookOutputResourceResolver);
76
77
 
@@ -23,6 +23,7 @@ import {
23
23
  NOTEBOOK_CELL_EXECUTING, NOTEBOOK_CELL_EXECUTION_STATE,
24
24
  NOTEBOOK_CELL_FOCUSED, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE,
25
25
  NOTEBOOK_CELL_TYPE, NOTEBOOK_HAS_OUTPUTS, NOTEBOOK_KERNEL, NOTEBOOK_KERNEL_SELECTED,
26
+ NOTEBOOK_OUTPUT_INPUT_FOCUSED,
26
27
  NOTEBOOK_VIEW_TYPE
27
28
  } from '../contributions/notebook-context-keys';
28
29
  import { NotebookEditorWidget } from '../notebook-editor-widget';
@@ -87,6 +88,7 @@ export class NotebookContextManager {
87
88
  // Cell Selection realted keys
88
89
  this.scopedStore.setContext(NOTEBOOK_CELL_FOCUSED, !!widget.model?.selectedCell);
89
90
  widget.model?.onDidChangeSelectedCell(e => {
91
+ this.selectedCellChanged(e.cell);
90
92
  this.scopedStore.setContext(NOTEBOOK_CELL_FOCUSED, !!e);
91
93
  this.onDidChangeContextEmitter.fire(this.createContextKeyChangedEvent([NOTEBOOK_CELL_FOCUSED]));
92
94
  });
@@ -99,7 +101,10 @@ export class NotebookContextManager {
99
101
  }
100
102
  }));
101
103
 
102
- widget.model?.onDidChangeSelectedCell(e => this.selectedCellChanged(e));
104
+ widget.onDidChangeOutputInputFocus(focus => {
105
+ this.scopedStore.setContext(NOTEBOOK_OUTPUT_INPUT_FOCUSED, focus);
106
+ this.onDidChangeContextEmitter.fire(this.createContextKeyChangedEvent([NOTEBOOK_OUTPUT_INPUT_FOCUSED]));
107
+ });
103
108
 
104
109
  this.onDidChangeContextEmitter.fire(this.createContextKeyChangedEvent([NOTEBOOK_VIEW_TYPE, NOTEBOOK_KERNEL_SELECTED, NOTEBOOK_KERNEL]));
105
110
  }
@@ -88,6 +88,15 @@ export class NotebookExecutionService {
88
88
 
89
89
  // request execution
90
90
  if (validCellExecutions.length > 0) {
91
+ const cellRemoveListener = notebook.onDidAddOrRemoveCell(e => {
92
+ if (e.rawEvent.changes.some(c => c.deleteCount > 0)) {
93
+ const executionsToCancel = validCellExecutions.filter(exec => !notebook.cells.find(cell => cell.handle === exec.cellHandle));
94
+ if (executionsToCancel.length > 0) {
95
+ kernel.cancelNotebookCellExecution(notebook.uri, executionsToCancel.map(c => c.cellHandle));
96
+ executionsToCancel.forEach(exec => exec.complete({}));
97
+ }
98
+ }
99
+ });
91
100
  await this.runExecutionParticipants(validCellExecutions);
92
101
 
93
102
  this.notebookKernelService.selectKernelForNotebook(kernel, notebook);
@@ -97,6 +106,9 @@ export class NotebookExecutionService {
97
106
  if (unconfirmed.length) {
98
107
  unconfirmed.forEach(exe => exe.complete({}));
99
108
  }
109
+
110
+ cellRemoveListener.dispose();
111
+
100
112
  }
101
113
  }
102
114
 
@@ -14,11 +14,11 @@
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, Resource, ResourceProvider, URI } from '@theia/core';
17
+ import { Emitter, Resource, ResourceProvider, UNTITLED_SCHEME, 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';
21
- import { CellKind, NotebookData } from '../../common';
21
+ import { NotebookData } from '../../common';
22
22
  import { NotebookModel } from '../view-model/notebook-model';
23
23
  import { NotebookService } from './notebook-service';
24
24
  import { NotebookTypeRegistry } from '../notebook-type-registry';
@@ -28,6 +28,7 @@ import { match } from '@theia/core/lib/common/glob';
28
28
  export interface UntitledResource {
29
29
  untitledResource: URI | undefined
30
30
  }
31
+
31
32
  @injectable()
32
33
  export class NotebookModelResolverService {
33
34
 
@@ -49,14 +50,15 @@ export class NotebookModelResolverService {
49
50
  readonly onDidSaveNotebook = this.onDidSaveNotebookEmitter.event;
50
51
 
51
52
  async resolve(resource: URI, viewType?: string): Promise<NotebookModel> {
52
-
53
+ const existingModel = this.notebookService.getNotebookEditorModel(resource);
53
54
  if (!viewType) {
54
- const existingViewType = this.notebookService.getNotebookEditorModel(resource)?.viewType;
55
- if (existingViewType) {
56
- viewType = existingViewType;
55
+ if (existingModel) {
56
+ return existingModel;
57
57
  } else {
58
58
  viewType = this.findViewTypeForResource(resource);
59
59
  }
60
+ } else if (existingModel?.viewType === viewType) {
61
+ return existingModel;
60
62
  }
61
63
 
62
64
  if (!viewType) {
@@ -86,7 +88,7 @@ export class NotebookModelResolverService {
86
88
  const suffix = this.getPossibleFileEnding(notebookTypeInfo.selector ?? []) ?? '';
87
89
  for (let counter = 1; ; counter++) {
88
90
  const candidate = new URI()
89
- .withScheme('untitled')
91
+ .withScheme(UNTITLED_SCHEME)
90
92
  .withPath(`Untitled-notebook-${counter}${suffix}`)
91
93
  .withQuery(viewType);
92
94
  if (!this.notebookService.getNotebookEditorModel(candidate)) {
@@ -94,7 +96,7 @@ export class NotebookModelResolverService {
94
96
  break;
95
97
  }
96
98
  }
97
- } else if (arg.untitledResource.scheme === 'untitled') {
99
+ } else if (arg.untitledResource.scheme === UNTITLED_SCHEME) {
98
100
  resource = arg.untitledResource;
99
101
  } else {
100
102
  throw new Error('Invalid untitled resource: ' + arg.untitledResource.toString() + ' untitled resources with associated file path are not supported yet');
@@ -106,18 +108,10 @@ export class NotebookModelResolverService {
106
108
  return this.resolve(resource, viewType);
107
109
  }
108
110
 
109
- protected async resolveExistingNotebookData(resource: Resource, viewType: string): Promise<NotebookData> {
111
+ async resolveExistingNotebookData(resource: Resource, viewType: string): Promise<NotebookData> {
110
112
  if (resource.uri.scheme === 'untitled') {
111
-
112
113
  return {
113
- cells: [
114
- {
115
- cellKind: CellKind.Markup,
116
- language: 'markdown',
117
- outputs: [],
118
- source: ''
119
- }
120
- ],
114
+ cells: [],
121
115
  metadata: {}
122
116
  };
123
117
  } else {
@@ -31,7 +31,7 @@ export class NotebookMonacoTextModelService {
31
31
  protected readonly monacoTextModelService: MonacoTextModelService;
32
32
 
33
33
  protected readonly cellmodels = new ReferenceCollection<string, MonacoEditorModel>(
34
- uri => this.monacoTextModelService.createUnmangedModel(new URI(uri))
34
+ uri => this.monacoTextModelService.createUnmanagedModel(new URI(uri))
35
35
  );
36
36
 
37
37
  getOrCreateNotebookCellModelReference(uri: URI): Promise<Reference<MonacoEditorModel>> {
@@ -39,7 +39,7 @@ export class NotebookMonacoTextModelService {
39
39
  }
40
40
 
41
41
  async createTextModelsForNotebook(notebook: NotebookModel): Promise<void> {
42
- await Promise.all(notebook.cells.map(cell => this.getOrCreateNotebookCellModelReference(cell.uri)));
42
+ await Promise.all(notebook.cells.map(cell => cell.resolveTextModel()));
43
43
  }
44
44
 
45
45
  get onDidCreateNotebookCellModel(): Event<MonacoEditorModel> {
@@ -110,16 +110,13 @@ export class NotebookService implements Disposable {
110
110
  }
111
111
 
112
112
  async createNotebookModel(data: NotebookData, viewType: string, resource: Resource): Promise<NotebookModel> {
113
- const serializer = this.notebookProviders.get(viewType)?.serializer;
114
- if (!serializer) {
115
- throw new Error('no notebook serializer for ' + viewType);
116
- }
117
-
113
+ const dataProvider = await this.getNotebookDataProvider(viewType);
114
+ const serializer = dataProvider.serializer;
118
115
  const model = this.notebookModelFactory({ data, resource, viewType, serializer });
119
116
  this.notebookModels.set(resource.uri.toString(), model);
120
117
  // Resolve cell text models right after creating the notebook model
121
118
  // This ensures that all text models are available in the plugin host
122
- this.textModelService.createTextModelsForNotebook(model);
119
+ await this.textModelService.createTextModelsForNotebook(model);
123
120
  this.didAddNotebookDocumentEmitter.fire(model);
124
121
  model.onDidDispose(() => {
125
122
  this.notebookModels.delete(resource.uri.toString());
@@ -129,13 +126,11 @@ export class NotebookService implements Disposable {
129
126
  }
130
127
 
131
128
  async getNotebookDataProvider(viewType: string): Promise<NotebookProviderInfo> {
132
- await this.ready.promise;
133
-
134
- const result = await this.waitForNotebookProvider(viewType);
135
- if (!result) {
129
+ try {
130
+ return await this.waitForNotebookProvider(viewType);
131
+ } catch {
136
132
  throw new Error(`No provider registered for view type: '${viewType}'`);
137
133
  }
138
- return result;
139
134
  }
140
135
 
141
136
  /**
@@ -143,11 +138,12 @@ export class NotebookService implements Disposable {
143
138
  * It takes a few seconds for the plugin host to start so that notebook data providers can be registered.
144
139
  * This methods waits until the notebook provider is registered.
145
140
  */
146
- protected async waitForNotebookProvider(type: string): Promise<NotebookProviderInfo | undefined> {
147
- if (this.notebookProviders.has(type)) {
148
- return this.notebookProviders.get(type);
141
+ protected waitForNotebookProvider(type: string): Promise<NotebookProviderInfo> {
142
+ const existing = this.notebookProviders.get(type);
143
+ if (existing) {
144
+ return Promise.resolve(existing);
149
145
  }
150
- const deferred = new Deferred<NotebookProviderInfo | undefined>();
146
+ const deferred = new Deferred<NotebookProviderInfo>();
151
147
  // 20 seconds of timeout
152
148
  const timeoutDuration = 20_000;
153
149
 
@@ -161,7 +157,12 @@ export class NotebookService implements Disposable {
161
157
  if (viewType === type) {
162
158
  clearTimeout(timeout);
163
159
  disposable.dispose();
164
- deferred.resolve(this.notebookProviders.get(type));
160
+ const newProvider = this.notebookProviders.get(type);
161
+ if (!newProvider) {
162
+ deferred.reject(new Error(`Notebook provider for type ${type} is invalid`));
163
+ } else {
164
+ deferred.resolve(newProvider);
165
+ }
165
166
  }
166
167
  });
167
168
  timeout = setTimeout(() => {
@@ -170,7 +171,9 @@ export class NotebookService implements Disposable {
170
171
  deferred.reject(new Error(`Timed out while waiting for notebook serializer for type ${type} to be registered`));
171
172
  }, timeoutDuration);
172
173
 
173
- await Promise.all(this.willUseNotebookSerializerEmitter.fire(type));
174
+ this.ready.promise.then(() => {
175
+ this.willUseNotebookSerializerEmitter.fire(type);
176
+ });
174
177
 
175
178
  return deferred.promise;
176
179
  }