@theia/plugin-ext-vscode 1.75.0-next.8 → 1.76.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/lib/browser/plugin-vscode-commands-contribution.d.ts +18 -2
  2. package/lib/browser/plugin-vscode-commands-contribution.d.ts.map +1 -1
  3. package/lib/browser/plugin-vscode-commands-contribution.js +207 -1
  4. package/lib/browser/plugin-vscode-commands-contribution.js.map +1 -1
  5. package/lib/browser/plugin-vscode-commands-contribution.spec.d.ts +2 -0
  6. package/lib/browser/plugin-vscode-commands-contribution.spec.d.ts.map +1 -0
  7. package/lib/browser/plugin-vscode-commands-contribution.spec.js +61 -0
  8. package/lib/browser/plugin-vscode-commands-contribution.spec.js.map +1 -0
  9. package/lib/common/plugin-vscode-types.d.ts +1 -1
  10. package/lib/node/local-vsix-file-plugin-deployer-resolver.d.ts +2 -0
  11. package/lib/node/local-vsix-file-plugin-deployer-resolver.d.ts.map +1 -1
  12. package/lib/node/local-vsix-file-plugin-deployer-resolver.js +8 -2
  13. package/lib/node/local-vsix-file-plugin-deployer-resolver.js.map +1 -1
  14. package/lib/node/plugin-vscode-deployer-participant.d.ts +2 -0
  15. package/lib/node/plugin-vscode-deployer-participant.d.ts.map +1 -1
  16. package/lib/node/plugin-vscode-deployer-participant.js +7 -1
  17. package/lib/node/plugin-vscode-deployer-participant.js.map +1 -1
  18. package/lib/node/plugin-vscode-directory-handler.d.ts +6 -2
  19. package/lib/node/plugin-vscode-directory-handler.d.ts.map +1 -1
  20. package/lib/node/plugin-vscode-directory-handler.js +8 -2
  21. package/lib/node/plugin-vscode-directory-handler.js.map +1 -1
  22. package/lib/node/plugin-vscode-file-handler.d.ts +2 -0
  23. package/lib/node/plugin-vscode-file-handler.d.ts.map +1 -1
  24. package/lib/node/plugin-vscode-file-handler.js +8 -2
  25. package/lib/node/plugin-vscode-file-handler.js.map +1 -1
  26. package/lib/node/scanner-vscode.d.ts.map +1 -1
  27. package/lib/node/scanner-vscode.js +8 -47
  28. package/lib/node/scanner-vscode.js.map +1 -1
  29. package/package.json +18 -17
  30. package/src/browser/plugin-vscode-commands-contribution.spec.ts +68 -0
  31. package/src/browser/plugin-vscode-commands-contribution.ts +239 -3
  32. package/src/node/local-vsix-file-plugin-deployer-resolver.ts +7 -3
  33. package/src/node/plugin-vscode-deployer-participant.ts +6 -2
  34. package/src/node/plugin-vscode-directory-handler.ts +11 -5
  35. package/src/node/plugin-vscode-file-handler.ts +7 -3
  36. package/src/node/scanner-vscode.ts +9 -52
@@ -14,7 +14,7 @@
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
16
 
