@theia/plugin-ext 1.22.0-next.3 → 1.22.0-next.30

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 (87) hide show
  1. package/lib/common/plugin-api-rpc.d.ts +4 -3
  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/plugin-protocol.d.ts +5 -0
  5. package/lib/common/plugin-protocol.d.ts.map +1 -1
  6. package/lib/common/plugin-protocol.js.map +1 -1
  7. package/lib/main/browser/comments/comments-context-key-service.js +1 -1
  8. package/lib/main/browser/comments/comments-context-key-service.js.map +1 -1
  9. package/lib/main/browser/comments/comments-contribution.js +1 -1
  10. package/lib/main/browser/comments/comments-contribution.js.map +1 -1
  11. package/lib/main/browser/custom-editors/custom-editor-opener.d.ts +3 -3
  12. package/lib/main/browser/custom-editors/custom-editor-opener.d.ts.map +1 -1
  13. package/lib/main/browser/custom-editors/custom-editor-opener.js +1 -1
  14. package/lib/main/browser/custom-editors/custom-editor-opener.js.map +1 -1
  15. package/lib/main/browser/custom-editors/custom-editors-main.d.ts +3 -3
  16. package/lib/main/browser/custom-editors/custom-editors-main.d.ts.map +1 -1
  17. package/lib/main/browser/custom-editors/custom-editors-main.js +34 -6
  18. package/lib/main/browser/custom-editors/custom-editors-main.js.map +1 -1
  19. package/lib/main/browser/custom-editors/plugin-custom-editor-registry.d.ts +3 -3
  20. package/lib/main/browser/custom-editors/plugin-custom-editor-registry.d.ts.map +1 -1
  21. package/lib/main/browser/custom-editors/plugin-custom-editor-registry.js +3 -3
  22. package/lib/main/browser/custom-editors/plugin-custom-editor-registry.js.map +1 -1
  23. package/lib/main/browser/debug/debug-main.d.ts +1 -0
  24. package/lib/main/browser/debug/debug-main.d.ts.map +1 -1
  25. package/lib/main/browser/debug/debug-main.js +10 -0
  26. package/lib/main/browser/debug/debug-main.js.map +1 -1
  27. package/lib/main/browser/dialogs-main.js +8 -8
  28. package/lib/main/browser/dialogs-main.js.map +1 -1
  29. package/lib/main/browser/menus/menus-contribution-handler.d.ts.map +1 -1
  30. package/lib/main/browser/menus/menus-contribution-handler.js +4 -6
  31. package/lib/main/browser/menus/menus-contribution-handler.js.map +1 -1
  32. package/lib/main/browser/view/plugin-view-registry.js +1 -1
  33. package/lib/main/browser/view/plugin-view-registry.js.map +1 -1
  34. package/lib/main/browser/view/plugin-view-widget.d.ts +5 -3
  35. package/lib/main/browser/view/plugin-view-widget.d.ts.map +1 -1
  36. package/lib/main/browser/view/plugin-view-widget.js +12 -4
  37. package/lib/main/browser/view/plugin-view-widget.js.map +1 -1
  38. package/lib/main/browser/view/tree-view-widget.d.ts +1 -2
  39. package/lib/main/browser/view/tree-view-widget.d.ts.map +1 -1
  40. package/lib/main/browser/view/tree-view-widget.js +5 -6
  41. package/lib/main/browser/view/tree-view-widget.js.map +1 -1
  42. package/lib/main/browser/view/view-context-key-service.d.ts +0 -4
  43. package/lib/main/browser/view/view-context-key-service.d.ts.map +1 -1
  44. package/lib/main/browser/view/view-context-key-service.js +1 -14
  45. package/lib/main/browser/view/view-context-key-service.js.map +1 -1
  46. package/lib/main/node/plugin-deployer-impl.d.ts +6 -9
  47. package/lib/main/node/plugin-deployer-impl.d.ts.map +1 -1
  48. package/lib/main/node/plugin-deployer-impl.js +32 -24
  49. package/lib/main/node/plugin-deployer-impl.js.map +1 -1
  50. package/lib/main/node/plugin-server-handler.d.ts +2 -2
  51. package/lib/main/node/plugin-server-handler.d.ts.map +1 -1
  52. package/lib/main/node/plugin-server-handler.js +6 -3
  53. package/lib/main/node/plugin-server-handler.js.map +1 -1
  54. package/lib/plugin/custom-editors.d.ts +2 -1
  55. package/lib/plugin/custom-editors.d.ts.map +1 -1
  56. package/lib/plugin/custom-editors.js +2 -4
  57. package/lib/plugin/custom-editors.js.map +1 -1
  58. package/lib/plugin/node/debug/debug.d.ts +1 -0
  59. package/lib/plugin/node/debug/debug.d.ts.map +1 -1
  60. package/lib/plugin/node/debug/debug.js +3 -0
  61. package/lib/plugin/node/debug/debug.js.map +1 -1
  62. package/lib/plugin/plugin-context.d.ts.map +1 -1
  63. package/lib/plugin/plugin-context.js +3 -0
  64. package/lib/plugin/plugin-context.js.map +1 -1
  65. package/lib/plugin/types-impl.js +1 -1
  66. package/lib/plugin/types-impl.js.map +1 -1
  67. package/lib/plugin/types-impl.spec.js +33 -0
  68. package/lib/plugin/types-impl.spec.js.map +1 -1
  69. package/package.json +23 -25
  70. package/src/common/plugin-api-rpc.ts +4 -3
  71. package/src/common/plugin-protocol.ts +7 -1
  72. package/src/main/browser/custom-editors/custom-editor-opener.tsx +4 -4
  73. package/src/main/browser/custom-editors/custom-editors-main.ts +41 -8
  74. package/src/main/browser/custom-editors/plugin-custom-editor-registry.ts +6 -6
  75. package/src/main/browser/debug/debug-main.ts +11 -0
  76. package/src/main/browser/dialogs-main.ts +7 -7
  77. package/src/main/browser/menus/menus-contribution-handler.ts +3 -7
  78. package/src/main/browser/view/plugin-view-widget.ts +14 -4
  79. package/src/main/browser/view/tree-view-widget.tsx +4 -5
  80. package/src/main/browser/view/view-context-key-service.ts +0 -14
  81. package/src/main/node/plugin-deployer-impl.ts +38 -27
  82. package/src/main/node/plugin-server-handler.ts +8 -4
  83. package/src/plugin/custom-editors.ts +3 -4
  84. package/src/plugin/node/debug/debug.ts +4 -0
  85. package/src/plugin/plugin-context.ts +3 -0
  86. package/src/plugin/types-impl.spec.ts +37 -1
  87. package/src/plugin/types-impl.ts +1 -1
