@theia/notebook 1.55.0-next.14 → 1.55.0-next.37

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 (41) hide show
  1. package/lib/browser/contributions/notebook-cell-actions-contribution.d.ts.map +1 -1
  2. package/lib/browser/contributions/notebook-cell-actions-contribution.js +49 -8
  3. package/lib/browser/contributions/notebook-cell-actions-contribution.js.map +1 -1
  4. package/lib/browser/notebook-frontend-module.d.ts.map +1 -1
  5. package/lib/browser/notebook-frontend-module.js +2 -0
  6. package/lib/browser/notebook-frontend-module.js.map +1 -1
  7. package/lib/browser/service/notebook-cell-status-bar-service.d.ts +39 -0
  8. package/lib/browser/service/notebook-cell-status-bar-service.d.ts.map +1 -0
  9. package/lib/browser/service/notebook-cell-status-bar-service.js +69 -0
  10. package/lib/browser/service/notebook-cell-status-bar-service.js.map +1 -0
  11. package/lib/browser/view/notebook-cell-editor.d.ts +1 -0
  12. package/lib/browser/view/notebook-cell-editor.d.ts.map +1 -1
  13. package/lib/browser/view/notebook-cell-editor.js +19 -13
  14. package/lib/browser/view/notebook-cell-editor.js.map +1 -1
  15. package/lib/browser/view/notebook-cell-toolbar.js +1 -1
  16. package/lib/browser/view/notebook-cell-toolbar.js.map +1 -1
  17. package/lib/browser/view/notebook-code-cell-view.d.ts +13 -3
  18. package/lib/browser/view/notebook-code-cell-view.d.ts.map +1 -1
  19. package/lib/browser/view/notebook-code-cell-view.js +47 -2
  20. package/lib/browser/view/notebook-code-cell-view.js.map +1 -1
  21. package/lib/browser/view/notebook-main-toolbar.js +4 -4
  22. package/lib/browser/view/notebook-main-toolbar.js.map +1 -1
  23. package/lib/browser/view/notebook-markdown-cell-view.d.ts +4 -0
  24. package/lib/browser/view/notebook-markdown-cell-view.d.ts.map +1 -1
  25. package/lib/browser/view/notebook-markdown-cell-view.js +13 -3
  26. package/lib/browser/view/notebook-markdown-cell-view.js.map +1 -1
  27. package/lib/browser/view-model/notebook-cell-model.d.ts +7 -0
  28. package/lib/browser/view-model/notebook-cell-model.d.ts.map +1 -1
  29. package/lib/browser/view-model/notebook-cell-model.js +11 -2
  30. package/lib/browser/view-model/notebook-cell-model.js.map +1 -1
  31. package/package.json +7 -7
  32. package/src/browser/contributions/notebook-cell-actions-contribution.ts +56 -9
  33. package/src/browser/notebook-frontend-module.ts +2 -0
  34. package/src/browser/service/notebook-cell-status-bar-service.ts +94 -0
  35. package/src/browser/style/index.css +19 -0
  36. package/src/browser/view/notebook-cell-editor.tsx +18 -11
  37. package/src/browser/view/notebook-cell-toolbar.tsx +1 -1
  38. package/src/browser/view/notebook-code-cell-view.tsx +65 -4
  39. package/src/browser/view/notebook-main-toolbar.tsx +4 -4
  40. package/src/browser/view/notebook-markdown-cell-view.tsx +20 -3
  41. package/src/browser/view-model/notebook-cell-model.ts +18 -2
@@ -51,6 +51,7 @@ import { NotebookOptionsService } from './service/notebook-options';
51
51
  import { NotebookUndoRedoHandler } from './contributions/notebook-undo-redo-handler';
52
52
  import { NotebookStatusBarContribution } from './contributions/notebook-status-bar-contribution';
53
53
  import { NotebookCellEditorService } from './service/notebook-cell-editor-service';
54
+ import { NotebookCellStatusBarService } from './service/notebook-cell-status-bar-service';
54
55
 
