@theia/plugin-ext 1.48.3 → 1.49.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/lib/common/plugin-api-rpc-model.d.ts +2 -2
  2. package/lib/common/plugin-api-rpc-model.d.ts.map +1 -1
  3. package/lib/common/plugin-protocol.d.ts +2 -0
  4. package/lib/common/plugin-protocol.d.ts.map +1 -1
  5. package/lib/common/plugin-protocol.js.map +1 -1
  6. package/lib/hosted/browser/hosted-plugin.d.ts.map +1 -1
  7. package/lib/hosted/browser/hosted-plugin.js +1 -0
  8. package/lib/hosted/browser/hosted-plugin.js.map +1 -1
  9. package/lib/hosted/node/scanners/scanner-theia.d.ts +1 -1
  10. package/lib/hosted/node/scanners/scanner-theia.d.ts.map +1 -1
  11. package/lib/hosted/node/scanners/scanner-theia.js +2 -2
  12. package/lib/hosted/node/scanners/scanner-theia.js.map +1 -1
  13. package/lib/main/browser/custom-editors/plugin-custom-editor-registry.d.ts +4 -8
  14. package/lib/main/browser/custom-editors/plugin-custom-editor-registry.d.ts.map +1 -1
  15. package/lib/main/browser/custom-editors/plugin-custom-editor-registry.js +18 -33
  16. package/lib/main/browser/custom-editors/plugin-custom-editor-registry.js.map +1 -1
  17. package/lib/main/browser/menus/plugin-menu-command-adapter.d.ts +1 -0
  18. package/lib/main/browser/menus/plugin-menu-command-adapter.d.ts.map +1 -1
  19. package/lib/main/browser/menus/plugin-menu-command-adapter.js +38 -0
  20. package/lib/main/browser/menus/plugin-menu-command-adapter.js.map +1 -1
  21. package/lib/main/browser/menus/vscode-theia-menu-mappings.d.ts +2 -2
  22. package/lib/main/browser/menus/vscode-theia-menu-mappings.d.ts.map +1 -1
  23. package/lib/main/browser/menus/vscode-theia-menu-mappings.js +3 -0
  24. package/lib/main/browser/menus/vscode-theia-menu-mappings.js.map +1 -1
  25. package/lib/main/browser/notebooks/notebook-dto.js +1 -1
  26. package/lib/main/browser/notebooks/notebook-dto.js.map +1 -1
  27. package/lib/main/browser/notebooks/notebook-kernels-main.d.ts.map +1 -1
  28. package/lib/main/browser/notebooks/notebook-kernels-main.js +8 -1
  29. package/lib/main/browser/notebooks/notebook-kernels-main.js.map +1 -1
  30. package/lib/main/browser/notebooks/renderers/cell-output-webview.d.ts.map +1 -1
  31. package/lib/main/browser/notebooks/renderers/cell-output-webview.js +14 -1
  32. package/lib/main/browser/notebooks/renderers/cell-output-webview.js.map +1 -1
  33. package/lib/main/browser/notebooks/renderers/output-webview-internal.js +5 -5
  34. package/lib/main/browser/notebooks/renderers/output-webview-internal.js.map +1 -1
  35. package/lib/main/browser/plugin-contribution-handler.js +4 -4
  36. package/lib/main/browser/plugin-contribution-handler.js.map +1 -1
  37. package/lib/main/browser/view/plugin-view-registry.d.ts +6 -0
  38. package/lib/main/browser/view/plugin-view-registry.d.ts.map +1 -1
  39. package/lib/main/browser/view/plugin-view-registry.js +44 -27
  40. package/lib/main/browser/view/plugin-view-registry.js.map +1 -1
  41. package/lib/main/node/plugin-deployer-impl.d.ts.map +1 -1
  42. package/lib/main/node/plugin-deployer-impl.js +22 -9
  43. package/lib/main/node/plugin-deployer-impl.js.map +1 -1
  44. package/lib/plugin/authentication-ext.d.ts.map +1 -1
  45. package/lib/plugin/authentication-ext.js +9 -0
  46. package/lib/plugin/authentication-ext.js.map +1 -1
  47. package/lib/plugin/notebook/notebook-document.d.ts +1 -3
  48. package/lib/plugin/notebook/notebook-document.d.ts.map +1 -1
  49. package/lib/plugin/notebook/notebook-document.js +2 -16
  50. package/lib/plugin/notebook/notebook-document.js.map +1 -1
  51. package/lib/plugin/notebook/notebooks.d.ts.map +1 -1
  52. package/lib/plugin/notebook/notebooks.js +12 -10
  53. package/lib/plugin/notebook/notebooks.js.map +1 -1
  54. package/lib/plugin/plugin-context.d.ts.map +1 -1
  55. package/lib/plugin/plugin-context.js +8 -1
  56. package/lib/plugin/plugin-context.js.map +1 -1
  57. package/lib/plugin/tests.d.ts +4 -0
  58. package/lib/plugin/tests.d.ts.map +1 -1
  59. package/lib/plugin/tests.js +4 -0
  60. package/lib/plugin/tests.js.map +1 -1
  61. package/lib/plugin/type-converters.js +3 -2
  62. package/lib/plugin/type-converters.js.map +1 -1
  63. package/lib/plugin/types-impl.d.ts +65 -7
  64. package/lib/plugin/types-impl.d.ts.map +1 -1
  65. package/lib/plugin/types-impl.js +120 -6
  66. package/lib/plugin/types-impl.js.map +1 -1
  67. package/package.json +29 -29
  68. package/src/common/plugin-api-rpc-model.ts +2 -2
  69. package/src/common/plugin-protocol.ts +2 -0
  70. package/src/hosted/browser/hosted-plugin.ts +1 -0
  71. package/src/hosted/node/scanners/scanner-theia.ts +2 -2
  72. package/src/main/browser/custom-editors/plugin-custom-editor-registry.ts +14 -36
  73. package/src/main/browser/menus/plugin-menu-command-adapter.ts +39 -0
  74. package/src/main/browser/menus/vscode-theia-menu-mappings.ts +3 -0
  75. package/src/main/browser/notebooks/notebook-dto.ts +1 -1
  76. package/src/main/browser/notebooks/notebook-kernels-main.ts +9 -2
  77. package/src/main/browser/notebooks/renderers/cell-output-webview.tsx +14 -1
  78. package/src/main/browser/notebooks/renderers/output-webview-internal.ts +5 -5
  79. package/src/main/browser/plugin-contribution-handler.ts +4 -4
  80. package/src/main/browser/view/plugin-view-registry.ts +52 -27
  81. package/src/main/browser/webview/pre/host.js +1 -1
  82. package/src/main/node/plugin-deployer-impl.ts +20 -9
  83. package/src/plugin/authentication-ext.ts +11 -0
  84. package/src/plugin/notebook/notebook-document.ts +2 -17
  85. package/src/plugin/notebook/notebooks.ts +16 -12
  86. package/src/plugin/plugin-context.ts +16 -2
  87. package/src/plugin/tests.ts +5 -0
  88. package/src/plugin/type-converters.ts +5 -5
  89. package/src/plugin/types-impl.ts +114 -14
