@theia/plugin-ext 1.44.0 → 1.45.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 (115) hide show
  1. package/lib/common/plugin-api-rpc.d.ts +2 -1
  2. package/lib/common/plugin-api-rpc.d.ts.map +1 -1
  3. package/lib/common/plugin-api-rpc.js.map +1 -1
  4. package/lib/common/proxy-handler.d.ts.map +1 -1
  5. package/lib/common/proxy-handler.js +3 -1
  6. package/lib/common/proxy-handler.js.map +1 -1
  7. package/lib/common/test-types.d.ts +9 -0
  8. package/lib/common/test-types.d.ts.map +1 -1
  9. package/lib/common/test-types.js +36 -1
  10. package/lib/common/test-types.js.map +1 -1
  11. package/lib/hosted/browser/hosted-plugin.d.ts +2 -0
  12. package/lib/hosted/browser/hosted-plugin.d.ts.map +1 -1
  13. package/lib/hosted/browser/hosted-plugin.js +54 -6
  14. package/lib/hosted/browser/hosted-plugin.js.map +1 -1
  15. package/lib/hosted/node/plugin-activation-events.d.ts.map +1 -1
  16. package/lib/hosted/node/plugin-activation-events.js +1 -1
  17. package/lib/hosted/node/plugin-activation-events.js.map +1 -1
  18. package/lib/main/browser/debug/plugin-debug-service.d.ts.map +1 -1
  19. package/lib/main/browser/debug/plugin-debug-service.js +7 -0
  20. package/lib/main/browser/debug/plugin-debug-service.js.map +1 -1
  21. package/lib/main/browser/menus/plugin-menu-command-adapter.d.ts +1 -0
  22. package/lib/main/browser/menus/plugin-menu-command-adapter.d.ts.map +1 -1
  23. package/lib/main/browser/menus/plugin-menu-command-adapter.js +30 -0
  24. package/lib/main/browser/menus/plugin-menu-command-adapter.js.map +1 -1
  25. package/lib/main/browser/menus/vscode-theia-menu-mappings.d.ts +2 -2
  26. package/lib/main/browser/menus/vscode-theia-menu-mappings.d.ts.map +1 -1
  27. package/lib/main/browser/menus/vscode-theia-menu-mappings.js +6 -1
  28. package/lib/main/browser/menus/vscode-theia-menu-mappings.js.map +1 -1
  29. package/lib/main/browser/notebooks/notebook-documents-and-editors-main.d.ts +4 -2
  30. package/lib/main/browser/notebooks/notebook-documents-and-editors-main.d.ts.map +1 -1
  31. package/lib/main/browser/notebooks/notebook-documents-and-editors-main.js +34 -21
  32. package/lib/main/browser/notebooks/notebook-documents-and-editors-main.js.map +1 -1
  33. package/lib/main/browser/notebooks/notebook-documents-main.d.ts.map +1 -1
  34. package/lib/main/browser/notebooks/notebook-documents-main.js +8 -9
  35. package/lib/main/browser/notebooks/notebook-documents-main.js.map +1 -1
  36. package/lib/main/browser/notebooks/notebook-dto.d.ts +3 -0
  37. package/lib/main/browser/notebooks/notebook-dto.d.ts.map +1 -1
  38. package/lib/main/browser/notebooks/notebook-dto.js +27 -34
  39. package/lib/main/browser/notebooks/notebook-dto.js.map +1 -1
  40. package/lib/main/browser/notebooks/notebook-kernels-main.js +3 -3
  41. package/lib/main/browser/notebooks/notebook-kernels-main.js.map +1 -1
  42. package/lib/main/browser/notebooks/notebooks-main.d.ts +12 -1
  43. package/lib/main/browser/notebooks/notebooks-main.d.ts.map +1 -1
  44. package/lib/main/browser/notebooks/notebooks-main.js.map +1 -1
  45. package/lib/main/browser/notebooks/renderers/cell-output-webview.d.ts +1 -2
  46. package/lib/main/browser/notebooks/renderers/cell-output-webview.d.ts.map +1 -1
  47. package/lib/main/browser/notebooks/renderers/cell-output-webview.js +1 -1
  48. package/lib/main/browser/notebooks/renderers/cell-output-webview.js.map +1 -1
  49. package/lib/main/browser/plugin-shared-style.d.ts.map +1 -1
  50. package/lib/main/browser/plugin-shared-style.js +3 -2
  51. package/lib/main/browser/plugin-shared-style.js.map +1 -1
  52. package/lib/main/browser/webview/webview.d.ts +13 -1
  53. package/lib/main/browser/webview/webview.d.ts.map +1 -1
  54. package/lib/main/browser/webview/webview.js +28 -1
  55. package/lib/main/browser/webview/webview.js.map +1 -1
  56. package/lib/main/node/plugin-deployer-contribution.d.ts.map +1 -1
  57. package/lib/main/node/plugin-deployer-contribution.js +2 -1
  58. package/lib/main/node/plugin-deployer-contribution.js.map +1 -1
  59. package/lib/main/node/plugin-deployer-impl.d.ts.map +1 -1
  60. package/lib/main/node/plugin-deployer-impl.js +2 -1
  61. package/lib/main/node/plugin-deployer-impl.js.map +1 -1
  62. package/lib/plugin/command-registry.d.ts.map +1 -1
  63. package/lib/plugin/command-registry.js +9 -3
  64. package/lib/plugin/command-registry.js.map +1 -1
  65. package/lib/plugin/notebook/notebook-document.js +3 -3
  66. package/lib/plugin/notebook/notebook-document.js.map +1 -1
  67. package/lib/plugin/notebook/notebooks.d.ts.map +1 -1
  68. package/lib/plugin/notebook/notebooks.js +7 -4
  69. package/lib/plugin/notebook/notebooks.js.map +1 -1
  70. package/lib/plugin/plugin-manager.d.ts +1 -1
  71. package/lib/plugin/plugin-manager.d.ts.map +1 -1
  72. package/lib/plugin/plugin-manager.js +3 -23
  73. package/lib/plugin/plugin-manager.js.map +1 -1
  74. package/lib/plugin/tests.d.ts +6 -1
  75. package/lib/plugin/tests.d.ts.map +1 -1
  76. package/lib/plugin/tests.js +22 -0
  77. package/lib/plugin/tests.js.map +1 -1
  78. package/lib/plugin/type-converters.d.ts +1 -12
  79. package/lib/plugin/type-converters.d.ts.map +1 -1
  80. package/lib/plugin/type-converters.js +3 -121
  81. package/lib/plugin/type-converters.js.map +1 -1
  82. package/lib/plugin/types-impl.d.ts +1 -0
  83. package/lib/plugin/types-impl.d.ts.map +1 -1
  84. package/lib/plugin/types-impl.js.map +1 -1
  85. package/lib/plugin/window-state.d.ts.map +1 -1
  86. package/lib/plugin/window-state.js +3 -4
  87. package/lib/plugin/window-state.js.map +1 -1
  88. package/package.json +29 -29
  89. package/src/common/plugin-api-rpc.ts +2 -1
  90. package/src/common/proxy-handler.ts +3 -1
  91. package/src/common/test-types.ts +20 -0
  92. package/src/hosted/browser/hosted-plugin.ts +51 -6
  93. package/src/hosted/node/plugin-activation-events.ts +10 -9
  94. package/src/main/browser/debug/plugin-debug-service.ts +7 -0
  95. package/src/main/browser/menus/plugin-menu-command-adapter.ts +30 -0
  96. package/src/main/browser/menus/vscode-theia-menu-mappings.ts +7 -2
  97. package/src/main/browser/notebooks/notebook-documents-and-editors-main.ts +36 -22
  98. package/src/main/browser/notebooks/notebook-documents-main.ts +11 -12
  99. package/src/main/browser/notebooks/notebook-dto.ts +24 -34
  100. package/src/main/browser/notebooks/notebook-kernels-main.ts +1 -1
  101. package/src/main/browser/notebooks/notebooks-main.ts +13 -2
  102. package/src/main/browser/notebooks/renderers/cell-output-webview.tsx +3 -3
  103. package/src/main/browser/plugin-shared-style.ts +3 -2
  104. package/src/main/browser/webview/pre/main.js +27 -2
  105. package/src/main/browser/webview/webview.ts +32 -1
  106. package/src/main/node/plugin-deployer-contribution.ts +2 -1
  107. package/src/main/node/plugin-deployer-impl.ts +2 -1
  108. package/src/plugin/command-registry.ts +8 -3
  109. package/src/plugin/notebook/notebook-document.ts +8 -8
  110. package/src/plugin/notebook/notebooks.ts +6 -4
  111. package/src/plugin/plugin-manager.ts +4 -24
  112. package/src/plugin/tests.ts +25 -1
  113. package/src/plugin/type-converters.ts +3 -123
  114. package/src/plugin/types-impl.ts +1 -0
  115. package/src/plugin/window-state.ts +4 -4
