Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@
{
"command": "python-envs.refreshPackages",
"group": "inline",
"when": "view == env-managers && viewItem == python-package-root"
"when": "view == env-managers && viewItem =~ /.*pythonEnvironment.*/"
},
{
"command": "python-envs.packages",
Expand Down Expand Up @@ -395,7 +395,7 @@
{
"command": "python-envs.refreshPackages",
"group": "inline",
"when": "view == python-projects && viewItem == python-package-root"
"when": "view == python-projects && viewItem == python-env"
},
{
"command": "python-envs.removePythonProject",
Expand Down
2 changes: 1 addition & 1 deletion src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ export async function activate(context: ExtensionContext): Promise<PythonEnviron
await Promise.all(envManagers.managers.map((m) => m.refresh(undefined)));
}),
commands.registerCommand('python-envs.refreshPackages', async (item) => {
await refreshPackagesCommand(item);
await refreshPackagesCommand(item, envManagers);
}),
commands.registerCommand('python-envs.create', async (item) => {
return await createEnvironmentCommand(item, envManagers, projectManager);
Expand Down
33 changes: 21 additions & 12 deletions src/features/envCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,10 @@ import {
EnvManagerTreeItem,
EnvTreeItemKind,
GlobalProjectItem,
PackageRootTreeItem,
PackageTreeItem,
ProjectEnvironment,
ProjectItem,
ProjectPackage,
ProjectPackageRootTreeItem,
PythonEnvTreeItem,
} from './views/treeViewItems';

Expand All @@ -48,15 +46,25 @@ export async function refreshManagerCommand(context: unknown): Promise<void> {
}
}

export async function refreshPackagesCommand(context: unknown) {
if (context instanceof ProjectPackageRootTreeItem) {
const view = context as ProjectPackageRootTreeItem;
const manager = view.manager;
await manager.refresh(view.environment);
} else if (context instanceof PackageRootTreeItem) {
const view = context as PackageRootTreeItem;
const manager = view.manager;
await manager.refresh(view.environment);
export async function refreshPackagesCommand(context: unknown, managers?: EnvironmentManagers): Promise<void> {
if (context instanceof ProjectEnvironment) {
const view = context as ProjectEnvironment;
if (managers) {
const pkgManager = managers.getPackageManager(view.parent.project.uri);
if (pkgManager) {
await pkgManager.refresh(view.environment);
}
}
} else if (context instanceof PythonEnvTreeItem) {
const view = context as PythonEnvTreeItem;
const envManager =
view.parent.kind === EnvTreeItemKind.environmentGroup
? view.parent.parent.manager
: view.parent.manager;
const pkgManager = managers?.getPackageManager(envManager.preferredPackageManagerId);
if (pkgManager) {
await pkgManager.refresh(view.environment);
}
} else {
traceVerbose(`Invalid context for refresh command: ${context}`);
}
Expand Down Expand Up @@ -192,7 +200,8 @@ export async function removeEnvironmentCommand(context: unknown, managers: Envir
export async function handlePackageUninstall(context: unknown, em: EnvironmentManagers) {
if (context instanceof PackageTreeItem || context instanceof ProjectPackage) {
const moduleName = context.pkg.name;
const environment = context.parent.environment;
const environment =
context instanceof ProjectPackage ? context.parent.environment : context.parent.environment;
const packageManager = em.getPackageManager(environment);
await packageManager?.manage(environment, { uninstall: [moduleName], install: [] });
return;
Expand Down
55 changes: 17 additions & 38 deletions src/features/views/envManagersView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,10 @@ import {
EnvTreeItem,
EnvManagerTreeItem,
PythonEnvTreeItem,
PackageRootTreeItem,
PackageTreeItem,
EnvTreeItemKind,
NoPythonEnvTreeItem,
EnvInfoTreeItem,
PackageRootInfoTreeItem,
PythonGroupEnvTreeItem,
} from './treeViewItems';
import { createSimpleDebounce } from '../../common/utils/debounce';
Expand All @@ -31,7 +29,6 @@ export class EnvManagerView implements TreeDataProvider<EnvTreeItem>, Disposable
>();
private revealMap = new Map<string, PythonEnvTreeItem>();
private managerViews = new Map<string, EnvManagerTreeItem>();
private packageRoots = new Map<string, PackageRootTreeItem>();
private selected: Map<string, string> = new Map();
private disposables: Disposable[] = [];

Expand All @@ -42,7 +39,6 @@ export class EnvManagerView implements TreeDataProvider<EnvTreeItem>, Disposable

this.disposables.push(
new Disposable(() => {
this.packageRoots.clear();
this.revealMap.clear();
this.managerViews.clear();
this.selected.clear();
Expand Down Expand Up @@ -165,32 +161,18 @@ export class EnvManagerView implements TreeDataProvider<EnvTreeItem>, Disposable
const views: EnvTreeItem[] = [];

if (pkgManager) {
const item = new PackageRootTreeItem(parent, pkgManager, environment);
this.packageRoots.set(environment.envId.id, item);
views.push(item);
const packages = await pkgManager.getPackages(environment);
if (packages && packages.length > 0) {
views.push(...packages.map((p) => new PackageTreeItem(p, parent, pkgManager)));
} else {
views.push(new EnvInfoTreeItem(parent, ProjectViews.noPackages));
}
} else {
views.push(new EnvInfoTreeItem(parent, ProjectViews.noPackageManager));
}

return views;
}

if (element.kind === EnvTreeItemKind.packageRoot) {
const root = element as PackageRootTreeItem;
const manager = root.manager;
const environment = root.environment;

let packages = await manager.getPackages(environment);
const views: EnvTreeItem[] = [];

if (packages) {
views.push(...packages.map((p) => new PackageTreeItem(p, root, manager)));
} else {
views.push(new PackageRootInfoTreeItem(root, ProjectViews.noPackages));
}

return views;
}
}

getParent(element: EnvTreeItem): ProviderResult<EnvTreeItem> {
Expand Down Expand Up @@ -219,35 +201,32 @@ export class EnvManagerView implements TreeDataProvider<EnvTreeItem>, Disposable
}

private onDidChangePackages(args: InternalDidChangePackagesEventArgs) {
const pkgRoot = this.packageRoots.get(args.environment.envId.id);
if (pkgRoot) {
this.fireDataChanged(pkgRoot);
const view = Array.from(this.revealMap.values()).find(
(v) => v.environment.envId.id === args.environment.envId.id
);
if (view) {
this.fireDataChanged(view);
}
}

private onDidChangePackageManager(args: DidChangePackageManagerEventArgs) {
const roots = Array.from(this.packageRoots.values()).filter((r) => r.manager.id === args.manager.id);
this.fireDataChanged(roots);
private onDidChangePackageManager(_args: DidChangePackageManagerEventArgs) {
// Since we removed the packageRoots level, just refresh all environments
// This is a simplified approach that isn't as targeted but ensures packages get refreshed
this.fireDataChanged(undefined);
}

public environmentChanged(e: DidChangeEnvironmentEventArgs) {
const views = [];
if (e.old) {
this.selected.delete(e.old.envId.id);
let view: EnvTreeItem | undefined = this.packageRoots.get(e.old.envId.id);
if (!view) {
view = this.managerViews.get(e.old.envId.managerId);
}
const view: EnvTreeItem | undefined = this.revealMap.get(e.old.envId.id);
if (view) {
views.push(view);
}
}
if (e.new) {
this.selected.set(e.new.envId.id, e.uri === undefined ? 'global' : e.uri.fsPath);
let view: EnvTreeItem | undefined = this.packageRoots.get(e.new.envId.id);
if (!view) {
view = this.managerViews.get(e.new.envId.managerId);
}
const view: EnvTreeItem | undefined = this.revealMap.get(e.new.envId.id);
if (view && !views.includes(view)) {
views.push(view);
}
Expand Down
47 changes: 23 additions & 24 deletions src/features/views/projectView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ import {
ProjectEnvironmentInfo,
ProjectItem,
ProjectPackage,
ProjectPackageRootInfoTreeItem,
ProjectPackageRootTreeItem,
ProjectTreeItem,
ProjectTreeItemKind,
} from './treeViewItems';
Expand All @@ -34,7 +32,7 @@ export class ProjectView implements TreeDataProvider<ProjectTreeItem> {
>();
private projectViews: Map<string, ProjectItem> = new Map();
private revealMap: Map<string, ProjectEnvironment> = new Map();
private packageRoots: Map<string, ProjectPackageRootTreeItem> = new Map();
private packageRoots: Map<string, ProjectEnvironment> = new Map();
private disposables: Disposable[] = [];
private debouncedUpdateProject = createSimpleDebounce(500, () => this.updateProject());
public constructor(private envManagers: EnvironmentManagers, private projectManager: PythonProjectManager) {
Expand Down Expand Up @@ -83,7 +81,8 @@ export class ProjectView implements TreeDataProvider<ProjectTreeItem> {

private updatePackagesForEnvironment(e: PythonEnvironment): void {
const views: ProjectTreeItem[] = [];
this.packageRoots.forEach((v) => {
// Look for environments matching this environment ID and refresh them
this.revealMap.forEach((v) => {
if (v.environment.envId.id === e.envId.id) {
views.push(v);
}
Expand Down Expand Up @@ -125,8 +124,16 @@ export class ProjectView implements TreeDataProvider<ProjectTreeItem> {
return element.treeItem;
}

/**
* Returns the children of a given element in the project tree view:
* If param is undefined, return root project items
* If param is a project, returns its environments.
* If param is an environment, returns its packages.
* @param element The tree item for which to get children.
*/
async getChildren(element?: ProjectTreeItem | undefined): Promise<ProjectTreeItem[] | undefined> {
if (element === undefined) {
// Return the root items
this.projectViews.clear();
const views: ProjectTreeItem[] = [];
const projects = this.projectManager.getProjects();
Expand Down Expand Up @@ -187,38 +194,30 @@ export class ProjectView implements TreeDataProvider<ProjectTreeItem> {
}

if (element.kind === ProjectTreeItemKind.environment) {
// Return packages directly under the environment

const environmentItem = element as ProjectEnvironment;
const parent = environmentItem.parent;
const uri = parent.id === 'global' ? undefined : parent.project.uri;
const pkgManager = this.envManagers.getPackageManager(uri);
const environment = environmentItem.environment;

const views: ProjectTreeItem[] = [];
if (!pkgManager) {
return [new ProjectEnvironmentInfo(environmentItem, ProjectViews.noPackageManager)];
}

if (pkgManager) {
const item = new ProjectPackageRootTreeItem(environmentItem, pkgManager, environment);
this.packageRoots.set(uri ? uri.fsPath : 'global', item);
views.push(item);
} else {
views.push(new ProjectEnvironmentInfo(environmentItem, ProjectViews.noPackageManager));
let packages = await pkgManager.getPackages(environment);
if (!packages) {
return [new ProjectEnvironmentInfo(environmentItem, ProjectViews.noPackages)];
}
return views;
}

if (element.kind === ProjectTreeItemKind.packageRoot) {
const root = element as ProjectPackageRootTreeItem;
const manager = root.manager;
const environment = root.environment;
let packages = await manager.getPackages(environment);
const views: ProjectTreeItem[] = [];
// Store the reference for refreshing packages
this.packageRoots.set(uri ? uri.fsPath : 'global', environmentItem);

if (packages) {
return packages.map((p) => new ProjectPackage(root, p, manager));
} else {
views.push(new ProjectPackageRootInfoTreeItem(root, ProjectViews.noPackages));
}
return packages.map((p) => new ProjectPackage(environmentItem, p, pkgManager));
}

//return nothing if the element is not a project, environment, or undefined
return undefined;
}
getParent(element: ProjectTreeItem): ProviderResult<ProjectTreeItem> {
Expand Down
Loading