diff --git a/package.json b/package.json index 12bd4e7..21dff5c 100644 --- a/package.json +++ b/package.json @@ -158,17 +158,34 @@ "category": "Solution Explorer", "icon": "$(add)" }, + { + "command": "solutionExplorer.addLocalTool", + "title": "Add local tool", + "category": "Solution Explorer", + "icon": "$(add)" + }, { "command": "solutionExplorer.removePackage", "title": "Remove package", "category": "Solution Explorer", "icon": "$(trash)" }, + { + "command": "solutionExplorer.removeLocalTool", + "title": "Remove local tool", + "category": "Solution Explorer", + "icon": "$(trash)" + }, { "command": "solutionExplorer.updatePackagesVersion", "title": "Update packages version", "category": "Solution Explorer" }, + { + "command": "solutionExplorer.updateLocalToolsVersion", + "title": "Update local tools version", + "category": "Solution Explorer" + }, { "command": "solutionExplorer.addProjectReference", "title": "Add reference", @@ -491,6 +508,16 @@ "when": "view == slnexpl && viewItem == project-referenced-package-cps", "group": "inline" }, + { + "command": "solutionExplorer.removeLocalTool", + "when": "view == slnexpl && viewItem == local-tool", + "group": "2_workspace" + }, + { + "command": "solutionExplorer.removeLocalTool", + "when": "view == slnexpl && viewItem == local-tool", + "group": "inline" + }, { "command": "solutionExplorer.updatePackagesVersion", "when": "view == slnexpl && viewItem == project-cps", @@ -501,6 +528,11 @@ "when": "view == slnexpl && viewItem == project-referenced-packages-cps", "group": "2_workspace" }, + { + "command": "solutionExplorer.updateLocalToolsVersion", + "when": "view == slnexpl && viewItem == local-tools", + "group": "2_workspace" + }, { "command": "solutionExplorer.addProjectReference", "when": "view == slnexpl && viewItem == project-cps", @@ -896,6 +928,16 @@ "when": "view == slnbrw && viewItem == project-referenced-packages-cps", "group": "inline" }, + { + "command": "solutionExplorer.addLocalTool", + "when": "view == slnbrw && viewItem == local-tools", + "group": "2_workspace" + }, + { + "command": "solutionExplorer.addLocalTool", + "when": "view == slnbrw && viewItem == local-tools", + "group": "inline" + }, { "command": "solutionExplorer.removePackage", "when": "view == slnbrw && viewItem == project-referenced-package-cps", @@ -906,6 +948,16 @@ "when": "view == slnbrw && viewItem == project-referenced-package-cps", "group": "inline" }, + { + "command": "solutionExplorer.removeLocalTool", + "when": "view == slnbrw && viewItem == local-tool", + "group": "2_workspace" + }, + { + "command": "solutionExplorer.removeLocalTool", + "when": "view == slnbrw && viewItem == local-tool", + "group": "inline" + }, { "command": "solutionExplorer.updatePackagesVersion", "when": "view == slnbrw && viewItem == project-cps", @@ -916,6 +968,11 @@ "when": "view == slnbrw && viewItem == project-referenced-packages-cps", "group": "2_workspace" }, + { + "command": "solutionExplorer.updateLocalToolsVersion", + "when": "view == slnbrw && viewItem == local-tools", + "group": "2_workspace" + }, { "command": "solutionExplorer.addProjectReference", "when": "view == slnbrw && viewItem == project-cps", @@ -1252,6 +1309,12 @@ "key": "delete", "mac": "delete" }, + { + "command": "solutionExplorer.removeLocalTool", + "when": "view == slnexpl && viewItem == local-tool", + "key": "delete", + "mac": "delete" + }, { "command": "solutionExplorer.removeProjectReference", "when": "view == slnexpl && viewItem == project-referenced-project-cps", @@ -1432,6 +1495,12 @@ "key": "delete", "mac": "delete" }, + { + "command": "solutionExplorer.removeLocalTool", + "when": "view == slnbrw && viewItem == local-tool", + "key": "delete", + "mac": "delete" + }, { "command": "solutionExplorer.removeProjectReference", "when": "view == slnbrw && viewItem == project-referenced-project-cps", diff --git a/src/SolutionExplorerCommands.ts b/src/SolutionExplorerCommands.ts index 3a04db1..d04e6fd 100644 --- a/src/SolutionExplorerCommands.ts +++ b/src/SolutionExplorerCommands.ts @@ -17,6 +17,7 @@ export class SolutionExplorerCommands { this.commands['addExistingProject'] = new cmds.AddExistingProjectCommand(provider); this.commands['addNewProject'] = new cmds.AddNewProjectCommand(provider); this.commands['addPackage'] = new cmds.AddPackageCommand(); + this.commands['addLocalTool'] = new cmds.AddLocalToolCommand(); this.commands['addProjectReference'] = new cmds.AddProjectReferenceCommand(); this.commands['addSolutionFile'] = new cmds.AddExistingFileToSolutionFolderCommand(); this.commands['build'] = new cmds.BuildCommand(); @@ -41,6 +42,7 @@ export class SolutionExplorerCommands { this.commands['publish'] = new cmds.PublishCommand(); this.commands['refresh'] = new cmds.RefreshCommand(provider); this.commands['removePackage'] = new cmds.RemovePackageCommand(); + this.commands['removeLocalTool'] = new cmds.RemoveLocalToolCommand(); this.commands['removeProject'] = new cmds.RemoveProjectCommand(); this.commands['removeProjectReference'] = new cmds.RemoveProjectReferenceCommand(); this.commands['removeSolutionFolder'] = new cmds.RemoveSolutionFolderCommand(); @@ -53,6 +55,7 @@ export class SolutionExplorerCommands { this.commands['showActiveFileInExplorer'] = new cmds.SelectActiveDocumentCommand(provider); this.commands['test'] = new cmds.TestCommand(); this.commands['updatePackagesVersion'] = new cmds.UpdatePackagesVersionCommand(); + this.commands['updateLocalToolsVersion'] = new cmds.UpdateLocalToolsVersionCommand(); this.commands['watchRun'] = new cmds.WatchRunCommand(); this.commands['openSolution'] = new cmds.OpenSolutionCommand(eventAggregator); } diff --git a/src/SolutionTreeItemCollection.ts b/src/SolutionTreeItemCollection.ts index f8d02ba..3481cd9 100644 --- a/src/SolutionTreeItemCollection.ts +++ b/src/SolutionTreeItemCollection.ts @@ -1,7 +1,7 @@ import { SolutionExplorerProvider } from "@SolutionExplorerProvider"; import { SolutionFile } from "@core/Solutions"; import { TreeItem, TreeItemFactory } from "@tree"; - +import { LocalTools } from "@core/Utilities/LocalTools"; export class SolutionTreeItemCollection { private children: TreeItem[] | undefined = undefined; @@ -28,13 +28,17 @@ export class SolutionTreeItemCollection { } public async addSolution(solutionPath: string, rootPath: string, solutionProvider: SolutionExplorerProvider): Promise { - const solution = await SolutionFile.parse(solutionPath); - const item = await TreeItemFactory.createFromSolution(solutionProvider, solution, rootPath); if (!this.children) { this.children = []; } + const solution = await SolutionFile.parse(solutionPath); + + const localTools = LocalTools.getInstalledLocalTools(rootPath); + const localToolsItem = await TreeItemFactory.createFromLocalTools(solutionProvider, solution, rootPath, localTools); + this.children.push(localToolsItem); - this.children.push(item); + const solutionItem = await TreeItemFactory.createFromSolution(solutionProvider, solution, rootPath); + this.children.push(solutionItem); } public getLoadedChildTreeItemById(id: string): TreeItem | undefined { diff --git a/src/actions/AddLocalToolReference.ts b/src/actions/AddLocalToolReference.ts new file mode 100644 index 0000000..e1203d8 --- /dev/null +++ b/src/actions/AddLocalToolReference.ts @@ -0,0 +1,24 @@ +import { TerminalCommand } from "@extensions/defaultTerminalCommands"; +import { CustomTerminalAction } from "./base/CustomTerminalAction"; + +export class AddLocalToolReference extends CustomTerminalAction { + constructor(private readonly workspaceRoot: string, private readonly packageId: string, packageVersion?: string) { + super({ + name: AddLocalToolReference.getTerminalCommand(workspaceRoot, packageId, packageVersion), + parameters: { packageId, packageVersion: packageVersion || "" }, + workingFolder: workspaceRoot + }); + } + + public toString(): string { + return `Add local tool reference ${this.packageId} to workspace ${this.workspaceRoot}`; + } + + private static getTerminalCommand(workspaceRoot: string, packageId: string, packageVersion: string | undefined): TerminalCommand { + if (packageVersion) { + return "addLocalToolReferenceWithVersion"; + } else { + return "addLocalToolReference"; + } + } +} diff --git a/src/actions/RemoveLocalToolReference.ts b/src/actions/RemoveLocalToolReference.ts new file mode 100644 index 0000000..57ead0f --- /dev/null +++ b/src/actions/RemoveLocalToolReference.ts @@ -0,0 +1,15 @@ +import { CustomTerminalAction } from "./base/CustomTerminalAction"; + +export class RemoveLocalToolReference extends CustomTerminalAction { + constructor(private readonly workspaceRoot: string, private readonly packageId: string) { + super({ + name: "removeLocalToolReference", + parameters: { packageId }, + workingFolder: workspaceRoot + }); + } + + public toString(): string { + return `Remove local tool reference ${this.packageId} from workspace ${this.workspaceRoot}`; + } +} diff --git a/src/actions/UpdateLocalToolReference.ts b/src/actions/UpdateLocalToolReference.ts new file mode 100644 index 0000000..232512a --- /dev/null +++ b/src/actions/UpdateLocalToolReference.ts @@ -0,0 +1,15 @@ +import { CustomTerminalAction } from "./base/CustomTerminalAction"; + +export class UpdateLocalToolReference extends CustomTerminalAction { + constructor(private readonly workspaceRoot: string, private readonly packageId: string) { + super({ + name: 'updateLocalToolReference', + parameters: { packageId }, + workingFolder: workspaceRoot + }); + } + + public toString(): string { + return `Update local tool reference ${this.packageId} in workspace ${this.workspaceRoot}`; + } +} diff --git a/src/actions/index.ts b/src/actions/index.ts index 5d91056..a13e0e3 100644 --- a/src/actions/index.ts +++ b/src/actions/index.ts @@ -43,3 +43,6 @@ export * from "./Run"; export * from "./SelectActiveDocumentInTree"; export * from "./Test"; export * from "./Watch"; +export * from './AddLocalToolReference' +export * from './RemoveLocalToolReference' +export * from './UpdateLocalToolReference' diff --git a/src/commands/AddLocalToolCommand.ts b/src/commands/AddLocalToolCommand.ts new file mode 100644 index 0000000..b80a02a --- /dev/null +++ b/src/commands/AddLocalToolCommand.ts @@ -0,0 +1,30 @@ +import * as dialogs from '@extensions/dialogs'; +import { TreeItem } from "@tree"; +import { Action, AddLocalToolReference } from "@actions"; +import { AddPackageCommand } from "@commands"; + +export class AddLocalToolCommand extends AddPackageCommand { + constructor() { + super('Add local tool'); + } + + public shouldRun(item: TreeItem): boolean { + return item && !!item.workspaceRoot; + } + + public async getActions(item: TreeItem): Promise { + if (!item || !item.workspaceRoot) { return []; } + + this.wizard = new dialogs.Wizard('Add local dotnet tool') + .selectOption('Select a feed', () => this.getNugetFeeds(item.workspaceRoot) ) + .searchOption('Search a tool', search => this.searchAndMapNugetPackages(search, 'dotnettool'), '') + .selectOption('Select a tool', () => this.getCurrentPackageVersions(), () => this.getCurrentPackageDefaultVersion()); + + const parameters = await this.wizard.run(); + if (!parameters) { + return []; + } + + return [ new AddLocalToolReference(item.workspaceRoot, parameters[1], parameters[2]) ]; + } +} diff --git a/src/commands/AddPackageCommand.ts b/src/commands/AddPackageCommand.ts index ac54d9a..7f043c6 100644 --- a/src/commands/AddPackageCommand.ts +++ b/src/commands/AddPackageCommand.ts @@ -5,11 +5,11 @@ import { Action, AddPackageReference } from "@actions"; import { ActionsCommand } from "@commands"; export class AddPackageCommand extends ActionsCommand { - private nugetFeeds: nuget.NugetFeed[] = []; - private lastNugetPackages: nuget.NugetPackage[] = []; - private wizard: dialogs.Wizard | undefined; - constructor() { - super('Add package'); + protected nugetFeeds: nuget.NugetFeed[] = []; + protected lastNugetPackages: nuget.NugetPackage[] = []; + protected wizard: dialogs.Wizard | undefined; + constructor(title: string = 'Add package') { + super(title); } public shouldRun(item: TreeItem): boolean { @@ -33,7 +33,7 @@ export class AddPackageCommand extends ActionsCommand { return [ new AddPackageReference(item.project.fullPath, parameters[1], parameters[2]) ]; } - private async getNugetFeeds(projectFullPath: string): Promise { + protected async getNugetFeeds(projectFullPath: string): Promise { this.nugetFeeds = await nuget.getNugetFeeds(projectFullPath); if (this.nugetFeeds.length === 0) { const defaultNugetFeed = await nuget.getDefaultNugetFeed(); @@ -43,7 +43,7 @@ export class AddPackageCommand extends ActionsCommand { return this.nugetFeeds.map(f => f.name); } - private async searchAndMapNugetPackages(packageName: string): Promise { + protected async searchAndMapNugetPackages(packageName: string, packageType: string = ''): Promise { if (!this.wizard || !this.wizard.context || !this.wizard.context.results) { return []; } @@ -52,11 +52,11 @@ export class AddPackageCommand extends ActionsCommand { const feed = this.nugetFeeds.find(f => f.name === feedName); if (!feed) { return []; } - this.lastNugetPackages = await nuget.searchNugetPackage(feed, packageName); + this.lastNugetPackages = await nuget.searchNugetPackage(feed, packageName, packageType); return this.lastNugetPackages.map(p => p.id); } - private getCurrentPackageVersions(): Promise { + protected getCurrentPackageVersions(): Promise { if (!this.wizard || !this.wizard.context || !this.wizard.context.results) { return Promise.resolve([]); } @@ -69,7 +69,7 @@ export class AddPackageCommand extends ActionsCommand { return Promise.resolve(nugetPackage.versions.map(v => v.version).reverse()); } - private getCurrentPackageDefaultVersion(): Promise { + protected getCurrentPackageDefaultVersion(): Promise { if (!this.wizard || !this.wizard.context || !this.wizard.context.results) { return Promise.resolve(""); } const nugetPackage = this.lastNugetPackages.find(p => p.id === this.wizard?.context?.results[1]); diff --git a/src/commands/RemoveLocalToolCommand.ts b/src/commands/RemoveLocalToolCommand.ts new file mode 100644 index 0000000..a983fb1 --- /dev/null +++ b/src/commands/RemoveLocalToolCommand.ts @@ -0,0 +1,19 @@ +import { TreeItem } from "@tree"; +import { Action, RemoveLocalToolReference } from "@actions"; +import { ActionsCommand } from "@commands"; + +export class RemoveLocalToolCommand extends ActionsCommand { + constructor() { + super('Remove local tool'); + } + + public shouldRun(item: TreeItem): boolean { + return !!item && !!item.workspaceRoot && !!item.path; + } + + public async getActions(item: TreeItem): Promise { + if (!item || !item.workspaceRoot || !item.path) { return []; } + + return [ new RemoveLocalToolReference(item.workspaceRoot, item.path) ]; + } +} diff --git a/src/commands/UpdateLocalToolsVersionCommand.ts b/src/commands/UpdateLocalToolsVersionCommand.ts new file mode 100644 index 0000000..789aa96 --- /dev/null +++ b/src/commands/UpdateLocalToolsVersionCommand.ts @@ -0,0 +1,20 @@ +import { Action, UpdateLocalToolReference } from "@actions"; +import { ActionsCommand } from "@commands"; +import { LocalToolsTreeItem } from "@tree/items/LocalToolsTreeItem"; + +export class UpdateLocalToolsVersionCommand extends ActionsCommand { + constructor() { + super('UpdateLocalToolsVersion'); + } + + public shouldRun(item: LocalToolsTreeItem): boolean { + return !!item && !!item.workspaceRoot; + } + + public async getActions(item: LocalToolsTreeItem): Promise { + if (!item || !item.workspaceRoot) { return []; } + + const references = item.getLocalTools(); + return references.map(reference => new UpdateLocalToolReference(item.workspaceRoot, reference.name)); + } +} diff --git a/src/commands/index.ts b/src/commands/index.ts index c0f488a..0310a76 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -36,4 +36,7 @@ export * from "./RunCommand"; export * from "./SelectActiveDocumentCommand"; export * from "./TestCommand"; export * from "./UpdatePackagesVersionCommand"; -export * from "./WatchRunCommand"; \ No newline at end of file +export * from "./WatchRunCommand"; +export * from "./AddLocalToolCommand"; +export * from "./RemoveLocalToolCommand"; +export * from "./UpdateLocalToolsVersionCommand"; \ No newline at end of file diff --git a/src/core/Utilities/LocalTools.ts b/src/core/Utilities/LocalTools.ts new file mode 100644 index 0000000..1ba84cb --- /dev/null +++ b/src/core/Utilities/LocalTools.ts @@ -0,0 +1,36 @@ +import { execSync } from 'child_process'; + +export type LocalTool = { + name: string, + version: string + commands?: string +} + +export class LocalTools { + public static getInstalledLocalTools(rootPath: string): LocalTool[] { + let buffer = execSync('dotnet tool list --local', { + cwd: rootPath + }); + if (!buffer) { + return []; + } + + const localTools: LocalTool[] = []; + + let lines = buffer.toString().split('\n'); + if (lines.length > 2) { + lines.splice(0, 2); /* ignore header */ + lines.forEach(line => { + let [name, version, commands] = line.split(' ').filter(element => element); + if (name && version) { + localTools.push({ + name, + version, + commands + }); + } + }); + } + return localTools; + } +} \ No newline at end of file diff --git a/src/extensions/defaultTerminalCommands.ts b/src/extensions/defaultTerminalCommands.ts index ba6d247..4241780 100644 --- a/src/extensions/defaultTerminalCommands.ts +++ b/src/extensions/defaultTerminalCommands.ts @@ -17,5 +17,9 @@ export const defaultTerminalCommands = { restore: [ "dotnet", "restore", "\"$projectPath\"" ], run: [ "dotnet", "run", "--project", "\"$projectPath\"" ], test: [ "dotnet", "test", "\"$projectPath\"" ], - watch: [ "dotnet", "watch", "run", "--project", "\"$projectPath\"" ] + watch: [ "dotnet", "watch", "run", "--project", "\"$projectPath\"" ], + addLocalToolReference: [ "dotnet", "tool", "install", "--local", "\"$packageId\"" ], + addLocalToolReferenceWithVersion: [ "dotnet", "tool", "install", "--local", "\"$packageId\"", "--version", "\"$packageVersion\"" ], + removeLocalToolReference: [ "dotnet", "tool", "uninstall", "--local", "\"$packageId\"" ], + updateLocalToolReference: [ "dotnet", "tool", "update", "--local", "\"$packageId\"" ], }; diff --git a/src/extensions/nuget.ts b/src/extensions/nuget.ts index 3577d19..5170fe8 100644 --- a/src/extensions/nuget.ts +++ b/src/extensions/nuget.ts @@ -91,7 +91,7 @@ export async function getNugetApiServices(feed: NugetFeed): Promise<{[id: string } } -export async function searchNugetPackage(feed: NugetFeed, packageName: string): Promise { +export async function searchNugetPackage(feed: NugetFeed, packageName: string, packageType: string): Promise { if (!feed) { return []; } @@ -104,7 +104,7 @@ export async function searchNugetPackage(feed: NugetFeed, packageName: string): throw new Error(`Nuget search API URL is not found for feed ${feed.name}`); } - const searchUrl = `${feed.searchApiUrl}?q=${packageName}&skip=0&take=50`; + const searchUrl = `${feed.searchApiUrl}?q=${packageName}&skip=0&take=50&packageType=${packageType}`; const response = await fetch(searchUrl, getFetchOptions(feed)); const json = await response.json() as any; if (!json.data || json.data.length === 0) { diff --git a/src/tree/ContextValues.ts b/src/tree/ContextValues.ts index 1789e9a..9d23267 100644 --- a/src/tree/ContextValues.ts +++ b/src/tree/ContextValues.ts @@ -8,6 +8,8 @@ export class ContextValues { public static readonly projectReferencedProject: string = 'project-referenced-project'; public static readonly projectReferencedPackages: string = 'project-referenced-packages'; public static readonly projectReferencedPackage: string = 'project-referenced-package'; + public static readonly localTools: string = 'local-tools'; + public static readonly localTool: string = 'local-tool'; public static readonly projectFolder: string = 'project-folder'; public static readonly projectFile: string = 'project-file'; public static readonly error: string = 'error'; diff --git a/src/tree/TreeItem.ts b/src/tree/TreeItem.ts index 0dac076..ca491bf 100644 --- a/src/tree/TreeItem.ts +++ b/src/tree/TreeItem.ts @@ -159,7 +159,9 @@ export abstract class TreeItem extends vscode.TreeItem { ContextValues.projectReferencedProject, ContextValues.projectReferencedProjects, ContextValues.projectReferences, - ContextValues.solutionFolder + ContextValues.solutionFolder, + ContextValues.localTool, + ContextValues.localTools, ]; if (ignoreTypes.indexOf(this.contextValue) >= 0) { diff --git a/src/tree/TreeItemFactory.ts b/src/tree/TreeItemFactory.ts index f45211c..e00f8d3 100644 --- a/src/tree/TreeItemFactory.ts +++ b/src/tree/TreeItemFactory.ts @@ -14,6 +14,8 @@ import { ProjectFileTreeItem } from "@tree/items/ProjectFileTreeItem"; import { CpsProjectTreeItem } from "@tree/items/cps/CpsProjectTreeItem"; import { StandardProjectTreeItem } from "@tree/items/standard/StandardProjectTreeItem"; import { SolutionFileTreeItem } from "@tree/items/SolutionFileTreeItem"; +import { LocalToolsTreeItem } from "./items/LocalToolsTreeItem"; +import { LocalTool } from "@core/Utilities/LocalTools"; export async function createFromSolution(provider: SolutionExplorerProvider, solution: SolutionFile, workspaceRoot: string): Promise { let context = new TreeItemContext(provider, solution, workspaceRoot); @@ -23,6 +25,12 @@ export async function createFromSolution(provider: SolutionExplorerProvider, sol return treeItem; } +export async function createFromLocalTools(provider: SolutionExplorerProvider, solution: SolutionFile, workspaceRoot: string, localTools: LocalTool[]) { + const context = new TreeItemContext(provider, solution, workspaceRoot); + const localToolsItem = new LocalToolsTreeItem(context, localTools); + return localToolsItem; +} + export async function createItemsFromSolution(context: TreeItemContext, solution: SolutionFile, projectInSolution?: ProjectInSolution): Promise { let result: TreeItem[] = []; let folders: ProjectInSolution[] = []; diff --git a/src/tree/TreeItemIconProvider.ts b/src/tree/TreeItemIconProvider.ts index 2d18aa7..ebfd0c2 100644 --- a/src/tree/TreeItemIconProvider.ts +++ b/src/tree/TreeItemIconProvider.ts @@ -73,5 +73,9 @@ export async function findIconPath(name: string, path: string, contextValue: str return await getIconPathFromExtension(path, 'csproj.svg'); } + if (contextValue.startsWith(ContextValues.localTool)) { + return getIconPath('PackageReference.svg','PackageReference-dark.svg'); + } + return getIconPath('file.svg'); } diff --git a/src/tree/items/LocalToolTreeItem.ts b/src/tree/items/LocalToolTreeItem.ts new file mode 100644 index 0000000..95d5e48 --- /dev/null +++ b/src/tree/items/LocalToolTreeItem.ts @@ -0,0 +1,14 @@ +import { PackageReference } from "@core/Projects"; +import { TreeItem, TreeItemCollapsibleState, TreeItemContext, ContextValues } from "@tree"; + +export class LocalToolTreeItem extends TreeItem { + constructor(context: TreeItemContext, pkgRef: PackageReference) { + super(context, pkgRef.name, TreeItemCollapsibleState.None, ContextValues.localTool, pkgRef.name); + this.description = pkgRef.version; + this.allowIconTheme = false; + } + + protected loadThemeIcon(fullpath: string): void { + super.loadThemeIcon(fullpath + ".nupkg"); + } +} diff --git a/src/tree/items/LocalToolsTreeItem.ts b/src/tree/items/LocalToolsTreeItem.ts new file mode 100644 index 0000000..5818c00 --- /dev/null +++ b/src/tree/items/LocalToolsTreeItem.ts @@ -0,0 +1,48 @@ +import { PackageReference } from "@core/Projects"; +import { LocalTool, LocalTools } from "@core/Utilities/LocalTools"; +import { EventTypes, IEvent, IFileEvent, ISubscription } from "@events"; +import { TreeItem, TreeItemCollapsibleState, TreeItemContext, ContextValues } from "@tree"; +import { LocalToolTreeItem } from "./LocalToolTreeItem"; + +export class LocalToolsTreeItem extends TreeItem { + private subscription: ISubscription | undefined; + + constructor(context: TreeItemContext, private localTools: LocalTool[]) { + super( + context, + 'Local Tools', + localTools.length > 0 ? TreeItemCollapsibleState.Collapsed : TreeItemCollapsibleState.None, + ContextValues.localTools + ); + this.allowIconTheme = false; + this.subscription = context.eventAggregator.subscribe(EventTypes.file, evt => this.onFileEvent(evt)); + } + + public dispose(): void { + if (this.subscription) { + this.subscription.dispose(); + this.subscription = undefined; + } + super.dispose(); + } + + public getLocalTools(): LocalTool[] { + return this.localTools; + } + + protected async createChildren(childContext: TreeItemContext): Promise { + return this.localTools.map((localTool) => new LocalToolTreeItem( + childContext, + new PackageReference(localTool.name, localTool.version) + )); + } + + private onFileEvent(event: IEvent): void { + const fileEvent = event; + if (fileEvent.path.endsWith('dotnet-tools.json')) { + this.localTools = LocalTools.getInstalledLocalTools(this.context.workspaceRoot); + this.collapsibleState = this.localTools.length > 0 ? TreeItemCollapsibleState.Collapsed : TreeItemCollapsibleState.None; + this.refresh(); + } + } +}