@theia/notebook 1.53.2 → 1.55.0-next.14

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 (84) hide show
  1. package/lib/browser/contributions/notebook-actions-contribution.d.ts.map +1 -1
  2. package/lib/browser/contributions/notebook-actions-contribution.js +5 -2
  3. package/lib/browser/contributions/notebook-actions-contribution.js.map +1 -1
  4. package/lib/browser/contributions/notebook-cell-actions-contribution.d.ts.map +1 -1
  5. package/lib/browser/contributions/notebook-cell-actions-contribution.js +10 -6
  6. package/lib/browser/contributions/notebook-cell-actions-contribution.js.map +1 -1
  7. package/lib/browser/contributions/notebook-status-bar-contribution.d.ts +7 -9
  8. package/lib/browser/contributions/notebook-status-bar-contribution.d.ts.map +1 -1
  9. package/lib/browser/contributions/notebook-status-bar-contribution.js +21 -33
  10. package/lib/browser/contributions/notebook-status-bar-contribution.js.map +1 -1
  11. package/lib/browser/index.d.ts +1 -0
  12. package/lib/browser/index.d.ts.map +1 -1
  13. package/lib/browser/index.js +1 -0
  14. package/lib/browser/index.js.map +1 -1
  15. package/lib/browser/notebook-editor-widget.d.ts +4 -0
  16. package/lib/browser/notebook-editor-widget.d.ts.map +1 -1
  17. package/lib/browser/notebook-editor-widget.js +27 -4
  18. package/lib/browser/notebook-editor-widget.js.map +1 -1
  19. package/lib/browser/notebook-frontend-module.d.ts.map +1 -1
  20. package/lib/browser/notebook-frontend-module.js +3 -1
  21. package/lib/browser/notebook-frontend-module.js.map +1 -1
  22. package/lib/browser/notebook-open-handler.d.ts +3 -2
  23. package/lib/browser/notebook-open-handler.d.ts.map +1 -1
  24. package/lib/browser/notebook-open-handler.js +12 -5
  25. package/lib/browser/notebook-open-handler.js.map +1 -1
  26. package/lib/browser/renderers/cell-output-webview.d.ts +17 -3
  27. package/lib/browser/renderers/cell-output-webview.d.ts.map +1 -1
  28. package/lib/browser/renderers/cell-output-webview.js +2 -1
  29. package/lib/browser/renderers/cell-output-webview.js.map +1 -1
  30. package/lib/browser/service/notebook-cell-editor-service.d.ts +19 -0
  31. package/lib/browser/service/notebook-cell-editor-service.d.ts.map +1 -0
  32. package/lib/browser/service/notebook-cell-editor-service.js +77 -0
  33. package/lib/browser/service/notebook-cell-editor-service.js.map +1 -0
  34. package/lib/browser/service/notebook-editor-widget-service.d.ts +4 -0
  35. package/lib/browser/service/notebook-editor-widget-service.d.ts.map +1 -1
  36. package/lib/browser/service/notebook-editor-widget-service.js +19 -0
  37. package/lib/browser/service/notebook-editor-widget-service.js.map +1 -1
  38. package/lib/browser/view/notebook-cell-editor.d.ts +2 -0
  39. package/lib/browser/view/notebook-cell-editor.d.ts.map +1 -1
  40. package/lib/browser/view/notebook-cell-editor.js +12 -1
  41. package/lib/browser/view/notebook-cell-editor.js.map +1 -1
  42. package/lib/browser/view/notebook-cell-list-view.d.ts +4 -1
  43. package/lib/browser/view/notebook-cell-list-view.d.ts.map +1 -1
  44. package/lib/browser/view/notebook-cell-list-view.js +36 -13
  45. package/lib/browser/view/notebook-cell-list-view.js.map +1 -1
  46. package/lib/browser/view/notebook-code-cell-view.d.ts +19 -9
  47. package/lib/browser/view/notebook-code-cell-view.d.ts.map +1 -1
  48. package/lib/browser/view/notebook-code-cell-view.js +58 -70
  49. package/lib/browser/view/notebook-code-cell-view.js.map +1 -1
  50. package/lib/browser/view/notebook-markdown-cell-view.d.ts +3 -0
  51. package/lib/browser/view/notebook-markdown-cell-view.d.ts.map +1 -1
  52. package/lib/browser/view/notebook-markdown-cell-view.js +17 -5
  53. package/lib/browser/view/notebook-markdown-cell-view.js.map +1 -1
  54. package/lib/browser/view-model/notebook-cell-model.d.ts +5 -0
  55. package/lib/browser/view-model/notebook-cell-model.d.ts.map +1 -1
  56. package/lib/browser/view-model/notebook-cell-model.js +10 -0
  57. package/lib/browser/view-model/notebook-cell-model.js.map +1 -1
  58. package/lib/browser/view-model/notebook-cell-output-model.d.ts +0 -3
  59. package/lib/browser/view-model/notebook-cell-output-model.d.ts.map +1 -1
  60. package/lib/browser/view-model/notebook-cell-output-model.js +0 -6
  61. package/lib/browser/view-model/notebook-cell-output-model.js.map +1 -1
  62. package/lib/browser/view-model/notebook-model.d.ts +2 -1
  63. package/lib/browser/view-model/notebook-model.d.ts.map +1 -1
  64. package/lib/browser/view-model/notebook-model.js +3 -0
  65. package/lib/browser/view-model/notebook-model.js.map +1 -1
  66. package/package.json +8 -8
  67. package/src/browser/contributions/notebook-actions-contribution.ts +4 -1
  68. package/src/browser/contributions/notebook-cell-actions-contribution.ts +10 -7
  69. package/src/browser/contributions/notebook-status-bar-contribution.ts +23 -34
  70. package/src/browser/index.ts +1 -0
  71. package/src/browser/notebook-editor-widget.tsx +35 -10
  72. package/src/browser/notebook-frontend-module.ts +6 -2
  73. package/src/browser/notebook-open-handler.ts +13 -7
  74. package/src/browser/renderers/cell-output-webview.ts +21 -3
  75. package/src/browser/service/notebook-cell-editor-service.ts +74 -0
  76. package/src/browser/service/notebook-editor-widget-service.ts +20 -0
  77. package/src/browser/style/index.css +41 -10
  78. package/src/browser/view/notebook-cell-editor.tsx +18 -5
  79. package/src/browser/view/notebook-cell-list-view.tsx +44 -13
  80. package/src/browser/view/notebook-code-cell-view.tsx +82 -87
  81. package/src/browser/view/notebook-markdown-cell-view.tsx +19 -5
  82. package/src/browser/view-model/notebook-cell-model.ts +13 -0
  83. package/src/browser/view-model/notebook-cell-output-model.ts +0 -8
  84. package/src/browser/view-model/notebook-model.ts +5 -1