55
56
  export default new ContainerModule((bind, unbind, isBound, rebind) => {
56
57
  bind(NotebookColorContribution).toSelf().inSingletonScope();
@@ -74,6 +75,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
74
75
  bind(NotebookKernelQuickPickService).toSelf().inSingletonScope();
75
76
  bind(NotebookClipboardService).toSelf().inSingletonScope();
76
77
  bind(NotebookCellEditorService).toSelf().inSingletonScope();
78
+ bind(NotebookCellStatusBarService).toSelf().inSingletonScope();
77
79
 
78
80
  bind(NotebookCellResourceResolver).toSelf().inSingletonScope();
79
81
  bind(ResourceResolver).toService(NotebookCellResourceResolver);
@@ -0,0 +1,94 @@
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
+ * Copyright (c) Microsoft Corporation. All rights reserved.
18
+ * Licensed under the MIT License. See License.txt in the project root for license information.
19
+ *--------------------------------------------------------------------------------------------*/
20
+
21
+ import { CancellationToken, Command, Disposable, Emitter, Event, URI } from '@theia/core';
22
+ import { CellStatusbarAlignment } from '../../common';
23
+ import { ThemeColor } from '@theia/core/lib/common/theme';
24
+ import { AccessibilityInformation } from '@theia/core/lib/common/accessibility';
25
+ import { injectable } from '@theia/core/shared/inversify';
26
+ import { MarkdownString } from '@theia/core/lib/common/markdown-rendering';
27
+
28
+ export interface NotebookCellStatusBarItem {
29
+ readonly alignment: CellStatusbarAlignment;
30
+ readonly priority?: number;
31
+ readonly text: string;
32
+ readonly color?: string | ThemeColor;
33
+ readonly backgroundColor?: string | ThemeColor;
34
+ readonly tooltip?: string | MarkdownString;
35
+ readonly command?: string | (Command & { arguments?: unknown[] });
36
+ readonly accessibilityInformation?: AccessibilityInformation;
37
+ readonly opacity?: string;
38
+ readonly onlyShowWhenActive?: boolean;
39
+ }
40
+ export interface NotebookCellStatusBarItemList {
41
+ items: NotebookCellStatusBarItem[];
42
+ dispose?(): void;
43
+ }
44
+
45
+ export interface NotebookCellStatusBarItemProvider {
46
+ viewType: string;
47
+ onDidChangeStatusBarItems?: Event<void>;
48
+ provideCellStatusBarItems(uri: URI, index: number, token: CancellationToken): Promise<NotebookCellStatusBarItemList | undefined>;
49
+ }
50
+
51
+ @injectable()
52
+ export class NotebookCellStatusBarService implements Disposable {
53
+
54
+ protected readonly onDidChangeProvidersEmitter = new Emitter<void>();
55
+ readonly onDidChangeProviders: Event<void> = this.onDidChangeProvidersEmitter.event;
56
+
57
+ protected readonly onDidChangeItemsEmitter = new Emitter<void>();
58
+ readonly onDidChangeItems: Event<void> = this.onDidChangeItemsEmitter.event;
59
+
60
+ protected readonly providers: NotebookCellStatusBarItemProvider[] = [];
61
+
62
+ registerCellStatusBarItemProvider(provider: NotebookCellStatusBarItemProvider): Disposable {
63
+ this.providers.push(provider);
64
+ let changeListener: Disposable | undefined;
65
+ if (provider.onDidChangeStatusBarItems) {
66
+ changeListener = provider.onDidChangeStatusBarItems(() => this.onDidChangeItemsEmitter.fire());
67
+ }
68
+
69
+ this.onDidChangeProvidersEmitter.fire();
70
+
71
+ return Disposable.create(() => {
72
+ changeListener?.dispose();
73
+ const idx = this.providers.findIndex(p => p === provider);
74
+ this.providers.splice(idx, 1);
75
+ });
76
+ }
77
+
78
+ async getStatusBarItemsForCell(notebookUri: URI, cellIndex: number, viewType: string, token: CancellationToken): Promise<NotebookCellStatusBarItemList[]> {
79
+ const providers = this.providers.filter(p => p.viewType === viewType || p.viewType === '*');
80
+ return Promise.all(providers.map(async p => {
81
+ try {
82
+ return await p.provideCellStatusBarItems(notebookUri, cellIndex, token) ?? { items: [] };
83
+ } catch (e) {
84
+ console.error(e);
85
+ return { items: [] };
86
+ }
87
+ }));
88
+ }
89
+
90
+ dispose(): void {
91
+ this.onDidChangeItemsEmitter.dispose();
92
+ this.onDidChangeProvidersEmitter.dispose();
93
+ }
94
+ }
@@ -508,3 +508,22 @@ mark.theia-find-match.theia-find-match-selected {
508
508
  color: var(--theia-editor-findMatchForeground);
509
509
  background-color: var(--theia-editor-findMatchBackground);
510
510
  }
511
+
512
+ .cell-status-bar-item {
513
+ align-items: center;
514
+ display: flex;
515
+ height: 16px;
516
+ margin: 0 3px;
517
+ overflow: hidden;
518
+ padding: 0 3px;
519
+ text-overflow: clip;
520
+ white-space: pre;
521
+ }
522
+
523
+ .cell-status-item-has-command {
524
+ cursor: pointer;
525
+ }
526
+
527
+ .cell-status-item-has-command:hover {
528
+ background-color: var(--theia-toolbar-hoverBackground);
529
+ }
@@ -103,15 +103,7 @@ export class CellEditor extends React.Component<CellEditorProps, {}> {
103
103
  this.props.notebookContextManager.scopedStore.setContext(NOTEBOOK_CELL_CURSOR_LAST_LINE, currentLine === lineCount);
104
104
  }));