17
- import { Command, CommandContribution, CommandRegistry, environment, isOSX, CancellationTokenSource, MessageService, isArray } from '@theia/core';
17
+ import { Command, CommandContribution, CommandRegistry, environment, isOSX, CancellationTokenSource, MessageService, isArray, ILogger } from '@theia/core';
18
18
  import {
19
19
  ApplicationShell,
20
20
  CommonCommands,
@@ -50,7 +50,7 @@ import { ViewColumn } from '@theia/plugin-ext/lib/plugin/types-impl';
50
50
  import { WorkspaceCommands } from '@theia/workspace/lib/browser';
51
51
  import { WorkspaceService, WorkspaceInput } from '@theia/workspace/lib/browser/workspace-service';
52
52
  import { DiffService } from '@theia/workspace/lib/browser/diff-service';
53
- import { inject, injectable, optional } from '@theia/core/shared/inversify';
53
+ import { inject, injectable, optional, named } from '@theia/core/shared/inversify';
54
54
  import { Position } from '@theia/plugin-ext/lib/common/plugin-api-rpc';
55
55
  import { URI } from '@theia/core/shared/vscode-uri';
56
56
  import { PluginDeployOptions, PluginIdentifiers, PluginServer } from '@theia/plugin-ext/lib/common/plugin-protocol';
@@ -159,6 +159,88 @@ export interface HidDeviceData {
159
159
  readonly collections: [];
160
160
  }
161
161
 
162
+ export type EditorGroupNavigationDirection = 'left' | 'right' | 'up' | 'down';
163
+
164
+ export interface EditorGroupNavigationRect {
165
+ left: number;
166
+ right: number;
167
+ top: number;
168
+ bottom: number;
169
+ width: number;
170
+ height: number;
171
+ }
172
+
173
+ type EditorGroupNavigationScore = [
174
+ orthogonalRank: number,
175
+ orthogonalGap: number,
176
+ primaryDistance: number,
177
+ orthogonalCenterDistance: number,
178
+ orthogonalStart: number
179
+ ];
180
+
181
+ function isInDirection(source: EditorGroupNavigationRect, candidate: EditorGroupNavigationRect, direction: EditorGroupNavigationDirection): boolean {
182
+ const sourceCenter = rectCenter(source);
183
+ const candidateCenter = rectCenter(candidate);
184
+ switch (direction) {
185
+ case 'left':
186
+ return candidateCenter.x < sourceCenter.x;
187
+ case 'right':
188
+ return candidateCenter.x > sourceCenter.x;
189
+ case 'up':
190
+ return candidateCenter.y < sourceCenter.y;
191
+ case 'down':
192
+ return candidateCenter.y > sourceCenter.y;
193
+ }
194
+ }
195
+
196
+ function score(source: EditorGroupNavigationRect, candidate: EditorGroupNavigationRect, direction: EditorGroupNavigationDirection): EditorGroupNavigationScore {
197
+ const horizontal = direction === 'left' || direction === 'right';
198
+ const sourceCenter = rectCenter(source);
199
+ const candidateCenter = rectCenter(candidate);
200
+ const orthogonalOverlap = horizontal
201
+ ? intervalOverlap(source.top, source.bottom, candidate.top, candidate.bottom)
202
+ : intervalOverlap(source.left, source.right, candidate.left, candidate.right);
203
+ return [
204
+ orthogonalOverlap > 0 ? 0 : 1,
205
+ Math.max(0, -orthogonalOverlap),
206
+ directionalDistance(source, candidate, direction),
207
+ horizontal ? Math.abs(sourceCenter.y - candidateCenter.y) : Math.abs(sourceCenter.x - candidateCenter.x),
208
+ horizontal ? candidate.top : candidate.left
209
+ ];
210
+ }
211
+
212
+ function compareScore(left: EditorGroupNavigationScore, right: EditorGroupNavigationScore): number {
213
+ return left[0] - right[0]
214
+ || left[1] - right[1]
215
+ || left[2] - right[2]
216
+ || left[3] - right[3]
217
+ || left[4] - right[4];
218
+ }
219
+
220
+ function directionalDistance(source: EditorGroupNavigationRect, candidate: EditorGroupNavigationRect, direction: EditorGroupNavigationDirection): number {
221
+ switch (direction) {
222
+ case 'left':
223
+ return Math.max(0, source.left - candidate.right);
224
+ case 'right':
225
+ return Math.max(0, candidate.left - source.right);
226
+ case 'up':
227
+ return Math.max(0, source.top - candidate.bottom);
228
+ case 'down':
229
+ return Math.max(0, candidate.top - source.bottom);
230
+ }
231
+ }
232
+
233
+ function rectCenter(rect: EditorGroupNavigationRect): { x: number, y: number } {
234
+ return {
235
+ x: rect.left + rect.width / 2,
236
+ y: rect.top + rect.height / 2
237
+ };
238
+ }
239
+
240
+ function intervalOverlap(start: number, end: number, candidateStart: number, candidateEnd: number): number {
241
+ return Math.min(end, candidateEnd) - Math.max(start, candidateStart);
242
+ }
243
+
162
244
  @injectable()
163
245
  export class PluginVscodeCommandsContribution implements CommandContribution {
164
246
  @inject(CommandService)
@@ -206,6 +288,9 @@ export class PluginVscodeCommandsContribution implements CommandContribution {
206
288
  @inject(ScmContribution)
207
289
  protected scmContribution: ScmContribution;
208
290
 
291
+ @inject(ILogger) @named('plugin-ext-vscode:PluginVscodeCommandsContribution')
292
+ protected readonly logger: ILogger;
293
+
209
294
  private async openWith(commandId: string, resource: URI, columnOrOptions?: ViewColumn | TextDocumentShowOptions, openerId?: string): Promise<boolean> {
210
295
  if (!resource) {
211
296
  throw new Error(`${commandId} command requires at least URI argument.`);
@@ -251,6 +336,105 @@ export class PluginVscodeCommandsContribution implements CommandContribution {
251
336
  return false;
252
337
  }
253
338
 
339
+ protected navigateEditorGroup(direction: EditorGroupNavigationDirection): boolean {
340
+ const current = this.currentMainAreaTabBar();
341
+ const currentRect = current && this.getEditorGroupRect(current);
342
+ if (!current || current.titles.length === 0 || !currentRect) {
343
+ return false;
344
+ }
345
+
346
+ const candidates: TabBar<Widget>[] = [];
347
+ const candidateRects: EditorGroupNavigationRect[] = [];
348
+ for (const tabBar of this.shell.mainAreaTabBars) {
349
+ if (tabBar === current || tabBar.titles.length === 0) {
350
+ continue;
351
+ }
352
+ const candidateRect = this.getEditorGroupRect(tabBar);
353
+ if (candidateRect) {
354
+ candidates.push(tabBar);
355
+ candidateRects.push(candidateRect);
356
+ }
357
+ }
358
+ const index = this.findClosestEditorGroup(currentRect, candidateRects, direction);
359
+ return index === -1 ? false : this.activateEditorGroup(candidates[index]);
360
+ }
361
+
362
+ protected findClosestEditorGroup(source: EditorGroupNavigationRect, candidates: ReadonlyArray<EditorGroupNavigationRect>, direction: EditorGroupNavigationDirection): number {
363
+ let bestIndex = -1;
364
+ let bestScore: EditorGroupNavigationScore | undefined;
365
+ for (let index = 0; index < candidates.length; index++) {
366
+ const candidate = candidates[index];
367
+ if (!isInDirection(source, candidate, direction)) {
368
+ continue;
369
+ }
370
+ const candidateScore = score(source, candidate, direction);
371
+ if (!bestScore || compareScore(candidateScore, bestScore) < 0) {
372
+ bestIndex = index;
373
+ bestScore = candidateScore;
374
+ }
375
+ }
376
+ return bestIndex;
377
+ }
378
+
379
+ protected navigateEditorGroups(): boolean {
380
+ const current = this.currentMainAreaTabBar();
381
+ const tabBars = this.shell.mainAreaTabBars.filter(tabBar => tabBar.titles.length > 0);
382
+ if (!current || tabBars.length < 2) {
383
+ return false;
384
+ }
385
+ const currentIndex = tabBars.indexOf(current);
386
+ if (currentIndex === -1) {
387
+ return false;
388
+ }
389
+ const target = tabBars[(currentIndex + 1) % tabBars.length];
390
+ return this.activateEditorGroup(target);
391
+ }
392
+
393
+ protected currentMainAreaTabBar(): TabBar<Widget> | undefined {
394
+ const mainAreaTabBars = this.shell.mainAreaTabBars;
395
+ const currentTabBar = this.shell.currentTabBar;
396
+ if (currentTabBar && mainAreaTabBars.includes(currentTabBar)) {
397
+ return currentTabBar;
398
+ }
399
+ const currentEditor = this.editorManager.currentEditor || this.editorManager.activeEditor;
400
+ if (currentEditor) {
401
+ const tabBar = this.shell.getTabBarFor(currentEditor);
402
+ if (tabBar && mainAreaTabBars.includes(tabBar)) {
403
+ return tabBar;
404
+ }
405
+ }
406
+ return undefined;
407
+ }
408
+
409
+ protected getEditorGroupRect(tabBar: TabBar<Widget>): EditorGroupNavigationRect | undefined {
410
+ const title = tabBar.currentTitle || tabBar.titles[0];
411
+ const rects = [
412
+ tabBar.node.getBoundingClientRect(),
413
+ title?.owner.node.getBoundingClientRect()
414
+ ].filter((rect): rect is DOMRect => !!rect && rect.width > 0 && rect.height > 0);
415
+ if (rects.length === 0) {
416
+ return undefined;
417
+ }
418
+ const left = Math.min(...rects.map(rect => rect.left));
419
+ const right = Math.max(...rects.map(rect => rect.right));
420
+ const top = Math.min(...rects.map(rect => rect.top));
421
+ const bottom = Math.max(...rects.map(rect => rect.bottom));
422
+ return { left, right, top, bottom, width: right - left, height: bottom - top };
423
+ }
424
+
425
+ protected activateEditorGroup(tabBar: TabBar<Widget>): boolean {
426
+ let title = tabBar.currentTitle;
427
+ if (!title && tabBar.titles.length > 0) {
428
+ tabBar.currentIndex = 0;
429
+ title = tabBar.currentTitle;
430
+ }
431
+ if (!title) {
432
+ return false;
433
+ }
434
+ this.shell.activateWidget(title.owner.id);
435
+ return true;
436
+ }
437
+
254
438
  registerCommands(commands: CommandRegistry): void {
255
439
  commands.registerCommand(VscodeCommands.GET_CODE_EXCHANGE_ENDPOINTS, {
256
440
  execute: () => undefined // this is a dummy implementation: only used in the case of web apps, which is not supported yet.
@@ -268,7 +452,7 @@ export class PluginVscodeCommandsContribution implements CommandContribution {
268
452
  const message = nls.localizeByDefault("Unable to open '{0}'", resource.path);
269
453
  const reason = nls.localizeByDefault('Error: {0}', error.message);
270
454
  this.messageService.error(`${message}\n${reason}`);
271
- console.warn(error);
455
+ this.logger.warn(error);
272
456
  }
273
457
  }
274
458
  });
@@ -353,35 +537,44 @@ export class PluginVscodeCommandsContribution implements CommandContribution {
353
537
  commands.registerCommand({ id: 'workbench.action.files.openFileFolder' }, {
354
538
  execute: () => commands.executeCommand(WorkspaceCommands.OPEN.id)
355
539
  });
540
+ commands.registerAlias('workbench.action.files.openFileFolder', WorkspaceCommands.OPEN.id);
356
541
  }
357
542
 
358
543
  commands.registerCommand({ id: 'workbench.action.files.openFile' }, {
359
544
  execute: () => commands.executeCommand(WorkspaceCommands.OPEN_FILE.id)
360
545
  });
546
+ commands.registerAlias('workbench.action.files.openFile', WorkspaceCommands.OPEN_FILE.id);
361
547
  commands.registerCommand({ id: 'workbench.action.files.openFolder' }, {
362
548
  execute: () => commands.executeCommand(WorkspaceCommands.OPEN_FOLDER.id)
363
549
  });
550
+ commands.registerAlias('workbench.action.files.openFolder', WorkspaceCommands.OPEN_FOLDER.id);
364
551
  commands.registerCommand({ id: 'workbench.action.addRootFolder' }, {
365
552
  execute: () => commands.executeCommand(WorkspaceCommands.ADD_FOLDER.id)
366
553
  });
554
+ commands.registerAlias('workbench.action.addRootFolder', WorkspaceCommands.ADD_FOLDER.id);
367
555
  commands.registerCommand({ id: 'workbench.action.saveWorkspaceAs' }, {
368
556
  execute: () => commands.executeCommand(WorkspaceCommands.SAVE_WORKSPACE_AS.id)
369
557
  });
558
+ commands.registerAlias('workbench.action.saveWorkspaceAs', WorkspaceCommands.SAVE_WORKSPACE_AS.id);
370
559
  commands.registerCommand({ id: 'workbench.action.gotoLine' }, {
371
560
  execute: () => commands.executeCommand(EditorCommands.GOTO_LINE_COLUMN.id)
372
561
  });
562
+ commands.registerAlias('workbench.action.gotoLine', EditorCommands.GOTO_LINE_COLUMN.id);
373
563
  commands.registerCommand({ id: 'workbench.action.quickOpen' }, {
374
564
  execute: (prefix?: unknown) => this.quickInput.open(typeof prefix === 'string' ? prefix : '')
375
565
  });
376
566
  commands.registerCommand({ id: 'workbench.action.openSettings' }, {
377
567
  execute: (query?: string) => commands.executeCommand(CommonCommands.OPEN_PREFERENCES.id, query)
378
568
  });
569
+ commands.registerAlias('workbench.action.openSettings', CommonCommands.OPEN_PREFERENCES.id);
379
570
  commands.registerCommand({ id: 'workbench.action.openWorkspaceConfigFile' }, {
380
571
  execute: () => commands.executeCommand(WorkspaceCommands.OPEN_WORKSPACE_FILE.id)
381
572
  });
573
+ commands.registerAlias('workbench.action.openWorkspaceConfigFile', WorkspaceCommands.OPEN_WORKSPACE_FILE.id);
382
574
  commands.registerCommand({ id: 'workbench.files.action.refreshFilesExplorer' }, {
383
575
  execute: () => commands.executeCommand(FileNavigatorCommands.REFRESH_NAVIGATOR.id)
384
576
  });
577
+ commands.registerAlias('workbench.files.action.refreshFilesExplorer', FileNavigatorCommands.REFRESH_NAVIGATOR.id);
385
578
  commands.registerCommand(VscodeCommands.INSTALL_EXTENSION_FROM_ID_OR_URI, {
386
579
  execute: async (vsixUriOrExtensionId: TheiaURI | UriComponents | string) => {
387
580
  if (typeof vsixUriOrExtensionId === 'string') {
@@ -443,6 +636,7 @@ export class PluginVscodeCommandsContribution implements CommandContribution {
443
636
  commands.registerCommand({ id: 'workbench.action.closeActiveEditor' }, {
444
637
  execute: () => commands.executeCommand(CommonCommands.CLOSE_MAIN_TAB.id)
445
638
  });
639
+ commands.registerAlias('workbench.action.closeActiveEditor', CommonCommands.CLOSE_MAIN_TAB.id);
446
640
  commands.registerCommand({ id: 'workbench.action.closeOtherEditors' }, {
447
641
  execute: async (uri?: monaco.Uri) => {
448
642
  let editor = this.editorManager.currentEditor || this.shell.currentWidget;
@@ -560,15 +754,53 @@ export class PluginVscodeCommandsContribution implements CommandContribution {
560
754
  commands.registerCommand({ id: 'workbench.action.previousEditor' }, {
561
755
  execute: () => this.shell.activatePreviousTab()
562
756
  });
757
+ commands.registerCommand({
758
+ id: 'workbench.action.navigateLeft',
759
+ label: nls.localizeByDefault('Navigate to the View on the Left'),
760
+ category: nls.localizeByDefault('View')
761
+ }, {
762
+ execute: () => this.navigateEditorGroup('left')
763
+ });
764
+ commands.registerCommand({
765
+ id: 'workbench.action.navigateRight',
766
+ label: nls.localizeByDefault('Navigate to the View on the Right'),
767
+ category: nls.localizeByDefault('View')
768
+ }, {
769
+ execute: () => this.navigateEditorGroup('right')
770
+ });
771
+ commands.registerCommand({
772
+ id: 'workbench.action.navigateUp',
773
+ label: nls.localizeByDefault('Navigate to the View Above'),
774
+ category: nls.localizeByDefault('View')
775
+ }, {
776
+ execute: () => this.navigateEditorGroup('up')
777
+ });
778
+ commands.registerCommand({
779
+ id: 'workbench.action.navigateDown',
780
+ label: nls.localizeByDefault('Navigate to the View Below'),
781
+ category: nls.localizeByDefault('View')
782
+ }, {
783
+ execute: () => this.navigateEditorGroup('down')
784
+ });
785
+ commands.registerCommand({
786
+ id: 'workbench.action.navigateEditorGroups',
787
+ label: nls.localizeByDefault('Navigate Between Editor Groups'),
788
+ category: nls.localizeByDefault('View')
789
+ }, {
790
+ execute: () => this.navigateEditorGroups()
791
+ });
563
792
  commands.registerCommand({ id: 'workbench.action.navigateBack' }, {
564
793
  execute: () => commands.executeCommand(EditorCommands.GO_BACK.id)
565
794
  });
795
+ commands.registerAlias('workbench.action.navigateBack', EditorCommands.GO_BACK.id);
566
796
  commands.registerCommand({ id: 'workbench.action.navigateForward' }, {
567
797
  execute: () => commands.executeCommand(EditorCommands.GO_FORWARD.id)
568
798
  });
799
+ commands.registerAlias('workbench.action.navigateForward', EditorCommands.GO_FORWARD.id);
569
800
  commands.registerCommand({ id: 'workbench.action.navigateToLastEditLocation' }, {
570
801
  execute: () => commands.executeCommand(EditorCommands.GO_LAST_EDIT.id)
571
802
  });
803
+ commands.registerAlias('workbench.action.navigateToLastEditLocation', EditorCommands.GO_LAST_EDIT.id);
572
804
 
573
805
  commands.registerCommand({ id: 'openInTerminal' }, {
574
806
  execute: (resource: URI) => this.terminalContribution.openInTerminal(new TheiaURI(resource.toString()))
@@ -872,6 +1104,7 @@ export class PluginVscodeCommandsContribution implements CommandContribution {
872
1104
  }, {
873
1105
  execute: () => commands.executeCommand(WorkspaceCommands.NEW_FOLDER.id)
874
1106
  });
1107
+ commands.registerAlias('explorer.newFolder', WorkspaceCommands.NEW_FOLDER.id);
875
1108
  commands.registerCommand({
876
1109
  id: 'workbench.action.terminal.sendSequence'
877
1110
  }, {
@@ -907,16 +1140,19 @@ export class PluginVscodeCommandsContribution implements CommandContribution {
907
1140
  }, {
908
1141
  execute: () => commands.executeCommand(FileNavigatorCommands.FOCUS.id)
909
1142
  });
1143
+ commands.registerAlias('workbench.view.explorer', FileNavigatorCommands.FOCUS.id);
910
1144
  commands.registerCommand({
911
1145
  id: 'copyFilePath'
912
1146
  }, {
913
1147
  execute: () => commands.executeCommand(CommonCommands.COPY_PATH.id)
914
1148
  });
1149
+ commands.registerAlias('copyFilePath', CommonCommands.COPY_PATH.id);
915
1150
  commands.registerCommand({
916
1151
  id: 'copyRelativeFilePath'
917
1152
  }, {
918
1153
  execute: () => commands.executeCommand(WorkspaceCommands.COPY_RELATIVE_FILE_PATH.id)
919
1154
  });
1155
+ commands.registerAlias('copyRelativeFilePath', WorkspaceCommands.COPY_RELATIVE_FILE_PATH.id);
920
1156
  commands.registerCommand({
921
1157
  id: 'revealInExplorer'
922
1158
  }, {
@@ -15,12 +15,13 @@
15
15
  // *****************************************************************************
16
16
 
17
17
  import * as path from 'path';
18
- import { inject, injectable } from '@theia/core/shared/inversify';
18
+ import { inject, injectable, named } from '@theia/core/shared/inversify';
19
19
  import { PluginDeployerResolverContext, PluginIdentifiers } from '@theia/plugin-ext';
20
20
  import { LocalPluginDeployerResolver } from '@theia/plugin-ext/lib/main/node/resolvers/local-plugin-deployer-resolver';
21
21
  import { PluginVSCodeEnvironment } from '../common/plugin-vscode-environment';
22
22
  import { isVSCodePluginFile } from './plugin-vscode-file-handler';
23
23
  import { existsInDeploymentDir, unpackToDeploymentDir, extractExtensionIdentityFromVsix } from './plugin-vscode-utils';
24
+ import { ILogger } from '@theia/core';
24
25
 
25
26
  @injectable()
26
27
  export class LocalVSIXFilePluginDeployerResolver extends LocalPluginDeployerResolver {
@@ -29,6 +30,9 @@ export class LocalVSIXFilePluginDeployerResolver extends LocalPluginDeployerReso
29
30
 
30
31
  @inject(PluginVSCodeEnvironment) protected readonly environment: PluginVSCodeEnvironment;
31
32
 
33
+ @inject(ILogger) @named('plugin-ext-vscode:LocalVSIXFilePluginDeployerResolver')
34
+ protected override readonly logger: ILogger;
35
+
32
36
  protected get supportedScheme(): string {
33
37
  return LocalVSIXFilePluginDeployerResolver.LOCAL_FILE;
34
38
  }
@@ -47,10 +51,10 @@ export class LocalVSIXFilePluginDeployerResolver extends LocalPluginDeployerReso
47
51
  // Fallback to filename-based ID if package.json cannot be read
48
52
  // This maintains backward compatibility for edge cases
49
53
  const fallbackId = path.basename(localPath, LocalVSIXFilePluginDeployerResolver.FILE_EXTENSION);
50
- console.warn(`[${pluginResolverContext.getOriginId()}]: Could not read extension identity from VSIX, falling back to filename: ${fallbackId}`);
54
+ this.logger.warn(`[${pluginResolverContext.getOriginId()}]: Could not read extension identity from VSIX, falling back to filename: ${fallbackId}`);
51
55
 
52
56
  if (await existsInDeploymentDir(this.environment, fallbackId)) {
53
- console.log(`[${pluginResolverContext.getOriginId()}]: Target dir already exists in plugin deployment dir`);
57
+ this.logger.info(`[${pluginResolverContext.getOriginId()}]: Target dir already exists in plugin deployment dir`);
54
58
  return;
55
59
  }
56
60
 
@@ -14,12 +14,13 @@
14
14
  // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
15
15
  // *****************************************************************************
16
16
 
17
- import { injectable, inject } from '@theia/core/shared/inversify';
17
+ import { injectable, inject, named } from '@theia/core/shared/inversify';
18
18
  import * as fs from '@theia/core/shared/fs-extra';
19
19
  import { FileUri } from '@theia/core/lib/node';
20
20
  import { PluginVSCodeEnvironment } from '../common/plugin-vscode-environment';
21
21
  import { PluginDeployerParticipant, PluginDeployerStartContext } from '@theia/plugin-ext/lib/common/plugin-protocol';
22
22
  import { LocalVSIXFilePluginDeployerResolver } from './local-vsix-file-plugin-deployer-resolver';
23
+ import { ILogger } from '@theia/core';
23
24
 
24
25
  @injectable()
25
26
  export class PluginVSCodeDeployerParticipant implements PluginDeployerParticipant {
@@ -27,6 +28,9 @@ export class PluginVSCodeDeployerParticipant implements PluginDeployerParticipan
27
28
  @inject(PluginVSCodeEnvironment)
28
29
  protected readonly environments: PluginVSCodeEnvironment;
29
30
 
31
+ @inject(ILogger) @named('plugin-ext-vscode:PluginVSCodeDeployerParticipant')
32
+ protected readonly logger: ILogger;
33
+
30
34
  async onWillStart(context: PluginDeployerStartContext): Promise<void> {
31
35
  const extensionDeploymentDirUri = await this.environments.getDeploymentDirUri();
32
36
  context.userEntries.push(extensionDeploymentDirUri.withScheme('local-dir').toString());
@@ -39,7 +43,7 @@ export class PluginVSCodeDeployerParticipant implements PluginDeployerParticipan
39
43
  for (const file of files) {
40
44
  if (file.endsWith(LocalVSIXFilePluginDeployerResolver.FILE_EXTENSION)) {
41
45
  const extensionUri = userExtensionDirUri.resolve(file).withScheme('local-file').toString();
42
- console.log(`found drop-in extension "${extensionUri}"`);
46
+ this.logger.info(`found drop-in extension "${extensionUri}"`);
43
47
  context.userEntries.push(extensionUri);
44
48
  }
45
49
  }
@@ -16,8 +16,8 @@
16
16
 
17
17
  import * as path from 'path';
18
18
  import * as fs from '@theia/core/shared/fs-extra';
19
- import { inject, injectable } from '@theia/core/shared/inversify';
20
- import type { RecursivePartial, URI } from '@theia/core';
19
+ import { inject, injectable, named } from '@theia/core/shared/inversify';
20
+ import { ILogger, type URI } from '@theia/core';
21
21
  import { Deferred, firstTrue } from '@theia/core/lib/common/promise-util';
22
22
  import {
23
23
  PluginDeployerDirectoryHandler, PluginDeployerEntry, PluginDeployerDirectoryHandlerContext,
@@ -26,6 +26,9 @@ import {
26
26
  import { PluginCliContribution } from '@theia/plugin-ext/lib/main/node/plugin-cli-contribution';
27
27
  import { TMP_DIR_PREFIX } from './plugin-vscode-utils';
28
28
 
29
+ /** Fields read while resolving a VS Code extension directory */
30
+ type PluginPackageResolveInput = Partial<Pick<PluginPackage, 'name' | 'version' | 'publisher' | 'engines'>>;
31
+
29
32
  @injectable()
30
33
  export class PluginVsCodeDirectoryHandler implements PluginDeployerDirectoryHandler {
31
34
 
@@ -33,8 +36,11 @@ export class PluginVsCodeDirectoryHandler implements PluginDeployerDirectoryHand
33
36
 
34
37
  @inject(PluginCliContribution) protected readonly pluginCli: PluginCliContribution;
35
38
 
39
+ @inject(ILogger) @named('plugin-ext-vscode:PluginVsCodeDirectoryHandler')
40
+ protected readonly logger: ILogger;
41
+
36
42
  async accept(plugin: PluginDeployerEntry): Promise<boolean> {
37
- console.debug(`Resolving "${plugin.id()}" as a VS Code extension...`);
43
+ this.logger.debug(`Resolving "${plugin.id()}" as a VS Code extension...`);
38
44
  if (plugin.path().startsWith(TMP_DIR_PREFIX)) {
39
45
  // avoid adding corrupted plugins from temporary directories
40
46
  return false;
@@ -92,7 +98,7 @@ export class PluginVsCodeDirectoryHandler implements PluginDeployerDirectoryHand
92
98
 
93
99
  protected resolvePackage(plugin: PluginDeployerEntry, options?: {
94
100
  pluginPath: string
95
- pck?: RecursivePartial<PluginPackage>
101
+ pck?: PluginPackageResolveInput
96
102
  }): boolean {
97
103
  const { pluginPath, pck } = options || {
98
104
  pluginPath: plugin.path(),
@@ -107,7 +113,7 @@ export class PluginVsCodeDirectoryHandler implements PluginDeployerDirectoryHand
107
113
  plugin.rootPath = plugin.path();
108
114
  plugin.updatePath(pluginPath);
109
115
  }
110
- console.debug(`Resolved "${plugin.id()}" to a VS Code extension "${pck.name}@${pck.version}" with engines:`, pck.engines);
116
+ this.logger.debug(`Resolved "${plugin.id()}" to a VS Code extension "${pck.name}@${pck.version}" with engines:`, pck.engines);
111
117
  return true;
112
118
  }
113
119
 
@@ -16,11 +16,12 @@
16
16
 
17
17
  import { PluginDeployerFileHandler, PluginDeployerEntry, PluginDeployerFileHandlerContext } from '@theia/plugin-ext';
18
18
  import * as filenamify from 'filenamify';
19
- import { inject, injectable } from '@theia/core/shared/inversify';
19
+ import { inject, injectable, named } from '@theia/core/shared/inversify';
20
20
  import * as fs from '@theia/core/shared/fs-extra';
21
21
  import { PluginVSCodeEnvironment } from '../common/plugin-vscode-environment';
22
22
  import { FileUri } from '@theia/core/lib/common/file-uri';
23
23
  import { unpackToDeploymentDir } from './plugin-vscode-utils';
24
+ import { ILogger } from '@theia/core';
24
25
 
25
26
  export const isVSCodePluginFile = (pluginPath?: string) => Boolean(pluginPath && (pluginPath.endsWith('.vsix') || pluginPath.endsWith('.tgz')));
26
27
 
@@ -29,6 +30,9 @@ export class PluginVsCodeFileHandler implements PluginDeployerFileHandler {
29
30
  @inject(PluginVSCodeEnvironment)
30
31
  protected readonly environment: PluginVSCodeEnvironment;
31
32
 
33
+ @inject(ILogger) @named('plugin-ext-vscode:PluginVsCodeFileHandler')
34
+ protected readonly logger: ILogger;
35
+
32
36
  async accept(resolvedPlugin: PluginDeployerEntry): Promise<boolean> {
33
37
  return resolvedPlugin.isFile().then(file => {
34
38
  if (!file) {
@@ -42,7 +46,7 @@ export class PluginVsCodeFileHandler implements PluginDeployerFileHandler {
42
46
  const id = this.getNormalizedExtensionId(context.pluginEntry().id());
43
47
  const extensionDeploymentDir = await unpackToDeploymentDir(this.environment, context.pluginEntry().path(), id);
44
48
  context.pluginEntry().updatePath(extensionDeploymentDir);
45
- console.log(`root path: ${context.pluginEntry().rootPath}`);
49
+ this.logger.info(`root path: ${context.pluginEntry().rootPath}`);
46
50
  const originalPath = context.pluginEntry().originalPath();
47
51
  if (originalPath && originalPath !== extensionDeploymentDir) {
48
52
  const tempDirUri = await this.environment.getTempDirUri();
@@ -50,7 +54,7 @@ export class PluginVsCodeFileHandler implements PluginDeployerFileHandler {
50
54
  try {
51
55
  await fs.remove(FileUri.fsPath(originalPath));
52
56
  } catch (e) {
53
- console.error(`[${id}]: failed to remove temporary files: "${originalPath}"`, e);
57
+ this.logger.error(`[${id}]: failed to remove temporary files: "${originalPath}"`, e);
54
58
  }
55
59
  }
56
60
  }
@@ -16,10 +16,11 @@
16
16
 
17
17
  import * as path from 'path';
18
18
  import { injectable } from '@theia/core/shared/inversify';
19
- import { PluginScanner, PluginEngine, PluginPackage, PluginModel, PluginLifecycle, PluginEntryPoint, buildFrontendModuleName, UIKind, PluginIdentifiers } from '@theia/plugin-ext';
19
+ import { PluginScanner, PluginEngine, PluginPackage, PluginModel, PluginLifecycle, PluginIdentifiers, UIKind } from '@theia/plugin-ext';
20
20
  import { TheiaPluginScanner } from '@theia/plugin-ext/lib/hosted/node/scanners/scanner-theia';
21
21
  import { environment } from '@theia/core/shared/@theia/application-package/lib/environment';
22
22
  import { VSCodeExtensionUri } from '../common/plugin-vscode-uri';
23
+ import { buildLifecycle, buildModelForVsCode } from '@theia/plugin-utils/lib/common/plugin-model';
23
24
 
24
25
  const uiKind = environment.electron.is() ? UIKind.Desktop : UIKind.Web;
25
26
 
@@ -33,49 +34,13 @@ export class VsCodePluginScanner extends TheiaPluginScanner implements PluginSca
33
34
  }
34
35
 
35
36
  override getModel(plugin: PluginPackage): PluginModel {
36
- // publisher can be empty on vscode extension development
37
- const publisher = plugin.publisher ?? PluginIdentifiers.UNPUBLISHED;
38
-
39
- // Only one entrypoint is valid in vscode extensions
40
- // Mimic choosing frontend (web extension) and backend (local/remote extension) as described here:
41
- // https://code.visualstudio.com/api/advanced-topics/extension-host#preferred-extension-location
42
- const entryPoint: PluginEntryPoint = {};
43
-
44
- // Act like codespaces when run in the browser (UIKind === 'web' and extensionKind is ['ui'])
45
- const preferFrontend = uiKind === UIKind.Web && (plugin.extensionKind?.length === 1 && plugin.extensionKind[0] === 'ui');
46
-
47
- if (plugin.browser && (!plugin.main || preferFrontend)) {
48
- // Use frontend if available and there is no backend or frontend is preferred
49
- entryPoint.frontend = plugin.browser;
50
- } else {
51
- // Default to using backend
52
- entryPoint.backend = plugin.main;
53
- }
54
- if (plugin.theiaPlugin?.headless) {
55
- // Support the Theia-specific extension for headless plugins
56
- entryPoint.headless = plugin.theiaPlugin?.headless;
57
- }
58
-
59
- const result: PluginModel = {
60
- packagePath: plugin.packagePath,
37
+ const result = buildModelForVsCode({
38
+ ...plugin,
39
+ publisher: plugin.publisher ?? PluginIdentifiers.UNPUBLISHED,
61
40
  packageUri: this.pluginUriFactory.createUri(plugin).toString(),
62
- // see id definition: https://github.com/microsoft/vscode/blob/15916055fe0cb9411a5f36119b3b012458fe0a1d/src/vs/platform/extensions/common/extensions.ts#L167-L169
63
- id: `${publisher.toLowerCase()}.${plugin.name.toLowerCase()}`,
64
- name: plugin.name,
65
- publisher: publisher,
66
- version: plugin.version,
67
- displayName: plugin.displayName,
68
- description: plugin.description,
69
- engine: {
70
- type: this.VSCODE_TYPE,
71
- version: plugin.engines[this.VSCODE_TYPE]
72
- },
73
- entryPoint,
74
- iconUrl: plugin.icon && PluginPackage.toPluginUrl(plugin, plugin.icon),
75
- l10n: plugin.l10n,
76
- readmeUrl: this.getReadmeUrl(plugin),
77
- licenseUrl: this.getLicenseUrl(plugin)
78
- };
41
+ }, { uiKind: uiKind === UIKind.Web ? 'web' : 'desktop' });
42
+ result.licenseUrl = this.getLicenseUrl(plugin);
43
+ result.readmeUrl = this.getReadmeUrl(plugin);
79
44
  this.applyTrustExtraction(plugin, result);
80
45
  return result;
81
46
  }
@@ -84,29 +49,21 @@ export class VsCodePluginScanner extends TheiaPluginScanner implements PluginSca
84
49
  * Maps extension dependencies to deployable extension dependencies.
85
50
  */
86
51
  override getDependencies(plugin: PluginPackage): Map<string, string> | undefined {
87
- // Store the list of dependencies.
88
52
  const dependencies = new Map<string, string>();
89
- // Iterate through the list of dependencies from `extensionDependencies` and `extensionPack`.
90
53
  for (const dependency of [plugin.extensionDependencies, plugin.extensionPack]) {
91
54
  if (dependency !== undefined) {
92
- // Iterate over the list of dependencies present, and add them to the collection.
93
55
  dependency.forEach((dep: string) => {
94
56
  const dependencyId = dep.toLowerCase();
95
57
  dependencies.set(dependencyId, VSCodeExtensionUri.fromId(dependencyId).toString());
96
58
  });
97
59
  }
98
60
  }
99
- // Return the map of dependencies if present, else `undefined`.
100
61
  return dependencies.size > 0 ? dependencies : undefined;
101
62
  }
102
63
 
103
64
  override getLifecycle(plugin: PluginPackage): PluginLifecycle {
104
65
  return {
105
- startMethod: 'activate',
106
- stopMethod: 'deactivate',
107
- frontendModuleName: buildFrontendModuleName(plugin),
108
-
109
- frontendInitPath: 'plugin-vscode-init-fe.js',
66
+ ...buildLifecycle(plugin, 'vscode'),
110
67
  backendInitPath: path.join(__dirname, 'plugin-vscode-init'),
111
68
  };
112
69
  }