@@ -18,7 +18,7 @@ import * as React from '@theia/core/shared/react';
18
18
  import { CommandRegistry, MenuModelRegistry, URI } from '@theia/core';
19
19
  import { ReactWidget, Navigatable, SaveableSource, Message, DelegatingSaveable, lock, unlock, animationFrame } from '@theia/core/lib/browser';
20
20
  import { ReactNode } from '@theia/core/shared/react';
21
- import { CellKind } from '../common';
21
+ import { CellKind, NotebookCellsChangeType } from '../common';
22
22
  import { CellRenderer as CellRenderer, NotebookCellListView } from './view/notebook-cell-list-view';
23
23
  import { NotebookCodeCellRenderer } from './view/notebook-code-cell-view';
24
24
  import { NotebookMarkdownCellRenderer } from './view/notebook-markdown-cell-view';
@@ -35,6 +35,8 @@ import { NotebookViewportService } from './view/notebook-viewport-service';
35
35
  import { NotebookCellCommands } from './contributions/notebook-cell-actions-contribution';
36
36
  import { NotebookFindWidget } from './view/notebook-find-widget';
37
37
  import debounce = require('lodash/debounce');
38
+ import { CellOutputWebview, CellOutputWebviewFactory } from './renderers/cell-output-webview';
39
+ import { NotebookCellOutputModel } from './view-model/notebook-cell-output-model';
38
40
  const PerfectScrollbar = require('react-perfect-scrollbar');
39
41
 
40
42
  export const NotebookEditorWidgetContainerFactory = Symbol('NotebookEditorWidgetContainerFactory');
