@theia/plugin-ext 1.47.1 → 1.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/lib/common/plugin-api-rpc.d.ts +19 -0
  2. package/lib/common/plugin-api-rpc.d.ts.map +1 -1
  3. package/lib/common/plugin-api-rpc.js +12 -1
  4. package/lib/common/plugin-api-rpc.js.map +1 -1
  5. package/lib/main/browser/documents-main.d.ts +2 -1
  6. package/lib/main/browser/documents-main.d.ts.map +1 -1
  7. package/lib/main/browser/documents-main.js +2 -1
  8. package/lib/main/browser/documents-main.js.map +1 -1
  9. package/lib/main/browser/languages-main.d.ts.map +1 -1
  10. package/lib/main/browser/languages-main.js +0 -1
  11. package/lib/main/browser/languages-main.js.map +1 -1
  12. package/lib/main/browser/main-context.d.ts.map +1 -1
  13. package/lib/main/browser/main-context.js +5 -11
  14. package/lib/main/browser/main-context.js.map +1 -1
  15. package/lib/main/browser/notebooks/notebook-documents-main.d.ts +11 -5
  16. package/lib/main/browser/notebooks/notebook-documents-main.d.ts.map +1 -1
  17. package/lib/main/browser/notebooks/notebook-documents-main.js +11 -0
  18. package/lib/main/browser/notebooks/notebook-documents-main.js.map +1 -1
  19. package/lib/main/browser/notebooks/notebook-kernels-main.d.ts.map +1 -1
  20. package/lib/main/browser/notebooks/notebook-kernels-main.js +16 -10
  21. package/lib/main/browser/notebooks/notebook-kernels-main.js.map +1 -1
  22. package/lib/main/browser/notebooks/notebooks-main.d.ts +12 -10
  23. package/lib/main/browser/notebooks/notebooks-main.d.ts.map +1 -1
  24. package/lib/main/browser/notebooks/notebooks-main.js +36 -7
  25. package/lib/main/browser/notebooks/notebooks-main.js.map +1 -1
  26. package/lib/main/browser/notebooks/renderers/cell-output-webview.d.ts.map +1 -1
  27. package/lib/main/browser/notebooks/renderers/cell-output-webview.js +5 -1
  28. package/lib/main/browser/notebooks/renderers/cell-output-webview.js.map +1 -1
  29. package/lib/main/browser/notebooks/renderers/output-webview-internal.d.ts.map +1 -1
  30. package/lib/main/browser/notebooks/renderers/output-webview-internal.js +7 -0
  31. package/lib/main/browser/notebooks/renderers/output-webview-internal.js.map +1 -1
  32. package/lib/main/browser/plugin-ext-frontend-module.d.ts.map +1 -1
  33. package/lib/main/browser/plugin-ext-frontend-module.js +3 -0
  34. package/lib/main/browser/plugin-ext-frontend-module.js.map +1 -1
  35. package/lib/main/browser/terminal-main.d.ts +11 -1
  36. package/lib/main/browser/terminal-main.d.ts.map +1 -1
  37. package/lib/main/browser/terminal-main.js +37 -0
  38. package/lib/main/browser/terminal-main.js.map +1 -1
  39. package/lib/main/browser/text-editor-main.d.ts.map +1 -1
  40. package/lib/main/browser/text-editor-main.js +6 -0
  41. package/lib/main/browser/text-editor-main.js.map +1 -1
  42. package/lib/main/browser/text-editors-main.d.ts +4 -3
  43. package/lib/main/browser/text-editors-main.d.ts.map +1 -1
  44. package/lib/main/browser/text-editors-main.js +18 -6
  45. package/lib/main/browser/text-editors-main.js.map +1 -1
  46. package/lib/main/browser/webview/webview-secondary-window-support.d.ts +8 -0
  47. package/lib/main/browser/webview/webview-secondary-window-support.d.ts.map +1 -0
  48. package/lib/main/browser/webview/webview-secondary-window-support.js +52 -0
  49. package/lib/main/browser/webview/webview-secondary-window-support.js.map +1 -0
  50. package/lib/plugin/dialogs.js +1 -1
  51. package/lib/plugin/dialogs.js.map +1 -1
  52. package/lib/plugin/notebook/notebook-document.d.ts.map +1 -1
  53. package/lib/plugin/notebook/notebook-document.js +16 -0
  54. package/lib/plugin/notebook/notebook-document.js.map +1 -1
  55. package/lib/plugin/notebook/notebook-kernels.d.ts +5 -2
  56. package/lib/plugin/notebook/notebook-kernels.d.ts.map +1 -1
  57. package/lib/plugin/notebook/notebook-kernels.js +17 -7
  58. package/lib/plugin/notebook/notebook-kernels.js.map +1 -1
  59. package/lib/plugin/notebook/notebooks.d.ts.map +1 -1
  60. package/lib/plugin/notebook/notebooks.js +18 -1
  61. package/lib/plugin/notebook/notebooks.js.map +1 -1
  62. package/lib/plugin/plugin-context.d.ts.map +1 -1
  63. package/lib/plugin/plugin-context.js +5 -1
  64. package/lib/plugin/plugin-context.js.map +1 -1
  65. package/lib/plugin/preference-registry.js +4 -4
  66. package/lib/plugin/preference-registry.js.map +1 -1
  67. package/lib/plugin/quick-open.d.ts.map +1 -1
  68. package/lib/plugin/quick-open.js +0 -1
  69. package/lib/plugin/quick-open.js.map +1 -1
  70. package/lib/plugin/terminal-ext.d.ts +3 -0
  71. package/lib/plugin/terminal-ext.d.ts.map +1 -1
  72. package/lib/plugin/terminal-ext.js +19 -0
  73. package/lib/plugin/terminal-ext.js.map +1 -1
  74. package/lib/plugin/types-impl.d.ts +2 -1
  75. package/lib/plugin/types-impl.d.ts.map +1 -1
  76. package/lib/plugin/types-impl.js +1 -0
  77. package/lib/plugin/types-impl.js.map +1 -1
  78. package/lib/plugin/webviews.d.ts +2 -0
  79. package/lib/plugin/webviews.d.ts.map +1 -1
  80. package/lib/plugin/webviews.js +7 -0
  81. package/lib/plugin/webviews.js.map +1 -1
  82. package/package.json +29 -29
  83. package/src/common/plugin-api-rpc.ts +29 -0
  84. package/src/main/browser/documents-main.ts +4 -0
  85. package/src/main/browser/languages-main.ts +0 -1
  86. package/src/main/browser/main-context.ts +7 -11
  87. package/src/main/browser/notebooks/notebook-documents-main.ts +20 -5
  88. package/src/main/browser/notebooks/notebook-kernels-main.ts +15 -10
  89. package/src/main/browser/notebooks/notebooks-main.ts +41 -12
  90. package/src/main/browser/notebooks/renderers/cell-output-webview.tsx +5 -1
  91. package/src/main/browser/notebooks/renderers/output-webview-internal.ts +8 -0
  92. package/src/main/browser/plugin-ext-frontend-module.ts +3 -0
  93. package/src/main/browser/terminal-main.ts +46 -0
  94. package/src/main/browser/text-editor-main.ts +7 -1
  95. package/src/main/browser/text-editors-main.ts +25 -6
  96. package/src/main/browser/webview/pre/main.js +2 -2
  97. package/src/main/browser/webview/webview-secondary-window-support.ts +47 -0
  98. package/src/plugin/dialogs.ts +1 -1
  99. package/src/plugin/notebook/notebook-document.ts +14 -1
  100. package/src/plugin/notebook/notebook-kernels.ts +22 -8
  101. package/src/plugin/notebook/notebooks.ts +19 -2
  102. package/src/plugin/plugin-context.ts +8 -2
  103. package/src/plugin/preference-registry.ts +4 -4
  104. package/src/plugin/quick-open.ts +0 -1
  105. package/src/plugin/terminal-ext.ts +20 -1
  106. package/src/plugin/types-impl.ts +2 -1
  107. package/src/plugin/webviews.ts +9 -0
