Skip to content
Draft
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
58 changes: 54 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,12 @@
"category": "Python",
"icon": "$(check)"
},
{
"command": "python-envs.setEnvSelected",
"title": "%python-envs.setEnvSelected.title%",
"category": "Python",
"icon": "$(pass-filled)"
},
{
"command": "python-envs.remove",
"title": "%python-envs.remove.title%",
Expand Down Expand Up @@ -272,12 +278,24 @@
"category": "Python Envs",
"icon": "$(copy)"
},
{
"command": "python-envs.copyEnvPathCopied",
"title": "%python-envs.copyEnvPathCopied.title%",
"category": "Python Envs",
"icon": "$(clippy)"
},
{
"command": "python-envs.copyProjectPath",
"title": "%python-envs.copyProjectPath.title%",
"category": "Python Envs",
"icon": "$(copy)"
},
{
"command": "python-envs.copyProjectPathCopied",
"title": "%python-envs.copyProjectPathCopied.title%",
"category": "Python Envs",
"icon": "$(clippy)"
},
{
"command": "python-envs.terminal.revertStartupScriptChanges",
"title": "%python-envs.terminal.revertStartupScriptChanges.title%",
Expand Down Expand Up @@ -321,6 +339,10 @@
"command": "python-envs.setEnv",
"when": "false"
},
{
"command": "python-envs.setEnvSelected",
"when": "false"
},
{
"command": "python-envs.remove",
"when": "false"
Expand Down Expand Up @@ -381,10 +403,18 @@
"command": "python-envs.copyEnvPath",
"when": "false"
},
{
"command": "python-envs.copyEnvPathCopied",
"when": "false"
},
{
"command": "python-envs.copyProjectPath",
"when": "false"
},
{
"command": "python-envs.copyProjectPathCopied",
"when": "false"
},
{
"command": "python-envs.createAny",
"when": "false"
Expand Down Expand Up @@ -419,7 +449,12 @@
{
"command": "python-envs.setEnv",
"group": "inline",
"when": "view == env-managers && viewItem =~ /.*pythonEnvironment.*/"
"when": "view == env-managers && viewItem =~ /.*pythonEnvironment.*/ && viewItem =~ /^((?!selected).)*$/"
},
{
"command": "python-envs.setEnvSelected",
"group": "inline",
"when": "view == env-managers && viewItem =~ /.*pythonEnvironment.*/ && viewItem =~ /.*selected.*/"
},
{
"command": "python-envs.createTerminal",
Expand All @@ -438,7 +473,12 @@
{
"command": "python-envs.copyEnvPath",
"group": "inline",
"when": "view == env-managers && viewItem =~ /.*pythonEnvironment.*/"
"when": "view == env-managers && viewItem =~ /.*pythonEnvironment.*/ && viewItem =~ /^((?!copied).)*$/"
},
{
"command": "python-envs.copyEnvPathCopied",
"group": "inline",
"when": "view == env-managers && viewItem =~ /.*pythonEnvironment.*/ && viewItem =~ /.*copied.*/"
},
{
"command": "python-envs.uninstallPackage",
Expand All @@ -448,7 +488,12 @@
{
"command": "python-envs.copyEnvPath",
"group": "inline",
"when": "view == python-projects && viewItem == python-env"
"when": "view == python-projects && viewItem =~ /python-env/ && viewItem =~ /^((?!copied).)*$/"
},
{
"command": "python-envs.copyEnvPathCopied",
"group": "inline",
"when": "view == python-projects && viewItem =~ /python-env/ && viewItem =~ /.*copied.*/"
},
{
"command": "python-envs.remove",
Expand All @@ -471,7 +516,12 @@
{
"command": "python-envs.copyProjectPath",
"group": "inline",
"when": "view == python-projects && viewItem =~ /.*python-workspace.*/"
"when": "view == python-projects && viewItem =~ /.*python-workspace.*/ && viewItem =~ /^((?!copied).)*$/"
},
{
"command": "python-envs.copyProjectPathCopied",
"group": "inline",
"when": "view == python-projects && viewItem =~ /.*python-workspace.*/ && viewItem =~ /.*copied.*/"
},
{
"command": "python-envs.revealProjectInExplorer",
Expand Down
3 changes: 3 additions & 0 deletions package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@
"python-envs.addPythonProjectGivenResource.title": "Add as Python Project",
"python-envs.removePythonProject.title": "Remove Python Project",
"python-envs.copyEnvPath.title": "Copy Environment Path",
"python-envs.copyEnvPathCopied.title": "Copied!",
"python-envs.copyProjectPath.title": "Copy Project Path",
"python-envs.copyProjectPathCopied.title": "Copied!",
"python-envs.create.title": "Create Environment",
"python-envs.createAny.title": "Create Environment",
"python-envs.set.title": "Set Project Environment",
"python-envs.setEnv.title": "Set As Project Environment",
"python-envs.setEnvSelected.title": "Set!",
"python-envs.remove.title": "Delete Environment",
"python-envs.refreshAllManagers.title": "Refresh All Environment Managers",
"python-envs.refreshPackages.title": "Refresh Packages List",
Expand Down
29 changes: 26 additions & 3 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ import { EnvManagerView } from './features/views/envManagersView';
import { ProjectView } from './features/views/projectView';
import { PythonStatusBarImpl } from './features/views/pythonStatusBar';
import { updateViewsAndStatus } from './features/views/revealHandler';
import { ProjectItem } from './features/views/treeViewItems';
import { TemporaryStateManager } from './features/views/temporaryStateManager';
import { ProjectItem, PythonEnvTreeItem } from './features/views/treeViewItems';
import {
collectEnvironmentInfo,
getEnvManagerAndPackageManagerConfigLevels,
Expand Down Expand Up @@ -146,10 +147,14 @@ export async function activate(context: ExtensionContext): Promise<PythonEnviron
setPythonApi(envManagers, projectManager, projectCreators, terminalManager, envVarManager);
const api = await getPythonApi();
const sysPythonManager = createDeferred<SysPythonManager>();
const managerView = new EnvManagerView(envManagers);

const temporaryStateManager = new TemporaryStateManager();
context.subscriptions.push(temporaryStateManager);

const managerView = new EnvManagerView(envManagers, temporaryStateManager);
context.subscriptions.push(managerView);

const workspaceView = new ProjectView(envManagers, projectManager);
const workspaceView = new ProjectView(envManagers, projectManager, temporaryStateManager);
context.subscriptions.push(workspaceView);
workspaceView.initialize();

Expand Down Expand Up @@ -224,6 +229,12 @@ export async function activate(context: ExtensionContext): Promise<PythonEnviron
}),
commands.registerCommand('python-envs.setEnv', async (item) => {
await setEnvironmentCommand(item, envManagers, projectManager);
if (item instanceof PythonEnvTreeItem) {
temporaryStateManager.setState(item.environment.envId.id, 'selected');
}
}),
commands.registerCommand('python-envs.setEnvSelected', async () => {
// No-op: This command is just for showing the feedback icon
}),
commands.registerCommand('python-envs.setEnvManager', async () => {
await setEnvManagerCommand(envManagers, projectManager);
Expand Down Expand Up @@ -283,9 +294,21 @@ export async function activate(context: ExtensionContext): Promise<PythonEnviron
}),
commands.registerCommand('python-envs.copyEnvPath', async (item) => {
await copyPathToClipboard(item);
if (item?.environment?.envId) {
temporaryStateManager.setState(item.environment.envId.id, 'copied');
}
}),
commands.registerCommand('python-envs.copyEnvPathCopied', () => {
// No-op: provides the checkmark icon
}),
commands.registerCommand('python-envs.copyProjectPath', async (item) => {
await copyPathToClipboard(item);
if (item?.project?.uri) {
temporaryStateManager.setState(item.project.uri.fsPath, 'copied');
}
}),
commands.registerCommand('python-envs.copyProjectPathCopied', () => {
// No-op: provides the checkmark icon
}),
commands.registerCommand('python-envs.revealProjectInExplorer', async (item) => {
await revealProjectInExplorer(item);
Expand Down
39 changes: 31 additions & 8 deletions src/features/views/envManagersView.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Disposable, Event, EventEmitter, ProviderResult, TreeDataProvider, TreeItem, TreeView, window } from 'vscode';
import { DidChangeEnvironmentEventArgs, EnvironmentGroupInfo, PythonEnvironment } from '../../api';
import { ProjectViews } from '../../common/localize';
import { createSimpleDebounce } from '../../common/utils/debounce';
import {
DidChangeEnvironmentManagerEventArgs,
DidChangePackageManagerEventArgs,
Expand All @@ -9,18 +11,21 @@ import {
InternalEnvironmentManager,
InternalPackageManager,
} from '../../internal.api';
import { ITemporaryStateManager } from './temporaryStateManager';
import {
EnvTreeItem,
EnvInfoTreeItem,
EnvManagerTreeItem,
PythonEnvTreeItem,
PackageTreeItem,
EnvTreeItem,
EnvTreeItemKind,
NoPythonEnvTreeItem,
EnvInfoTreeItem,
PackageTreeItem,
PythonEnvTreeItem,
PythonGroupEnvTreeItem,
} from './treeViewItems';
import { createSimpleDebounce } from '../../common/utils/debounce';
import { ProjectViews } from '../../common/localize';

const COPIED_STATE = 'copied';
const SELECTED_STATE = 'selected';
const ENV_STATE_KEYS = [COPIED_STATE, SELECTED_STATE];

export class EnvManagerView implements TreeDataProvider<EnvTreeItem>, Disposable {
private treeView: TreeView<EnvTreeItem>;
Expand All @@ -32,7 +37,7 @@ export class EnvManagerView implements TreeDataProvider<EnvTreeItem>, Disposable
private selected: Map<string, string> = new Map();
private disposables: Disposable[] = [];

public constructor(public providers: EnvironmentManagers) {
public constructor(public providers: EnvironmentManagers, private stateManager: ITemporaryStateManager) {
this.treeView = window.createTreeView<EnvTreeItem>('env-managers', {
treeDataProvider: this,
});
Expand All @@ -59,6 +64,15 @@ export class EnvManagerView implements TreeDataProvider<EnvTreeItem>, Disposable
this.onDidChangePackageManager(p);
}),
);

this.disposables.push(
this.stateManager.onDidChangeState(({ itemId }) => {
const view = this.revealMap.get(itemId);
if (view) {
this.fireDataChanged(view);
}
}),
);
}

dispose() {
Expand All @@ -77,6 +91,15 @@ export class EnvManagerView implements TreeDataProvider<EnvTreeItem>, Disposable
onDidChangeTreeData: Event<void | EnvTreeItem | EnvTreeItem[] | null | undefined> = this.treeDataChanged.event;

getTreeItem(element: EnvTreeItem): TreeItem | Thenable<TreeItem> {
if (element.kind === EnvTreeItemKind.environment && element instanceof PythonEnvTreeItem) {
const itemId = element.environment.envId.id;
const currentContext = element.treeItem.contextValue ?? '';
element.treeItem.contextValue = this.stateManager.updateContextValue(
itemId,
currentContext,
ENV_STATE_KEYS,
);
}
return element.treeItem;
}

Expand Down Expand Up @@ -202,7 +225,7 @@ export class EnvManagerView implements TreeDataProvider<EnvTreeItem>, Disposable

private onDidChangePackages(args: InternalDidChangePackagesEventArgs) {
const view = Array.from(this.revealMap.values()).find(
(v) => v.environment.envId.id === args.environment.envId.id
(v) => v.environment.envId.id === args.environment.envId.id,
);
if (view) {
this.fireDataChanged(view);
Expand Down
40 changes: 39 additions & 1 deletion src/features/views/projectView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { ProjectViews } from '../../common/localize';
import { createSimpleDebounce } from '../../common/utils/debounce';
import { onDidChangeConfiguration } from '../../common/workspace.apis';
import { EnvironmentManagers, PythonProjectManager } from '../../internal.api';
import { ITemporaryStateManager } from './temporaryStateManager';
import {
GlobalProjectItem,
NoProjectEnvironment,
Expand All @@ -25,6 +26,10 @@ import {
ProjectTreeItemKind,
} from './treeViewItems';

const COPIED_STATE = 'copied';
const SELECTED_STATE = 'selected';
const ENV_STATE_KEYS = [COPIED_STATE, SELECTED_STATE];

export class ProjectView implements TreeDataProvider<ProjectTreeItem> {
private treeView: TreeView<ProjectTreeItem>;
private _treeDataChanged: EventEmitter<ProjectTreeItem | ProjectTreeItem[] | null | undefined> = new EventEmitter<
Expand All @@ -35,7 +40,11 @@ export class ProjectView implements TreeDataProvider<ProjectTreeItem> {
private packageRoots: Map<string, ProjectEnvironment> = new Map();
private disposables: Disposable[] = [];
private debouncedUpdateProject = createSimpleDebounce(500, () => this.updateProject());
public constructor(private envManagers: EnvironmentManagers, private projectManager: PythonProjectManager) {
public constructor(
private envManagers: EnvironmentManagers,
private projectManager: PythonProjectManager,
private stateManager: ITemporaryStateManager,
) {
this.treeView = window.createTreeView<ProjectTreeItem>('python-projects', {
treeDataProvider: this,
});
Expand Down Expand Up @@ -69,6 +78,20 @@ export class ProjectView implements TreeDataProvider<ProjectTreeItem> {
}
}),
);

this.disposables.push(
this.stateManager.onDidChangeState(({ itemId }) => {
const projectView = this.projectViews.get(itemId);
if (projectView) {
this._treeDataChanged.fire(projectView);
return;
}
const envView = Array.from(this.revealMap.values()).find((v) => v.environment.envId.id === itemId);
if (envView) {
this._treeDataChanged.fire(envView);
}
}),
);
}

initialize(): void {
Expand Down Expand Up @@ -121,6 +144,21 @@ export class ProjectView implements TreeDataProvider<ProjectTreeItem> {
this._treeDataChanged.event;

getTreeItem(element: ProjectTreeItem): TreeItem | Thenable<TreeItem> {
if (element.kind === ProjectTreeItemKind.project && element instanceof ProjectItem) {
const itemId = element.project.uri.fsPath;
const currentContext = element.treeItem.contextValue ?? '';
element.treeItem.contextValue = this.stateManager.updateContextValue(itemId, currentContext, [
COPIED_STATE,
]);
} else if (element.kind === ProjectTreeItemKind.environment && element instanceof ProjectEnvironment) {
const itemId = element.environment.envId.id;
const currentContext = element.treeItem.contextValue ?? '';
element.treeItem.contextValue = this.stateManager.updateContextValue(
itemId,
currentContext,
ENV_STATE_KEYS,
);
}
return element.treeItem;
}

Expand Down
Loading
Loading