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
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ All notable changes to the "Conda Wingman" extension will be documented in this

Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.

## [1.2.0] - 2026-04

### Added
- **Clickable package links** — package names in YAML files link to anaconda.org (conda deps) or PyPI (pip deps)
- **Hover tooltips** — hover over packages to see description and latest version from PyPI
- **Switch Environment command** — quick pick of all conda envs, activate any one from the palette
- **Active env in status bar** — shows conda env name and Python version, click to switch
- **Auto-set Python interpreter** — automatically sets `python.defaultInterpreterPath` from detected conda env
- `condaWingman.autoSetInterpreter` setting to control interpreter auto-setting

## [1.1.0] - 2026-04

### Added
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code additions look good, but here are some suggestions for improvement and potential bug risks:

  1. Input Validation: Ensure that input from the user (such as package names) is validated to prevent security vulnerabilities like injection attacks.

  2. Error Handling: Implement robust error handling mechanisms to gracefully handle unexpected issues, preventing crashes or data loss.

  3. Testing: Add comprehensive unit tests to cover new functionality thoroughly, ensuring that changes work as expected and don't break existing features.

  4. Documentation: Update documentation within the codebase to reflect the new features, describing usage, configurations, and potential limitations.

  5. Performance Optimization: Monitor performance impact of new features, optimizing code if any slowdowns are noticed, especially in hover tooltips that may load external data.

  6. Versioning: Follow consistent versioning practices to maintain clarity on changes made between versions and ensure compatibility with dependency requirements.

Overall, the new features seem beneficial for user experience, but attention to these suggestions can enhance reliability and usability.

Expand Down
7 changes: 5 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ No build step — the extension runs directly from JS source files.

```
extension.js (activate: check conda, register commands, wire status bar, config listener)
├── commands.js (4 command handlers: build, activate, export, delete)
├── statusBarItems.js (CustomStatusBarItem class, 4 items, showAll/hideAll)
├── commands.js (5 command handlers: build, activate, export, delete, switch)
├── statusBarItems.js (CustomStatusBarItem class, 4 command items + env info item, showAll/hideAll)
├── interpreter.js (find conda env Python path, set python.defaultInterpreterPath)
├── documentLinks.js (clickable package links in YAML → anaconda.org / PyPI)
├── codeLens.js (hover tooltips with PyPI package info)
├── config.js (reads condaWingman.* settings)
└── utils.js (sendCommandToTerminal, YAML helpers, activeFileIsYAML)
```
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here are some suggestions based on the provided code patch:

  1. Code Structure:

    • The addition of new files such as interpreter.js, documentLinks.js, and codeLens.js seems appropriate for better organization and separation of concerns.
  2. Functionality Expansion:

    • Adding a new command handler for switch in commands.js is a good improvement to enhance functionality.
    • Implementing clickable package links in YAML through documentLinks.js and hover tooltips with PyPI package info using codeLens.js seem like useful features.
  3. Consistency:

    • Ensure consistency in naming conventions, coding styles, and documentation across all files for better maintainability.
  4. Error Handling:

    • Make sure to handle errors appropriately, especially when performing tasks like finding the Conda environment Python path in interpreter.js.
  5. Testing:

    • It would be beneficial to include unit tests to cover the new features and any modifications made to ensure that they work correctly and do not introduce regressions.
  6. Documentation:

    • Add comments or update the README to reflect the new features added and give usage instructions if needed.

Overall, the changes and additions seem valuable for enhancing the extension's functionality. Pay attention to error handling, maintain consistent coding standards, and consider testing to ensure the reliability and robustness of the extension.