@@ -44,6 +46,9 @@ export function createNotebookEditorWidgetContainer(parent: interfaces.Container
44
46
 
45
47
  child.bind(NotebookEditorProps).toConstantValue(props);
46
48
 
49
+ const cellOutputWebviewFactory: CellOutputWebviewFactory = parent.get(CellOutputWebviewFactory);
50
+ child.bind(CellOutputWebview).toConstantValue(cellOutputWebviewFactory());
51
+
47
52
  child.bind(NotebookContextManager).toSelf().inSingletonScope();
48
53
  child.bind(NotebookMainToolbarRenderer).toSelf().inSingletonScope();
49
54
  child.bind(NotebookCellToolbarFactory).toSelf().inSingletonScope();
@@ -104,6 +109,9 @@ export class NotebookEditorWidget extends ReactWidget implements Navigatable, Sa
104
109
  @inject(NotebookViewportService)
105
110
  protected readonly viewportService: NotebookViewportService;
106
111
 
112
+ @inject(CellOutputWebview)
113
+ protected readonly cellOutputWebview: CellOutputWebview;
114
+
107
115
  protected readonly onDidChangeModelEmitter = new Emitter<void>();
108
116
  readonly onDidChangeModel = this.onDidChangeModelEmitter.event;
109
117
 
@@ -173,11 +181,18 @@ export class NotebookEditorWidget extends ReactWidget implements Navigatable, Sa
173
181
  this.commandRegistry.executeCommand(NotebookCellCommands.EDIT_COMMAND.id, model, model.cells[0]);
174
182
  model.setSelectedCell(model.cells[0]);
175
183
  }
184
+ model.onDidChangeContent(changeEvents => {
185
+ const cellEvent = changeEvents.filter(event => event.kind === NotebookCellsChangeType.Move || event.kind === NotebookCellsChangeType.ModelChange);
186
+ if (cellEvent.length > 0) {
187
+ this.cellOutputWebview.cellsChanged(cellEvent);
188
+ }
189
+ });
176
190
  });
177
191
  }
178
192
 