@@ -21,6 +21,9 @@ import { URI as CodeUri } from '@theia/core/shared/vscode-uri';
21
21
  import { TreeWidgetSelection } from '@theia/core/lib/browser/tree/tree-widget-selection';
22
22
  import { ScmRepository } from '@theia/scm/lib/browser/scm-repository';
23
23
  import { ScmService } from '@theia/scm/lib/browser/scm-service';
24
+ import { DirtyDiffWidget } from '@theia/scm/lib/browser/dirty-diff/dirty-diff-widget';
25
+ import { Change, LineRange } from '@theia/scm/lib/browser/dirty-diff/diff-computer';
26
+ import { IChange } from '@theia/monaco-editor-core/esm/vs/editor/common/diff/legacyLinesDiffComputer';
24
27
  import { TimelineItem } from '@theia/timeline/lib/common/timeline-model';
25
28
  import { ScmCommandArg, TimelineCommandArg, TreeViewItemReference } from '../../../common';
26
29
  import { TestItemReference, TestMessageArg } from '../../../common/test-types';
@@ -105,6 +108,7 @@ export class PluginMenuCommandAdapter implements MenuCommandAdapter {
105
108
  ['scm/resourceState/context', toScmArgs],
106
109
  ['scm/title', () => [this.toScmArg(this.scmService.selectedRepository)]],
107
110
  ['testing/message/context', toTestMessageArgs],
111
+ ['scm/change/title', (...args) => this.toScmChangeArgs(...args)],
108
112
  ['timeline/item/context', (...args) => this.toTimelineArgs(...args)],
109
113
  ['view/item/context', (...args) => this.toTreeArgs(...args)],
110
114
  ['view/title', noArgs],
@@ -229,6 +233,41 @@ export class PluginMenuCommandAdapter implements MenuCommandAdapter {
229
233
  }
230
234
  }
231
235
 