Expand Down
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,28 @@ The supported commands are:
```
- **VS Code Command Palette:** `>Conda Wingman: Delete Conda Environment`

### Switch Environment
- **Command:** Pick from all available conda environments and activate the selected one.
- **VS Code Command Palette:** `>Conda Wingman: Switch Environment`

### Clickable Package Links
Package names in conda environment YAML files are clickable — conda packages link to [anaconda.org](https://anaconda.org), pip sub-dependencies link to [PyPI](https://pypi.org).

### Hover Tooltips
Hover over a package name in a YAML file to see its description and latest version from PyPI.

### Active Environment in Status Bar
The status bar shows the current conda environment name and Python version, detected from the open YAML file. Click it to switch environments.

### Auto-Set Python Interpreter
When a conda environment is detected, the workspace Python interpreter (`python.defaultInterpreterPath`) is automatically set to point to it.

## Settings

| Setting | Default | Description |
|---|---|---|
| `condaWingman.showStatusBarItems` | `true` | Show/hide status bar buttons |
| `condaWingman.autoSetInterpreter` | `true` | Auto-set workspace Python interpreter from conda env |

## Release Notes

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review:

  1. Addition of New Features:

    • Addition of the "Switch Environment" functionality is clear and well-described.
    • Clickable package links, hover tooltips, and displaying active environment in the status bar seem like useful features.
  2. Potential Improvements:

    • Consider adding error handling for scenarios where the selected conda environment may not be valid.
    • Ensure that clickable package links work as intended for all cases.
    • Double-check that activating various environments works seamlessly without any conflicts.
  3. Auto-Set Python Interpreter:

    • The auto-set Python interpreter feature could potentially conflict with existing interpreter configurations. Properly handle cases where conflicts arise.
    • Provide a way to disable this feature if users prefer manual control over the interpreter setting.
  4. Settings Table:

    • Ensure that the descriptions in the settings table are concise and clear for users to understand their purpose easily.
  5. Testing:

    • Thoroughly test the new features and settings in different scenarios to ensure they function correctly in all situations.
  6. Documentation:

    • Update documentation to reflect these new features and settings for user reference.
  7. Release Notes:

    • Update the release notes with details about the added features and changes for clarity.

Overall, the code patch appears to introduce valuable enhancements. However, attention should be given to potential edge cases, conflicts, and user preferences regarding the auto-setting of the Python interpreter.

Expand Down
14 changes: 12 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "conda-wingman",
"displayName": "Conda Wingman",
"description": "Status bar buttons and commands for managing Conda environments from YAML files.",
"version": "1.1.0",
"version": "1.2.0",
"publisher": "DJSaunders1997",
"engines": {
"vscode": "^1.86.0"
Expand Down Expand Up @@ -31,7 +31,8 @@
"onCommand:conda-wingman.buildCondaYAML",
"onCommand:conda-wingman.activateCondaYAML",
"onCommand:conda-wingman.writeRequirementsFile",
"onCommand:conda-wingman.deleteCondaEnv"
"onCommand:conda-wingman.deleteCondaEnv",
"onCommand:conda-wingman.switchEnvironment"
],
"main": "./src/extension.js",
"contributes": {
Expand All @@ -51,6 +52,10 @@
{
"command": "conda-wingman.deleteCondaEnv",
"title": "Conda Wingman: Delete Environment"
},
{
"command": "conda-wingman.switchEnvironment",
"title": "Conda Wingman: Switch Environment"
}
],
"configuration": {
Expand All @@ -60,6 +65,11 @@
"type": "boolean",
"default": true,
"description": "Show Conda Wingman buttons in the status bar when a YAML file is open."
},
"condaWingman.autoSetInterpreter": {
"type": "boolean",
"default": true,
"description": "Automatically set the workspace Python interpreter when a conda environment is detected."
}
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review:

Bug Risks:

  1. Potential Command Error: Ensure that the switchEnvironment command functionality is correctly implemented as there could be risks associated with environment switching logic.

Improvements:

  1. Document Changes: Update the README or documentation to reflect the new features added in version 1.2.0, such as switching environments and any other enhancements.

  2. Code Comments: Add or review existing comments for complex or critical logic to improve readability and understanding for maintainability.

  3. Testing: Consider adding unit tests to cover new functionality introduced. Test cases for switching environments ensure stability.

  4. Error Handling: Implement error handling for edge cases, particularly during environment switching activities, to avoid unexpected crashes.

  5. User Confirmation: For potentially risky operations like environment deletion or switching, consider adding user confirmation prompts to prevent accidental actions.

  6. Performance Optimization: If the extension has performance bottlenecks, profiling and optimizing it could enhance user experience.

  7. Security Audit: If the extension interacts with external resources, ensure that inputs are properly sanitized and validated to prevent security vulnerabilities.

  8. Feedback Mechanism: Consider adding a feedback mechanism to allow users to report bugs or provide suggestions directly from within the extension.

Overall, the changes appear straightforward, but thorough testing and consideration of potential edge cases and user experience improvements are recommended.

Expand Down
156 changes: 156 additions & 0 deletions src/codeLens.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
// Provides hover tooltips on package names in conda environment YAML files,
// showing package description and latest version from PyPI.

const vscode = require("vscode");
const https = require("https");
const { findCondaDepPositions } = require("./documentLinks");

/** Simple in-memory cache: pkgName -> { version, summary, fetchedAt } */
const cache = new Map();
const CACHE_TTL_MS = 10 * 60 * 1000; // 10 minutes

/** Invisible decoration type used only to attach hover tooltips to package names */
const hoverDecorationType = vscode.window.createTextEditorDecorationType({});

/**
* Fetches package info from the PyPI JSON API.
* Returns { version, summary } or null on failure.
*/
function fetchPypiInfo(pkgName) {
return new Promise(resolve => {
const url = `https://pypi.org/pypi/${encodeURIComponent(pkgName)}/json`;
const req = https.get(url, { timeout: 5000 }, res => {
if (res.statusCode !== 200) {
res.resume();
resolve(null);
return;
}
let data = "";
res.on("data", chunk => { data += chunk; });
res.on("end", () => {
try {
const json = JSON.parse(data);
resolve({
version: json.info.version,
summary: json.info.summary || "",
});
} catch {
resolve(null);
}
});
});
req.on("error", () => resolve(null));
req.on("timeout", () => { req.destroy(); resolve(null); });
});
}