package/package.json CHANGED
@@ -1,37 +1,37 @@
1
1
  {
2
2
  "name": "@theia/plugin-ext",
3
- "version": "1.44.0",
3
+ "version": "1.45.1",
4
4
  "description": "Theia - Plugin Extension",
5
5
  "main": "lib/common/index.js",
6
6
  "typings": "lib/common/index.d.ts",
7
7
  "dependencies": {
8
- "@theia/bulk-edit": "1.44.0",
9
- "@theia/callhierarchy": "1.44.0",
10
- "@theia/console": "1.44.0",
11
- "@theia/core": "1.44.0",
12
- "@theia/debug": "1.44.0",
13
- "@theia/editor": "1.44.0",
14
- "@theia/editor-preview": "1.44.0",
15
- "@theia/file-search": "1.44.0",
16
- "@theia/filesystem": "1.44.0",
17
- "@theia/markers": "1.44.0",
18
- "@theia/messages": "1.44.0",
19
- "@theia/monaco": "1.44.0",
8
+ "@theia/bulk-edit": "1.45.1",
9
+ "@theia/callhierarchy": "1.45.1",
10
+ "@theia/console": "1.45.1",
11
+ "@theia/core": "1.45.1",
12
+ "@theia/debug": "1.45.1",
13
+ "@theia/editor": "1.45.1",
14
+ "@theia/editor-preview": "1.45.1",
15
+ "@theia/file-search": "1.45.1",
16
+ "@theia/filesystem": "1.45.1",
17
+ "@theia/markers": "1.45.1",
18
+ "@theia/messages": "1.45.1",
19
+ "@theia/monaco": "1.45.1",
20
20
  "@theia/monaco-editor-core": "1.72.3",
21
- "@theia/navigator": "1.44.0",
22
- "@theia/notebook": "1.44.0",
23
- "@theia/output": "1.44.0",
24
- "@theia/plugin": "1.44.0",
25
- "@theia/preferences": "1.44.0",
26
- "@theia/scm": "1.44.0",
27
- "@theia/search-in-workspace": "1.44.0",
28
- "@theia/task": "1.44.0",
29
- "@theia/terminal": "1.44.0",
30
- "@theia/test": "1.44.0",
31
- "@theia/timeline": "1.44.0",
32
- "@theia/typehierarchy": "1.44.0",
33
- "@theia/variable-resolver": "1.44.0",
34
- "@theia/workspace": "1.44.0",
21
+ "@theia/navigator": "1.45.1",
22
+ "@theia/notebook": "1.45.1",
23
+ "@theia/output": "1.45.1",
24
+ "@theia/plugin": "1.45.1",
25
+ "@theia/preferences": "1.45.1",
26
+ "@theia/scm": "1.45.1",
27
+ "@theia/search-in-workspace": "1.45.1",
28
+ "@theia/task": "1.45.1",
29
+ "@theia/terminal": "1.45.1",
30
+ "@theia/test": "1.45.1",
31
+ "@theia/timeline": "1.45.1",
32
+ "@theia/typehierarchy": "1.45.1",
33
+ "@theia/variable-resolver": "1.45.1",
34
+ "@theia/workspace": "1.45.1",
35
35
  "@types/mime": "^2.0.1",
36
36
  "@vscode/debugprotocol": "^1.51.0",
37
37
  "@vscode/proxy-agent": "^0.13.2",
@@ -88,7 +88,7 @@
88
88
  "watch": "theiaext watch"
89
89
  },
90
90
  "devDependencies": {
91
- "@theia/ext-scripts": "1.44.0",
91
+ "@theia/ext-scripts": "1.45.1",
92
92
  "@types/decompress": "^4.2.2",
93
93
  "@types/escape-html": "^0.0.20",
94
94
  "@types/lodash.clonedeep": "^4.5.3",
@@ -97,5 +97,5 @@
97
97
  "nyc": {
98
98
  "extends": "../../configs/nyc.json"
99
99
  },
100
- "gitHead": "46349875c7ff0e58c3c77ffe4eaa53ac74fa97a5"
100
+ "gitHead": "3837c50544190b80d0ad8e87aa9fa9f286c70fcc"
101
101
  }
@@ -234,6 +234,7 @@ export interface PluginManagerInitializeParams {
234
234
  extApi?: ExtPluginApi[]
235
235
  webview: WebviewInitData
236
236
  jsonValidation: PluginJsonValidationContribution[]
237
+ supportedActivationEvents?: string[]
237
238
  }
238
239
 
239
240
  export interface PluginManagerStartParams {
@@ -2342,7 +2343,7 @@ export interface NotebookOutputItemDto {
2342
2343
  export interface NotebookOutputDto {
2343
2344
  outputId: string;
2344
2345
  items: NotebookOutputItemDto[];
2345
- metadata?: Record<string, any>;
2346
+ metadata?: Record<string, unknown>;
2346
2347
  }
2347
2348
 
2348
2349
  export interface NotebookCellDataDto {
@@ -48,11 +48,13 @@ export class ClientProxyHandler<T extends object> implements ProxyHandler<T> {
48
48
  }
49
49
 
50
50
  private initializeRpc(): void {
51
+ // we need to set the flag to true before waiting for the channel provider. Otherwise `get` might
52
+ // get called again and we'll try to open a channel more than once
53
+ this.isRpcInitialized = true;
51
54
  const clientOptions: RpcProtocolOptions = { encoder: this.encoder, decoder: this.decoder, mode: 'clientOnly' };
52
55
  this.channelProvider().then(channel => {
53
56
  const rpc = new RpcProtocol(channel, undefined, clientOptions);
54
57
  this.rpcDeferred.resolve(rpc);
55
- this.isRpcInitialized = true;
56
58
  });
57
59
  }
58
60
 
@@ -84,6 +84,7 @@ export interface TestMessageDTO {
84
84
  readonly actual?: string;
85
85
  readonly location?: Location;
86
86
  readonly message: string | MarkdownString;
87
+ readonly contextValue?: string;
87
88
  }
88
89
 
89
90
  export interface TestItemDTO {
@@ -131,3 +132,22 @@ export namespace TestItemReference {
131
132
  }
132
133
  }
133
134
 
135
+ export interface TestMessageArg {
136
+ testItemReference: TestItemReference | undefined,
137
+ testMessage: TestMessageDTO
138
+ }
139
+
140
+ export namespace TestMessageArg {
141
+ export function is(arg: unknown): arg is TestMessageArg {
142
+ return isObject<TestMessageArg>(arg)
143
+ && isObject<TestMessageDTO>(arg.testMessage)
144
+ && (MarkdownString.is(arg.testMessage.message) || typeof arg.testMessage.message === 'string');
145
+ }
146
+
147
+ export function create(testItemReference: TestItemReference | undefined, testMessageDTO: TestMessageDTO): TestMessageArg {
148
+ return {
149
+ testItemReference: testItemReference,
150
+ testMessage: testMessageDTO
151
+ };
152
+ }
153
+ }
@@ -80,6 +80,30 @@ export const ALL_ACTIVATION_EVENT = '*';
80
80
  @injectable()
81
81
  export class HostedPluginSupport {
82
82
 
83
+ protected static ADDITIONAL_ACTIVATION_EVENTS_ENV = 'ADDITIONAL_ACTIVATION_EVENTS';
84
+ protected static BUILTIN_ACTIVATION_EVENTS = [
85
+ '*',
86
+ 'onLanguage',
87
+ 'onCommand',
88
+ 'onDebug',
89
+ 'onDebugInitialConfigurations',
90
+ 'onDebugResolve',
91
+ 'onDebugAdapterProtocolTracker',
92
+ 'onDebugDynamicConfigurations',
93
+ 'onTaskType',
94
+ 'workspaceContains',
95
+ 'onView',
96
+ 'onUri',
97
+ 'onTerminalProfile',
98
+ 'onWebviewPanel',
99
+ 'onFileSystem',
100
+ 'onCustomEditor',
101
+ 'onStartupFinished',
102
+ 'onAuthenticationRequest',
103
+ 'onNotebook',
104
+ 'onNotebookSerializer'
105
+ ];
106
+
83
107
  protected readonly clientId = UUID.uuid4();
84
108
 
85
109
  protected container: interfaces.Container;
@@ -377,8 +401,12 @@ export class HostedPluginSupport {
377
401
  waitPluginsMeasurement.error('Backend deployment failed.');
378
402
  }
379
403
  }
380
-
381
- syncPluginsMeasurement?.log(`Sync of ${this.getPluginCount(initialized)}`);
404
+ if (initialized > 0) {
405
+ // Only log sync measurement if there are were plugins to sync.
406
+ syncPluginsMeasurement?.log(`Sync of ${this.getPluginCount(initialized)}`);
407
+ } else {
408
+ syncPluginsMeasurement.stop();
409
+ }
382
410
  }
383
411
 
384
412
  /**
@@ -416,8 +444,12 @@ export class HostedPluginSupport {
416
444
  }));
417
445
  }
418
446
  }
419
-
420
- loadPluginsMeasurement.log(`Load contributions of ${this.getPluginCount(loaded)}`);
447
+ if (loaded > 0) {
448
+ // Only log load measurement if there are were plugins to load.
449
+ loadPluginsMeasurement?.log(`Load contributions of ${this.getPluginCount(loaded)}`);
450
+ } else {
451
+ loadPluginsMeasurement.stop();
452
+ }
421
453
 
422
454
  return hostContributions;
423
455
  }
@@ -488,7 +520,11 @@ export class HostedPluginSupport {
488
520
  return;
489
521
  }
490
522
 
491
- startPluginsMeasurement.log(`Start of ${this.getPluginCount(started)}`);
523
+ if (started > 0) {
524
+ startPluginsMeasurement.log(`Start of ${this.getPluginCount(started)}`);
525
+ } else {
526
+ startPluginsMeasurement.stop();
527
+ }
492
528
  }
493
529
 
494
530
  protected async obtainManager(host: string, hostContributions: PluginContributions[], toDisconnect: DisposableCollection): Promise<PluginManagerExt | undefined> {
@@ -519,6 +555,13 @@ export class HostedPluginSupport {
519
555
  }
520
556
 
521
557
  const isElectron = environment.electron.is();
558
+
559
+ const supportedActivationEvents = [...HostedPluginSupport.BUILTIN_ACTIVATION_EVENTS];
560
+ const additionalActivationEvents = await this.envServer.getValue(HostedPluginSupport.ADDITIONAL_ACTIVATION_EVENTS_ENV);
561
+ if (additionalActivationEvents && additionalActivationEvents.value) {
562
+ additionalActivationEvents.value.split(',').forEach(event => supportedActivationEvents.push(event));
563
+ }
564
+
522
565
  await manager.$init({
523
566
  preferences: getPreferences(this.preferenceProviderProvider, this.workspaceService.tryGetRoots()),
524
567
  globalState,
@@ -536,11 +579,13 @@ export class HostedPluginSupport {
536
579
  webviewResourceRoot,
537
580
  webviewCspSource
538
581
  },
539
- jsonValidation
582
+ jsonValidation,
583
+ supportedActivationEvents
540
584
  });
541
585
  if (toDisconnect.disposed) {
542
586
  return undefined;
543
587
  }
588
+ this.activationEvents.forEach(event => manager!.$activateByEvent(event));
544
589
  }
545
590
  return manager;
546
591
  }
@@ -20,6 +20,7 @@ import {
20
20
  PluginPackage,
21
21
  PluginPackageAuthenticationProvider,
22
22
  PluginPackageCommand,
23
+ PluginPackageContribution,
23
24
  PluginPackageCustomEditor,
24
25
  PluginPackageLanguageContribution,
25
26
  PluginPackageNotebook,
@@ -31,7 +32,7 @@ import {
31
32
  * This function will update the manifest based on the plugin contributions.
32
33
  */
33
34
  export function updateActivationEvents(manifest: PluginPackage): void {
34
- if (!isObject(manifest) || !isObject(manifest.contributes) || !manifest.contributes) {
35
+ if (!isObject<PluginPackage>(manifest) || !isObject<PluginPackageContribution>(manifest.contributes) || !manifest.contributes) {
35
36
  return;
36
37
  }
37
38
 
@@ -42,8 +43,8 @@ export function updateActivationEvents(manifest: PluginPackage): void {
42
43
  const commands = Array.isArray(value) ? value : [value];
43
44
  updateCommandsContributions(commands, activationEvents);
44
45
  }
45
- if (Array.isArray(manifest.contributes.views)) {
46
- const views = flatten(Object.values(manifest.contributes.views)) as PluginPackageView[];
46
+ if (isObject(manifest.contributes.views)) {
47
+ const views = flatten(Object.values(manifest.contributes.views));
47
48
  updateViewsContribution(views, activationEvents);
48
49
  }
49
50
  if (Array.isArray(manifest.contributes.customEditors)) {
@@ -64,7 +65,7 @@ export function updateActivationEvents(manifest: PluginPackage): void {
64
65
 
65
66
  function updateViewsContribution(views: PluginPackageView[], activationEvents: Set<string>): void {
66
67
  for (const view of views) {
67
- if (isObject(view) && typeof view.id === 'string') {
68
+ if (isObject<PluginPackageView>(view) && typeof view.id === 'string') {
68
69
  activationEvents.add(`onView:${view.id}`);
69
70
  }
70
71
  }
@@ -72,7 +73,7 @@ function updateViewsContribution(views: PluginPackageView[], activationEvents: S
72
73
 
73
74
  function updateCustomEditorsContribution(customEditors: PluginPackageCustomEditor[], activationEvents: Set<string>): void {
74
75
  for (const customEditor of customEditors) {
75
- if (isObject(customEditor) && typeof customEditor.viewType === 'string') {
76
+ if (isObject<PluginPackageCustomEditor>(customEditor) && typeof customEditor.viewType === 'string') {
76
77
  activationEvents.add(`onCustomEditor:${customEditor.viewType}`);
77
78
  }
78
79
  }
@@ -80,7 +81,7 @@ function updateCustomEditorsContribution(customEditors: PluginPackageCustomEdito
80
81
 
81
82
  function updateCommandsContributions(commands: PluginPackageCommand[], activationEvents: Set<string>): void {
82
83
  for (const command of commands) {
83
- if (isObject(command) && typeof command.command === 'string') {
84
+ if (isObject<PluginPackageCommand>(command) && typeof command.command === 'string') {
84
85
  activationEvents.add(`onCommand:${command.command}`);
85
86
  }
86
87
  }
@@ -88,7 +89,7 @@ function updateCommandsContributions(commands: PluginPackageCommand[], activatio
88
89
 
89
90
  function updateAuthenticationProviderContributions(authProviders: PluginPackageAuthenticationProvider[], activationEvents: Set<string>): void {
90
91
  for (const authProvider of authProviders) {
91
- if (isObject(authProvider) && typeof authProvider.id === 'string') {
92
+ if (isObject<PluginPackageAuthenticationProvider>(authProvider) && typeof authProvider.id === 'string') {
92
93
  activationEvents.add(`onAuthenticationRequest:${authProvider.id}`);
93
94
  }
94
95
  }
@@ -96,7 +97,7 @@ function updateAuthenticationProviderContributions(authProviders: PluginPackageA
96
97
 
97
98
  function updateLanguageContributions(languages: PluginPackageLanguageContribution[], activationEvents: Set<string>): void {
98
99
  for (const language of languages) {
99
- if (isObject(language) && typeof language.id === 'string') {
100
+ if (isObject<PluginPackageLanguageContribution>(language) && typeof language.id === 'string') {
100
101
  activationEvents.add(`onLanguage:${language.id}`);
101
102
  }
102
103
  }
@@ -104,7 +105,7 @@ function updateLanguageContributions(languages: PluginPackageLanguageContributio
104
105
 
105
106
  function updateNotebookContributions(notebooks: PluginPackageNotebook[], activationEvents: Set<string>): void {
106
107
  for (const notebook of notebooks) {
107
- if (isObject(notebook) && typeof notebook.type === 'string') {
108
+ if (isObject<PluginPackageNotebook>(notebook) && typeof notebook.type === 'string') {
108
109
  activationEvents.add(`onNotebookSerializer:${notebook.type}`);
109
110
  }
110
111
  }
@@ -97,6 +97,13 @@ export class PluginDebugService implements DebugService {
97
97
  }, 100);
98
98
 
99
99
  registerDebugConfigurationProvider(provider: PluginDebugConfigurationProvider): Disposable {
100
+ if (this.configurationProviders.has(provider.handle)) {
101
+ const configuration = this.configurationProviders.get(provider.handle);
102
+ if (configuration && configuration.type !== provider.type) {
103
+ console.warn(`Different debug configuration provider with type '${configuration.type}' already registered.`);
104
+ provider.handle = this.configurationProviders.size;
105
+ }
106
+ }
100
107
  const handle = provider.handle;
101
108
  this.configurationProviders.set(handle, provider);
102
109
  this.fireOnDidConfigurationProvidersChanged();
@@ -23,10 +23,13 @@ import { ScmRepository } from '@theia/scm/lib/browser/scm-repository';
23
23
  import { ScmService } from '@theia/scm/lib/browser/scm-service';
24
24
  import { TimelineItem } from '@theia/timeline/lib/common/timeline-model';
25
25
  import { ScmCommandArg, TimelineCommandArg, TreeViewItemReference } from '../../../common';
26
+ import { TestItemReference, TestMessageArg } from '../../../common/test-types';
26
27
  import { PluginScmProvider, PluginScmResource, PluginScmResourceGroup } from '../scm-main';
27
28
  import { TreeViewWidget } from '../view/tree-view-widget';
28
29
  import { CodeEditorWidgetUtil, codeToTheiaMappings, ContributionPoint } from './vscode-theia-menu-mappings';
29
30
  import { TAB_BAR_TOOLBAR_CONTEXT_MENU } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
31
+ import { TestItem, TestMessage } from '@theia/test/lib/browser/test-service';
32
+ import { fromLocation } from '../hierarchy/hierarchy-types-converters';
30
33
 
31
34
  export type ArgumentAdapter = (...args: unknown[]) => unknown[];
32
35
 
@@ -79,6 +82,7 @@ export class PluginMenuCommandAdapter implements MenuCommandAdapter {
79
82
  @postConstruct()
80
83
  protected init(): void {
81
84
  const toCommentArgs: ArgumentAdapter = (...args) => this.toCommentArgs(...args);
85
+ const toTestMessageArgs: ArgumentAdapter = (...args) => this.toTestMessageArgs(...args);
82
86
  const firstArgOnly: ArgumentAdapter = (...args) => [args[0]];
83
87
  const noArgs: ArgumentAdapter = () => [];
84
88
  const toScmArgs: ArgumentAdapter = (...args) => this.toScmArgs(...args);
@@ -100,9 +104,11 @@ export class PluginMenuCommandAdapter implements MenuCommandAdapter {
100
104
  ['scm/resourceGroup/context', toScmArgs],
101
105
  ['scm/resourceState/context', toScmArgs],
102
106
  ['scm/title', () => [this.toScmArg(this.scmService.selectedRepository)]],
107
+ ['testing/message/context', toTestMessageArgs],
103
108
  ['timeline/item/context', (...args) => this.toTimelineArgs(...args)],
104
109
  ['view/item/context', (...args) => this.toTreeArgs(...args)],
105
110
  ['view/title', noArgs],
111
+ ['webview/context', noArgs]
106
112
  ]).forEach(([contributionPoint, adapter]) => {
107
113
  if (adapter) {
108
114
  const paths = codeToTheiaMappings.get(contributionPoint);
@@ -229,6 +235,30 @@ export class PluginMenuCommandAdapter implements MenuCommandAdapter {
229
235
  return timelineArgs;
230
236
  }
231
237
 
238
+ protected toTestMessageArgs(...args: any[]): any[] {
239
+ let testItem: TestItem | undefined;
240
+ let testMessage: TestMessage | undefined;
241
+ for (const arg of args) {
242
+ if (TestItem.is(arg)) {
243
+ testItem = arg;
244
+ } else if (Array.isArray(arg) && TestMessage.is(arg[0])) {
245
+ testMessage = arg[0];
246
+ }
247
+ }
248
+ if (testMessage) {
249
+ const testItemReference = (testItem && testItem.controller) ? TestItemReference.create(testItem.controller.id, testItem.path) : undefined;
250
+ const testMessageDTO = {
251
+ message: testMessage.message,
252
+ actual: testMessage.actual,
253
+ expected: testMessage.expected,
254
+ contextValue: testMessage.contextValue,
255
+ location: testMessage.location ? fromLocation(testMessage.location) : undefined
256
+ };
257
+ return [TestMessageArg.create(testItemReference, testMessageDTO)];
258
+ }
259
+ return [];
260
+ }
261
+
232
262
  protected toTimelineArg(arg: TimelineItem): TimelineCommandArg {
233
263
  return {
234
264
  timelineHandle: arg.handle,
@@ -29,9 +29,10 @@ import { ScmTreeWidget } from '@theia/scm/lib/browser/scm-tree-widget';
29
29
  import { TIMELINE_ITEM_CONTEXT_MENU } from '@theia/timeline/lib/browser/timeline-tree-widget';
30
30
  import { COMMENT_CONTEXT, COMMENT_THREAD_CONTEXT, COMMENT_TITLE } from '../comments/comment-thread-widget';
31
31
  import { VIEW_ITEM_CONTEXT_MENU } from '../view/tree-view-widget';
32
- import { WebviewWidget } from '../webview/webview';
32
+ import { WEBVIEW_CONTEXT_MENU, WebviewWidget } from '../webview/webview';
33
33
  import { EDITOR_LINENUMBER_CONTEXT_MENU } from '@theia/editor/lib/browser/editor-linenumber-contribution';
34
34
  import { TEST_VIEW_CONTEXT_MENU } from '@theia/test/lib/browser/view/test-view-contribution';
35
+ import { TEST_RUNS_CONTEXT_MENU } from '@theia/test/lib/browser/view/test-run-view-contribution';
35
36
 
36
37
  export const PLUGIN_EDITOR_TITLE_MENU = ['plugin_editor/title'];
37
38
  export const PLUGIN_EDITOR_TITLE_RUN_MENU = ['plugin_editor/title/run'];
@@ -57,8 +58,10 @@ export const implementedVSCodeContributionPoints = [
57
58
  'scm/title',
58
59
  'timeline/item/context',
59
60
  'testing/item/context',
61
+ 'testing/message/context',
60
62
  'view/item/context',
61
- 'view/title'
63
+ 'view/title',
64
+ 'webview/context'
62
65
  ] as const;
63
66
 
64
67
  export type ContributionPoint = (typeof implementedVSCodeContributionPoints)[number];
@@ -82,9 +85,11 @@ export const codeToTheiaMappings = new Map<ContributionPoint, MenuPath[]>([
82
85
  ['scm/resourceState/context', [ScmTreeWidget.RESOURCE_CONTEXT_MENU]],
83
86
  ['scm/title', [PLUGIN_SCM_TITLE_MENU]],
84
87
  ['testing/item/context', [TEST_VIEW_CONTEXT_MENU]],
88
+ ['testing/message/context', [TEST_RUNS_CONTEXT_MENU]],
85
89
  ['timeline/item/context', [TIMELINE_ITEM_CONTEXT_MENU]],
86
90
  ['view/item/context', [VIEW_ITEM_CONTEXT_MENU]],
87
91
  ['view/title', [PLUGIN_VIEW_TITLE_MENU]],
92
+ ['webview/context', [WEBVIEW_CONTEXT_MENU]]
88
93
  ]);
89
94
 
90
95
  type CodeEditorWidget = EditorWidget | WebviewWidget;
@@ -23,7 +23,7 @@ import { interfaces } from '@theia/core/shared/inversify';
23
23
  import { UriComponents } from '@theia/core/lib/common/uri';
24
24
  import { NotebookEditorWidget, NotebookService, NotebookEditorWidgetService } from '@theia/notebook/lib/browser';
25
25
  import { NotebookModel } from '@theia/notebook/lib/browser/view-model/notebook-model';
26
- import { MAIN_RPC_CONTEXT, NotebookDocumentsAndEditorsDelta, NotebookDocumentsAndEditorsMain, NotebookModelAddedData, NotebooksExt } from '../../../common';
26
+ import { MAIN_RPC_CONTEXT, NotebookDocumentsAndEditorsDelta, NotebookDocumentsAndEditorsMain, NotebookEditorAddData, NotebookModelAddedData, NotebooksExt } from '../../../common';
27
27
  import { RPCProtocol } from '../../../common/rpc-protocol';
28
28
  import { NotebookDto } from './notebook-dto';
29
29
  import { WidgetManager } from '@theia/core/lib/browser';
@@ -31,6 +31,7 @@ import { NotebookEditorsMainImpl } from './notebook-editors-main';
31
31
  import { NotebookDocumentsMainImpl } from './notebook-documents-main';
32
32
  import { diffMaps, diffSets } from '../../../common/collections';
33
33
  import { Mutex } from 'async-mutex';
34
+ import throttle = require('@theia/core/shared/lodash.throttle');
34
35
 
35
36
  interface NotebookAndEditorDelta {
36
37
  removedDocuments: UriComponents[];
@@ -42,7 +43,7 @@ interface NotebookAndEditorDelta {
42
43
  }
43
44
 
44
45
  class NotebookAndEditorState {
45
- static delta(before: NotebookAndEditorState | undefined, after: NotebookAndEditorState): NotebookAndEditorDelta {
46
+ static computeDelta(before: NotebookAndEditorState | undefined, after: NotebookAndEditorState): NotebookAndEditorDelta {
46
47
  if (!before) {
47
48
  return {
48
49
  addedDocuments: [...after.documents],
@@ -106,12 +107,12 @@ export class NotebooksAndEditorsMain implements NotebookDocumentsAndEditorsMain
106
107
  this.notebookEditorService = container.get(NotebookEditorWidgetService);
107
108
  this.WidgetManager = container.get(WidgetManager);
108
109
 
109
- this.notebookService.onDidAddNotebookDocument(async () => this.updateState(), this, this.disposables);
110
- this.notebookService.onDidRemoveNotebookDocument(async () => this.updateState(), this, this.disposables);
110
+ this.notebookService.onDidAddNotebookDocument(async () => this.throttleStateUpdate(), this, this.disposables);
111
+ this.notebookService.onDidRemoveNotebookDocument(async () => this.throttleStateUpdate(), this, this.disposables);
111
112
  // this.WidgetManager.onActiveEditorChanged(() => this.updateState(), this, this.disposables);
112
113
  this.notebookEditorService.onDidAddNotebookEditor(async editor => this.handleEditorAdd(editor), this, this.disposables);
113
114
  this.notebookEditorService.onDidRemoveNotebookEditor(async editor => this.handleEditorRemove(editor), this, this.disposables);
114
- this.notebookEditorService.onDidChangeFocusedEditor(async editor => this.updateState(editor), this, this.disposables);
115
+ this.notebookEditorService.onDidChangeFocusedEditor(async editor => this.throttleStateUpdate(editor), this, this.disposables);
115
116
  }
116
117
 
117
118
  dispose(): void {
@@ -129,16 +130,18 @@ export class NotebooksAndEditorsMain implements NotebookDocumentsAndEditorsMain
129
130
  } else {
130
131
  this.editorListeners.set(editor.id, [disposable]);
131
132
  }
132
- await this.updateState();
133
+ await this.throttleStateUpdate();
133
134
  }
134
135
 
135
136
  private handleEditorRemove(editor: NotebookEditorWidget): void {
136
137
  const listeners = this.editorListeners.get(editor.id);
137
138
  listeners?.forEach(listener => listener.dispose());
138
139
  this.editorListeners.delete(editor.id);
139
- this.updateState();
140
+ this.throttleStateUpdate();
140
141
  }
141
142
 
143
+ private throttleStateUpdate = throttle((focusedEditor?: NotebookEditorWidget) => this.updateState(focusedEditor), 100);
144
+
142
145
  private async updateState(focusedEditor?: NotebookEditorWidget): Promise<void> {
143
146
  await this.updateMutex.runExclusive(async () => this.doUpdateState(focusedEditor));
144
147
  }
@@ -148,10 +151,8 @@ export class NotebooksAndEditorsMain implements NotebookDocumentsAndEditorsMain
148
151
  const editors = new Map<string, NotebookEditorWidget>();
149
152
  const visibleEditorsMap = new Map<string, NotebookEditorWidget>();
150
153
 
151
- for (const editor of this.notebookEditorService.listNotebookEditors()) {
152
- if (editor.model) {
153
- editors.set(editor.id, editor);
154
- }
154
+ for (const editor of this.notebookEditorService.getNotebookEditors()) {
155
+ editors.set(editor.id, editor);
155
156
  }
156
157
 
157
158
  const activeNotebookEditor = this.notebookEditorService.focusedEditor;
@@ -167,7 +168,7 @@ export class NotebooksAndEditorsMain implements NotebookDocumentsAndEditorsMain
167
168
 
168
169
  const notebookEditors = this.WidgetManager.getWidgets(NotebookEditorWidget.ID) as NotebookEditorWidget[];
169
170
  for (const notebookEditor of notebookEditors) {
170
- if (notebookEditor?.model && editors.has(notebookEditor.id) && notebookEditor.isVisible) {
171
+ if (editors.has(notebookEditor.id) && notebookEditor.isVisible) {
171
172
  visibleEditorsMap.set(notebookEditor.id, notebookEditor);
172
173
  }
173
174
  }
@@ -176,12 +177,12 @@ export class NotebooksAndEditorsMain implements NotebookDocumentsAndEditorsMain
176
177
  new Set(this.notebookService.listNotebookDocuments()),
177
178
  editors,
178
179
  activeEditor, visibleEditorsMap);
179
- await this.onDelta(NotebookAndEditorState.delta(this.currentState, newState));
180
+ await this.onDelta(NotebookAndEditorState.computeDelta(this.currentState, newState));
180
181
  this.currentState = newState;
181
182
  }
182
183
 
183
184
  private async onDelta(delta: NotebookAndEditorDelta): Promise<void> {
184
- if (NotebooksAndEditorsMain._isDeltaEmpty(delta)) {
185
+ if (NotebooksAndEditorsMain.isDeltaEmpty(delta)) {
185
186
  return;
186
187
  }
187
188
 
@@ -191,7 +192,7 @@ export class NotebooksAndEditorsMain implements NotebookDocumentsAndEditorsMain
191
192
  newActiveEditor: delta.newActiveEditor,
192
193
  visibleEditors: delta.visibleEditors,
193
194
  addedDocuments: delta.addedDocuments.map(NotebooksAndEditorsMain.asModelAddData),
194
- // addedEditors: delta.addedEditors.map(this.asEditorAddData, this),
195
+ addedEditors: delta.addedEditors.map(NotebooksAndEditorsMain.asEditorAddData),
195
196
  };
196
197
 
197
198
  // send to extension FIRST
@@ -204,23 +205,23 @@ export class NotebooksAndEditorsMain implements NotebookDocumentsAndEditorsMain
204
205
  this.notebookEditorsMain.handleEditorsAdded(delta.addedEditors);
205
206
  }
206
207
 
207
- private static _isDeltaEmpty(delta: NotebookAndEditorDelta): boolean {
208
- if (delta.addedDocuments !== undefined && delta.addedDocuments.length > 0) {
208
+ private static isDeltaEmpty(delta: NotebookAndEditorDelta): boolean {
209
+ if (delta.addedDocuments?.length) {
209
210
  return false;
210
211
  }
211
- if (delta.removedDocuments !== undefined && delta.removedDocuments.length > 0) {
212
+ if (delta.removedDocuments?.length) {
212
213
  return false;
213
214
  }
214
- if (delta.addedEditors !== undefined && delta.addedEditors.length > 0) {
215
+ if (delta.addedEditors?.length) {
215
216
  return false;
216
217
  }
217
- if (delta.removedEditors !== undefined && delta.removedEditors.length > 0) {
218
+ if (delta.removedEditors?.length) {
218
219
  return false;
219
220
  }
220
- if (delta.visibleEditors !== undefined && delta.visibleEditors.length > 0) {
221
+ if (delta.visibleEditors?.length) {
221
222
  return false;
222
223
  }
223
- if (delta.newActiveEditor !== undefined) {
224
+ if (delta.newActiveEditor) {
224
225
  return false;
225
226
  }
226
227
  return true;
@@ -235,4 +236,17 @@ export class NotebooksAndEditorsMain implements NotebookDocumentsAndEditorsMain
235
236
  cells: e.cells.map(NotebookDto.toNotebookCellDto)
236
237
  };
237
238
  }
239
+
240
+ private static asEditorAddData(notebookEditor: NotebookEditorWidget): NotebookEditorAddData {
241
+ const uri = notebookEditor.getResourceUri();
242
+ if (!uri) {
243
+ throw new Error('Notebook editor without resource URI');
244
+ }
245
+ return {
246
+ id: notebookEditor.id,
247
+ documentUri: uri.toComponents(),
248
+ selections: [],
249
+ visibleRanges: []
250
+ };
251
+ }
238
252
  }