From a59e7188679d7cbbbe45976a498faab100c9739e Mon Sep 17 00:00:00 2001 From: BrunoV21 Date: Mon, 21 Jul 2025 22:11:41 +0100 Subject: [PATCH 1/6] removed python dependencies --- python/requirements.txt | 1 - python/tide.py | 90 ----------- src/pythonEnvironmentManager.ts | 278 -------------------------------- 3 files changed, 369 deletions(-) delete mode 100644 python/requirements.txt delete mode 100644 python/tide.py delete mode 100644 src/pythonEnvironmentManager.ts diff --git a/python/requirements.txt b/python/requirements.txt deleted file mode 100644 index 6694d06..0000000 --- a/python/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -codetide==0.0.2 \ No newline at end of file diff --git a/python/tide.py b/python/tide.py deleted file mode 100644 index 5b07b58..0000000 --- a/python/tide.py +++ /dev/null @@ -1,90 +0,0 @@ -from codetide.core.defaults import DEFAULT_SERIALIZATION_PATH -from codetide import CodeTide - -from pathlib import Path -import argparse -import asyncio -import time - -def safe_print(string :str): - try: - # First try printing directly - print(string) - except (UnicodeEncodeError, UnicodeError): - try: - # Try with UTF-8 encoding - import sys - if sys.stdout.encoding != 'utf-8': - sys.stdout.reconfigure(encoding='utf-8') # Python 3.7+ - print(string) - except Exception: - # Fallback to ASCII-safe output - print(string.encode('ascii', 'replace').decode('ascii')) - -async def init_project(args, force_build: bool = False, flush: bool = False) -> CodeTide: - storagePath = Path(args.project_path) / DEFAULT_SERIALIZATION_PATH - try: - if force_build: - raise FileNotFoundError() - - tide = CodeTide.deserialize(storagePath) - await tide.check_for_updates(serialize=True, include_cached_ids=True) - if flush: - safe_print(f"[INIT] Initialized from cache: {storagePath}") - - except FileNotFoundError: - st = time.time() - tide = await CodeTide.from_path(rootpath=args.project_path) - tide.serialize(storagePath, include_cached_ids=True) - if flush: - safe_print(f"[INIT] Fresh parse of {args.project_path}: {len(tide.codebase.root)} files in {time.time()-st:.2f}s") - return tide - -async def handle_get(args): - tide = await init_project(args) - result = tide.get(args.ids, degree=args.degree, as_string=True) - if result: - safe_print(result) - else: - safe_print(f"[GET] No matches found for {args.ids}") - -async def handle_tree(args): - tide = await init_project(args) - result = tide.codebase.get_tree_view(args.include_modules, args.include_types) - safe_print(result) - -async def handle_reset(args): - tide = await init_project(args) - await tide._reset() - tide.serialize(include_cached_ids=True) - safe_print(f"reseted project in {args.project_path}") - -async def main(): - parser = argparse.ArgumentParser(description="CLI for VSCode Extension") - subparsers = parser.add_subparsers(dest="command", required=True) - - parser_project = subparsers.add_parser("project", help="Initialize project parser") - parser_project.add_argument("project_path", help="Path to the current workspace/project") - parser_project.set_defaults(func=init_project, force_build=True, flush=True) - - parser_get = subparsers.add_parser("get", help="Get one or more items by ID") - parser_get.add_argument("project_path", help="Path to the current workspace/project") - parser_get.add_argument("ids", nargs="+", help="List of item IDs to get") - parser_get.add_argument("--degree", type=int, default=1, help="Depth of retrieval") - parser_get.set_defaults(func=handle_get) - - parser_tree = subparsers.add_parser("tree", help="Get tree view of the codebase") - parser_tree.add_argument("project_path", help="Path to the current workspace/project") - parser_tree.add_argument("--include-modules", action="store_true", help="Include modules in tree view") - parser_tree.add_argument("--include-types", action="store_true", help="Include types in tree view") - parser_tree.set_defaults(func=handle_tree) - - parser_parse = subparsers.add_parser("refresh", help="Refresh a tide project by reseting it") - parser_parse.add_argument("project_path", help="Path to the current workspace/project") - parser_parse.set_defaults(func=handle_reset) - - args = parser.parse_args() - await args.func(args) - -if __name__ == "__main__": - asyncio.run(main()) \ No newline at end of file diff --git a/src/pythonEnvironmentManager.ts b/src/pythonEnvironmentManager.ts deleted file mode 100644 index 54a29b9..0000000 --- a/src/pythonEnvironmentManager.ts +++ /dev/null @@ -1,278 +0,0 @@ -import * as vscode from 'vscode'; -import * as fs from 'fs'; -import * as path from 'path'; -import { exec } from 'child_process'; -import { promisify } from 'util'; - -const execAsync = promisify(exec); - -export class PythonEnvironmentManager { - private extensionContext: vscode.ExtensionContext; - private extensionId: string; - - constructor(context: vscode.ExtensionContext, extensionId: string) { - this.extensionContext = context; - this.extensionId = extensionId; - } - - /** - * Main setup method that checks Python installation and sets up virtual environment - */ - async setupPythonEnvironment(): Promise { - // Check if Python is installed - if (!(await this.isPythonInstalled())) { - const action = await vscode.window.showErrorMessage( - 'CodeTide Extension requires Python to be installed. Please install Python and restart VSCode.', - 'Download Python', - 'Cancel' - ); - - if (action === 'Download Python') { - vscode.env.openExternal(vscode.Uri.parse('https://www.python.org/downloads/')); - } - - throw new Error('Python is not installed'); - } - - // Check and setup virtual environment - const venvPath = this.getVenvPath(); - const requirementsPath = this.getRequirementsPath(); - - if (!fs.existsSync(venvPath)) { - // Create environment if it doesn't exist - await this.createVirtualEnvironment(venvPath, requirementsPath); - } - // Otherwise do nothing - no automatic updates - } - - /** - * Explicitly update the Python dependencies - */ - async updateDependencies(): Promise { - const venvPath = this.getVenvPath(); - const requirementsPath = this.getRequirementsPath(); - - if (!fs.existsSync(venvPath)) { - vscode.window.showErrorMessage('Python environment does not exist. Please reinstall the extension.'); - return; - } - - try { - await vscode.window.withProgress({ - location: vscode.ProgressLocation.Notification, - title: "CodeTide: Updating Python dependencies...", - cancellable: false - }, async () => { - const pipPath = this.getPipCommand(venvPath); - await execAsync(`"${pipPath}" install -r "${requirementsPath}"`); - - // Update the requirements timestamp - const venvStatsPath = path.join(venvPath, '.requirements_timestamp'); - const requirementsStats = fs.statSync(requirementsPath); - fs.writeFileSync(venvStatsPath, requirementsStats.mtimeMs.toString()); - }); - - vscode.window.showInformationMessage('CodeTide: Dependencies updated successfully!'); - } catch (error) { - vscode.window.showErrorMessage(`Failed to update dependencies: ${error}`); - } - } - - /** - * Check if Python is installed on the system - */ - private async isPythonInstalled(): Promise { - try { - // Try different Python commands that might be available - const pythonCommands = ['python3', 'python', 'py']; - - for (const cmd of pythonCommands) { - try { - await execAsync(`${cmd} --version`); - return true; - } catch { - continue; - } - } - - return false; - } catch { - return false; - } - } - - /** - * Create a new virtual environment and install dependencies - */ - private async createVirtualEnvironment(venvPath: string, requirementsPath: string): Promise { - return new Promise((resolve, reject) => { - vscode.window.withProgress({ - location: vscode.ProgressLocation.Notification, - title: "CodeTide: Setting up Python environment...", - cancellable: false - }, async (progress) => { - try { - progress.report({ increment: 0, message: "Creating virtual environment..." }); - - // Get Python command - const pythonCmd = await this.getPythonCommand(); - - // Create virtual environment - await execAsync(`${pythonCmd} -m venv "${venvPath}"`); - - progress.report({ increment: 50, message: "Installing dependencies..." }); - - // Install requirements - if (fs.existsSync(requirementsPath)) { - const pipPath = this.getPipCommand(venvPath); - await execAsync(`"${pipPath}" install -r "${requirementsPath}"`); - - // Store requirements timestamp - const venvStatsPath = path.join(venvPath, '.requirements_timestamp'); - const requirementsStats = fs.statSync(requirementsPath); - fs.writeFileSync(venvStatsPath, requirementsStats.mtimeMs.toString()); - } - - progress.report({ increment: 100, message: "Setup complete!" }); - - vscode.window.showInformationMessage('CodeTide: Python environment setup completed successfully!'); - resolve(); - - } catch (error) { - reject(new Error(`Failed to create virtual environment: ${error}`)); - } - }); - }); - } - - /** - * Get the Python command that works on the system - */ - private async getPythonCommand(): Promise { - const pythonCommands = ['python3', 'python', 'py']; - - for (const cmd of pythonCommands) { - try { - await execAsync(`${cmd} --version`); - return cmd; - } catch { - continue; - } - } - - throw new Error('No Python command found'); - } - - /** - * Get the pip command path for the virtual environment - */ - private getPipCommand(venvPath: string): string { - const isWindows = process.platform === 'win32'; - if (isWindows) { - return path.join(venvPath, 'Scripts', 'pip.exe'); - } else { - return path.join(venvPath, 'bin', 'pip'); - } - } - - /** - * Get the Python executable path from the virtual environment - */ - getPythonExecutablePath(): string { - const venvPath = this.getVenvPath(); - const isWindows = process.platform === 'win32'; - - if (isWindows) { - return path.join(venvPath, 'Scripts', 'python.exe'); - } else { - return path.join(venvPath, 'bin', 'python'); - } - } - - /** - * Get the virtual environment path - */ - private getVenvPath(): string { - return path.join(this.extensionContext.extensionPath, 'codetide.venv'); - } - - /** - * Get the requirements.txt path - */ - private getRequirementsPath(): string { - return path.join(this.extensionContext.extensionPath, 'python', 'requirements.txt'); - } - - /** - * Check if the virtual environment exists and is valid - */ - isVenvValid(): boolean { - const venvPath = this.getVenvPath(); - const pythonPath = this.getPythonExecutablePath(); - - return fs.existsSync(venvPath) && fs.existsSync(pythonPath); - } - - /** - * Reinstall the Python virtual environment - */ - async reinstallVirtualEnvironment(): Promise { - const venvPath = this.getVenvPath(); - const requirementsPath = this.getRequirementsPath(); - - // Remove existing virtual environment - if (fs.existsSync(venvPath)) { - const isWindows = process.platform === 'win32'; - const rmCommand = isWindows ? `rmdir /s /q "${venvPath}"` : `rm -rf "${venvPath}"`; - await execAsync(rmCommand); - } - - // Recreate virtual environment - await this.createVirtualEnvironment(venvPath, requirementsPath); - } - - /** - * Register commands related to Python environment management - */ - registerCommands(): vscode.Disposable[] { - const commands: vscode.Disposable[] = []; - - // Command to reinstall Python environment - commands.push(vscode.commands.registerCommand('extension.reinstallPythonEnv', async () => { - try { - await this.reinstallVirtualEnvironment(); - vscode.window.showInformationMessage('CodeTide: Python environment reinstalled successfully!'); - } catch (error) { - vscode.window.showErrorMessage(`Failed to reinstall Python environment: ${error}`); - } - })); - - // Command to update Python dependencies - commands.push(vscode.commands.registerCommand('extension.updatePythonDependencies', async () => { - try { - await this.updateDependencies(); - } catch (error) { - vscode.window.showErrorMessage(`Failed to update dependencies: ${error}`); - } - })); - - // Command to check Python environment status - commands.push(vscode.commands.registerCommand('extension.checkPythonEnv', async () => { - try { - const isInstalled = await this.isPythonInstalled(); - const isVenvValid = this.isVenvValid(); - - let status = 'Python Environment Status:\n'; - status += `• Python installed: ${isInstalled ? '✓' : '✗'}\n`; - status += `• Virtual environment: ${isVenvValid ? '✓' : '✗'}\n`; - status += `• Virtual environment path: ${this.getVenvPath()}`; - - vscode.window.showInformationMessage(status); - } catch (error) { - vscode.window.showErrorMessage(`Error checking Python environment: ${error}`); - } - })); - - return commands; - } -} \ No newline at end of file From 8fdf7bee7c745d8ce1543bc49cb28f1c28f8b37e Mon Sep 17 00:00:00 2001 From: BrunoV21 Date: Mon, 21 Jul 2025 22:12:11 +0100 Subject: [PATCH 2/6] added uVManager.ts --- src/uvManager.ts | 299 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 299 insertions(+) create mode 100644 src/uvManager.ts diff --git a/src/uvManager.ts b/src/uvManager.ts new file mode 100644 index 0000000..d9ff574 --- /dev/null +++ b/src/uvManager.ts @@ -0,0 +1,299 @@ +import * as vscode from 'vscode'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as os from 'os'; +import { exec } from 'child_process'; +import { promisify } from 'util'; + +const execAsync = promisify(exec); + +interface UVConfig { + uvxPath?: string; + uvPath?: string; + customInstallPath?: string; +} + +export class UVManager { + private context: vscode.ExtensionContext; + private configPath: string; + private config: UVConfig = {}; + + constructor(context: vscode.ExtensionContext) { + this.context = context; + this.configPath = path.join(context.globalStorageUri.fsPath, 'uv-config.json'); + this.loadConfig(); + } + + /** + * Load configuration from JSON file + */ + private loadConfig(): void { + try { + if (fs.existsSync(this.configPath)) { + const configData = fs.readFileSync(this.configPath, 'utf8'); + this.config = JSON.parse(configData); + } + } catch (error) { + console.error('Failed to load UV config:', error); + this.config = {}; + } + } + + /** + * Save configuration to JSON file + */ + private saveConfig(): void { + try { + // Ensure directory exists + const configDir = path.dirname(this.configPath); + if (!fs.existsSync(configDir)) { + fs.mkdirSync(configDir, { recursive: true }); + } + + fs.writeFileSync(this.configPath, JSON.stringify(this.config, null, 2)); + } catch (error) { + console.error('Failed to save UV config:', error); + } + } + + /** + * Get platform-specific default paths + */ + private getDefaultPaths(): { uvx: string; uv: string } { + const isWindows = os.platform() === 'win32'; + const homeDir = os.homedir(); + + if (isWindows) { + return { + uvx: path.join(homeDir, '.local', 'bin', 'uvx.exe'), + uv: path.join(homeDir, '.local', 'bin', 'uv.exe') + }; + } else { + return { + uvx: path.join(homeDir, '.local', 'bin', 'uvx'), + uv: path.join(homeDir, '.local', 'bin', 'uv') + }; + } + } + + /** + * Check if a file exists at the given path + */ + private async fileExists(filePath: string): Promise { + try { + await fs.promises.access(filePath, fs.constants.F_OK); + return true; + } catch { + return false; + } + } + + /** + * Search for UV/UVX in system PATH + */ + private async searchInPath(executable: string): Promise { + try { + const isWindows = os.platform() === 'win32'; + const command = isWindows ? `where ${executable}` : `which ${executable}`; + + const { stdout } = await execAsync(command); + const paths = stdout.trim().split('\n'); + + for (const execPath of paths) { + if (await this.fileExists(execPath.trim())) { + return execPath.trim(); + } + } + } catch { + // Command failed, executable not found in PATH + } + + return null; + } + + /** + * Find UVX executable path + */ + public async findUVX(): Promise { + // Check if we have a custom path stored + if (this.config.customInstallPath) { + const customUVX = path.join(this.config.customInstallPath, os.platform() === 'win32' ? 'uvx.exe' : 'uvx'); + if (await this.fileExists(customUVX)) { + return customUVX; + } + } + + // Check stored paths + if (this.config.uvxPath && await this.fileExists(this.config.uvxPath)) { + return this.config.uvxPath; + } + + // Check default paths + const defaultPaths = this.getDefaultPaths(); + if (await this.fileExists(defaultPaths.uvx)) { + this.config.uvxPath = defaultPaths.uvx; + this.saveConfig(); + return defaultPaths.uvx; + } + + // Search in system PATH + const pathResult = await this.searchInPath('uvx'); + if (pathResult) { + this.config.uvxPath = pathResult; + this.saveConfig(); + return pathResult; + } + + return null; + } + + /** + * Install UV using platform-specific commands + */ + private async installUV(): Promise { + try { + const isWindows = os.platform() === 'win32'; + let command: string; + + if (isWindows) { + command = 'powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"'; + } else { + command = 'curl -LsSf https://astral.sh/uv/install.sh | sh'; + } + + vscode.window.showInformationMessage('Installing UV... This may take a few minutes.'); + + await execAsync(command, { timeout: 120000 }); // 2 minute timeout + + // Wait a moment for installation to complete + await new Promise(resolve => setTimeout(resolve, 2000)); + + return true; + } catch (error) { + console.error('UV installation failed:', error); + return false; + } + } + + /** + * Show manual installation instructions and prompt for path + */ + private async promptManualInstallation(): Promise { + const isWindows = os.platform() === 'win32'; + const installCommand = isWindows + ? 'powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"' + : 'curl -LsSf https://astral.sh/uv/install.sh | sh'; + + const message = `UV installation failed. Please install UV manually using the following command: + +${installCommand} + +After installation, please provide the path to the UV installation directory.`; + + const result = await vscode.window.showWarningMessage( + message, + { modal: true }, + 'Provide Installation Path', + 'Cancel' + ); + + if (result === 'Provide Installation Path') { + const installPath = await vscode.window.showInputBox({ + prompt: 'Enter the path to the UV installation directory (e.g., /home/user/.local/bin or C:\\Users\\user\\.local\\bin)', + placeHolder: isWindows ? 'C:\\Users\\user\\.local\\bin' : '/home/user/.local/bin', + validateInput: (value) => { + if (!value || value.trim().length === 0) { + return 'Please enter a valid path'; + } + return null; + } + }); + + if (installPath) { + this.config.customInstallPath = installPath.trim(); + this.saveConfig(); + + // Verify the installation + const uvxPath = await this.findUVX(); + if (uvxPath) { + vscode.window.showInformationMessage('UV path configured successfully!'); + } else { + vscode.window.showErrorMessage('UVX not found in the provided path. Please check the installation.'); + } + } + } + } + + /** + * Ensure UVX is available, install if necessary + */ + public async ensureUVX(): Promise { + // First, try to find existing installation + let uvxPath = await this.findUVX(); + if (uvxPath) { + return uvxPath; + } + + // Try to install UV + const installSuccess = await this.installUV(); + + if (installSuccess) { + // Check if installation worked + uvxPath = await this.findUVX(); + if (uvxPath) { + vscode.window.showInformationMessage('UV installed successfully!'); + return uvxPath; + } + } + + // Installation failed, prompt for manual installation + await this.promptManualInstallation(); + + // Try once more after manual configuration + return await this.findUVX(); + } + + /** + * Get UV executable path (for uv commands) + */ + public async getUVPath(): Promise { + // If we have uvx, we likely have uv in the same directory + const uvxPath = await this.findUVX(); + if (uvxPath) { + const uvPath = uvxPath.replace(/uvx(.exe)?$/, 'uv$1'); + if (await this.fileExists(uvPath)) { + return uvPath; + } + } + + // Check stored UV path + if (this.config.uvPath && await this.fileExists(this.config.uvPath)) { + return this.config.uvPath; + } + + // Search in PATH + const pathResult = await this.searchInPath('uv'); + if (pathResult) { + this.config.uvPath = pathResult; + this.saveConfig(); + return pathResult; + } + + return null; + } + + /** + * Reset configuration (for debugging/testing) + */ + public resetConfig(): void { + this.config = {}; + this.saveConfig(); + } + + /** + * Get current configuration + */ + public getConfig(): UVConfig { + return { ...this.config }; + } +} \ No newline at end of file From 00e8563bfa4603555404b65ae3237a3e871bc4f4 Mon Sep 17 00:00:00 2001 From: BrunoV21 Date: Mon, 21 Jul 2025 22:12:24 +0100 Subject: [PATCH 3/6] updated runPythonCommands to use uvx --- src/runPythonCommand.ts | 157 ++++++++++++++++++++++++++++------------ 1 file changed, 111 insertions(+), 46 deletions(-) diff --git a/src/runPythonCommand.ts b/src/runPythonCommand.ts index 4b94450..52ed878 100644 --- a/src/runPythonCommand.ts +++ b/src/runPythonCommand.ts @@ -1,59 +1,124 @@ - import { exec } from 'child_process'; import * as path from 'path'; import * as vscode from 'vscode'; +import { getUVXPath } from './extension'; -export function RunPythonCommand( +export async function RunPythonCommand( command: string, args: string[], title = 'Running CodeTide SubProcess', onResult?: (output: string) => void ): Promise { - const pythonScript = path.join(__dirname, '..', 'python', 'tide.py'); - const venvPython = process.platform === 'win32' - ? path.join(__dirname, '..', 'codetide.venv', 'Scripts', 'python.exe') - : path.join(__dirname, '..', 'codetide.venv', 'bin', 'python'); - - const fullCommand = `"${venvPython}" "${pythonScript}" ${command} ${args.map(arg => `"${arg}"`).join(' ')}`; - - return new Promise((resolve, reject) => { - vscode.window.withProgress( - { - location: vscode.ProgressLocation.Notification, - title, - cancellable: false - }, - async (progress) => { - progress.report({ message: 'Working ...' }); - - try { - const output = await new Promise((execResolve, execReject) => { - exec(fullCommand, (err, stdout, stderr) => { - if (err) { - vscode.window.showErrorMessage(`Python error: ${err.message}`); - execReject(err); - return; - } - - if (stderr) { - console.error(`Python stderr: ${stderr}`); - } - - const output = stdout.trim(); - if (onResult) { - onResult(output); - } else if (output.length > 0) { - vscode.window.showInformationMessage(`[CodeTide] ${output}`); - } - - execResolve(output); + return new Promise(async (resolve, reject) => { + try { + // Get UVX path from UV Manager + const uvxPath = await getUVXPath(); + + if (!uvxPath) { + vscode.window.showErrorMessage( + 'UVX not found. Please run "CodeTide: Setup UV" command first.', + 'Setup UV' + ).then(selection => { + if (selection === 'Setup UV') { + vscode.commands.executeCommand('codetide.setupUV'); + } + }); + reject(new Error('UVX not available')); + return; + } + + // Build the command arguments + const uvxArgs = ['--from', 'codetide', 'codetide-cli', command, ...args]; + + // Create the full command - use the exact path to avoid PATH issues + const fullCommand = `"${uvxPath}" ${uvxArgs.map(arg => `"${arg}"`).join(' ')}`; + + console.log('UVX Path:', uvxPath); + console.log('Full command:', fullCommand); + + // Get the directory containing uvx for PATH + const uvxDir = path.dirname(uvxPath); + + // Prepare environment with uvx directory in PATH + const envWithUvx = { + ...process.env, + PATH: `${uvxDir}${path.delimiter}${process.env.PATH}`, + }; + + vscode.window.withProgress( + { + location: vscode.ProgressLocation.Notification, + title, + cancellable: false + }, + async (progress) => { + progress.report({ message: 'Working ...' }); + + try { + const output = await new Promise((execResolve, execReject) => { + exec(fullCommand, { env: envWithUvx }, (err, stdout, stderr) => { + if (err) { + // Enhanced error handling + const errorMessage = `UVX execution failed: ${err.message}`; + console.error('UVX Error:', err); + console.error('stderr:', stderr); + + // Check for common UVX issues + if (err.message.includes('ENOENT')) { + vscode.window.showErrorMessage( + 'UVX executable not found. The installation may be corrupted.', + 'Reinstall UV' + ).then(selection => { + if (selection === 'Reinstall UV') { + vscode.commands.executeCommand('codetide.setupUV'); + } + }); + } else if (stderr.includes('package not found') || stderr.includes('codetide')) { + vscode.window.showErrorMessage( + 'CodeTide CLI package not found. Make sure it\'s available on PyPI or install it manually.', + 'Install Manually' + ).then(selection => { + if (selection === 'Install Manually') { + vscode.env.openExternal(vscode.Uri.parse('https://pypi.org/project/codetide/')); + } + }); + } else { + vscode.window.showErrorMessage(errorMessage); + } + + execReject(err); + return; + } + + if (stderr) { + console.warn(`UVX stderr: ${stderr}`); + // Only show stderr as warning if it's not just informational + if (stderr.includes('error') || stderr.includes('Error')) { + vscode.window.showWarningMessage(`UVX Warning: ${stderr}`); + } + } + + const trimmedOutput = stdout.trim(); + if (onResult) { + onResult(trimmedOutput); + } else if (trimmedOutput.length > 0) { + vscode.window.showInformationMessage(`[CodeTide] ${trimmedOutput}`); + } + + execResolve(trimmedOutput); + }); }); - }); - resolve(); - } catch (error) { - reject(error); + + resolve(); + } catch (error) { + console.error('Command execution error:', error); + reject(error); + } } - } - ); + ); + } catch (error) { + console.error('RunPythonCommand setup error:', error); + reject(error); + } }); } \ No newline at end of file From 38589bce1f8fbac8ccd8c5085d5ae1c1d5349016 Mon Sep 17 00:00:00 2001 From: BrunoV21 Date: Mon, 21 Jul 2025 22:12:41 +0100 Subject: [PATCH 4/6] updated extension.ts to use uvx --- src/extension.ts | 151 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 133 insertions(+), 18 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index ed07aa9..839c066 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,38 +1,146 @@ import { FuzzyAutocomplete } from './fuzzyAutoComplete'; import { RunPythonCommand } from './runPythonCommand'; -import { PythonEnvironmentManager } from './pythonEnvironmentManager'; +// import { PythonEnvironmentManager } from './pythonEnvironmentManager'; +import { UVManager } from './uvManager'; import * as vscode from 'vscode'; -let pythonEnvManager: PythonEnvironmentManager; +// let pythonEnvManager: PythonEnvironmentManager; +let uvManager: UVManager; export async function activate(context: vscode.ExtensionContext) { try { - // Initialize Python Environment Manager with extension ID - const extensionId = 'your.publisher.codetide'; // Replace with your actual extension ID - pythonEnvManager = new PythonEnvironmentManager(context, extensionId); + uvManager = new UVManager(context); - // Check Python installation and setup virtual environment - await pythonEnvManager.setupPythonEnvironment(); + // Ensure UVX is available + vscode.window.showInformationMessage('CodeTide: Checking UV installation...'); + const uvxPath = await uvManager.ensureUVX(); - // Register Python environment management commands - const envCommands = pythonEnvManager.registerCommands(); - context.subscriptions.push(...envCommands); + if (uvxPath) { + vscode.window.showInformationMessage(`CodeTide: UV is ready at ${uvxPath}`); + } else { + vscode.window.showWarningMessage('CodeTide: UV is not available. Some features may not work.'); + } // Initialize the main extension functionality initializeExtension(context); + // Register UV-related commands + registerUVCommands(context); // Show success message vscode.window.showInformationMessage('CodeTide Extension activated successfully!'); } catch (error) { vscode.window.showErrorMessage(`CodeTide Extension failed to initialize: ${error}`); + registerUVCommands(context); + return; + } +} + +function registerUVCommands(context: vscode.ExtensionContext) { + // Command to check UV status + context.subscriptions.push(vscode.commands.registerCommand('codetide.checkUVStatus', async () => { + if (!uvManager) { + vscode.window.showErrorMessage('UV Manager not initialized'); + return; + } + + const uvxPath = await uvManager.findUVX(); + const uvPath = await uvManager.getUVPath(); + const config = uvManager.getConfig(); - // Still register basic commands even if Python setup fails - const envCommands = pythonEnvManager?.registerCommands() || []; - context.subscriptions.push(...envCommands); + const statusMessage = `UV Status: +UVX: ${uvxPath || 'Not found'} +UV: ${uvPath || 'Not found'} +Custom Path: ${config.customInstallPath || 'None'}`; - return; + vscode.window.showInformationMessage(statusMessage); + })); + + // Command to reinstall/setup UV + context.subscriptions.push(vscode.commands.registerCommand('codetide.setupUV', async () => { + if (!uvManager) { + vscode.window.showErrorMessage('UV Manager not initialized'); + return; + } + + try { + vscode.window.showInformationMessage('Setting up UV...'); + const uvxPath = await uvManager.ensureUVX(); + + if (uvxPath) { + vscode.window.showInformationMessage(`UV setup successful! Located at: ${uvxPath}`); + } else { + vscode.window.showWarningMessage('UV setup completed but UVX path not found.'); + } + } catch (error) { + vscode.window.showErrorMessage(`UV setup failed: ${error}`); + } + })); + + // Command to reset UV configuration + context.subscriptions.push(vscode.commands.registerCommand('codetide.resetUVConfig', async () => { + if (!uvManager) { + vscode.window.showErrorMessage('UV Manager not initialized'); + return; + } + + const result = await vscode.window.showWarningMessage( + 'This will reset all UV configuration. Continue?', + { modal: true }, + 'Yes', + 'No' + ); + + if (result === 'Yes') { + uvManager.resetConfig(); + vscode.window.showInformationMessage('UV configuration reset successfully.'); + } + })); + + // Command to run UV commands directly + context.subscriptions.push(vscode.commands.registerCommand('codetide.runUVCommand', async () => { + if (!uvManager) { + vscode.window.showErrorMessage('UV Manager not initialized'); + return; + } + + const uvxPath = await uvManager.findUVX(); + if (!uvxPath) { + vscode.window.showErrorMessage('UVX not found. Please run "CodeTide: Setup UV" first.'); + return; + } + + const command = await vscode.window.showInputBox({ + prompt: 'Enter UV command (e.g., "run python --version")', + placeHolder: 'run python --version' + }); + + if (command) { + const workspacePath = getWorkspacePath(); + if (!workspacePath) return; + + // You can modify RunPythonCommand to accept uvx path, or create a new function + // For now, showing how you might integrate it: + vscode.window.showInformationMessage(`Running: uvx ${command}`); + // Implementation depends on how you want to execute uvx commands + } + })); +} + +// Helper function to get UVX path for use in other parts of your extension +export async function getUVXPath(): Promise { + if (!uvManager) { + return null; } + return await uvManager.findUVX(); +} + +// Helper function to get UV path for use in other parts of your extension +export async function getUVPath(): Promise { + if (!uvManager) { + return null; + } + return await uvManager.getUVPath(); } function initializeExtension(context: vscode.ExtensionContext) { @@ -48,10 +156,11 @@ function initializeExtension(context: vscode.ExtensionContext) { return workspacePath; }; - // Project parser command - context.subscriptions.push(vscode.commands.registerCommand('extension.runParser', () => { + // Modified project parser command to potentially use UV + context.subscriptions.push(vscode.commands.registerCommand('extension.runParser', async () => { const workspacePath = getWorkspacePath(); if (!workspacePath) return; + RunPythonCommand('project', [workspacePath], 'CodeTide: Initialize Project'); })); @@ -282,8 +391,14 @@ function initializeExtension(context: vscode.ExtensionContext) { })); } -export function getPythonEnvironmentManager(): PythonEnvironmentManager { - return pythonEnvManager; +// Helper function to get workspace path (moved here to be accessible by UV commands) +function getWorkspacePath(): string | null { + const workspacePath = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath; + if (!workspacePath) { + vscode.window.showErrorMessage("No workspace is open."); + return null; + } + return workspacePath; } export function deactivate() { From 7da8df9f5e875baa37668decd204d8c29a5dfa0b Mon Sep 17 00:00:00 2001 From: BrunoV21 Date: Mon, 21 Jul 2025 22:16:29 +0100 Subject: [PATCH 5/6] updated README --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 4dd6c8c..f878cb0 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,6 @@ ![CodeTide in Action](https://raw.githubusercontent.com/BrunoV21/CodeTide-vsExtension/main/assets/codetide-demo.gif) -*(Example GIF showing context selection and Copilot integration)* - ## Key Features - **Automatic Codebase Parsing** - Intelligently indexes your entire project structure From c4182770d45767cc3e3ec654847bc5ac99fa2b49 Mon Sep 17 00:00:00 2001 From: BrunoV21 Date: Mon, 21 Jul 2025 22:26:37 +0100 Subject: [PATCH 6/6] removed deprectade python files from package.json --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 2a7e9a2..60f7fd6 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,6 @@ "main": "./dist/extension.js", "files": [ "dist", - "python", "assets" ], "activationEvents": [