/**
* Returns cached PyPI info or fetches it, with TTL-based expiry.
*/
async function getPypiInfo(pkgName) {
const cached = cache.get(pkgName);
if (cached && (Date.now() - cached.fetchedAt) < CACHE_TTL_MS) {
return cached;
}
const info = await fetchPypiInfo(pkgName);
if (info) {
cache.set(pkgName, { ...info, fetchedAt: Date.now() });
}
return info;
}

/** Track the current update so we can cancel stale runs */
let updateCounter = 0;

/**
* Updates hover decorations for the given text editor.
* Only applies to YAML files that look like conda environment files.
*/
async function updateDecorations(editor) {
if (!editor) return;

const filePath = editor.document.uri.path;
if (!filePath.endsWith(".yml") && !filePath.endsWith(".yaml")) return;

const thisUpdate = ++updateCounter;
const text = editor.document.getText();
const positions = findCondaDepPositions(text);

if (positions.length === 0) {
editor.setDecorations(hoverDecorationType, []);
return;
}

const results = await Promise.all(
positions.map(async (pos) => {
const info = await getPypiInfo(pos.name);
return { ...pos, info };
})
);

// Check we haven't been superseded by a newer update
if (thisUpdate !== updateCounter) return;
if (editor !== vscode.window.activeTextEditor) return;

const hoverDecorations = [];

for (const { lineNum, colStart, colEnd, name, isPip, info } of results) {
if (!info) continue;

// Build hover tooltip content
const parts = [];
if (info.summary) parts.push(info.summary);
parts.push(`**Latest version:** ${info.version}`);

// Link to the right package index
if (isPip) {
parts.push(`[View on PyPI](https://pypi.org/project/${name}/)`);
} else {
parts.push(`[View on Anaconda](https://anaconda.org/conda-forge/${name})`);
parts.push(`[View on PyPI](https://pypi.org/project/${name}/)`);
}

hoverDecorations.push({
range: new vscode.Range(lineNum, colStart, lineNum, colEnd),
hoverMessage: new vscode.MarkdownString(parts.join("\n\n")),
});
}

editor.setDecorations(hoverDecorationType, hoverDecorations);
}

/** Debounce timer for document changes */
let debounceTimer;

/**
* Registers hover tooltip decorations for conda YAML files.
* @param {vscode.ExtensionContext} context
*/
function registerCodeLens(context) {
// Decorate the active editor if it's a YAML file
if (vscode.window.activeTextEditor) {
updateDecorations(vscode.window.activeTextEditor);
}

// Re-decorate when switching editors
context.subscriptions.push(
vscode.window.onDidChangeActiveTextEditor(editor => {
if (editor) {
updateDecorations(editor);
}
})
);

// Re-decorate on document changes (debounced)
context.subscriptions.push(
vscode.workspace.onDidChangeTextDocument(e => {
const editor = vscode.window.activeTextEditor;
if (editor && e.document === editor.document) {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => updateDecorations(editor), 1000);
}
})
);
}

module.exports = { registerCodeLens };
55 changes: 55 additions & 0 deletions src/commands.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const vscode = require("vscode");
const path = require("path");
const { execSync } = require("child_process");