236
+ protected toScmChangeArgs(...args: any[]): any[] {
237
+ const arg = args[0];
238
+ if (arg instanceof DirtyDiffWidget) {
239
+ const toIChange = (change: Change): IChange => {
240
+ const convert = (range: LineRange): [number, number] => {
241
+ let startLineNumber;
242
+ let endLineNumber;
243
+ if (!LineRange.isEmpty(range)) {
244
+ startLineNumber = range.start + 1;
245
+ endLineNumber = range.end;
246
+ } else {
247
+ startLineNumber = range.start;
248
+ endLineNumber = 0;
249
+ }
250
+ return [startLineNumber, endLineNumber];
251
+ };
252
+ const { previousRange, currentRange } = change;
253
+ const [originalStartLineNumber, originalEndLineNumber] = convert(previousRange);
254
+ const [modifiedStartLineNumber, modifiedEndLineNumber] = convert(currentRange);
255
+ return {
256
+ originalStartLineNumber,
257
+ originalEndLineNumber,
258
+ modifiedStartLineNumber,
259
+ modifiedEndLineNumber
260
+ };
261
+ };
262
+ return [
263
+ arg.uri['codeUri'],
264
+ arg.changes.map(toIChange),
265
+ arg.currentChangeIndex
266
+ ];
267
+ }
268
+ return [];
269
+ }
270
+
232
271
  protected toTimelineArgs(...args: any[]): any[] {
233
272
  const timelineArgs: any[] = [];
234
273
  const arg = args[0];
@@ -26,6 +26,7 @@ import { DebugVariablesWidget } from '@theia/debug/lib/browser/view/debug-variab
26
26
  import { EditorWidget, EDITOR_CONTEXT_MENU } from '@theia/editor/lib/browser';
27
27
  import { NAVIGATOR_CONTEXT_MENU } from '@theia/navigator/lib/browser/navigator-contribution';
28
28
  import { ScmTreeWidget } from '@theia/scm/lib/browser/scm-tree-widget';
29
+ import { PLUGIN_SCM_CHANGE_TITLE_MENU } from '@theia/scm/lib/browser/dirty-diff/dirty-diff-widget';
29
30
  import { TIMELINE_ITEM_CONTEXT_MENU } from '@theia/timeline/lib/browser/timeline-tree-widget';
30
31
  import { COMMENT_CONTEXT, COMMENT_THREAD_CONTEXT, COMMENT_TITLE } from '../comments/comment-thread-widget';
31
32
  import { VIEW_ITEM_CONTEXT_MENU } from '../view/tree-view-widget';
@@ -53,6 +54,7 @@ export const implementedVSCodeContributionPoints = [
53
54
  'editor/title/run',
54
55
  'editor/lineNumber/context',
55
56
  'explorer/context',
57
+ 'scm/change/title',
56
58
  'scm/resourceFolder/context',
57
59
  'scm/resourceGroup/context',
58
60
  'scm/resourceState/context',
@@ -84,6 +86,7 @@ export const codeToTheiaMappings = new Map<ContributionPoint, MenuPath[]>([
84
86
  ['editor/title/run', [PLUGIN_EDITOR_TITLE_RUN_MENU]],
85
87
  ['editor/lineNumber/context', [EDITOR_LINENUMBER_CONTEXT_MENU]],
86
88
  ['explorer/context', [NAVIGATOR_CONTEXT_MENU]],
89
+ ['scm/change/title', [PLUGIN_SCM_CHANGE_TITLE_MENU]],
87
90
  ['scm/resourceFolder/context', [ScmTreeWidget.RESOURCE_FOLDER_CONTEXT_MENU]],
88
91
  ['scm/resourceGroup/context', [ScmTreeWidget.RESOURCE_GROUP_CONTEXT_MENU]],
89
92
  ['scm/resourceState/context', [ScmTreeWidget.RESOURCE_CONTEXT_MENU]],
@@ -94,7 +94,7 @@ export namespace NotebookDto {
94
94
  return {
95
95
  handle: cell.handle,
96
96
  uri: cell.uri.toComponents(),
97
- source: cell.text.split(eol),
97
+ source: cell.text.split(/\r?\n/g),
98
98
  eol,
99
99
  language: cell.language,
100
100
  cellKind: cell.cellKind,
@@ -145,7 +145,7 @@ export class NotebookKernelsMainImpl implements NotebookKernelsMain {
145
145
  this.notebookEditorWidgetService = container.get(NotebookEditorWidgetService);
146
146
 
147
147
  this.notebookEditorWidgetService.onDidAddNotebookEditor(editor => {
148
- editor.onDidRecieveKernelMessage(async message => {
148
+ editor.onDidReceiveKernelMessage(async message => {
149
149
  const kernel = this.notebookKernelService.getSelectedOrSuggestedKernel(editor.model!);
150
150
  if (kernel) {
151
151
  this.proxy.$acceptKernelMessageFromRenderer(kernel.handle, editor.id, message);
@@ -209,9 +209,16 @@ export class NotebookKernelsMainImpl implements NotebookKernelsMain {
209
209
  }
210
210
  }(handle, data, this.languageService);
211
211
 
212
+ // this is for when a kernel is bound to a notebook while being registered
213
+ const autobindListener = this.notebookKernelService.onDidChangeSelectedKernel(e => {
214
+ if (e.newKernel === kernel.id) {
215
+ this.proxy.$acceptNotebookAssociation(handle, e.notebook.toComponents(), true);
216
+ }
217
+ });
218
+
212
219
  const registration = this.notebookKernelService.registerKernel(kernel);
213
220
  this.kernels.set(handle, [kernel, registration]);
214
-
221
+ autobindListener.dispose();
215
222
  }
216
223
 
217
224
  $updateKernel(handle: number, data: Partial<NotebookKernelDto>): void {
@@ -117,7 +117,20 @@ export class CellOutputWebviewImpl implements CellOutputWebview, Disposable {
117
117
  }
118
118
 
119
119
  this.webviewWidget = await this.widgetManager.getOrCreateWidget(WebviewWidget.FACTORY_ID, { id: this.id });
120
- this.webviewWidget.setContentOptions({ allowScripts: true });
120
+ this.webviewWidget.setContentOptions({
121
+ allowScripts: true,
122
+ // eslint-disable-next-line max-len
123
+ // list taken from https://github.com/microsoft/vscode/blob/a27099233b956dddc2536d4a0d714ab36266d897/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts#L762-L774
124
+ enableCommandUris: [
125
+ 'github-issues.authNow',
126
+ 'workbench.extensions.search',
127
+ 'workbench.action.openSettings',
128
+ '_notebook.selectKernel',
129
+ 'jupyter.viewOutput',
130
+ 'workbench.action.openLargeOutput',
131
+ 'cellOutput.enableScrolling',
132
+ ]
133
+ });
121
134
  this.webviewWidget.setHTML(await this.createWebviewContent());
122
135
 
123
136
  this.webviewWidget.onMessage((message: FromWebviewMessage) => {
@@ -553,11 +553,11 @@ export async function outputWebviewPreload(ctx: PreloadContext): Promise<void> {
553
553
  renderers.getRenderer(event.data.rendererId)?.receiveMessage(event.data.message);
554
554
  break;
555
555
  case 'changePreferredMimetype':
556
- const outputId = event.data.outputId;
557
- const index = outputs.findIndex(output => output.outputId === outputId);
558
- outputs.splice(index, 1);
559
- clearOutput(outputs.splice(index, 1)[0]);
560
- renderers.render(outputs[index], event.data.mimeType, undefined, new AbortController().signal);
556
+ const mimeType = event.data.mimeType;
557
+ outputs.forEach(output => {
558
+ output.element.innerHTML = '';
559
+ renderers.render(output, mimeType, undefined, new AbortController().signal);
560
+ });
561
561
  break;
562
562
  case 'customKernelMessage':
563
563
  onDidReceiveKernelMessage.fire(event.data.message);
@@ -288,7 +288,7 @@ export class PluginContributionHandler {
288
288
  if (contributions.customEditors) {
289
289
  for (const customEditor of contributions.customEditors) {
290
290
  pushContribution(`customEditors.${customEditor.viewType}`,
291
- () => this.customEditorRegistry.registerCustomEditor(customEditor)
291
+ () => this.customEditorRegistry.registerCustomEditor(customEditor, plugin)
292
292
  );
293
293
  }
294
294
  }
@@ -434,7 +434,7 @@ export class PluginContributionHandler {
434
434
  if (contributions.notebooks) {
435
435
  for (const notebook of contributions.notebooks) {
436
436
  pushContribution(`notebook.${notebook.type}`,
437
- () => this.notebookTypeRegistry.registerNotebookType(notebook)
437
+ () => this.notebookTypeRegistry.registerNotebookType(notebook, plugin.metadata.model.displayName)
438
438
  );
439
439
  }
440
440
  }
@@ -463,7 +463,7 @@ export class PluginContributionHandler {
463
463
  return Disposable.NULL;
464
464
  }
465
465
  const toDispose = new DisposableCollection();
466
- for (const { iconUrl, themeIcon, command, category, title, originalTitle, enablement } of contribution.commands) {
466
+ for (const { iconUrl, themeIcon, command, category, shortTitle, title, originalTitle, enablement } of contribution.commands) {
467
467
  const reference = iconUrl && this.style.toIconClass(iconUrl);
468
468
  const icon = themeIcon && ThemeIcon.fromString(themeIcon);
469
469
  let iconClass;
@@ -473,7 +473,7 @@ export class PluginContributionHandler {
473
473
  } else if (icon) {
474
474
  iconClass = ThemeIcon.asClassName(icon);
475
475
  }
476
- toDispose.push(this.registerCommand({ id: command, category, label: title, originalLabel: originalTitle, iconClass }, enablement));
476
+ toDispose.push(this.registerCommand({ id: command, category, shortTitle, label: title, originalLabel: originalTitle, iconClass }, enablement));
477
477
  }
478
478
  return toDispose;
479
479
  }
@@ -55,6 +55,13 @@ export const PLUGIN_VIEW_DATA_FACTORY_ID = 'plugin-view-data';
55
55
 
56
56
  export type ViewDataProvider = (params: { state?: object, viewInfo: View }) => Promise<TreeViewWidget>;
57
57
 
58
+ export interface ViewContainerInfo {
59
+ id: string
60
+ location: string
61
+ options: ViewContainerTitleOptions
62
+ onViewAdded: () => void
63
+ }
64
+
58
65
  @injectable()
59
66
  export class PluginViewRegistry implements FrontendApplicationContribution {
60
67
 
@@ -96,7 +103,7 @@ export class PluginViewRegistry implements FrontendApplicationContribution {
96
103
 
97
104
  private readonly views = new Map<string, [string, View]>();
98
105
  private readonly viewsWelcome = new Map<string, ViewWelcome[]>();
99
- private readonly viewContainers = new Map<string, [string, ViewContainerTitleOptions]>();
106
+ private readonly viewContainers = new Map<string, ViewContainerInfo>();
100
107
  private readonly containerViews = new Map<string, string[]>();
101
108
  private readonly viewClauseContexts = new Map<string, Set<string> | undefined>();
102
109
 
@@ -324,34 +331,47 @@ export class PluginViewRegistry implements FrontendApplicationContribution {
324
331
 
325
332
  protected doRegisterViewContainer(id: string, location: string, options: ViewContainerTitleOptions): Disposable {
326
333
  const toDispose = new DisposableCollection();
327
- this.viewContainers.set(id, [location, options]);
328
334
  toDispose.push(Disposable.create(() => this.viewContainers.delete(id)));
329
335
  const toggleCommandId = `plugin.view-container.${id}.toggle`;
330
- toDispose.push(this.commands.registerCommand({
331
- id: toggleCommandId,
332
- label: 'Toggle ' + options.label + ' View'
333
- }, {
334
- execute: () => this.toggleViewContainer(id)
335
- }));
336
- toDispose.push(this.menus.registerMenuAction(CommonMenus.VIEW_VIEWS, {
337
- commandId: toggleCommandId,
338
- label: options.label
339
- }));
340
- toDispose.push(this.quickView?.registerItem({
341
- label: options.label,
342
- open: async () => {
343
- const widget = await this.openViewContainer(id);
336
+ // Some plugins may register empty view containers.
337
+ // We should not register commands for them immediately, as that leads to bad UX.
338
+ // Instead, we register commands the first time we add a view to them.
339
+ let activate = () => {
340
+ toDispose.push(this.commands.registerCommand({
341
+ id: toggleCommandId,
342
+ category: nls.localizeByDefault('View'),
343
+ label: nls.localizeByDefault('Toggle {0}', options.label)
344
+ }, {
345
+ execute: () => this.toggleViewContainer(id)
346
+ }));
347
+ toDispose.push(this.menus.registerMenuAction(CommonMenus.VIEW_VIEWS, {
348
+ commandId: toggleCommandId,
349
+ label: options.label
350
+ }));
351
+ toDispose.push(this.quickView?.registerItem({
352
+ label: options.label,
353
+ open: async () => {
354
+ const widget = await this.openViewContainer(id);
355
+ if (widget) {
356
+ this.shell.activateWidget(widget.id);
357
+ }
358
+ }
359
+ }));
360
+ toDispose.push(Disposable.create(async () => {
361
+ const widget = await this.getPluginViewContainer(id);
344
362
  if (widget) {
345
- this.shell.activateWidget(widget.id);
363
+ widget.dispose();
346
364
  }
347
- }
348
- }));
349
- toDispose.push(Disposable.create(async () => {
350
- const widget = await this.getPluginViewContainer(id);
351
- if (widget) {
352
- widget.dispose();
353
- }
354
- }));
365
+ }));
366
+ // Ignore every subsequent activation call
367
+ activate = () => { };
368
+ };
369
+ this.viewContainers.set(id, {
370
+ id,
371
+ location,
372
+ options,
373
+ onViewAdded: () => activate()
374
+ });
355
375
  return toDispose;
356
376
  }
357
377
 
@@ -374,6 +394,11 @@ export class PluginViewRegistry implements FrontendApplicationContribution {
374
394
  this.views.set(view.id, [viewContainerId, view]);
375
395
  toDispose.push(Disposable.create(() => this.views.delete(view.id)));
376
396
 
397
+ const containerInfo = this.viewContainers.get(viewContainerId);
398
+ if (containerInfo) {
399
+ containerInfo.onViewAdded();
400
+ }
401
+
377
402
  const containerViews = this.getContainerViews(viewContainerId);
378
403
  containerViews.push(view.id);
379
404
  this.containerViews.set(viewContainerId, containerViews);
@@ -634,7 +659,7 @@ export class PluginViewRegistry implements FrontendApplicationContribution {
634
659
  if (!data) {
635
660
  return undefined;
636
661
  }
637
- const [location] = data;
662
+ const { location } = data;
638
663
  const containerWidget = await this.getOrCreateViewContainerWidget(containerId);
639
664
  if (!containerWidget.isAttached) {
640
665
  await this.shell.addWidget(containerWidget, {
@@ -648,7 +673,7 @@ export class PluginViewRegistry implements FrontendApplicationContribution {
648
673
  protected async prepareViewContainer(viewContainerId: string, containerWidget: ViewContainerWidget): Promise<void> {
649
674
  const data = this.viewContainers.get(viewContainerId);
650
675
  if (data) {
651
- const [, options] = data;
676
+ const { options } = data;
652
677
  containerWidget.setTitleOptions(options);
653
678
  }
654
679
  for (const viewId of this.getContainerViews(viewContainerId)) {
@@ -31,7 +31,7 @@
31
31
  let sourceIsChildFrame = false;
32
32
  for (let i = 0; i < window.frames.length; i++) {
33
33
  const frame = window.frames[i];
34
- if (e.source === frame) {
34
+ if (e.origin === frame.origin) {
35
35
  sourceIsChildFrame = true;
36
36
  break;
37
37
  }
@@ -225,8 +225,20 @@ export class PluginDeployerImpl implements PluginDeployer {
225
225
  }
226
226
 
227
227
  protected async resolveAndHandle(id: string, type: PluginType, options?: PluginDeployOptions): Promise<PluginDeployerEntry[]> {
228
- const entries = await this.resolvePlugin(id, type, options);
229
- await this.applyFileHandlers(entries);
228
+ let entries = await this.resolvePlugin(id, type, options);
229
+ if (type === PluginType.User) {
230
+ await this.applyFileHandlers(entries);
231
+ } else {
232
+ const filteredEntries: PluginDeployerEntry[] = [];
233
+ for (const entry of entries) {
234
+ if (await entry.isFile()) {
235
+ this.logger.warn(`Only user plugins will be handled by file handlers, please unpack the plugin '${entry.id()}' manually.`);
236
+ } else {
237
+ filteredEntries.push(entry);
238
+ }
239
+ }
240
+ entries = filteredEntries;
241
+ }
230
242
  await this.applyDirectoryFileHandlers(entries);
231
243
  return entries;
232
244
  }
@@ -286,13 +298,12 @@ export class PluginDeployerImpl implements PluginDeployer {
286
298
  const pluginPaths = [...acceptedBackendPlugins, ...acceptedHeadlessPlugins].map(pluginEntry => pluginEntry.path());
287
299
  this.logger.debug('local path to deploy on remote instance', pluginPaths);
288
300
 
289
- const deployments = await Promise.all([
290
- // headless plugins are deployed like backend plugins
291
- this.pluginDeployerHandler.deployBackendPlugins(acceptedHeadlessPlugins),
292
- // start the backend plugins
293
- this.pluginDeployerHandler.deployBackendPlugins(acceptedBackendPlugins),
294
- this.pluginDeployerHandler.deployFrontendPlugins(acceptedFrontendPlugins)
295
- ]);
301
+ const deployments = [];
302
+ // start the backend plugins
303
+ deployments.push(await this.pluginDeployerHandler.deployBackendPlugins(acceptedBackendPlugins));
304
+ // headless plugins are deployed like backend plugins
305
+ deployments.push(await this.pluginDeployerHandler.deployBackendPlugins(acceptedHeadlessPlugins));
306
+ deployments.push(await this.pluginDeployerHandler.deployFrontendPlugins(acceptedFrontendPlugins));
296
307
  this.onDidDeployEmitter.fire(undefined);
297
308
  return deployments.reduce<number>((accumulated, current) => accumulated += current ?? 0, 0);
298
309
  }
@@ -63,6 +63,17 @@ export class AuthenticationExtImpl implements AuthenticationExt {
63
63
  }
64
64
 
65
65
  this.authenticationProviders.set(id, provider);
66
+
67
+ provider.getSessions().then(sessions => { // sessions might have been restored from secret storage
68
+ if (sessions.length > 0) {
69
+ this.proxy.$onDidChangeSessions(id, {
70
+ added: sessions,
71
+ removed: [],
72
+ changed: []
73
+ });
74
+ }
75
+ });
76
+
66
77
  const listener = provider.onDidChangeSessions(e => {
67
78
  this.proxy.$onDidChangeSessions(id, e);
68
79
  });
@@ -26,7 +26,6 @@ import { Disposable, URI } from '@theia/core';
26
26
  import * as typeConverters from '../type-converters';
27
27
  import { ModelAddedData, NotebookCellDto, NotebookCellsChangedEventDto, NotebookModelAddedData, NotebookOutputDto } from '../../common';
28
28
  import { NotebookRange } from '../types-impl';
29
- import { UriComponents } from '../../common/uri-components';
30
29
  import { DocumentsExtImpl } from '../documents';
31
30
 
32
31
  class RawContentChangeEvent {
@@ -49,7 +48,7 @@ class RawContentChangeEvent {
49
48
 
50
49
  export class Cell {
51
50
 
52
- static asModelAddData(notebook: theia.NotebookDocument, cell: NotebookCellDto): ModelAddedData & { notebook: theia.NotebookDocument } {
51
+ static asModelAddData(cell: NotebookCellDto): ModelAddedData {
53
52
  return {
54
53
  EOL: cell.eol,
55
54
  lines: cell.source,
@@ -57,7 +56,6 @@ export class Cell {
57
56
  uri: cell.uri,
58
57
  isDirty: false,
59
58
  versionId: 1,
60
- notebook,
61
59
  modeId: ''
62
60
  };
63
61
  }
@@ -348,8 +346,6 @@ export class NotebookDocument implements Disposable {
348
346
  }
349
347
 
350
348
  const contentChangeEvents: RawContentChangeEvent[] = [];
351
- const addedCellDocuments: ModelAddedData[] = [];
352
- const removedCellDocuments: UriComponents[] = [];
353
349
 
354
350
  splices.reverse().forEach(splice => {
355
351
  const cellDtos = splice.newItems;
@@ -357,18 +353,8 @@ export class NotebookDocument implements Disposable {
357
353
 
358
354
  const extCell = new Cell(this, this.editorsAndDocuments, cell);
359
355
  if (!initialization) {
360
- addedCellDocuments.push(Cell.asModelAddData(this.apiNotebook, cell));
361
356
  this.editorsAndDocuments.$acceptEditorsAndDocumentsDelta({
362
- addedDocuments: [
363
- {
364
- uri: cell.uri,
365
- versionId: 1,
366
- lines: cell.source,
367
- EOL: cell.eol,
368
- modeId: '',
369
- isDirty: false
370
- }
371
- ]
357
+ addedDocuments: [Cell.asModelAddData(cell)]
372
358
  });
373
359
  }
374
360
  return extCell;
@@ -377,7 +363,6 @@ export class NotebookDocument implements Disposable {
377
363
  const changeEvent = new RawContentChangeEvent(splice.start, splice.deleteCount, [], newCells);
378
364
  const deletedItems = this.cells.splice(splice.start, splice.deleteCount, ...newCells);
379
365
  for (const cell of deletedItems) {
380
- removedCellDocuments.push(cell.uri.toComponents());
381
366
  changeEvent.deletedItems.push(cell.apiCell);
382
367
  }
383
368
  contentChangeEvents.push(changeEvent);
@@ -22,7 +22,7 @@ import { CancellationToken, Disposable, DisposableCollection, Emitter, Event, UR
22
22
  import { URI as TheiaURI } from '../types-impl';
23
23
  import * as theia from '@theia/plugin';
24
24
  import {
25
- CommandRegistryExt, NotebookCellStatusBarListDto, NotebookDataDto,
25
+ CommandRegistryExt, ModelAddedData, NotebookCellStatusBarListDto, NotebookDataDto,
26
26
  NotebookDocumentsAndEditorsDelta, NotebookDocumentShowOptions, NotebookDocumentsMain, NotebookEditorAddData, NotebookEditorsMain, NotebooksExt, NotebooksMain, Plugin,
27
27
  PLUGIN_RPC_CONTEXT
28
28
  } from '../../common';
@@ -32,7 +32,7 @@ import { UriComponents } from '../../common/uri-components';
32
32
  import { CommandsConverter } from '../command-registry';
33
33
  import * as typeConverters from '../type-converters';
34
34
  import { BinaryBuffer } from '@theia/core/lib/common/buffer';
35
- import { NotebookDocument } from './notebook-document';
35
+ import { Cell, NotebookDocument } from './notebook-document';
36
36
  import { NotebookEditor } from './notebook-editor';
37
37
  import { EditorsAndDocumentsExtImpl } from '../editors-and-documents';
38
38
  import { DocumentsExtImpl } from '../documents';
@@ -204,6 +204,8 @@ export class NotebooksExtImpl implements NotebooksExt {
204
204
  }
205
205
 
206
206
  async $acceptDocumentsAndEditorsDelta(delta: NotebookDocumentsAndEditorsDelta): Promise<void> {
207
+ const removedCellDocuments: UriComponents[] = [];
208
+ const addedCellDocuments: ModelAddedData[] = [];
207
209
  if (delta.removedDocuments) {
208
210
  for (const uri of delta.removedDocuments) {
209
211
  const revivedUri = URI.fromComponents(uri);
@@ -213,6 +215,7 @@ export class NotebooksExtImpl implements NotebooksExt {
213
215
  document.dispose();
214
216
  this.documents.delete(revivedUri.toString());
215
217
  this.onDidCloseNotebookDocumentEmitter.fire(document.apiNotebook);
218
+ removedCellDocuments.push(...document.apiNotebook.getCells().map(cell => cell.document.uri));
216
219
  }
217
220
 
218
221
  for (const editor of this.editors.values()) {
@@ -223,6 +226,11 @@ export class NotebooksExtImpl implements NotebooksExt {
223
226
  }
224
227
  }
225
228
 
229
+ // publish all removed cell documents first
230
+ await this.textDocumentsAndEditors.$acceptEditorsAndDocumentsDelta({
231
+ removedDocuments: removedCellDocuments
232
+ });
233
+
226
234
  if (delta.addedDocuments) {
227
235
  for (const modelData of delta.addedDocuments) {
228
236
  const uri = TheiaURI.from(modelData.uri);
@@ -242,21 +250,17 @@ export class NotebooksExtImpl implements NotebooksExt {
242
250
  this.documents.get(uri.toString())?.dispose();
243
251
  this.documents.set(uri.toString(), document);
244
252
 
245
- this.textDocumentsAndEditors.$acceptEditorsAndDocumentsDelta({
246
- addedDocuments: modelData.cells.map(cell => ({
247
- uri: cell.uri,
248
- versionId: 1,
249
- lines: cell.source,
250
- EOL: cell.eol,
251
- modeId: '',
252
- isDirty: false
253
- }))
254
- });
253
+ addedCellDocuments.push(...modelData.cells.map(cell => Cell.asModelAddData(cell)));
255
254
 
256
255
  this.onDidOpenNotebookDocumentEmitter.fire(document.apiNotebook);
257
256
  }
258
257
  }
259
258
 
259
+ // publish all added cell documents in a separate call
260
+ await this.textDocumentsAndEditors.$acceptEditorsAndDocumentsDelta({
261
+ addedDocuments: addedCellDocuments
262
+ });
263
+
260
264
  if (delta.addedEditors) {
261
265
  for (const editorModelData of delta.addedEditors) {
262
266
  if (this.editors.has(editorModelData.id)) {
@@ -198,12 +198,19 @@ import {
198
198
  TextMergeTabInput,
199
199
  WebviewEditorTabInput,
200
200
  DocumentPasteEdit,
201
+ DocumentPasteEditKind,
202
+ DocumentPasteTriggerKind,
201
203
  ExternalUriOpenerPriority,
202
204
  EditSessionIdentityMatch,
203
205
  TerminalOutputAnchor,
204
206
  TerminalQuickFixTerminalCommand,
205
207
  TerminalQuickFixOpener,
206
- TestResultState
208
+ TestResultState,
209
+ BranchCoverage,
210
+ DeclarationCoverage,
211
+ FileCoverage,
212
+ StatementCoverage,
213
+ TestCoverageCount
207
214
  } from './types-impl';
208
215
  import { AuthenticationExtImpl } from './authentication-ext';
209
216
  import { SymbolKind } from '../common/plugin-api-rpc-model';
@@ -1398,11 +1405,18 @@ export function createAPIFactory(
1398
1405
  TerminalOutputAnchor,
1399
1406
  TerminalExitReason,
1400
1407
  DocumentPasteEdit,
1408
+ DocumentPasteEditKind,
1409
+ DocumentPasteTriggerKind,
1401
1410
  ExternalUriOpenerPriority,
1402
1411
  TerminalQuickFixTerminalCommand,
1403
1412
  TerminalQuickFixOpener,
1404
1413
  EditSessionIdentityMatch,
1405
- TestResultState
1414
+ TestResultState,
1415
+ BranchCoverage,
1416
+ DeclarationCoverage,
1417
+ FileCoverage,
1418
+ StatementCoverage,
1419
+ TestCoverageCount
1406
1420
  };
1407
1421
  };
1408
1422
  }
@@ -240,6 +240,8 @@ class TestRun implements theia.TestRun {
240
240
  onDidEnd: Event<void> = this.onDidEndEmitter.event;
241
241
  private onWillFlushEmitter = new Emitter<void>();
242
242
  onWillFlush: Event<void> = this.onWillFlushEmitter.event;
243
+ private onDidDisposeEmitter = new Emitter<void>();
244
+ onDidDispose: Event<void> = this.onDidDisposeEmitter.event;
243
245
 
244
246
  readonly id: string;
245
247
  private testStateDeltas = new Map<theia.TestItem, TestStateChangeDTO>();
@@ -293,6 +295,9 @@ class TestRun implements theia.TestRun {
293
295
  this.proxy.$notifyTestRunEnded(this.controller.id, this.id);
294
296
  }
295
297
 
298
+ /** @stubbed */
299
+ addCoverage(fileCoverage: theia.FileCoverage): void { }
300
+
296
301
  private checkNotEnded(test: theia.TestItem): boolean {
297
302
  if (this.ended) {
298
303
  console.warn(`Setting the state of test "${test.id}" is a no - op after the run ends.`);
@@ -749,9 +749,9 @@ export function isUriComponents(arg: unknown): arg is UriComponents {
749
749
  return isObject<UriComponents>(arg) &&
750
750
  typeof arg.scheme === 'string' &&
751
751
  (arg['$mid'] === 1 || (
752
- typeof arg.path === 'string' &&
753
- typeof arg.query === 'string' &&
754
- typeof arg.fragment === 'string'));
752
+ typeof arg.path === 'string' &&
753
+ typeof arg.query === 'string' &&
754
+ typeof arg.fragment === 'string'));
755
755
  }
756
756
 
757
757
  export function isModelCallHierarchyItem(arg: unknown): arg is model.CallHierarchyItem {
@@ -1522,8 +1522,8 @@ export namespace NotebookCellData {
1522
1522
  cellKind: NotebookCellKind.from(data.kind),
1523
1523
  language: data.languageId,
1524
1524
  source: data.value,
1525
- // metadata: data.metadata,
1526
- // internalMetadata: NotebookCellExecutionSummary.from(data.executionSummary ?? {}),
1525
+ metadata: data.metadata,
1526
+ internalMetadata: NotebookCellExecutionSummary.from(data.executionSummary ?? {}),
1527
1527
  outputs: data.outputs ? data.outputs.map(NotebookCellOutputConverter.from) : []
1528
1528
  };
1529
1529
  }