Skip to content

Commit

Permalink
Install vsix files from the explorer view (#13269)
Browse files Browse the repository at this point in the history
  • Loading branch information
dhuebner committed Feb 9, 2024
1 parent 3034c0a commit 2bb8237
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 25 deletions.
1 change: 1 addition & 0 deletions packages/vsx-registry/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"dependencies": {
"@theia/core": "1.46.0",
"@theia/filesystem": "1.46.0",
"@theia/navigator": "1.46.0",
"@theia/ovsx-client": "1.46.0",
"@theia/plugin-ext": "1.46.0",
"@theia/plugin-ext-vscode": "1.46.0",
Expand Down
7 changes: 7 additions & 0 deletions packages/vsx-registry/src/browser/vsx-extension-commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ export namespace VSXExtensionsCommands {
label: nls.localizeByDefault('Install from VSIX') + '...',
dialogLabel: nls.localizeByDefault('Install from VSIX')
};
export const INSTALL_VSIX: Command = {
id: 'vsxExtensions.installVSIX',
label: nls.localizeByDefault('Install Extension VSIX'),
originalLabel: 'Install Extension VSIX',
category: nls.localizeByDefault(EXTENSIONS_CATEGORY),
originalCategory: EXTENSIONS_CATEGORY,
};
export const INSTALL_ANOTHER_VERSION: Command = {
id: 'vsxExtensions.installAnotherVersion'
};
Expand Down
71 changes: 47 additions & 24 deletions packages/vsx-registry/src/browser/vsx-extensions-contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,29 +14,32 @@
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************

import { DateTime } from 'luxon';
import { injectable, inject, postConstruct } from '@theia/core/shared/inversify';
import debounce = require('@theia/core/shared/lodash.debounce');
import { Command, CommandRegistry } from '@theia/core/lib/common/command';
import { AbstractViewContribution } from '@theia/core/lib/browser/shell/view-contribution';
import { VSXExtensionsViewContainer } from './vsx-extensions-view-container';
import { VSXExtensionsModel } from './vsx-extensions-model';
import { CommonMenus, LabelProvider, PreferenceService, QuickInputService, QuickPickItem } from '@theia/core/lib/browser';
import { ClipboardService } from '@theia/core/lib/browser/clipboard-service';
import { ColorContribution } from '@theia/core/lib/browser/color-application-contribution';
import { ColorRegistry } from '@theia/core/lib/browser/color-registry';
import { Color } from '@theia/core/lib/common/color';
import { FrontendApplication } from '@theia/core/lib/browser/frontend-application';
import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application-contribution';
import { MenuModelRegistry, MessageService, nls } from '@theia/core/lib/common';
import { AbstractViewContribution } from '@theia/core/lib/browser/shell/view-contribution';
import { MenuModelRegistry, MessageService, SelectionService, nls } from '@theia/core/lib/common';
import { Color } from '@theia/core/lib/common/color';
import { Command, CommandRegistry } from '@theia/core/lib/common/command';
import URI from '@theia/core/lib/common/uri';
import { UriAwareCommandHandler } from '@theia/core/lib/common/uri-command-handler';
import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
import { FileDialogService, OpenFileDialogProps } from '@theia/filesystem/lib/browser';
import { LabelProvider, PreferenceService, QuickPickItem, QuickInputService, CommonMenus } from '@theia/core/lib/browser';
import { NAVIGATOR_CONTEXT_MENU } from '@theia/navigator/lib/browser/navigator-contribution';
import { OVSXApiFilter, VSXExtensionRaw } from '@theia/ovsx-client';
import { VscodeCommands } from '@theia/plugin-ext-vscode/lib/browser/plugin-vscode-commands-contribution';
import { VSXExtensionsContextMenu, VSXExtension } from './vsx-extension';
import { ClipboardService } from '@theia/core/lib/browser/clipboard-service';
import { BUILTIN_QUERY, INSTALLED_QUERY, RECOMMENDED_QUERY } from './vsx-extensions-search-model';
import { DateTime } from 'luxon';
import { OVSXClientProvider } from '../common/ovsx-client-provider';
import { IGNORE_RECOMMENDATIONS_ID } from './recommended-extensions/recommended-extensions-preference-contribution';
import { VSXExtension, VSXExtensionsContextMenu } from './vsx-extension';
import { VSXExtensionsCommands } from './vsx-extension-commands';
import { VSXExtensionRaw, OVSXApiFilter } from '@theia/ovsx-client';
import { OVSXClientProvider } from '../common/ovsx-client-provider';
import { VSXExtensionsModel } from './vsx-extensions-model';
import { BUILTIN_QUERY, INSTALLED_QUERY, RECOMMENDED_QUERY } from './vsx-extensions-search-model';
import { VSXExtensionsViewContainer } from './vsx-extensions-view-container';
import debounce = require('@theia/core/shared/lodash.debounce');

export namespace VSXCommands {
export const TOGGLE_EXTENSIONS: Command = {
Expand All @@ -57,6 +60,7 @@ export class VSXExtensionsContribution extends AbstractViewContribution<VSXExten
@inject(OVSXClientProvider) protected clientProvider: OVSXClientProvider;
@inject(OVSXApiFilter) protected vsxApiFilter: OVSXApiFilter;
@inject(QuickInputService) protected quickInput: QuickInputService;
@inject(SelectionService) protected readonly selectionService: SelectionService;

constructor() {
super({
Expand Down Expand Up @@ -95,6 +99,12 @@ export class VSXExtensionsContribution extends AbstractViewContribution<VSXExten
execute: () => this.installFromVSIX()
});

commands.registerCommand(VSXExtensionsCommands.INSTALL_VSIX,
UriAwareCommandHandler.MonoSelect(this.selectionService, {
execute: fileURI => this.installVSIX(fileURI)
}
));

commands.registerCommand(VSXExtensionsCommands.INSTALL_ANOTHER_VERSION, {
// Check downloadUrl to ensure we have an idea of where to look for other versions.
isEnabled: (extension: VSXExtension) => !extension.builtin && !!extension.downloadUrl,
Expand Down Expand Up @@ -143,6 +153,11 @@ export class VSXExtensionsContribution extends AbstractViewContribution<VSXExten
commandId: VSXExtensionsCommands.INSTALL_ANOTHER_VERSION.id,
label: nls.localizeByDefault('Install Another Version...'),
});
menus.registerMenuAction(NAVIGATOR_CONTEXT_MENU, {
commandId: VSXExtensionsCommands.INSTALL_VSIX.id,
label: VSXExtensionsCommands.INSTALL_VSIX.label,
when: 'resourceScheme == file && resourceExtname == .vsix'
});
}

registerColors(colors: ColorRegistry): void {
Expand Down Expand Up @@ -199,25 +214,33 @@ export class VSXExtensionsContribution extends AbstractViewContribution<VSXExten
title: VSXExtensionsCommands.INSTALL_FROM_VSIX.dialogLabel,
openLabel: nls.localizeByDefault('Install from VSIX'),
filters: { 'VSIX Extensions (*.vsix)': ['vsix'] },
canSelectMany: false
canSelectMany: false,
canSelectFiles: true
};
const extensionUri = await this.fileDialogService.showOpenDialog(props);
if (extensionUri) {
if (extensionUri.path.ext === '.vsix') {
const extensionName = this.labelProvider.getName(extensionUri);
try {
await this.commandRegistry.executeCommand(VscodeCommands.INSTALL_FROM_VSIX.id, extensionUri);
this.messageService.info(nls.localizeByDefault('Completed installing {0} extension from VSIX.', extensionName));
} catch (e) {
this.messageService.error(nls.localize('theia/vsx-registry/failedInstallingVSIX', 'Failed to install {0} from VSIX.', extensionName));
console.warn(e);
}
await this.installVSIX(extensionUri);
} else {
this.messageService.error(nls.localize('theia/vsx-registry/invalidVSIX', 'The selected file is not a valid "*.vsix" plugin.'));
}
}
}

/**
* Installs a local extension file.
*/
protected async installVSIX(fileURI: URI): Promise<void> {
const extensionName = this.labelProvider.getName(fileURI);
try {
await this.commandRegistry.executeCommand(VscodeCommands.INSTALL_FROM_VSIX.id, fileURI);
this.messageService.info(nls.localizeByDefault('Completed installing {0} extension from VSIX.', extensionName));
} catch (e) {
this.messageService.error(nls.localize('theia/vsx-registry/failedInstallingVSIX', 'Failed to install {0} from VSIX.', extensionName));
console.warn(e);
}
}

/**
* Given an extension, displays a quick pick of other compatible versions and installs the selected version.
*
Expand Down
11 changes: 10 additions & 1 deletion packages/vsx-registry/src/browser/vsx-extensions-widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
// *****************************************************************************

import { injectable, interfaces, postConstruct, inject } from '@theia/core/shared/inversify';
import { TreeModel, TreeNode } from '@theia/core/lib/browser';
import { Message, TreeModel, TreeNode } from '@theia/core/lib/browser';
import { SourceTreeWidget } from '@theia/core/lib/browser/source-tree';
import { VSXExtensionsSource, VSXExtensionsSourceOptions } from './vsx-extensions-source';
import { nls } from '@theia/core/lib/common/nls';
Expand Down Expand Up @@ -153,4 +153,13 @@ export class VSXExtensionsWidget extends SourceTreeWidget implements BadgeWidget
}
return super.renderTree(model);
}

protected override onAfterShow(msg: Message): void {
super.onAfterShow(msg);
if (this.options.id === VSXExtensionsSourceOptions.INSTALLED) {
// This is needed when an Extension was installed outside of the extension view.
// E.g. using explorer context menu.
this.doUpdateRows();
}
}
}
3 changes: 3 additions & 0 deletions packages/vsx-registry/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
{
"path": "../filesystem"
},
{
"path": "../navigator"
},
{
"path": "../plugin-ext"
},
Expand Down

0 comments on commit 2bb8237

Please sign in to comment.