105
105
 
106
- this.toDispose.push(this.props.cell.onWillBlurCellEditor(() => {
107
- let parent = this.container?.parentElement;
108
- while (parent && !parent.classList.contains('theia-notebook-cell')) {
109
- parent = parent.parentElement;
110
- }
111
- if (parent) {
112
- parent.focus();
113
- }
114
- }));
106
+ this.toDispose.push(this.props.cell.onWillBlurCellEditor(() => this.blurEditor()));
115
107
 
116
108
  this.toDispose.push(this.props.cell.onDidChangeEditorOptions(options => {
117
109
  this.editor?.getControl().updateOptions(options);
@@ -130,7 +122,7 @@ export class CellEditor extends React.Component<CellEditorProps, {}> {
130
122
 
131
123
  this.toDispose.push(this.props.notebookModel.onDidChangeSelectedCell(e => {
132
124
  if (e.cell !== this.props.cell && this.editor?.getControl().hasTextFocus()) {
133
- this.props.notebookContextManager.context?.focus();
125
+ this.blurEditor();
134
126
  }
135
127
  }));
136
128
  if (!this.props.notebookViewportService || (this.container && this.props.notebookViewportService.isElementInViewport(this.container))) {
@@ -212,6 +204,11 @@ export class CellEditor extends React.Component<CellEditorProps, {}> {
212
204
 
213
205
  this.toDispose.push(this.editor.getControl().onDidChangeCursorSelection(e => {
214
206
  const selectedText = this.editor!.getControl().getModel()!.getValueInRange(e.selection);
207
+ // TODO handle secondary selections
208
+ this.props.cell.selection = {
209
+ start: { line: e.selection.startLineNumber - 1, character: e.selection.startColumn - 1 },
210
+ end: { line: e.selection.endLineNumber - 1, character: e.selection.endColumn - 1 }
211
+ };
215
212
  this.props.notebookModel.selectedText = selectedText;
216
213
  }));
217
214
  this.toDispose.push(this.editor.getControl().onDidChangeCursorPosition(e => {
@@ -226,7 +223,7 @@ export class CellEditor extends React.Component<CellEditorProps, {}> {
226
223
  }));
227
224
  this.props.notebookCellEditorService.editorCreated(uri, this.editor);
228
225
  this.setMatches();
229
- if (cell.editing && notebookModel.selectedCell === cell) {
226
+ if (notebookModel.selectedCell === cell) {
230
227
  this.editor.getControl().focus();
231
228
  }
232
229
  }
@@ -273,4 +270,14 @@ export class CellEditor extends React.Component<CellEditorProps, {}> {
273
270
  </div >;
274
271
  }
275
272
 
273
+ protected blurEditor(): void {
274
+ let parent = this.container?.parentElement;
275
+ while (parent && !parent.classList.contains('theia-notebook-cell')) {
276
+ parent = parent.parentElement;
277
+ }
278
+ if (parent) {
279
+ parent.focus();
280
+ }
281
+ }
282
+
276
283
  }
@@ -48,7 +48,7 @@ abstract class NotebookCellActionBar extends React.Component<NotebookCellToolbar
48
48
  }
49
49
 
50
50
  protected renderItem(item: NotebookCellToolbarItem): React.ReactNode {
51
- return <div key={item.id} title={item.label} onClick={item.onClick} className={`${item.icon} ${ACTION_ITEM} theia-notebook-cell-toolbar-item`} />;
51
+ return <div key={item.id} id={item.id} title={item.label} onClick={item.onClick} className={`${item.icon} ${ACTION_ITEM} theia-notebook-cell-toolbar-item`} />;
52
52
  }
53
53
 
54
54
  }
@@ -27,7 +27,7 @@ import { NotebookCellActionContribution, NotebookCellCommands } from '../contrib
27
27
  import { CellExecution, NotebookExecutionStateService } from '../service/notebook-execution-state-service';
28
28
  import { codicon } from '@theia/core/lib/browser';
29
29
  import { NotebookCellExecutionState } from '../../common';
30
- import { CommandRegistry, DisposableCollection, nls } from '@theia/core';
30
+ import { CancellationToken, CommandRegistry, DisposableCollection, nls } from '@theia/core';
31
31
  import { NotebookContextManager } from '../service/notebook-context-manager';
32
32
  import { NotebookViewportService } from './notebook-viewport-service';
33
33
  import { EditorPreferences } from '@theia/editor/lib/browser';
@@ -36,6 +36,8 @@ import { MarkdownRenderer } from '@theia/core/lib/browser/markdown-rendering/mar
36
36
  import { MarkdownString } from '@theia/monaco-editor-core/esm/vs/base/common/htmlContent';
37
37
  import { NotebookCellEditorService } from '../service/notebook-cell-editor-service';
38
38
  import { CellOutputWebview } from '../renderers/cell-output-webview';
39
+ import { NotebookCellStatusBarItem, NotebookCellStatusBarItemList, NotebookCellStatusBarService } from '../service/notebook-cell-status-bar-service';
40
+ import { LabelParser } from '@theia/core/lib/browser/label-parser';
39
41
 
40
42
  @injectable()
41
43
  export class NotebookCodeCellRenderer implements CellRenderer {
@@ -75,6 +77,12 @@ export class NotebookCodeCellRenderer implements CellRenderer {
75
77
  @inject(CellOutputWebview)
76
78
  protected readonly outputWebview: CellOutputWebview;
77
79
 
80
+ @inject(NotebookCellStatusBarService)
81
+ protected readonly notebookCellStatusBarService: NotebookCellStatusBarService;
82
+
83
+ @inject(LabelParser)
84
+ protected readonly labelParser: LabelParser;
85
+
78
86
  render(notebookModel: NotebookModel, cell: NotebookCellModel, handle: number): React.ReactNode {
79
87
  return <div className='theia-notebook-cell-with-sidebar' ref={ref => observeCellHeight(ref, cell)}>
80
88
  <div className='theia-notebook-cell-editor-container'>
@@ -87,6 +95,8 @@ export class NotebookCodeCellRenderer implements CellRenderer {
87
95
  <NotebookCodeCellStatus cell={cell} notebook={notebookModel}
88
96
  commandRegistry={this.commandRegistry}
89
97
  executionStateService={this.executionStateService}
98
+ cellStatusBarService={this.notebookCellStatusBarService}
99
+ labelParser={this.labelParser}
90
100
  onClick={() => cell.requestFocusEditor()} />
91
101
  </div >
92
102
  </div >;
@@ -182,7 +192,9 @@ export interface NotebookCodeCellStatusProps {
182
192
  notebook: NotebookModel;
183
193
  cell: NotebookCellModel;
184
194
  commandRegistry: CommandRegistry;
195
+ cellStatusBarService: NotebookCellStatusBarService;
185
196
  executionStateService?: NotebookExecutionStateService;
197
+ labelParser: LabelParser;
186
198
  onClick: () => void;
187
199
  }
188
200
 
@@ -195,6 +207,8 @@ export class NotebookCodeCellStatus extends React.Component<NotebookCodeCellStat
195
207
 
196
208
  protected toDispose = new DisposableCollection();
197
209
 
210
+ protected statusBarItems: NotebookCellStatusBarItemList[] = [];
211
+
198
212
  constructor(props: NotebookCodeCellStatusProps) {
199
213
  super(props);
200
214
 
@@ -225,6 +239,19 @@ export class NotebookCodeCellStatus extends React.Component<NotebookCodeCellStat
225
239
  this.toDispose.push(props.cell.onDidChangeLanguage(() => {
226
240
  this.forceUpdate();
227
241
  }));
242
+
243
+ this.updateStatusBarItems();
244
+ this.props.cellStatusBarService.onDidChangeItems(() => this.updateStatusBarItems());
245
+ this.props.notebook.onContentChanged(() => this.updateStatusBarItems());
246
+ }
247
+
248
+ async updateStatusBarItems(): Promise<void> {
249
+ this.statusBarItems = await this.props.cellStatusBarService.getStatusBarItemsForCell(
250
+ this.props.notebook.uri,
251
+ this.props.notebook.cells.indexOf(this.props.cell),
252
+ this.props.notebook.viewType,
253
+ CancellationToken.None);
254
+ this.forceUpdate();
228
255
  }
229
256
 
230
257
  override componentWillUnmount(): void {
@@ -235,6 +262,7 @@ export class NotebookCodeCellStatus extends React.Component<NotebookCodeCellStat
235
262
  return <div className='notebook-cell-status' onClick={() => this.props.onClick()}>
236
263
  <div className='notebook-cell-status-left'>
237
264
  {this.props.executionStateService && this.renderExecutionState()}
265
+ {this.statusBarItems?.length && this.renderStatusBarItems()}
238
266
  </div>
239
267
  <div className='notebook-cell-status-right'>
240
268
  <span className='notebook-cell-language-label' onClick={() => {
@@ -244,7 +272,7 @@ export class NotebookCodeCellStatus extends React.Component<NotebookCodeCellStat
244
272
  </div>;
245
273
  }
246
274
 
247
- private renderExecutionState(): React.ReactNode {
275
+ protected renderExecutionState(): React.ReactNode {
248
276
  const state = this.state.currentExecution?.state;
249
277
  const { lastRunSuccess } = this.props.cell.internalMetadata;
250
278
 
@@ -270,7 +298,7 @@ export class NotebookCodeCellStatus extends React.Component<NotebookCodeCellStat
270
298
  </>;
271
299
  }
272
300
 
273
- private getExecutionTime(): number {
301
+ protected getExecutionTime(): number {
274
302
  const { runStartTime, runEndTime } = this.props.cell.internalMetadata;
275
303
  const { executionTime } = this.state;
276
304
  if (runStartTime !== undefined && runEndTime !== undefined) {
@@ -279,9 +307,42 @@ export class NotebookCodeCellStatus extends React.Component<NotebookCodeCellStat
279
307
  return executionTime;
280
308
  }
281
309
 
282
- private renderTime(ms: number): string {
310
+ protected renderTime(ms: number): string {
283
311
  return `${(ms / 1000).toLocaleString(undefined, { maximumFractionDigits: 1, minimumFractionDigits: 1 })}s`;
284
312
  }
313
+
314
+ protected renderStatusBarItems(): React.ReactNode {
315
+ return <>
316
+ {
317
+ this.statusBarItems.flatMap((itemList, listIndex) =>
318
+ itemList.items.map((item, index) => this.renderStatusBarItem(item, `${listIndex}-${index}`)
319
+ )
320
+ )
321
+ }
322
+ </>;
323
+ }
324
+
325
+ protected renderStatusBarItem(item: NotebookCellStatusBarItem, key: string): React.ReactNode {
326
+ const content = this.props.labelParser.parse(item.text).map(part => {
327
+ if (typeof part === 'string') {
328
+ return part;
329
+ } else {
330
+ return <span key={part.name} className={`codicon codicon-${part.name}`}></span>;
331
+ }
332
+ });
333
+ return <div key={key} className={`cell-status-bar-item ${item.command ? 'cell-status-item-has-command' : ''}`} onClick={async () => {
334
+ if (item.command) {
335
+ if (typeof item.command === 'string') {
336
+ this.props.commandRegistry.executeCommand(item.command);
337
+ } else {
338
+ this.props.commandRegistry.executeCommand(item.command.id, ...(item.command.arguments ?? []));
339
+ }
340
+ }
341
+ }}>
342
+ {content}
343
+ </div>;
344
+ }
345
+
285
346
  }
286
347
 
287
348
  interface NotebookCellOutputProps {
@@ -152,17 +152,17 @@ export class NotebookMainToolbar extends React.Component<NotebookMainToolbarProp
152
152
 
153
153
  override render(): React.ReactNode {
154
154
  const menuItems = this.getMenuItems();
155
- return <div className='theia-notebook-main-toolbar'>
155
+ return <div className='theia-notebook-main-toolbar' id='notebook-main-toolbar'>
156
156
  {menuItems.slice(0, menuItems.length - this.calculateNumberOfHiddenItems(menuItems)).map(item => this.renderMenuItem(item))}
157
157
  {
158
158
  this.state.numberOfHiddenItems > 0 &&
159
159
  <span className={`${codicon('ellipsis')} action-label theia-notebook-main-toolbar-item`} onClick={e => this.renderContextMenu(e.nativeEvent, menuItems)} />
160
160
  }
161
161
  <div ref={element => this.gapElementChanged(element)} style={{ flexGrow: 1 }}></div>
162
- <div className='theia-notebook-main-toolbar-item action-label'
162
+ <div className='theia-notebook-main-toolbar-item action-label' id={NotebookCommands.SELECT_KERNEL_COMMAND.id}
163
163
  onClick={() => this.props.commandRegistry.executeCommand(NotebookCommands.SELECT_KERNEL_COMMAND.id, this.props.notebookModel)}>
164
164
  <span className={codicon('server-environment')} />
165
- <span className=' theia-notebook-main-toolbar-item-text'>
165
+ <span className=' theia-notebook-main-toolbar-item-text' id='kernel-text'>
166
166
  {this.state.selectedKernelLabel ?? nls.localizeByDefault('Select Kernel')}
167
167
  </span>
168
168
  </div>
@@ -195,7 +195,7 @@ export class NotebookMainToolbar extends React.Component<NotebookMainToolbarProp
195
195
  const command = this.props.commandRegistry.getCommand(item.command ?? '') as NotebookCommand | undefined;
196
196
  const label = command?.shortTitle ?? item.label;
197
197
  const title = command?.tooltip ?? item.label;
198
- return <div key={item.id} title={title} className={`theia-notebook-main-toolbar-item action-label${this.getAdditionalClasses(item)}`}
198
+ return <div key={item.id} id={item.id} title={title} className={`theia-notebook-main-toolbar-item action-label${this.getAdditionalClasses(item)}`}
199
199
  onClick={() => {
200
200
  if (item.command && (!item.when || this.props.contextKeyService.match(item.when, this.props.editorNode))) {
201
201
  this.props.commandRegistry.executeCommand(item.command, this.props.notebookModel.uri);
@@ -30,6 +30,8 @@ import { NotebookCodeCellStatus } from './notebook-code-cell-view';
30
30
  import { NotebookEditorFindMatch, NotebookEditorFindMatchOptions } from './notebook-find-widget';
31
31
  import * as mark from 'advanced-mark.js';
32
32
  import { NotebookCellEditorService } from '../service/notebook-cell-editor-service';
33
+ import { NotebookCellStatusBarService } from '../service/notebook-cell-status-bar-service';
34
+ import { LabelParser } from '@theia/core/lib/browser/label-parser';
33
35
 
34
36
  @injectable()
35
37
  export class NotebookMarkdownCellRenderer implements CellRenderer {
@@ -51,6 +53,12 @@ export class NotebookMarkdownCellRenderer implements CellRenderer {
51
53
  @inject(NotebookCellEditorService)
52
54
  protected readonly notebookCellEditorService: NotebookCellEditorService;
53
55
 
56
+ @inject(NotebookCellStatusBarService)
57
+ protected readonly notebookCellStatusBarService: NotebookCellStatusBarService;
58
+
59
+ @inject(LabelParser)
60
+ protected readonly labelParser: LabelParser;
61
+
54
62
  render(notebookModel: NotebookModel, cell: NotebookCellModel): React.ReactNode {
55
63
  return <MarkdownCell
56
64
  markdownRenderer={this.markdownRenderer}
@@ -60,7 +68,10 @@ export class NotebookMarkdownCellRenderer implements CellRenderer {
60
68
  cell={cell}
61
69
  notebookModel={notebookModel}
62
70
  notebookContextManager={this.notebookContextManager}
63
- notebookCellEditorService={this.notebookCellEditorService} />;
71
+ notebookCellEditorService={this.notebookCellEditorService}
72
+ notebookCellStatusBarService={this.notebookCellStatusBarService}
73
+ labelParser={this.labelParser}
74
+ />;
64
75
  }
65
76
 
66
77
  renderSidebar(notebookModel: NotebookModel, cell: NotebookCellModel): React.ReactNode {
@@ -86,11 +97,15 @@ interface MarkdownCellProps {
86
97
  notebookModel: NotebookModel;
87
98
  notebookContextManager: NotebookContextManager;
88
99
  notebookOptionsService: NotebookOptionsService;
89
- notebookCellEditorService: NotebookCellEditorService
100
+ notebookCellEditorService: NotebookCellEditorService;
101
+ notebookCellStatusBarService: NotebookCellStatusBarService;
102
+ labelParser: LabelParser;
90
103
  }
91
104
 
92
105
  function MarkdownCell({
93
- markdownRenderer, monacoServices, cell, notebookModel, notebookContextManager, notebookOptionsService, commandRegistry, notebookCellEditorService
106
+ markdownRenderer, monacoServices, cell, notebookModel, notebookContextManager,
107
+ notebookOptionsService, commandRegistry, notebookCellEditorService, notebookCellStatusBarService,
108
+ labelParser
94
109
  }: MarkdownCellProps): React.JSX.Element {
95
110
  const [editMode, setEditMode] = React.useState(cell.editing);
96
111
  let empty = false;
@@ -147,6 +162,8 @@ function MarkdownCell({
147
162
  fontInfo={notebookOptionsService.editorFontInfo} />
148
163
  <NotebookCodeCellStatus cell={cell} notebook={notebookModel}
149
164
  commandRegistry={commandRegistry}
165
+ cellStatusBarService={notebookCellStatusBarService}
166
+ labelParser={labelParser}
150
167
  onClick={() => cell.requestFocusEditor()} />
151
168
  </div >) :
152
169
  (<div className='theia-notebook-markdown-content' key="markdown"
@@ -62,6 +62,10 @@ export interface NotebookCell {
62
62
  metadata: NotebookCellMetadata;
63
63
  internalMetadata: NotebookCellInternalMetadata;
64
64
  text: string;
65
+ /**
66
+ * The selection of the cell. Zero-based line/character coordinates.
67
+ */
68
+ selection: Range | undefined;
65
69
  onDidChangeOutputs?: Event<NotebookCellOutputsSplice>;
66
70
  onDidChangeOutputItems?: Event<CellOutput>;
67
71
  onDidChangeLanguage: Event<string>;
@@ -254,14 +258,26 @@ export class NotebookCellModel implements NotebookCell, Disposable {
254
258
  }
255
259
  }
256
260
 
261
+ protected _selection: Range | undefined = undefined;
262
+
263
+ get selection(): Range | undefined {
264
+ return this._selection;
265
+ }
266
+
267
+ set selection(selection: Range | undefined) {
268
+ this._selection = selection;
269
+ }
270
+
257
271
  protected _cellheight: number = 0;
258
272
  get cellHeight(): number {
259
273
  return this._cellheight;
260
274
  }
261
275
 
262
276
  set cellHeight(height: number) {
263
- this.onDidCellHeightChangeEmitter.fire(height);
264
- this._cellheight = height;
277
+ if (height !== this._cellheight) {
278
+ this.onDidCellHeightChangeEmitter.fire(height);
279
+ this._cellheight = height;
280
+ }
265
281
  }
266
282
 
267
283
  @postConstruct()