179
193
  protected async waitForData(): Promise<NotebookModel> {
180
194
  this._model = await this.props.notebookData;
195
+ this.cellOutputWebview.init(this._model, this);
181
196
  this.saveable.delegate = this._model;
182
197
  this.toDispose.push(this._model);
183
198
  this.toDispose.push(this._model.onDidChangeContent(() => {
@@ -212,7 +227,7 @@ export class NotebookEditorWidget extends ReactWidget implements Navigatable, Sa
212
227
 
213
228
  protected override onActivateRequest(msg: Message): void {
214
229
  super.onActivateRequest(msg);
215
- this.node.focus();
230
+ (this.node.getElementsByClassName('theia-notebook-main-container')[0] as HTMLDivElement)?.focus();
216
231
  }
217
232
 
218
233
  getResourceUri(): URI | undefined {
@@ -233,7 +248,7 @@ export class NotebookEditorWidget extends ReactWidget implements Navigatable, Sa
233
248
 
234
249
  protected render(): ReactNode {
235
250
  if (this._model) {
236
- return <div className='theia-notebook-main-container'>
251
+ return <div className='theia-notebook-main-container' tabIndex={-1}>
237
252
  <div className='theia-notebook-overlay'>
238
253
  <NotebookFindWidget
239
254
  ref={this._findWidgetRef}
@@ -261,17 +276,20 @@ export class NotebookEditorWidget extends ReactWidget implements Navigatable, Sa
261
276
  <PerfectScrollbar className='theia-notebook-scroll-container'
262
277
  ref={this.scrollBarRef}
263
278
  onScrollY={(e: HTMLDivElement) => this.viewportService.onScroll(e)}>
264
- <NotebookCellListView renderers={this.renderers}
265
- notebookModel={this._model}
266
- notebookContext={this.notebookContextManager}
267
- toolbarRenderer={this.cellToolbarFactory}
268
- commandRegistry={this.commandRegistry}
269
- menuRegistry={this.menuRegistry} />
279
+ <div className='theia-notebook-scroll-area'>
280
+ {this.cellOutputWebview.render()}
281
+ <NotebookCellListView renderers={this.renderers}
282
+ notebookModel={this._model}
283
+ notebookContext={this.notebookContextManager}
284
+ toolbarRenderer={this.cellToolbarFactory}
285
+ commandRegistry={this.commandRegistry}
286
+ menuRegistry={this.menuRegistry} />
287
+ </div>
270
288
  </PerfectScrollbar>
271
289
  </div>
272
290
  </div>;
273
291
  } else {
274
- return <div className='theia-notebook-main-container'>
292
+ return <div className='theia-notebook-main-container' tabIndex={-1}>
275
293
  <div className='theia-notebook-main-loading-indicator'></div>
276
294
  </div>;
277
295
  }
@@ -282,6 +300,12 @@ export class NotebookEditorWidget extends ReactWidget implements Navigatable, Sa
282
300
  this.notebookEditorService.removeNotebookEditor(this);
283
301
  }
284
302
 
303
+ requestOuputPresentationChange(cellHandle: number, output?: NotebookCellOutputModel): void {
304
+ if (output) {
305
+ this.cellOutputWebview.requestOutputPresentationUpdate(cellHandle, output);
306
+ }
307
+ }
308
+
285
309
  postKernelMessage(message: unknown): void {
286
310
  this.onDidPostKernelMessageEmitter.fire(message);
287
311
  }
@@ -307,6 +331,7 @@ export class NotebookEditorWidget extends ReactWidget implements Navigatable, Sa
307
331
  }
308
332
 
309
333
  override dispose(): void {
334
+ this.cellOutputWebview.dispose();
310
335
  this.notebookContextManager.dispose();
311
336
  this.onDidChangeModelEmitter.dispose();
312
337
  this.onDidPostKernelMessageEmitter.dispose();
@@ -16,7 +16,9 @@
16
16
  import '../../src/browser/style/index.css';
17
17
 
18
18
  import { ContainerModule } from '@theia/core/shared/inversify';
19
- import { FrontendApplicationContribution, KeybindingContribution, LabelProviderContribution, OpenHandler, UndoRedoHandler, WidgetFactory } from '@theia/core/lib/browser';
19
+ import {
20
+ FrontendApplicationContribution, KeybindingContribution, LabelProviderContribution, OpenHandler, UndoRedoHandler, WidgetFactory, WidgetStatusBarContribution
21
+ } from '@theia/core/lib/browser';
20
22
  import { ColorContribution } from '@theia/core/lib/browser/color-application-contribution';
21
23
  import { NotebookOpenHandler } from './notebook-open-handler';
22
24
  import { CommandContribution, MenuContribution, ResourceResolver, } from '@theia/core';
@@ -48,6 +50,7 @@ import { bindNotebookPreferences } from './contributions/notebook-preferences';
48
50
  import { NotebookOptionsService } from './service/notebook-options';
49
51
  import { NotebookUndoRedoHandler } from './contributions/notebook-undo-redo-handler';
50
52
  import { NotebookStatusBarContribution } from './contributions/notebook-status-bar-contribution';
53
+ import { NotebookCellEditorService } from './service/notebook-cell-editor-service';
51
54
 
52
55
  export default new ContainerModule((bind, unbind, isBound, rebind) => {
53
56
  bind(NotebookColorContribution).toSelf().inSingletonScope();
@@ -70,6 +73,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
70
73
  bind(NotebookKernelHistoryService).toSelf().inSingletonScope();
71
74
  bind(NotebookKernelQuickPickService).toSelf().inSingletonScope();
72
75
  bind(NotebookClipboardService).toSelf().inSingletonScope();
76
+ bind(NotebookCellEditorService).toSelf().inSingletonScope();
73
77
 
74
78
  bind(NotebookCellResourceResolver).toSelf().inSingletonScope();
75
79
  bind(ResourceResolver).toService(NotebookCellResourceResolver);
@@ -115,5 +119,5 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
115
119
  bind(UndoRedoHandler).toService(NotebookUndoRedoHandler);
116
120
 
117
121
  bind(NotebookStatusBarContribution).toSelf().inSingletonScope();
118
- bind(FrontendApplicationContribution).toService(NotebookStatusBarContribution);
122
+ bind(WidgetStatusBarContribution).toService(NotebookStatusBarContribution);
119
123
  });
@@ -15,8 +15,8 @@
15
15
  // *****************************************************************************
16
16
 
17
17
  import { URI, MaybePromise, Disposable } from '@theia/core';
18
- import { NavigatableWidgetOpenHandler, WidgetOpenerOptions } from '@theia/core/lib/browser';
19
- import { injectable } from '@theia/core/shared/inversify';
18
+ import { NavigatableWidgetOpenHandler, PreferenceService, WidgetOpenerOptions, getDefaultHandler, defaultHandlerPriority } from '@theia/core/lib/browser';
19
+ import { inject, injectable } from '@theia/core/shared/inversify';
20
20
  import { NotebookFileSelector, NotebookTypeDescriptor } from '../common/notebook-protocol';
21
21
  import { NotebookEditorWidget } from './notebook-editor-widget';
22
22
  import { match } from '@theia/core/lib/common/glob';
@@ -33,6 +33,9 @@ export class NotebookOpenHandler extends NavigatableWidgetOpenHandler<NotebookEd
33
33
 
34
34
  protected notebookTypes: NotebookTypeDescriptor[] = [];
35
35
 
36
+ @inject(PreferenceService)
37
+ protected readonly preferenceService: PreferenceService;
38
+
36
39
  registerNotebookType(notebookType: NotebookTypeDescriptor): Disposable {
37
40
  this.notebookTypes.push(notebookType);
38
41
  return Disposable.create(() => {
@@ -41,15 +44,16 @@ export class NotebookOpenHandler extends NavigatableWidgetOpenHandler<NotebookEd
41
44
  }
42
45
 
43
46
  canHandle(uri: URI, options?: NotebookWidgetOpenerOptions): MaybePromise<number> {
47
+ const defaultHandler = getDefaultHandler(uri, this.preferenceService);
44
48
  if (options?.notebookType) {
45
- return this.canHandleType(uri, this.notebookTypes.find(type => type.type === options.notebookType));
49
+ return this.canHandleType(uri, this.notebookTypes.find(type => type.type === options.notebookType), defaultHandler);
46
50
  }
47
- return Math.max(...this.notebookTypes.map(type => this.canHandleType(uri, type)));
51
+ return Math.max(...this.notebookTypes.map(type => this.canHandleType(uri, type), defaultHandler));
48
52
  }
49
53
 
50
- canHandleType(uri: URI, notebookType?: NotebookTypeDescriptor): number {
54
+ canHandleType(uri: URI, notebookType?: NotebookTypeDescriptor, defaultHandler?: string): number {
51
55
  if (notebookType?.selector && this.matches(notebookType.selector, uri)) {
52
- return this.calculatePriority(notebookType);
56
+ return notebookType.type === defaultHandler ? defaultHandlerPriority : this.calculatePriority(notebookType);
53
57
  } else {
54
58
  return 0;
55
59
  }
@@ -93,7 +97,9 @@ export class NotebookOpenHandler extends NavigatableWidgetOpenHandler<NotebookEd
93
97
  ...widgetOptions
94
98
  };
95
99
  }
96
- const notebookType = this.findHighestPriorityType(uri);
100
+ const defaultHandler = getDefaultHandler(uri, this.preferenceService);
101
+ const notebookType = this.notebookTypes.find(type => type.type === defaultHandler)
102
+ || this.findHighestPriorityType(uri);
97
103
  if (!notebookType) {
98
104
  throw new Error('No notebook types registered for uri: ' + uri.toString());
99
105
  }
@@ -14,20 +14,38 @@
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 } from '@theia/core';
18
- import { NotebookCellModel } from '../view-model/notebook-cell-model';
17
+ import { Disposable, Event } from '@theia/core';
19
18
  import { NotebookModel } from '../view-model/notebook-model';
19
+ import { NotebookEditorWidget } from '../notebook-editor-widget';
20
+ import { NotebookContentChangedEvent } from '../notebook-types';
21
+ import { NotebookCellOutputModel } from '../view-model/notebook-cell-output-model';
22
+ import { NotebookCellModel } from '../view-model/notebook-cell-model';
20
23
 
21
24
  export const CellOutputWebviewFactory = Symbol('outputWebviewFactory');
25
+ export const CellOutputWebview = Symbol('outputWebview');
22
26
 
23
- export type CellOutputWebviewFactory = (cell: NotebookCellModel, notebook: NotebookModel) => Promise<CellOutputWebview>;
27
+ export type CellOutputWebviewFactory = () => Promise<CellOutputWebview>;
28
+
29
+ export interface OutputRenderEvent {
30
+ cellHandle: number;
31
+ outputId: string;
32
+ outputHeight: number;
33
+ }
24
34
 
25
35
  export interface CellOutputWebview extends Disposable {
26
36
 
27
37
  readonly id: string;
28
38
 
39
+ init(notebook: NotebookModel, editor: NotebookEditorWidget): void;
40
+
29
41
  render(): React.ReactNode;
30
42
 
43
+ setCellHeight(cell: NotebookCellModel, height: number): void;
44
+ cellsChanged(cellEvent: NotebookContentChangedEvent[]): void;
45
+ onDidRenderOutput: Event<OutputRenderEvent>
46
+
47
+ requestOutputPresentationUpdate(cellHandle: number, output: NotebookCellOutputModel): void;
48
+
31
49
  attachWebview(): void;
32
50
  isAttached(): boolean
33
51
  }
@@ -0,0 +1,74 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2024 Typefox and others.
3
+ //
4
+ // This program and the accompanying materials are made available under the
5
+ // terms of the Eclipse Public License v. 2.0 which is available at
6
+ // http://www.eclipse.org/legal/epl-2.0.
7
+ //
8
+ // This Source Code may also be made available under the following Secondary
9
+ // Licenses when the conditions for such availability set forth in the Eclipse
10
+ // Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ // with the GNU Classpath Exception which is available at
12
+ // https://www.gnu.org/software/classpath/license.html.
13
+ //
14
+ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
+ // *****************************************************************************
16
+
17
+ import { Emitter, URI } from '@theia/core';
18
+ import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
19
+ import { SimpleMonacoEditor } from '@theia/monaco/lib/browser/simple-monaco-editor';
20
+ import { NotebookEditorWidgetService } from './notebook-editor-widget-service';
21
+ import { CellUri } from '../../common';
22
+
23
+ @injectable()
24
+ export class NotebookCellEditorService {
25
+
26
+ @inject(NotebookEditorWidgetService)
27
+ protected readonly notebookEditorWidgetService: NotebookEditorWidgetService;
28
+
29
+ protected onDidChangeCellEditorsEmitter = new Emitter<void>();
30
+ readonly onDidChangeCellEditors = this.onDidChangeCellEditorsEmitter.event;
31
+
32
+ protected onDidChangeFocusedCellEditorEmitter = new Emitter<SimpleMonacoEditor | undefined>();
33
+ readonly onDidChangeFocusedCellEditor = this.onDidChangeFocusedCellEditorEmitter.event;
34
+
35
+ protected currentActiveCell?: SimpleMonacoEditor;
36
+
37
+ protected currentCellEditors: Map<string, SimpleMonacoEditor> = new Map();
38
+
39
+ @postConstruct()
40
+ protected init(): void {
41
+ this.notebookEditorWidgetService.onDidChangeCurrentEditor(editor => {
42
+ // if defocus notebook editor or another notebook editor is focused, clear the active cell
43
+ if (!editor || (this.currentActiveCell && CellUri.parse(this.currentActiveCell.uri)?.notebook.toString() !== editor?.model?.uri.toString())) {
44
+ this.currentActiveCell = undefined;
45
+ this.onDidChangeFocusedCellEditorEmitter.fire(undefined);
46
+ }
47
+ });
48
+ }
49
+
50
+ get allCellEditors(): SimpleMonacoEditor[] {
51
+ return Array.from(this.currentCellEditors.values());
52
+ }
53
+
54
+ editorCreated(uri: URI, editor: SimpleMonacoEditor): void {
55
+ this.currentCellEditors.set(uri.toString(), editor);
56
+ this.onDidChangeCellEditorsEmitter.fire();
57
+ }
58
+
59
+ editorDisposed(uri: URI): void {
60
+ this.currentCellEditors.delete(uri.toString());
61
+ this.onDidChangeCellEditorsEmitter.fire();
62
+ }
63
+
64
+ editorFocusChanged(editor?: SimpleMonacoEditor): void {
65
+ if (editor) {
66
+ this.currentActiveCell = editor;
67
+ this.onDidChangeFocusedCellEditorEmitter.fire(editor);
68
+ }
69
+ }
70
+
71
+ getActiveCell(): SimpleMonacoEditor | undefined {
72
+ return this.currentActiveCell;
73
+ }
74
+ }
@@ -45,13 +45,23 @@ export class NotebookEditorWidgetService {
45
45
  protected readonly onDidChangeFocusedEditorEmitter = new Emitter<NotebookEditorWidget | undefined>();
46
46
  readonly onDidChangeFocusedEditor = this.onDidChangeFocusedEditorEmitter.event;
47
47
 
48
+ protected readonly onDidChangeCurrentEditorEmitter = new Emitter<NotebookEditorWidget | undefined>();
49
+ readonly onDidChangeCurrentEditor = this.onDidChangeCurrentEditorEmitter.event;
50
+
48
51
  focusedEditor?: NotebookEditorWidget = undefined;
49
52
 
53
+ currentEditor?: NotebookEditorWidget = undefined;
54
+
50
55
  @postConstruct()
51
56
  protected init(): void {
52
57
  this.applicationShell.onDidChangeActiveWidget(event => {
53
58
  this.notebookEditorFocusChanged(event.newValue as NotebookEditorWidget, event.newValue instanceof NotebookEditorWidget);
54
59
  });
60
+ this.applicationShell.onDidChangeCurrentWidget(event => {
61
+ if (event.newValue instanceof NotebookEditorWidget || event.oldValue instanceof NotebookEditorWidget) {
62
+ this.currentNotebookEditorChanged(event.newValue);
63
+ }
64
+ });
55
65
  }
56
66
 
57
67
  // --- editor management
@@ -98,4 +108,14 @@ export class NotebookEditorWidgetService {
98
108
  }
99
109
  }
100
110
 
111
+ currentNotebookEditorChanged(newEditor: unknown): void {
112
+ if (newEditor instanceof NotebookEditorWidget) {
113
+ this.currentEditor = newEditor;
114
+ this.onDidChangeCurrentEditorEmitter.fire(newEditor);
115
+ } else if (this.currentEditor?.isDisposed || !this.currentEditor?.isVisible) {
116
+ this.currentEditor = undefined;
117
+ this.onDidChangeCurrentEditorEmitter.fire(undefined);
118
+ }
119
+ }
120
+
101
121
  }
@@ -20,10 +20,24 @@
20
20
  }
21
21
 
22
22
  .theia-notebook-cell-list {
23
+ position: absolute;
24
+ top: 0;
25
+ width: 100%;
23
26
  overflow-y: auto;
24
27
  list-style: none;
25
28
  padding-left: 0px;
26
29
  background-color: var(--theia-notebook-editorBackground);
30
+ z-index: 0;
31
+ pointer-events: none;
32
+ }
33
+
34
+
35
+ .theia-notebook-cell-output-webview {
36
+ padding: 5px 0px;
37
+ margin: 0px 15px 0px 50px;
38
+ width: calc(100% - 60px);
39
+ position: absolute;
40
+ z-index: 0;
27
41
  }
28
42
 
29
43
  .theia-notebook-cell {
@@ -69,7 +83,8 @@
69
83
  /* Rendered Markdown Content */
70
84
 
71
85
  .theia-notebook-markdown-content {
72
- padding: 8px 16px 8px 36px;
86
+ pointer-events: all;
87
+ padding: 8px 16px 8px 0px;
73
88
  font-size: var(--theia-notebook-markdown-size);
74
89
  }
75
90
 
@@ -87,9 +102,13 @@
87
102
  padding-bottom: 0;
88
103
  }
89
104
 
105
+ .theia-notebook-markdown-sidebar {
106
+ width: 35px;
107
+ }
108
+
90
109
  /* Markdown cell edit mode */
91
110
  .theia-notebook-cell-content:has(.theia-notebook-markdown-editor-container>.theia-notebook-cell-editor) {
92
- margin-left: 36px;
111
+ pointer-events: all;
93
112
  margin-right: var(--theia-notebook-cell-editor-margin-right);
94
113
  outline: 1px solid var(--theia-notebook-cellBorderColor);
95
114
  }
@@ -108,13 +127,15 @@
108
127
  }
109
128
 
110
129
  .theia-notebook-cell-editor-container {
130
+ pointer-events: all;
111
131
  width: calc(100% - 46px);
112
132
  flex: 1;
113
133
  outline: 1px solid var(--theia-notebook-cellBorderColor);
114
134
  margin: 0px 16px 0px 10px;
115
135
  }
116
136
 
117
- .theia-notebook-cell.focused .theia-notebook-cell-editor-container {
137
+ /* Only mark an editor cell focused if the editor has focus */
138
+ .theia-notebook-cell-editor-container:has(.monaco-editor.focused) {
118
139
  outline-color: var(--theia-notebook-focusedEditorBorder);
119
140
  }
120
141
 
@@ -148,6 +169,7 @@
148
169
  }
149
170
 
150
171
  .theia-notebook-cell-toolbar {
172
+ pointer-events: all;
151
173
  border: 1px solid var(--theia-notebook-cellToolbarSeparator);
152
174
  display: flex;
153
175
  position: absolute;
@@ -160,11 +182,15 @@
160
182
  display: flex;
161
183
  flex-direction: column;
162
184
  padding: 2px;
163
- background-color: var(--theia-editor-background);
164
185
  flex-grow: 1;
165
186
  }
166
187
 
167
188
  .theia-notebook-cell-sidebar {
189
+ pointer-events: all;
190
+ display: flex;
191
+ }
192
+
193
+ .theia-notebook-cell-sidebar-actions {
168
194
  display: flex;
169
195
  flex-direction: column;
170
196
  }
@@ -193,6 +219,7 @@
193
219
  }
194
220
 
195
221
  .theia-notebook-cell-divider {
222
+ pointer-events: all;
196
223
  height: 25px;
197
224
  width: 100%;
198
225
  }
@@ -209,6 +236,10 @@
209
236
  overflow: hidden;
210
237
  }
211
238
 
239
+ .theia-notebook-main-container:focus {
240
+ outline: none;
241
+ }
242
+
212
243
  .theia-notebook-main-container .theia-notebook-main-loading-indicator {
213
244
  /* `progress-animation` is defined in `packages/core/src/browser/style/progress-bar.css` */
214
245
  animation: progress-animation 1.8s 0s infinite cubic-bezier(0.645, 0.045, 0.355, 1);
@@ -298,19 +329,19 @@
298
329
  margin: 1px 0 0 4px;
299
330
  }
300
331
 
301
- .theia-notebook-cell-output-webview {
302
- padding: 5px 0px;
303
- margin: 0px 15px 0px 9px;
304
- width: 100%;
305
- }
306
-
307
332
  .theia-notebook-cell-drop-indicator {
308
333
  height: 2px;
309
334
  background-color: var(--theia-notebook-focusedCellBorder);
310
335
  width: 100%;
311
336
  }
312
337
 
338
+ .theia-notebook-collapsed-output-container {
339
+ width: 0;
340
+ overflow: visible;
341
+ }
342
+
313
343
  .theia-notebook-collapsed-output {
344
+ text-wrap: nowrap;
314
345
  padding: 4px 8px;
315
346
  color: var(--theia-foreground);
316
347
  margin-left: 30px;
@@ -30,13 +30,15 @@ import { EditorExtensionsRegistry } from '@theia/monaco-editor-core/esm/vs/edito
30
30
  import { ModelDecorationOptions } from '@theia/monaco-editor-core/esm/vs/editor/common/model/textModel';
31
31
  import { IModelDeltaDecoration, OverviewRulerLane, TrackedRangeStickiness } from '@theia/monaco-editor-core/esm/vs/editor/common/model';
32
32
  import { animationFrame } from '@theia/core/lib/browser';
33
+ import { NotebookCellEditorService } from '../service/notebook-cell-editor-service';
33
34
 
34
35
  interface CellEditorProps {
35
- notebookModel: NotebookModel,
36
- cell: NotebookCellModel,
37
- monacoServices: MonacoEditorServices,
36
+ notebookModel: NotebookModel;
37
+ cell: NotebookCellModel;
38
+ monacoServices: MonacoEditorServices;
38
39
  notebookContextManager: NotebookContextManager;
39
- notebookViewportService?: NotebookViewportService,
40
+ notebookCellEditorService: NotebookCellEditorService;
41
+ notebookViewportService?: NotebookViewportService;
40
42
  fontInfo?: BareFontInfo;
41
43
  }
42
44
 
@@ -153,6 +155,9 @@ export class CellEditor extends React.Component<CellEditorProps, {}> {
153
155
  }
154
156
 
155
157
  protected disposeEditor(): void {
158
+ if (this.editor) {
159
+ this.props.notebookCellEditorService.editorDisposed(this.editor.uri);
160
+ }
156
161
  this.toDispose.dispose();
157
162
  this.toDispose = new DisposableCollection();
158
163
  }
@@ -197,7 +202,14 @@ export class CellEditor extends React.Component<CellEditorProps, {}> {
197
202
  }));