@@ -23,14 +23,14 @@ import { CommandRegistry, Emitter, MenuModelRegistry } from '@theia/core';
23
23
  import { SelectionService } from '@theia/core/lib/common';
24
24
  import { UriAwareCommandHandler } from '@theia/core/lib/common/uri-command-handler';
25
25
  import { NavigatorContextMenu } from '@theia/navigator/lib//browser/navigator-contribution';
26
- import { ApplicationShell, DefaultOpenerService, WidgetManager } from '@theia/core/lib/browser';
26
+ import { ApplicationShell, DefaultOpenerService, WidgetManager, WidgetOpenerOptions } from '@theia/core/lib/browser';
27
27
  import { CustomEditorWidget } from './custom-editor-widget';
28
28
 
29
29
  @injectable()
30
30
  export class PluginCustomEditorRegistry {
31
31
  private readonly editors = new Map<string, CustomEditor>();
32
32
  private readonly pendingEditors = new Set<CustomEditorWidget>();
33
- private readonly resolvers = new Map<string, (widget: CustomEditorWidget) => void>();
33
+ private readonly resolvers = new Map<string, (widget: CustomEditorWidget, options?: WidgetOpenerOptions) => void>();
34
34
 
35
35
  private readonly onWillOpenCustomEditorEmitter = new Emitter<string>();
36
36
  readonly onWillOpenCustomEditor = this.onWillOpenCustomEditorEmitter.event;
@@ -109,22 +109,22 @@ export class PluginCustomEditorRegistry {
109
109
  )
110
110
  );
111
111
  toDispose.push(
112
- editorOpenHandler.onDidOpenCustomEditor(widget => this.resolveWidget(widget))
112
+ editorOpenHandler.onDidOpenCustomEditor(event => this.resolveWidget(event[0], event[1]))
113
113
  );
114
114
  return toDispose;
115
115
  }
116
116
 