const {
sendCommandToTerminal,
Expand All @@ -9,6 +10,8 @@ const {
deleteEnvFromYAML,
createYAMLInputBox,
} = require("./utils");
const { getCondaInterpreterPath, setWorkspacePythonInterpreter } = require("./interpreter");
const { getConfig } = require("./config");
const {
activateEnvIcon,
writeEnvIcon,
Expand Down Expand Up @@ -102,9 +105,61 @@ async function writeRequirementsFile() {
writeEnvIcon.displayDefault();
}

/**
* Shows a quick pick of all conda environments and activates the selected one.
* Runs `conda env list --json` to get the list of environments.
* Also sets the workspace Python interpreter if autoSetInterpreter is enabled.
*/
async function switchEnvironment() {
let envs;
try {
const output = execSync("conda env list --json", { encoding: "utf8", timeout: 10000 });
const parsed = JSON.parse(output);
envs = parsed.envs || [];
} catch {
vscode.window.showErrorMessage("Failed to list conda environments. Is conda installed?");
return;
}

if (envs.length === 0) {
vscode.window.showInformationMessage("No conda environments found.");
return;
}

// Build quick pick items from env paths
// Each path looks like /home/user/miniconda3/envs/myenv or /home/user/miniconda3 (base)
const items = envs.map(envPath => {
const name = path.basename(envPath);
// The base env is the conda root dir itself, detect it
const isBase = !envPath.includes(path.join("envs", name));
return {
label: isBase ? "base" : name,
description: envPath,
envPath: envPath,
};
});

const selected = await vscode.window.showQuickPick(items, {
placeHolder: "Select a conda environment to activate",
});

if (!selected) return;

sendCommandToTerminal(`conda activate ${selected.label}`);

// Auto-set interpreter if enabled
if (getConfig().autoSetInterpreter) {
const interpreterPath = getCondaInterpreterPath(selected.label);
if (interpreterPath) {
setWorkspacePythonInterpreter(interpreterPath).catch(() => {});
}
}
}

module.exports = {
buildCondaYAML,
activateCondaYAML,
writeRequirementsFile,
deleteCondaEnv,
switchEnvironment,
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review:

  1. Imports:

    • Ensure that all necessary imports are present at the top of the file for better clarity and organization.
  2. Error Handling in switchEnvironment Function:

    • When catching errors after running execSync("conda env list --json", ...), it's good to provide more specific error messages for different types of potential failures for better debugging.
  3. User Messaging:

    • Provide a bit more context within the error messages shown to users for better understanding of what went wrong.
  4. Timeout in execSync:

    • Consider handling timeout errors explicitly if they occur during the execution of the command using execSync.
  5. Interpreter Path Retrieval:

    • Ensure thorough testing for cases where getCondaInterpreterPath(selected.label) might return null.
  6. Promise Handling:

    • Ensure proper error handling for promises in setWorkspacePythonInterpreter(interpreterPath).catch(() => {});. Logging errors or displaying them could be helpful for the developer.
  7. Dependency Isolation:

    • Verify if the functions being called inside this script (sendCommandToTerminal, getConfig, getCondaInterpreterPath, setWorkspacePythonInterpreter) handle edge cases appropriately to prevent unexpected behavior.
  8. Code Structure:

    • The order of function definitions seems logical, starting with buildCondaYAML and ending with switchEnvironment.

Bug Risks and Improvements:

  • Error Handling Improvement: Enhance error handling by providing more specific error messages and ensuring consistent error handling throughout the codebase.

  • Security Note: Be cautious with execSync which runs shell commands. Check input validation to avoid any potential security vulnerabilities like command injection.

  • Testing: Thoroughly test the switchEnvironment function with different scenarios such as empty environments, timeout cases, etc., to ensure it behaves as expected in all conditions.

  • Documentation: Consider adding comments and/or JSDoc style documentation to the functions for better code readability and understanding.

  • Linting and Formatting: Run a linter/formatter on the codebase to ensure consistent coding standards are applied.

  • Unit Testing: Implement unit tests for critical functions to ensure their correctness and improve code quality.

By addressing these points, you can enhance the robustness, reliability, and maintainability of the codebase.

1 change: 1 addition & 0 deletions src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ function getConfig() {
const cfg = vscode.workspace.getConfiguration('condaWingman');
return {
showStatusBarItems: cfg.get('showStatusBarItems', true),
autoSetInterpreter: cfg.get('autoSetInterpreter', true),
};
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code patch seems to be a simple modification to an existing function in a Visual Studio Code (VSCode) extension related to Conda environments. Here are some observations and suggestions for improvement:

  1. Bug Risk:

    • No obvious bugs are introduced by this change as long as the configuration keys 'showStatusBarItems' and 'autoSetInterpreter' are correctly defined in the CondaWingman extension's package.json or default settings.
  2. Improvements:

    • Variable naming: The variable cfg can be renamed to something more descriptive like config for better readability.
    • Error Handling: Consider adding error handling in case vscode.workspace.getConfiguration('condaWingman') fails to get the CondaWingman configuration.
    • Documentation: Adding comments above the function explaining its purpose and the configuration options being returned could be helpful for future maintenance.
  3. Scope for Expansion:

    • Depending on the functionality and future plans, you might want to extend this to handle other configurations or settings as needed.
  4. Code Efficiency:

    • Make sure that accessing configuration settings doesn't incur performance penalties, especially if these settings are queried frequently or in critical paths.
  5. Consistency:

    • Ensure consistency in coding style with the rest of the project to maintain readability.

Overall, the code change seems fine if it aligns with the intended functionality. Just pay attention to error handling and code documentation for clarity and maintainability.

Expand Down
Loading
Loading