198
203
  this.toDispose.push(this.editor.getControl().onDidFocusEditorText(() => {
199
204
  this.props.notebookModel.setSelectedCell(cell, false);
205
+ this.props.notebookCellEditorService.editorFocusChanged(this.editor);
206
+ }));
207
+ this.toDispose.push(this.editor.getControl().onDidBlurEditorText(() => {
208
+ if (this.props.notebookCellEditorService.getActiveCell()?.uri.toString() === this.props.cell.uri.toString()) {
209
+ this.props.notebookCellEditorService.editorFocusChanged(undefined);
210
+ }
200
211
  }));
212
+
201
213
  this.toDispose.push(this.editor.getControl().onDidChangeCursorSelection(e => {
202
214
  const selectedText = this.editor!.getControl().getModel()!.getValueInRange(e.selection);
203
215
  this.props.notebookModel.selectedText = selectedText;
@@ -212,10 +224,11 @@ export class CellEditor extends React.Component<CellEditorProps, {}> {
212
224
  this.props.notebookContextManager.scopedStore.setContext(NOTEBOOK_CELL_CURSOR_LAST_LINE, false);
213
225
  }
214
226
  }));
227
+ this.props.notebookCellEditorService.editorCreated(uri, this.editor);
228
+ this.setMatches();
215
229
  if (cell.editing && notebookModel.selectedCell === cell) {
216
230
  this.editor.getControl().focus();
217
231
  }
218
- this.setMatches();
219
232
  }
220
233
  }
221
234