117
- resolveWidget = (widget: CustomEditorWidget) => {
117
+ resolveWidget = (widget: CustomEditorWidget, options?: WidgetOpenerOptions) => {
118
118
  const resolver = this.resolvers.get(widget.viewType);
119
119
  if (resolver) {
120
- resolver(widget);
120
+ resolver(widget, options);
121
121
  } else {
122
122
  this.pendingEditors.add(widget);
123
123
  this.onWillOpenCustomEditorEmitter.fire(widget.viewType);
124
124
  }
125
125
  };
126
126
 
127
- registerResolver(viewType: string, resolver: (widget: CustomEditorWidget) => void): Disposable {
127
+ registerResolver(viewType: string, resolver: (widget: CustomEditorWidget, options?: WidgetOpenerOptions) => void): Disposable {
128
128
  if (this.resolvers.has(viewType)) {
129
129
  throw new Error(`Resolver for ${viewType} already registered`);
130
130
  }
@@ -284,6 +284,17 @@ export class DebugMainImpl implements DebugMain, Disposable {
284
284
  return !!session;
285
285
  }
286
286
 
287
+ async $stopDebugging(sessionId?: string): Promise<void> {
288
+ if (sessionId) {
289
+ const session = this.sessionManager.getSession(sessionId);
290
+ return this.sessionManager.terminateSession(session);
291
+ }
292
+ // Terminate all sessions if no session is provided.
293
+ for (const session of this.sessionManager.sessions) {
294
+ this.sessionManager.terminateSession(session);
295
+ }
296
+ }
297
+
287
298
  private toTheiaPluginApiBreakpoints(breakpoints: (SourceBreakpoint | FunctionBreakpoint)[]): Breakpoint[] {
288
299
  return breakpoints.map(b => this.toTheiaPluginApiBreakpoint(b));
289
300
  }
@@ -52,14 +52,14 @@ export class DialogsMainImpl implements DialogsMain {
52
52
  } catch {
53
53
  rootStat = undefined;
54
54
  }
55
- }
56
55
 
57
- // Try to use as root the parent folder of existing file URI/non existing URI
58
- if (rootStat && !rootStat.isDirectory || !rootStat) {
59
- try {
60
- rootStat = await this.fileService.resolve(new URI(defaultUri).parent);
61
- } catch {
62
- rootStat = undefined;
56
+ // Try to use as root the parent folder of existing file URI/non existing URI
57
+ if (rootStat && !rootStat.isDirectory || !rootStat) {
58
+ try {
59
+ rootStat = await this.fileService.resolve(new URI(defaultUri).parent);
60
+ } catch {
61
+ rootStat = undefined;
62
+ }
63
63
  }
64
64
  }
65
65
 
@@ -242,14 +242,10 @@ export class MenusContributionPointHandler {
242
242
  }
243
243
 
244
244
  protected registerViewTitleAction(location: string, action: Menu): Disposable {
245
- return this.registerTitleAction(location, { ...action, when: undefined }, {
245
+ return this.registerTitleAction(location, action, {
246
246
  execute: widget => widget instanceof PluginViewWidget && this.commands.executeCommand(action.command!),
247
- isEnabled: widget => widget instanceof PluginViewWidget &&
248
- this.viewContextKeys.with({ view: widget.options.viewId }, () =>
249
- this.commands.isEnabled(action.command!) && this.viewContextKeys.match(action.when)),
250
- isVisible: widget => widget instanceof PluginViewWidget &&
251
- this.viewContextKeys.with({ view: widget.options.viewId }, () =>
252
- this.commands.isVisible(action.command!) && this.viewContextKeys.match(action.when))
247
+ isEnabled: widget => widget instanceof PluginViewWidget && this.commands.isEnabled(action.command!),
248
+ isVisible: widget => widget instanceof PluginViewWidget && this.commands.isVisible(action.command!),
253
249
  });
254
250
  }
255
251
 
@@ -18,12 +18,12 @@ import { injectable, inject, postConstruct } from '@theia/core/shared/inversify'
18
18
  import { Panel, Widget } from '@theia/core/shared/@phosphor/widgets';
19
19
  import { MenuModelRegistry } from '@theia/core/lib/common/menu';
20
20
  import { CommandRegistry } from '@theia/core/lib/common/command';
21
- import { ViewContextKeyService } from './view-context-key-service';
22
21
  import { StatefulWidget } from '@theia/core/lib/browser/shell/shell-layout-restorer';
23
22
  import { Message } from '@theia/core/shared/@phosphor/messaging';
24
23
  import { TreeViewWidget } from './tree-view-widget';
25
24
  import { DescriptionWidget } from '@theia/core/lib/browser/view-container';
26
- import { Emitter } from '@theia/core/lib/common';
25
+ import { DisposableCollection, Emitter } from '@theia/core/lib/common';
26
+ import { ContextKeyService } from '@theia/core/lib/browser/context-key-service';
27
27
 
28
28
  @injectable()
29
29
  export class PluginViewWidgetIdentifier {
@@ -34,14 +34,16 @@ export class PluginViewWidgetIdentifier {
34
34
  @injectable()
35
35
  export class PluginViewWidget extends Panel implements StatefulWidget, DescriptionWidget {
36
36
 
37
+ protected readonly toDispose = new DisposableCollection();
38
+
37
39
  @inject(MenuModelRegistry)
38
40
  protected readonly menus: MenuModelRegistry;
39
41
 
40
42
  @inject(CommandRegistry)
41
43
  protected readonly commands: CommandRegistry;
42
44
 
43
- @inject(ViewContextKeyService)
44
- protected readonly contextKeys: ViewContextKeyService;
45
+ @inject(ContextKeyService)
46
+ protected readonly contextKeyService: ContextKeyService;
45
47
 
46
48
  @inject(PluginViewWidgetIdentifier)
47
49
  readonly options: PluginViewWidgetIdentifier;
@@ -59,6 +61,9 @@ export class PluginViewWidget extends Panel implements StatefulWidget, Descripti
59
61
  @postConstruct()
60
62
  protected init(): void {
61
63
  this.id = this.options.id;
64
+ const localContext = this.contextKeyService.createScoped(this.node);
65
+ localContext.setContext('view', this.options.viewId);
66
+ this.toDispose.push(localContext);
62
67
  }
63
68
 
64
69
  protected onActivateRequest(msg: Message): void {
@@ -148,6 +153,11 @@ export class PluginViewWidget extends Panel implements StatefulWidget, Descripti
148
153
  super.insertWidget(index, widget);
149
154
  this.updateWidgetMessage();
150
155
  }
156
+
157
+ dispose(): void {
158
+ this.toDispose.dispose();
159
+ super.dispose();
160
+ }
151
161
  }
152
162
  export namespace PluginViewWidget {
153
163
  export interface State {
@@ -36,14 +36,13 @@ import {
36
36
  import { MenuPath, MenuModelRegistry, ActionMenuNode } from '@theia/core/lib/common/menu';
37
37
  import * as React from '@theia/core/shared/react';
38
38
  import { PluginSharedStyle } from '../plugin-shared-style';
39
- import { ViewContextKeyService } from './view-context-key-service';
40
39
  import { ACTION_ITEM, Widget } from '@theia/core/lib/browser/widgets/widget';
41
40
  import { Emitter, Event } from '@theia/core/lib/common/event';
42
41
  import { MessageService } from '@theia/core/lib/common/message-service';
43
42
  import { View } from '../../../common/plugin-protocol';
44
43
  import CoreURI from '@theia/core/lib/common/uri';
45
44
  import { ContextKeyService } from '@theia/core/lib/browser/context-key-service';
46
- import * as markdownit from 'markdown-it';
45
+ import * as markdownit from '@theia/core/shared/markdown-it';
47
46
  import { isMarkdownString } from '../../../plugin/markdown-string';
48
47
 
49
48
  export const TREE_NODE_HYPERLINK = 'theia-TreeNodeHyperlink';
@@ -236,8 +235,8 @@ export class TreeViewWidget extends TreeViewWelcomeWidget {
236
235
  @inject(MenuModelRegistry)
237
236
  protected readonly menus: MenuModelRegistry;
238
237
 
239
- @inject(ViewContextKeyService)
240
- protected readonly contextKeys: ViewContextKeyService;
238
+ @inject(ContextKeyService)
239
+ protected readonly contextKeys: ContextKeyService;
241
240
 
242
241
  @inject(TreeViewWidgetIdentifier)
243
242
  readonly identifier: TreeViewWidgetIdentifier;
@@ -343,7 +342,7 @@ export class TreeViewWidget extends TreeViewWelcomeWidget {
343
342
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
344
343
  protected renderInlineCommand(node: ActionMenuNode, index: number, arg: any): React.ReactNode {
345
344
  const { icon } = node;
346
- if (!icon || !this.commands.isVisible(node.action.commandId, arg) || !this.contextKeys.match(node.action.when)) {
345
+ if (!icon || !this.commands.isVisible(node.action.commandId, arg) || !node.action.when || !this.contextKeys.match(node.action.when)) {
347
346
  return false;
348
347
  }
349
348
  const className = [TREE_NODE_SEGMENT_CLASS, TREE_NODE_TAIL_CLASS, icon, ACTION_ITEM, 'theia-tree-view-inline-action'].join(' ');
@@ -74,18 +74,4 @@ export class ViewContextKeyService {
74
74
  match(expression: string | undefined): boolean {
75
75
  return !expression || this.contextKeyService.match(expression);
76
76
  }
77
-
78
- with<T>(input: { view?: string, viewItem?: string }, cb: () => T): T {
79
- const view = this.view.get();
80
- const viewItem = this.viewItem.get();
81
- this.view.set(input.view);
82
- this.viewItem.set(input.viewItem);
83
- try {
84
- return cb();
85
- } finally {
86
- this.view.set(view);
87
- this.viewItem.set(viewItem);
88
- }
89
- }
90
-
91
77
  }
@@ -21,7 +21,7 @@ import {
21
21
  PluginDeployerResolver, PluginDeployerFileHandler, PluginDeployerDirectoryHandler,
22
22
  PluginDeployerEntry, PluginDeployer, PluginDeployerParticipant, PluginDeployerStartContext,
23
23
  PluginDeployerResolverInit, PluginDeployerFileHandlerContext,
24
- PluginDeployerDirectoryHandlerContext, PluginDeployerEntryType, PluginDeployerHandler, PluginType
24
+ PluginDeployerDirectoryHandlerContext, PluginDeployerEntryType, PluginDeployerHandler, PluginType, UnresolvedPluginEntry
25
25
  } from '../../common/plugin-protocol';
26
26
  import { PluginDeployerEntryImpl } from './plugin-deployer-entry-impl';
27
27
  import {
@@ -118,11 +118,16 @@ export class PluginDeployerImpl implements PluginDeployer {
118
118
  }
119
119
 
120
120
  const startDeployTime = performance.now();
121
- const [userPlugins, systemPlugins] = await Promise.all([
122
- this.resolvePlugins(context.userEntries, PluginType.User),
123
- this.resolvePlugins(context.systemEntries, PluginType.System)
124
- ]);
125
- await this.deployPlugins([...userPlugins, ...systemPlugins]);
121
+ const unresolvedUserEntries = context.userEntries.map(id => ({
122
+ id,
123
+ type: PluginType.User
124
+ }));
125
+ const unresolvedSystemEntries = context.systemEntries.map(id => ({
126
+ id,
127
+ type: PluginType.System
128
+ }));
129
+ const plugins = await this.resolvePlugins([...unresolvedUserEntries, ...unresolvedSystemEntries]);
130
+ await this.deployPlugins(plugins);
126
131
  this.logMeasurement('Deploy plugins list', startDeployTime);
127
132
  }
128
133
 
@@ -132,50 +137,53 @@ export class PluginDeployerImpl implements PluginDeployer {
132
137
  }
133
138
  }
134
139
 
135
- async deploy(pluginEntry: string, type: PluginType = PluginType.System): Promise<void> {
140
+ async deploy(plugin: UnresolvedPluginEntry): Promise<void> {
136
141
  const startDeployTime = performance.now();
137
- await this.deployMultipleEntries([pluginEntry], type);
142
+ await this.deployMultipleEntries([plugin]);
138
143
  this.logMeasurement('Deploy plugin entry', startDeployTime);
139
144
  }
140
145
 
141
- protected async deployMultipleEntries(pluginEntries: ReadonlyArray<string>, type: PluginType = PluginType.System): Promise<void> {
142
- const pluginsToDeploy = await this.resolvePlugins(pluginEntries, type);
146
+ protected async deployMultipleEntries(plugins: UnresolvedPluginEntry[]): Promise<void> {
147
+ const pluginsToDeploy = await this.resolvePlugins(plugins);
143
148
  await this.deployPlugins(pluginsToDeploy);
144
149
  }
145
150
 
146
151
  /**
147
152
  * Resolves plugins for the given type.
148
153
  *
149
- * One can call it multiple times for different types before triggering a single deploy, i.e.
154
+ * Only call it a single time before triggering a single deploy to prevent re-resolving of extension dependencies, i.e.
150
155
  * ```ts
151
156
  * const deployer: PluginDeployer;
152
- * deployer.deployPlugins([
153
- * ...await deployer.resolvePlugins(userEntries, PluginType.User),
154
- * ...await deployer.resolvePlugins(systemEntries, PluginType.System)
155
- * ]);
157
+ * deployer.deployPlugins(await deployer.resolvePlugins(allPluginEntries));
156
158
  * ```
157
159
  */
158
- async resolvePlugins(pluginEntries: ReadonlyArray<string>, type: PluginType): Promise<PluginDeployerEntry[]> {
160
+ async resolvePlugins(plugins: UnresolvedPluginEntry[]): Promise<PluginDeployerEntry[]> {
159
161
  const visited = new Set<string>();
160
162
  const pluginsToDeploy = new Map<string, PluginDeployerEntry>();
161
163
 
162
- let queue = [...pluginEntries];
164
+ let queue: UnresolvedPluginEntry[] = [...plugins];
163
165
  while (queue.length) {
164
- const dependenciesChunk: Array<Map<string, string>> = [];
165
- const workload: string[] = [];
166
+ const dependenciesChunk: Array<{
167
+ dependencies: Map<string, string>
168
+ type: PluginType
169
+ }> = [];
170
+ const workload: UnresolvedPluginEntry[] = [];
166
171
  while (queue.length) {
167
172
  const current = queue.shift()!;
168
- if (visited.has(current)) {
173
+ if (visited.has(current.id)) {
169
174
  continue;
170
175
  } else {
171
176
  workload.push(current);
172
177
  }
173
- visited.add(current);
178
+ visited.add(current.id);
174
179
  }
175
180
  queue = [];
176
- await Promise.all(workload.map(async current => {
181
+ await Promise.all(workload.map(async ({ id, type }) => {
182
+ if (type === undefined) {
183
+ type = PluginType.System;
184
+ }
177
185
  try {
178
- const pluginDeployerEntries = await this.resolvePlugin(current, type);
186
+ const pluginDeployerEntries = await this.resolvePlugin(id, type);
179
187
  await this.applyFileHandlers(pluginDeployerEntries);
180
188
  await this.applyDirectoryFileHandlers(pluginDeployerEntries);
181
189
  for (const deployerEntry of pluginDeployerEntries) {
@@ -183,18 +191,21 @@ export class PluginDeployerImpl implements PluginDeployer {
183
191
  if (dependencies && !pluginsToDeploy.has(dependencies.metadata.model.id)) {
184
192
  pluginsToDeploy.set(dependencies.metadata.model.id, deployerEntry);
185
193
  if (dependencies.mapping) {
186
- dependenciesChunk.push(dependencies.mapping);
194
+ dependenciesChunk.push({ dependencies: dependencies.mapping, type });
187
195
  }
188
196
  }
189
197
  }
190
198
  } catch (e) {
191
- console.error(`Failed to resolve plugins from '${current}'`, e);
199
+ console.error(`Failed to resolve plugins from '${id}'`, e);
192
200
  }
193
201
  }));
194
- for (const dependencies of dependenciesChunk) {
202
+ for (const { dependencies, type } of dependenciesChunk) {
195
203
  for (const [dependency, deployableDependency] of dependencies) {
196
204
  if (!pluginsToDeploy.has(dependency)) {
197
- queue.push(deployableDependency);
205
+ queue.push({
206
+ id: deployableDependency,
207
+ type
208
+ });
198
209
  }
199
210
  }
200
211
  }
@@ -18,7 +18,7 @@ import { injectable, inject } from '@theia/core/shared/inversify';
18
18
  import { CancellationToken } from '@theia/core/lib/common/cancellation';
19
19
  import { PluginDeployerImpl } from './plugin-deployer-impl';
20
20
  import { PluginsKeyValueStorage } from './plugins-key-value-storage';
21
- import { PluginServer, PluginDeployer, PluginStorageKind, PluginType } from '../../common/plugin-protocol';
21
+ import { PluginServer, PluginDeployer, PluginStorageKind, PluginType, UnresolvedPluginEntry } from '../../common/plugin-protocol';
22
22
  import { KeysToAnyValues, KeysToKeysToAnyValue } from '../../common/types';
23
23
 
24
24
  @injectable()
@@ -32,10 +32,14 @@ export class PluginServerHandler implements PluginServer {
32
32
 
33
33
  deploy(pluginEntry: string, arg2?: PluginType | CancellationToken): Promise<void> {
34
34
  const type = typeof arg2 === 'number' ? arg2 as PluginType : undefined;
35
- return this.doDeploy(pluginEntry, type);
35
+ return this.doDeploy({
36
+ id: pluginEntry,
37
+ type: type ?? PluginType.User
38
+ });
36
39
  }
37
- protected doDeploy(pluginEntry: string, type: PluginType = PluginType.User): Promise<void> {
38
- return this.pluginDeployer.deploy(pluginEntry, type);
40
+
41
+ protected doDeploy(pluginEntry: UnresolvedPluginEntry): Promise<void> {
42
+ return this.pluginDeployer.deploy(pluginEntry);
39
43
  }
40
44
 
41
45
  undeploy(pluginId: string): Promise<void> {
@@ -29,7 +29,7 @@ import { WebviewImpl, WebviewsExtImpl } from './webviews';
29
29
  import { CancellationToken, CancellationTokenSource } from '@theia/core/lib/common/cancellation';
30
30
  import { DisposableCollection } from '@theia/core/lib/common/disposable';
31
31
  import { WorkspaceExtImpl } from './workspace';
32
- import * as Converters from './type-converters';
32
+ import { WidgetOpenerOptions } from '@theia/core/lib/browser';
33
33
 
34
34
  export class CustomEditorsExtImpl implements CustomEditorsExt {
35
35
  private readonly proxy: CustomEditorsMain;
@@ -121,7 +121,7 @@ export class CustomEditorsExtImpl implements CustomEditorsExt {
121
121
  handler: string,
122
122
  viewType: string,
123
123
  title: string,
124
- position: number,
124
+ widgetOpenerOptions: WidgetOpenerOptions | undefined,
125
125
  options: theia.WebviewPanelOptions & theia.WebviewOptions,
126
126
  cancellation: CancellationToken
127
127
  ): Promise<void> {
@@ -129,10 +129,9 @@ export class CustomEditorsExtImpl implements CustomEditorsExt {
129
129
  if (!entry) {
130
130
  throw new Error(`No provider found for '${viewType}'`);
131
131
  }
132
- const viewColumn = Converters.toViewColumn(position);
133
132
  const panel = this.webviewExt.createWebviewPanel(viewType, title, {}, options, entry.plugin, handler);
134
133
  const webviewOptions = WebviewImpl.toWebviewOptions(options, this.workspace, entry.plugin);
135
- await this.proxy.$createCustomEditorPanel(handler, title, viewColumn, webviewOptions);
134
+ await this.proxy.$createCustomEditorPanel(handler, title, widgetOpenerOptions, webviewOptions);
136
135
 
137
136
  const revivedResource = URI.revive(resource);
138
137
 
@@ -168,6 +168,10 @@ export class DebugExtImpl implements DebugExt {
168
168
  return this.proxy.$startDebugging(folder, nameOrConfiguration, options);
169
169
  }
170
170
 
171
+ stopDebugging(session?: theia.DebugSession): PromiseLike<void> {
172
+ return this.proxy.$stopDebugging(session?.id);
173
+ }
174
+
171
175
  registerDebugAdapterDescriptorFactory(debugType: string, factory: theia.DebugAdapterDescriptorFactory): Disposable {
172
176
  if (this.descriptorFactories.has(debugType)) {
173
177
  throw new Error(`Descriptor factory for ${debugType} has been already registered`);
@@ -784,6 +784,9 @@ export function createAPIFactory(
784
784
  Thenable<boolean> {
785
785
  return debugExt.startDebugging(folder, nameOrConfiguration, options);
786
786
  },
787
+ stopDebugging(session?: theia.DebugSession): Thenable<void> {
788
+ return debugExt.stopDebugging(session);
789
+ },
787
790
  addBreakpoints(breakpoints: theia.Breakpoint[]): void {
788
791
  debugExt.addBreakpoints(breakpoints);
789
792
  },
@@ -14,13 +14,14 @@
14
14
  * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
15
  ********************************************************************************/
16
16
 
17
+ import { isWindows } from '@theia/core';
17
18
  import * as assert from 'assert';
18
19
  import * as types from './types-impl';
19
20
 
20
21
  describe('API Type Implementations:', () => {
21
22
 
22
23
  describe('URI:', () => {
23
- it('should convert to string', () => {
24
+ it('should convert to string', () => {
24
25
  const uriString = 'scheme://authority.com/foo/bar/zoz?query#fragment';
25
26
  const uri = types.URI.parse(uriString);
26
27
  // when
@@ -29,5 +30,40 @@ describe('API Type Implementations:', () => {
29
30
  // then
30
31
  assert.strictEqual(result, uriString);
31
32
  });
33
+
34
+ // Issue: #10370
35
+ it('should returns correct path while using joinPath()', () => {
36
+ if (isWindows) {
37
+ assert.strictEqual(types.URI.joinPath(types.URI.file('c:\\foo\\bar'), '/file.js').toString(), 'file:///c%3A/foo/bar/file.js');
38
+ assert.strictEqual(types.URI.joinPath(types.URI.file('c:\\foo\\bar\\'), 'file.js').toString(), 'file:///c%3A/foo/bar/file.js');
39
+ assert.strictEqual(types.URI.joinPath(types.URI.file('c:\\foo\\bar\\'), '/file.js').toString(), 'file:///c%3A/foo/bar/file.js');
40
+ assert.strictEqual(types.URI.joinPath(types.URI.file('c:\\'), '/file.js').toString(), 'file:///c%3A/file.js');
41
+ assert.strictEqual(types.URI.joinPath(types.URI.file('c:\\'), 'bar/file.js').toString(), 'file:///c%3A/bar/file.js');
42
+ assert.strictEqual(types.URI.joinPath(types.URI.file('c:\\foo'), './file.js').toString(), 'file:///c%3A/foo/file.js');
43
+ assert.strictEqual(types.URI.joinPath(types.URI.file('c:\\foo'), '/./file.js').toString(), 'file:///c%3A/foo/file.js');
44
+ assert.strictEqual(types.URI.joinPath(types.URI.file('C:\\foo'), '../file.js').toString(), 'file:///c%3A/file.js');
45
+ assert.strictEqual(types.URI.joinPath(types.URI.file('C:\\foo\\.'), '../file.js').toString(), 'file:///c%3A/file.js');
46
+ } else {
47
+ assert.strictEqual(types.URI.joinPath(types.URI.file('/foo/bar'), '/file.js').toString(), 'file:///foo/bar/file.js');
48
+ assert.strictEqual(types.URI.joinPath(types.URI.file('/foo/bar'), 'file.js').toString(), 'file:///foo/bar/file.js');
49
+ assert.strictEqual(types.URI.joinPath(types.URI.file('/foo/bar/'), '/file.js').toString(), 'file:///foo/bar/file.js');
50
+ assert.strictEqual(types.URI.joinPath(types.URI.file('/'), '/file.js').toString(), 'file:///file.js');
51
+ assert.strictEqual(types.URI.joinPath(types.URI.file('/foo/bar'), './file.js').toString(), 'file:///foo/bar/file.js');
52
+ assert.strictEqual(types.URI.joinPath(types.URI.file('/foo/bar'), '/./file.js').toString(), 'file:///foo/bar/file.js');
53
+ assert.strictEqual(types.URI.joinPath(types.URI.file('/foo/bar'), '../file.js').toString(), 'file:///foo/file.js');
54
+ }
55
+ assert.strictEqual(types.URI.joinPath(types.URI.parse('foo://a/foo/bar')).toString(), 'foo://a/foo/bar');
56
+ assert.strictEqual(types.URI.joinPath(types.URI.parse('foo://a/foo/bar'), '/file.js').toString(), 'foo://a/foo/bar/file.js');
57
+ assert.strictEqual(types.URI.joinPath(types.URI.parse('foo://a/foo/bar'), 'file.js').toString(), 'foo://a/foo/bar/file.js');
58
+ assert.strictEqual(types.URI.joinPath(types.URI.parse('foo://a/foo/bar/'), '/file.js').toString(), 'foo://a/foo/bar/file.js');
59
+ assert.strictEqual(types.URI.joinPath(types.URI.parse('foo://a/'), '/file.js').toString(), 'foo://a/file.js');
60
+ assert.strictEqual(types.URI.joinPath(types.URI.parse('foo://a/foo/bar/'), './file.js').toString(), 'foo://a/foo/bar/file.js');
61
+ assert.strictEqual(types.URI.joinPath(types.URI.parse('foo://a/foo/bar/'), '/./file.js').toString(), 'foo://a/foo/bar/file.js');
62
+ assert.strictEqual(types.URI.joinPath(types.URI.parse('foo://a/foo/bar/'), '../file.js').toString(), 'foo://a/foo/file.js');
63
+
64
+ assert.strictEqual(
65
+ types.URI.joinPath(types.URI.from({ scheme: 'myScheme', authority: 'authority', path: '/path', query: 'query', fragment: 'fragment' }), '/file.js').toString(),
66
+ 'myScheme://authority/path/file.js?query#fragment');
67
+ });
32
68
  });
33
69
  });
@@ -82,7 +82,7 @@ export class URI extends CodeURI implements theia.Uri {
82
82
  if (!uri.path) {
83
83
  throw new Error('\'joinPath\' called on URI without path');
84
84
  }
85
- const newPath = paths.resolve(uri.path, ...pathSegments);
85
+ const newPath = paths.posix.join(uri.path, ...pathSegments);
86
86
  return new URI(uri.scheme, uri.authority, newPath, uri.query, uri.fragment);
87
87
  }
88
88