@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.
- package/lib/browser/plugin-vscode-commands-contribution.d.ts +18 -2
- package/lib/browser/plugin-vscode-commands-contribution.d.ts.map +1 -1
- package/lib/browser/plugin-vscode-commands-contribution.js +207 -1
- package/lib/browser/plugin-vscode-commands-contribution.js.map +1 -1
- package/lib/browser/plugin-vscode-commands-contribution.spec.d.ts +2 -0
- package/lib/browser/plugin-vscode-commands-contribution.spec.d.ts.map +1 -0
- package/lib/browser/plugin-vscode-commands-contribution.spec.js +61 -0
- package/lib/browser/plugin-vscode-commands-contribution.spec.js.map +1 -0
- package/lib/common/plugin-vscode-types.d.ts +1 -1
- package/lib/node/local-vsix-file-plugin-deployer-resolver.d.ts +2 -0
- package/lib/node/local-vsix-file-plugin-deployer-resolver.d.ts.map +1 -1
- package/lib/node/local-vsix-file-plugin-deployer-resolver.js +8 -2
- package/lib/node/local-vsix-file-plugin-deployer-resolver.js.map +1 -1
- package/lib/node/plugin-vscode-deployer-participant.d.ts +2 -0
- package/lib/node/plugin-vscode-deployer-participant.d.ts.map +1 -1
- package/lib/node/plugin-vscode-deployer-participant.js +7 -1
- package/lib/node/plugin-vscode-deployer-participant.js.map +1 -1
- package/lib/node/plugin-vscode-directory-handler.d.ts +6 -2
- package/lib/node/plugin-vscode-directory-handler.d.ts.map +1 -1
- package/lib/node/plugin-vscode-directory-handler.js +8 -2
- package/lib/node/plugin-vscode-directory-handler.js.map +1 -1
- package/lib/node/plugin-vscode-file-handler.d.ts +2 -0
- package/lib/node/plugin-vscode-file-handler.d.ts.map +1 -1
- package/lib/node/plugin-vscode-file-handler.js +8 -2
- package/lib/node/plugin-vscode-file-handler.js.map +1 -1
- package/lib/node/scanner-vscode.d.ts.map +1 -1
- package/lib/node/scanner-vscode.js +8 -47
- package/lib/node/scanner-vscode.js.map +1 -1
- package/package.json +18 -17
- package/src/browser/plugin-vscode-commands-contribution.spec.ts +68 -0
- package/src/browser/plugin-vscode-commands-contribution.ts +239 -3
- package/src/node/local-vsix-file-plugin-deployer-resolver.ts +7 -3
- package/src/node/plugin-vscode-deployer-participant.ts +6 -2
- package/src/node/plugin-vscode-directory-handler.ts +11 -5
- package/src/node/plugin-vscode-file-handler.ts +7 -3
- 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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?:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
37
|
-
|
|
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
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
|
|
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
|
}
|