@@ -301,6 +301,7 @@ export interface TerminalServiceExt {
301
301
  $handleTerminalLink(link: ProvidedTerminalLink): Promise<void>;
302
302
  getEnvironmentVariableCollection(extensionIdentifier: string): theia.GlobalEnvironmentVariableCollection;
303
303
  $setShell(shell: string): void;
304
+ $reportOutputMatch(observerId: string, groups: string[]): void;
304
305
  }
305
306
  export interface OutputChannelRegistryExt {
306
307
  createOutputChannel(name: string, pluginInfo: PluginInfo): theia.OutputChannel,
@@ -438,6 +439,20 @@ export interface TerminalServiceMain {
438
439
  * @param providerId id of the terminal link provider to be unregistered.
439
440
  */
440
441
  $unregisterTerminalLinkProvider(providerId: string): Promise<void>;
442
+
443
+ /**
444
+ * Register a new terminal observer.
445
+ * @param providerId id of the terminal link provider to be registered.
446
+ * @param nrOfLinesToMatch the number of lines to match the outputMatcherRegex against
447
+ * @param outputMatcherRegex the regex to match the output to
448
+ */
449
+ $registerTerminalObserver(id: string, nrOfLinesToMatch: number, outputMatcherRegex: string): unknown;
450
+
451
+ /**
452
+ * Unregister the terminal observer with the specified id.
453
+ * @param providerId id of the terminal observer to be unregistered.
454
+ */
455
+ $unregisterTerminalObserver(id: string): unknown;
441
456
  }
442
457
 
443
458
  export interface AutoFocus {
@@ -1548,6 +1563,16 @@ export interface WorkspaceNotebookCellEditDto {
1548
1563
  cellEdit: CellEditOperationDto;
1549
1564
  }
1550
1565
 
1566
+ export namespace WorkspaceNotebookCellEditDto {
1567
+ export function is(arg: WorkspaceNotebookCellEditDto | WorkspaceFileEditDto | WorkspaceTextEditDto): arg is WorkspaceNotebookCellEditDto {
1568
+ return !!arg
1569
+ && 'resource' in arg
1570
+ && 'cellEdit' in arg
1571
+ && arg.cellEdit !== null
1572
+ && typeof arg.cellEdit === 'object';
1573
+ }
1574
+ }
1575
+
1551
1576
  export interface WorkspaceEditDto {
1552
1577
  edits: Array<WorkspaceTextEditDto | WorkspaceFileEditDto | WorkspaceNotebookCellEditDto>;
1553
1578
  }
@@ -2449,6 +2474,10 @@ export type NotebookRawContentEventDto =
2449
2474
  readonly outputItems: NotebookOutputItemDto[];
2450
2475
  readonly append: boolean;
2451
2476
  }
2477
+ | {
2478
+ readonly kind: notebookCommon.NotebookCellsChangeType.ChangeDocumentMetadata
2479
+ readonly metadata: notebookCommon.NotebookDocumentMetadata;
2480
+ }
2452
2481
  | notebookCommon.NotebookCellsChangeLanguageEvent
2453
2482
  | notebookCommon.NotebookCellsChangeMetadataEvent
2454
2483
  | notebookCommon.NotebookCellsChangeInternalMetadataEvent
@@ -32,6 +32,7 @@ import { dispose } from '../../common/disposable-util';
32
32
  import { MonacoLanguages } from '@theia/monaco/lib/browser/monaco-languages';
33
33
  import * as monaco from '@theia/monaco-editor-core';
34
34
  import { TextDocumentChangeReason } from '../../plugin/types-impl';
35
+ import { NotebookDocumentsMainImpl } from './notebooks/notebook-documents-main';
35
36
 
36
37
  /*---------------------------------------------------------------------------------------------
37
38
  * Copyright (c) Microsoft Corporation. All rights reserved.
@@ -90,6 +91,7 @@ export class DocumentsMainImpl implements DocumentsMain, Disposable {
90
91
 
91
92
  constructor(
92
93
  editorsAndDocuments: EditorsAndDocumentsMain,
94
+ notebookDocuments: NotebookDocumentsMainImpl,
93
95
  private readonly modelService: EditorModelService,
94
96
  rpc: RPCProtocol,
95
97
  private editorManager: EditorManager,
@@ -105,6 +107,8 @@ export class DocumentsMainImpl implements DocumentsMain, Disposable {
105
107
  this.toDispose.push(editorsAndDocuments.onDocumentRemove(documents => documents.forEach(this.onModelRemoved, this)));
106
108
  this.toDispose.push(modelService.onModelModeChanged(this.onModelChanged, this));
107
109
 
110
+ this.toDispose.push(notebookDocuments.onDidAddNotebookCellModel(this.onModelAdded, this));
111
+
108
112
  this.toDispose.push(modelService.onModelSaved(m => {
109
113
  this.proxy.$acceptModelSaved(m.textEditorModel.uri);
110
114
  }));
@@ -1434,7 +1434,6 @@ export function toMonacoWorkspaceEdit(data: WorkspaceEditDto | undefined): monac
1434
1434
  metadata: fileEdit.metadata
1435
1435
  };
1436
1436
  }
1437
- // TODO implement WorkspaceNotebookCellEditDto
1438
1437
  })
1439
1438
  };
1440
1439
  }
@@ -44,7 +44,6 @@ import { EditorManager } from '@theia/editor/lib/browser';
44
44
  import { EditorModelService } from './text-editor-model-service';
45
45
  import { OpenerService } from '@theia/core/lib/browser/opener-service';
46
46
  import { ApplicationShell } from '@theia/core/lib/browser/shell/application-shell';
47
- import { MonacoBulkEditService } from '@theia/monaco/lib/browser/monaco-bulk-edit-service';
48
47
  import { MainFileSystemEventService } from './main-file-system-event-service';
49
48
  import { LabelServiceMainImpl } from './label-service-main';
50
49
  import { TimelineMainImpl } from './timeline-main';
@@ -59,10 +58,8 @@ import { UntitledResourceResolver } from '@theia/core/lib/common/resource';
59
58
  import { ThemeService } from '@theia/core/lib/browser/theming';
60
59
  import { TabsMainImpl } from './tabs/tabs-main';
61
60
  import { NotebooksMainImpl } from './notebooks/notebooks-main';
62
- import { NotebookService } from '@theia/notebook/lib/browser';
63
61
  import { LocalizationMainImpl } from './localization-main';
64
62
  import { NotebookRenderersMainImpl } from './notebooks/notebook-renderers-main';
65
- import { HostedPluginSupport } from '../../hosted/browser/hosted-plugin';
66
63
  import { NotebookEditorsMainImpl } from './notebooks/notebook-editors-main';
67
64
  import { NotebookDocumentsMainImpl } from './notebooks/notebook-documents-main';
68
65
  import { NotebookKernelsMainImpl } from './notebooks/notebook-kernels-main';
@@ -93,28 +90,27 @@ export function setUpPluginApi(rpc: RPCProtocol, container: interfaces.Container
93
90
 
94
91
  const editorsAndDocuments = new EditorsAndDocumentsMain(rpc, container);
95
92
 
93
+ const notebookDocumentsMain = new NotebookDocumentsMainImpl(rpc, container);
94
+ rpc.set(PLUGIN_RPC_CONTEXT.NOTEBOOK_DOCUMENTS_MAIN, notebookDocumentsMain);
95
+
96
96
  const modelService = container.get(EditorModelService);
97
97
  const editorManager = container.get(EditorManager);
98
98
  const openerService = container.get<OpenerService>(OpenerService);
99
99
  const shell = container.get(ApplicationShell);
100
100
  const untitledResourceResolver = container.get(UntitledResourceResolver);
101
101
  const languageService = container.get(MonacoLanguages);
102
- const documentsMain = new DocumentsMainImpl(editorsAndDocuments, modelService, rpc, editorManager, openerService, shell, untitledResourceResolver, languageService);
102
+ const documentsMain = new DocumentsMainImpl(editorsAndDocuments, notebookDocumentsMain, modelService, rpc,
103
+ editorManager, openerService, shell, untitledResourceResolver, languageService);
103
104
  rpc.set(PLUGIN_RPC_CONTEXT.DOCUMENTS_MAIN, documentsMain);
104
105
 
105
- const notebookService = container.get(NotebookService);
106
- const pluginSupport = container.get(HostedPluginSupport);
107
- rpc.set(PLUGIN_RPC_CONTEXT.NOTEBOOKS_MAIN, new NotebooksMainImpl(rpc, notebookService, pluginSupport));
106
+ rpc.set(PLUGIN_RPC_CONTEXT.NOTEBOOKS_MAIN, new NotebooksMainImpl(rpc, container, commandRegistryMain));
108
107
  rpc.set(PLUGIN_RPC_CONTEXT.NOTEBOOK_RENDERERS_MAIN, new NotebookRenderersMainImpl(rpc, container));
109
108
  const notebookEditorsMain = new NotebookEditorsMainImpl(rpc, container);
110
109
  rpc.set(PLUGIN_RPC_CONTEXT.NOTEBOOK_EDITORS_MAIN, notebookEditorsMain);
111
- const notebookDocumentsMain = new NotebookDocumentsMainImpl(rpc, container);
112
- rpc.set(PLUGIN_RPC_CONTEXT.NOTEBOOK_DOCUMENTS_MAIN, notebookDocumentsMain);
113
110
  rpc.set(PLUGIN_RPC_CONTEXT.NOTEBOOK_DOCUMENTS_AND_EDITORS_MAIN, new NotebooksAndEditorsMain(rpc, container, notebookDocumentsMain, notebookEditorsMain));
114
111
  rpc.set(PLUGIN_RPC_CONTEXT.NOTEBOOK_KERNELS_MAIN, new NotebookKernelsMainImpl(rpc, container));
115
112
 
116
- const bulkEditService = container.get(MonacoBulkEditService);
117
- const editorsMain = new TextEditorsMainImpl(editorsAndDocuments, documentsMain, rpc, bulkEditService);
113
+ const editorsMain = new TextEditorsMainImpl(editorsAndDocuments, documentsMain, rpc, container);
118
114
  rpc.set(PLUGIN_RPC_CONTEXT.TEXT_EDITORS_MAIN, editorsMain);
119
115
 
120
116
  // start listening only after all clients are subscribed to events
@@ -14,24 +14,28 @@
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
16
 
17
- import { DisposableCollection } from '@theia/core';
17
+ import { DisposableCollection, Event } from '@theia/core';
18
18
  import { URI, UriComponents } from '@theia/core/lib/common/uri';
19
19
  import { interfaces } from '@theia/core/shared/inversify';
20
20
  import { NotebookModelResolverService } from '@theia/notebook/lib/browser';
21
21
  import { NotebookModel } from '@theia/notebook/lib/browser/view-model/notebook-model';
22
22
  import { NotebookCellsChangeType } from '@theia/notebook/lib/common';
23
+ import { NotebookMonacoTextModelService } from '@theia/notebook/lib/browser/service/notebook-monaco-text-model-service';
23
24
  import { MAIN_RPC_CONTEXT, NotebookCellsChangedEventDto, NotebookDataDto, NotebookDocumentsExt, NotebookDocumentsMain } from '../../../common';
24
25
  import { RPCProtocol } from '../../../common/rpc-protocol';
25
26
  import { NotebookDto } from './notebook-dto';
27
+ import { MonacoEditorModel } from '@theia/monaco/lib/browser/monaco-editor-model';
26
28
 
27
29
  export class NotebookDocumentsMainImpl implements NotebookDocumentsMain {
28
30
 
29
- private readonly disposables = new DisposableCollection();
31
+ protected readonly disposables = new DisposableCollection();
30
32
 
31
- private readonly proxy: NotebookDocumentsExt;
32
- private readonly documentEventListenersMapping = new Map<string, DisposableCollection>();
33
+ protected readonly proxy: NotebookDocumentsExt;
34
+ protected readonly documentEventListenersMapping = new Map<string, DisposableCollection>();
33
35
 
34
- private readonly notebookModelResolverService: NotebookModelResolverService;
36
+ protected readonly notebookModelResolverService: NotebookModelResolverService;
37
+
38
+ protected notebookMonacoTextModelService: NotebookMonacoTextModelService;
35
39
 
36
40
  constructor(
37
41
  rpc: RPCProtocol,
@@ -44,6 +48,11 @@ export class NotebookDocumentsMainImpl implements NotebookDocumentsMain {
44
48
  this.disposables.push(this.notebookModelResolverService.onDidChangeDirty(model => this.proxy.$acceptDirtyStateChanged(model.uri.toComponents(), model.isDirty())));
45
49
  this.disposables.push(this.notebookModelResolverService.onDidSaveNotebook(e => this.proxy.$acceptModelSaved(e)));
46
50
 
51
+ this.notebookMonacoTextModelService = container.get(NotebookMonacoTextModelService) as NotebookMonacoTextModelService;
52
+ }
53
+
54
+ get onDidAddNotebookCellModel(): Event<MonacoEditorModel> {
55
+ return this.notebookMonacoTextModelService.onDidCreateNotebookCellModel;
47
56
  }
48
57
 
49
58
  dispose(): void {
@@ -102,6 +111,12 @@ export class NotebookDocumentsMainImpl implements NotebookDocumentsMain {
102
111
  case NotebookCellsChangeType.ChangeCellInternalMetadata:
103
112
  eventDto.rawEvents.push(e);
104
113
  break;
114
+ case NotebookCellsChangeType.ChangeDocumentMetadata:
115
+ eventDto.rawEvents.push({
116
+ kind: e.kind,
117
+ metadata: e.metadata
118
+ });
119
+ break;
105
120
  }
106
121
  }
107
122
 
@@ -27,7 +27,6 @@ import {
27
27
  CellExecution, NotebookEditorWidgetService, NotebookExecutionStateService,
28
28
  NotebookKernelChangeEvent, NotebookKernelService, NotebookService
29
29
  } from '@theia/notebook/lib/browser';
30
- import { combinedDisposable } from '@theia/monaco-editor-core/esm/vs/base/common/lifecycle';
31
30
  import { interfaces } from '@theia/core/shared/inversify';
32
31
  import { NotebookKernelSourceAction } from '@theia/notebook/lib/common';
33
32
  import { NotebookDto } from './notebook-dto';
@@ -153,6 +152,20 @@ export class NotebookKernelsMainImpl implements NotebookKernelsMain {
153
152
  }
154
153
  });
155
154
  });
155
+ this.notebookKernelService.onDidChangeSelectedKernel(e => {
156
+ if (e.newKernel) {
157
+ const newKernelHandle = Array.from(this.kernels.entries()).find(([_, [kernel]]) => kernel.id === e.newKernel)?.[0];
158
+ if (newKernelHandle !== undefined) {
159
+ this.proxy.$acceptNotebookAssociation(newKernelHandle, e.notebook.toComponents(), true);
160
+ }
161
+ } else {
162
+ const oldKernelHandle = Array.from(this.kernels.entries()).find(([_, [kernel]]) => kernel.id === e.oldKernel)?.[0];
163
+ if (oldKernelHandle !== undefined) {
164
+ this.proxy.$acceptNotebookAssociation(oldKernelHandle, e.notebook.toComponents(), false);
165
+ }
166
+
167
+ }
168
+ });
156
169
  }
157
170
 
158
171
  async $postMessage(handle: number, editorId: string | undefined, message: unknown): Promise<boolean> {
@@ -196,16 +209,8 @@ export class NotebookKernelsMainImpl implements NotebookKernelsMain {
196
209
  }
197
210
  }(handle, data, this.languageService);
198
211
 
199
- const listener = this.notebookKernelService.onDidChangeSelectedKernel(e => {
200
- if (e.oldKernel === kernel.id) {
201
- this.proxy.$acceptNotebookAssociation(handle, e.notebook.toComponents(), false);
202
- } else if (e.newKernel === kernel.id) {
203
- this.proxy.$acceptNotebookAssociation(handle, e.notebook.toComponents(), true);
204
- }
205
- });
206
-
207
212
  const registration = this.notebookKernelService.registerKernel(kernel);
208
- this.kernels.set(handle, [kernel, combinedDisposable(listener, registration)]);
213
+ this.kernels.set(handle, [kernel, registration]);
209
214
 
210
215
  }
211
216
 
@@ -14,16 +14,19 @@
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
16
 
17
- import { CancellationToken, DisposableCollection, Emitter, Event } from '@theia/core';
17
+ import { CancellationToken, DisposableCollection, Emitter, Event, URI } from '@theia/core';
18
18
  import { BinaryBuffer } from '@theia/core/lib/common/buffer';
19
- import { NotebookCellStatusBarItem, NotebookData, TransientOptions } from '@theia/notebook/lib/common';
20
- import { NotebookService } from '@theia/notebook/lib/browser';
19
+ import { CellEditType, NotebookCellModelResource, NotebookCellStatusBarItem, NotebookData, NotebookModelResource, TransientOptions } from '@theia/notebook/lib/common';
20
+ import { NotebookService, NotebookWorkspaceEdit } from '@theia/notebook/lib/browser';
21
21
  import { Disposable } from '@theia/plugin';
22
- import { MAIN_RPC_CONTEXT, NotebooksExt, NotebooksMain } from '../../../common';
22
+ import { CommandRegistryMain, MAIN_RPC_CONTEXT, NotebooksExt, NotebooksMain, WorkspaceEditDto, WorkspaceNotebookCellEditDto } from '../../../common';
23
23
  import { RPCProtocol } from '../../../common/rpc-protocol';
24
24
  import { NotebookDto } from './notebook-dto';
25
25
  import { UriComponents } from '@theia/core/lib/common/uri';
26
26
  import { HostedPluginSupport } from '../../../hosted/browser/hosted-plugin';
27
+ import { NotebookModel } from '@theia/notebook/lib/browser/view-model/notebook-model';
28
+ import { NotebookCellModel } from '@theia/notebook/lib/browser/view-model/notebook-cell-model';
29
+ import { interfaces } from '@theia/core/shared/inversify';
27
30
 
28
31
  export interface NotebookCellStatusBarItemList {
29
32
  items: NotebookCellStatusBarItem[];
@@ -38,20 +41,35 @@ export interface NotebookCellStatusBarItemProvider {
38
41
 
39
42
  export class NotebooksMainImpl implements NotebooksMain {
40
43
 
41
- private readonly disposables = new DisposableCollection();
44
+ protected readonly disposables = new DisposableCollection();
42
45
 
43
- private readonly proxy: NotebooksExt;
44
- private readonly notebookSerializer = new Map<number, Disposable>();
45
- private readonly notebookCellStatusBarRegistrations = new Map<number, Disposable>();
46
+ protected notebookService: NotebookService;
47
+
48
+ protected readonly proxy: NotebooksExt;
49
+ protected readonly notebookSerializer = new Map<number, Disposable>();
50
+ protected readonly notebookCellStatusBarRegistrations = new Map<number, Disposable>();
46
51
 
47
52
  constructor(
48
53
  rpc: RPCProtocol,
49
- private notebookService: NotebookService,
50
- plugins: HostedPluginSupport
54
+ container: interfaces.Container,
55
+ commands: CommandRegistryMain
51
56
  ) {
57
+ this.notebookService = container.get(NotebookService);
58
+ const plugins = container.get(HostedPluginSupport);
59
+
52
60
  this.proxy = rpc.getProxy(MAIN_RPC_CONTEXT.NOTEBOOKS_EXT);
53
- notebookService.onWillUseNotebookSerializer(async event => plugins.activateByNotebookSerializer(event));
54
- notebookService.markReady();
61
+ this.notebookService.onWillUseNotebookSerializer(async event => plugins.activateByNotebookSerializer(event));
62
+ this.notebookService.markReady();
63
+ commands.registerArgumentProcessor({
64
+ processArgument: arg => {
65
+ if (arg instanceof NotebookModel) {
66
+ return NotebookModelResource.create(arg.uri);
67
+ } else if (arg instanceof NotebookCellModel) {
68
+ return NotebookCellModelResource.create(arg.uri);
69
+ }
70
+ return arg;
71
+ }
72
+ });
55
73
  }
56
74
 
57
75
  dispose(): void {
@@ -133,3 +151,14 @@ export class NotebooksMainImpl implements NotebooksMain {
133
151
  }
134
152
  }
135
153
 
154
+ export function toNotebookWorspaceEdit(dto: WorkspaceEditDto): NotebookWorkspaceEdit {
155
+ return {
156
+ edits: dto.edits.map((edit: WorkspaceNotebookCellEditDto) => ({
157
+ resource: URI.fromComponents(edit.resource),
158
+ edit: edit.cellEdit.editType === CellEditType.Replace ? {
159
+ ...edit.cellEdit,
160
+ cells: edit.cellEdit.cells.map(cell => NotebookDto.fromNotebookCellDataDto(cell))
161
+ } : edit.cellEdit
162
+ }))
163
+ };
164
+ }
@@ -99,6 +99,7 @@ export class CellOutputWebviewImpl implements CellOutputWebview, Disposable {
99
99
 
100
100
  if (this.editor) {
101
101
  this.toDispose.push(this.editor.onDidPostKernelMessage(message => {
102
+ // console.log('from extension customKernelMessage ', JSON.stringify(message));
102
103
  this.webviewWidget.sendMessage({
103
104
  type: 'customKernelMessage',
104
105
  message
@@ -106,6 +107,7 @@ export class CellOutputWebviewImpl implements CellOutputWebview, Disposable {
106
107
  }));
107
108
 
108
109
  this.toDispose.push(this.editor.onPostRendererMessage(messageObj => {
110
+ // console.log('from extension customRendererMessage ', JSON.stringify(messageObj));
109
111
  this.webviewWidget.sendMessage({
110
112
  type: 'customRendererMessage',
111
113
  ...messageObj
@@ -188,15 +190,17 @@ export class CellOutputWebviewImpl implements CellOutputWebview, Disposable {
188
190
  this.updateOutput({ newOutputs: this.cell.outputs, start: 0, deleteCount: 0 });
189
191
  break;
190
192
  case 'customRendererMessage':
193
+ // console.log('from webview customRendererMessage ', message.rendererId, '', JSON.stringify(message.message));
191
194
  this.messagingService.getScoped(this.editor.id).postMessage(message.rendererId, message.message);
192
195
  break;
193
196
  case 'didRenderOutput':
194
197
  this.webviewWidget.setIframeHeight(message.contentHeight + 5);
195
198
  break;
196
199
  case 'did-scroll-wheel':
197
- this.editor.node.children[0].children[1].scrollBy(message.deltaX, message.deltaY);
200
+ this.editor.node.getElementsByClassName('theia-notebook-viewport')[0].children[0].scrollBy(message.deltaX, message.deltaY);
198
201
  break;
199
202
  case 'customKernelMessage':
203
+ // console.log('from webview customKernelMessage ', JSON.stringify(message.message));
200
204
  this.editor.recieveKernelMessage(message.message);
201
205
  break;
202
206
  }
@@ -573,5 +573,13 @@ export async function outputWebviewPreload(ctx: PreloadContext): Promise<void> {
573
573
  });
574
574
  window.addEventListener('wheel', handleWheel);
575
575
 
576
+ (document.head as HTMLHeadElement & { originalAppendChild: typeof document.head.appendChild }).originalAppendChild = document.head.appendChild;
577
+ (document.head as HTMLHeadElement & { originalAppendChild: typeof document.head.appendChild }).appendChild = function appendChild<T extends Node>(node: T): T {
578
+ if (node instanceof HTMLScriptElement && node.src.includes('webviewuuid')) {
579
+ node.src = node.src.replace('webviewuuid', location.hostname.split('.')[0]);
580
+ }
581
+ return this.originalAppendChild(node);
582
+ };
583
+
576
584
  theia.postMessage(<webviewCommunication.WebviewInitialized>{ type: 'initialized' });
577
585
  }
@@ -90,6 +90,7 @@ import { CellOutputWebviewImpl, createCellOutputWebviewContainer } from './noteb
90
90
  import { NotebookCellModel } from '@theia/notebook/lib/browser/view-model/notebook-cell-model';
91
91
  import { NotebookModel } from '@theia/notebook/lib/browser/view-model/notebook-model';
92
92
  import { ArgumentProcessorContribution } from './command-registry-main';
93
+ import { WebviewSecondaryWindowSupport } from './webview/webview-secondary-window-support';
93
94
 
94
95
  export default new ContainerModule((bind, unbind, isBound, rebind) => {
95
96
 
@@ -187,6 +188,8 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
187
188
  bind(WebviewWidgetFactory).toDynamicValue(ctx => new WebviewWidgetFactory(ctx.container)).inSingletonScope();
188
189
  bind(WidgetFactory).toService(WebviewWidgetFactory);
189
190
  bind(WebviewContextKeys).toSelf().inSingletonScope();
191
+ bind(WebviewSecondaryWindowSupport).toSelf().inSingletonScope();
192
+ bind(FrontendApplicationContribution).toService(WebviewSecondaryWindowSupport);
190
193
  bind(FrontendApplicationContribution).toService(WebviewContextKeys);
191
194
 
192
195
  bind(CustomEditorContribution).toSelf().inSingletonScope();
@@ -30,6 +30,13 @@ import { getIconClass } from '../../plugin/terminal-ext';
30
30
  import { PluginTerminalRegistry } from './plugin-terminal-registry';
31
31
  import { CancellationToken } from '@theia/core';
32
32
  import { HostedPluginSupport } from '../../hosted/browser/hosted-plugin';
33
+ import debounce = require('@theia/core/shared/lodash.debounce');
34
+
35
+ interface TerminalObserverData {
36
+ nrOfLinesToMatch: number;
37
+ outputMatcherRegex: RegExp
38
+ disposables: DisposableCollection;
39
+ }
33
40
 
34
41
  /**
35
42
  * Plugin api service allows working with terminal emulator.
@@ -46,6 +53,7 @@ export class TerminalServiceMainImpl implements TerminalServiceMain, TerminalLin
46
53
  private readonly terminalLinkProviders: string[] = [];
47
54
 
48
55
  private readonly toDispose = new DisposableCollection();
56
+ private readonly observers = new Map<string, TerminalObserverData>();
49
57
 
50
58
  constructor(rpc: RPCProtocol, container: interfaces.Container) {
51
59
  this.terminals = container.get(TerminalService);
@@ -121,6 +129,8 @@ export class TerminalServiceMainImpl implements TerminalServiceMain, TerminalLin
121
129
  this.extProxy.$terminalOnInput(terminal.id, data);
122
130
  this.extProxy.$terminalStateChanged(terminal.id);
123
131
  }));
132
+
133
+ this.observers.forEach((observer, id) => this.observeTerminal(id, terminal, observer));
124
134
  }
125
135
 
126
136
  $write(id: string, data: string): void {
@@ -293,6 +303,42 @@ export class TerminalServiceMainImpl implements TerminalServiceMain, TerminalLin
293
303
  }
294
304
  }
295
305
 
306
+ $registerTerminalObserver(id: string, nrOfLinesToMatch: number, outputMatcherRegex: string): void {
307
+ const observerData = {
308
+ nrOfLinesToMatch: nrOfLinesToMatch,
309
+ outputMatcherRegex: new RegExp(outputMatcherRegex, 'm'),
310
+ disposables: new DisposableCollection()
311
+ };
312
+ this.observers.set(id, observerData);
313
+ this.terminals.all.forEach(terminal => {
314
+ this.observeTerminal(id, terminal, observerData);
315
+ });
316
+ }
317
+
318
+ protected observeTerminal(observerId: string, terminal: TerminalWidget, observerData: TerminalObserverData): void {
319
+ const doMatch = debounce(() => {
320
+ const lineCount = Math.min(observerData.nrOfLinesToMatch, terminal.buffer.length);
321
+ const lines = terminal.buffer.getLines(terminal.buffer.length - lineCount, lineCount);
322
+ const result = lines.join('\n').match(observerData.outputMatcherRegex);
323
+ if (result) {
324
+ this.extProxy.$reportOutputMatch(observerId, result.map(value => value));
325
+ }
326
+ });
327
+ observerData.disposables.push(terminal.onOutput(output => {
328
+ doMatch();
329
+ }));
330
+ }
331
+
332
+ $unregisterTerminalObserver(id: string): void {
333
+ const observer = this.observers.get(id);
334
+ if (observer) {
335
+ observer.disposables.dispose();
336
+ this.observers.delete(id);
337
+ } else {
338
+ throw new Error(`Unregistering unknown terminal observer: ${id}`);
339
+ }
340
+ }
341
+
296
342
  async provideLinks(line: string, terminal: TerminalWidget, cancellationToken?: CancellationToken | undefined): Promise<TerminalLink[]> {
297
343
  if (this.terminalLinkProviders.length < 1) {
298
344
  return [];
@@ -151,7 +151,7 @@ export class TextEditorMain implements Disposable {
151
151
  }
152
152
 
153
153
  if (typeof newConfiguration.lineNumbers !== 'undefined') {
154
- let lineNumbers: 'on' | 'off' | 'relative';
154
+ let lineNumbers: 'on' | 'off' | 'relative' | 'interval';
155
155
  switch (newConfiguration.lineNumbers) {
156
156
  case TextEditorLineNumbersStyle.On:
157
157
  lineNumbers = 'on';
@@ -159,6 +159,9 @@ export class TextEditorMain implements Disposable {
159
159
  case TextEditorLineNumbersStyle.Relative:
160
160
  lineNumbers = 'relative';
161
161
  break;
162
+ case TextEditorLineNumbersStyle.Interval:
163
+ lineNumbers = 'interval';
164
+ break;
162
165
  default:
163
166
  lineNumbers = 'off';
164
167
  }
@@ -400,6 +403,9 @@ export class TextEditorPropertiesMain {
400
403
  case monaco.editor.RenderLineNumbersType.Relative:
401
404
  lineNumbers = TextEditorLineNumbersStyle.Relative;
402
405
  break;
406
+ case monaco.editor.RenderLineNumbersType.Interval:
407
+ lineNumbers = TextEditorLineNumbersStyle.Interval;
408
+ break;
403
409
  default:
404
410
  lineNumbers = TextEditorLineNumbersStyle.On;
405
411
  break;
@@ -28,6 +28,7 @@ import {
28
28
  ThemeDecorationInstanceRenderOptions,
29
29
  DecorationOptions,
30
30
  WorkspaceEditDto,
31
+ WorkspaceNotebookCellEditDto,
31
32
  DocumentsMain,
32
33
  WorkspaceEditMetadataDto,
33
34
  } from '../../common/plugin-api-rpc';
@@ -46,7 +47,10 @@ import { ResourceEdit } from '@theia/monaco-editor-core/esm/vs/editor/browser/se
46
47
  import { IDecorationRenderOptions } from '@theia/monaco-editor-core/esm/vs/editor/common/editorCommon';
47
48
  import { StandaloneServices } from '@theia/monaco-editor-core/esm/vs/editor/standalone/browser/standaloneServices';
48
49
  import { ICodeEditorService } from '@theia/monaco-editor-core/esm/vs/editor/browser/services/codeEditorService';
49
- import { URI } from '@theia/core';
50
+ import { ArrayUtils, URI } from '@theia/core';
51
+ import { toNotebookWorspaceEdit } from './notebooks/notebooks-main';
52
+ import { interfaces } from '@theia/core/shared/inversify';
53
+ import { NotebookService } from '@theia/notebook/lib/browser';
50
54
 
51
55
  export class TextEditorsMainImpl implements TextEditorsMain, Disposable {
52
56
 
@@ -55,13 +59,20 @@ export class TextEditorsMainImpl implements TextEditorsMain, Disposable {
55
59
  private readonly editorsToDispose = new Map<string, DisposableCollection>();
56
60
  private readonly fileEndpoint = new Endpoint({ path: 'file' }).getRestUrl();
57
61
 
62
+ private readonly bulkEditService: MonacoBulkEditService;
63
+ private readonly notebookService: NotebookService;
64
+
58
65
  constructor(
59
66
  private readonly editorsAndDocuments: EditorsAndDocumentsMain,
60
67
  private readonly documents: DocumentsMain,
61
68
  rpc: RPCProtocol,
62
- private readonly bulkEditService: MonacoBulkEditService,
69
+ container: interfaces.Container
63
70
  ) {
64
71
  this.proxy = rpc.getProxy(MAIN_RPC_CONTEXT.TEXT_EDITORS_EXT);
72
+
73
+ this.bulkEditService = container.get(MonacoBulkEditService);
74
+ this.notebookService = container.get(NotebookService);
75
+
65
76
  this.toDispose.push(editorsAndDocuments);
66
77
  this.toDispose.push(editorsAndDocuments.onTextEditorAdd(editors => editors.forEach(this.onTextEditorAdd, this)));
67
78
  this.toDispose.push(editorsAndDocuments.onTextEditorRemove(editors => editors.forEach(this.onTextEditorRemove, this)));
@@ -128,11 +139,19 @@ export class TextEditorsMainImpl implements TextEditorsMain, Disposable {
128
139
  }
129
140
 
130
141
  async $tryApplyWorkspaceEdit(dto: WorkspaceEditDto, metadata?: WorkspaceEditMetadataDto): Promise<boolean> {
131
- const workspaceEdit = toMonacoWorkspaceEdit(dto);
142
+ const [notebookEdits, monacoEdits] = ArrayUtils.partition(dto.edits, edit => WorkspaceNotebookCellEditDto.is(edit));
132
143
  try {
133
- const edits = ResourceEdit.convert(workspaceEdit);
134
- const { isApplied } = await this.bulkEditService.apply(edits, { respectAutoSaveConfig: metadata?.isRefactoring });
135
- return isApplied;
144
+ if (notebookEdits.length > 0) {
145
+ const workspaceEdit = toNotebookWorspaceEdit({ edits: notebookEdits });
146
+ return this.notebookService.applyWorkspaceEdit(workspaceEdit);
147
+ }
148
+ if (monacoEdits.length > 0) {
149
+ const workspaceEdit = toMonacoWorkspaceEdit({ edits: monacoEdits });
150
+ const edits = ResourceEdit.convert(workspaceEdit);
151
+ const { isApplied } = await this.bulkEditService.apply(edits, { respectAutoSaveConfig: metadata?.isRefactoring });
152
+ return isApplied;
153
+ }
154
+ return false;
136
155
  } catch {
137
156
  return false;
138
157
  }
@@ -146,7 +146,7 @@
146
146
  */
147
147
  function getDefaultScript(state) {
148
148
  return `
149
- const acquireVsCodeApi = (function() {
149
+ globalThis.acquireVsCodeApi = (function() {
150
150
  const originalPostMessage = window.parent.postMessage.bind(window.parent);
151
151
  const originalConsole = {...console};
152
152
  const targetOrigin = '*';
@@ -198,7 +198,7 @@ const acquireVsCodeApi = (function() {
198
198
  });
199
199
  };
200
200
  })();
201
- const acquireTheiaApi = acquireVsCodeApi;
201
+ globalThis.acquireTheiaApi = acquireVsCodeApi;
202
202
  delete window.parent;
203
203
  delete window.top;
204
204
  delete window.frameElement;
@@ -0,0 +1,47 @@
1
+ // *****************************************************************************
2
+ // Copyright (C) 2024 STMicroelectronics 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 { MaybePromise } from '@theia/core/lib/common';
18
+ import { FrontendApplication, FrontendApplicationContribution } from '@theia/core/lib/browser';
19
+ import { inject, injectable } from '@theia/core/shared/inversify';
20
+ import { SecondaryWindowHandler } from '@theia/core/lib/browser/secondary-window-handler';
21
+ import { WebviewWidget } from './webview';
22
+
23
+ @injectable()
24
+ export class WebviewSecondaryWindowSupport implements FrontendApplicationContribution {
25
+ @inject(SecondaryWindowHandler)
26
+ protected readonly secondaryWindowHandler: SecondaryWindowHandler;
27
+
28
+ onStart(app: FrontendApplication): MaybePromise<void> {
29
+ this.secondaryWindowHandler.onDidAddWidget(([widget, win]) => {
30
+ if (widget instanceof WebviewWidget) {
31
+ const script = win.document.createElement('script');
32
+ script.text = `
33
+ window.addEventListener('message', e => {
34
+ // Only process messages from Theia main window
35
+ if (e.source === window.opener) {
36
+ // Delegate message to iframe
37
+ const frame = window.document.getElementsByTagName('iframe').item(0);
38
+ if (frame) {
39
+ frame.contentWindow?.postMessage({ ...e.data }, '*');
40
+ }
41
+ }
42
+ }); `;
43
+ win.document.head.append(script);
44
+ }
45
+ });
46
+ }
47
+ }
@@ -41,7 +41,7 @@ export class DialogsExtImpl {
41
41
  if (result) {
42
42
  const uris = [];
43
43
  for (let i = 0; i < result.length; i++) {
44
- const uri = URI.parse('file://' + result[i]);
44
+ const uri = URI.file(result[i]);
45
45
  uris.push(uri);
46
46
  }
47
47
  resolve(uris);