diff --git a/CHANGELOG.md b/CHANGELOG.md index a010dcf..f57c063 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # 更新日志 -本文档记录 "Switch2IDEA" 扩展的所有重要更新。 +本文档记录 "Switch2JETBRAIN" 扩展的所有重要更新。 ## [1.0.0] diff --git a/README.md b/README.md index d5eb909..0d92b81 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,18 @@ -# Switch2IDEA +# Switch2JETBRAIN [中文](README_zh.md) > 💡 Recommended to use with [Switch2Cursor](https://github.com/qczone/switch2cursor) in IDEA -[![Visual Studio Marketplace](https://img.shields.io/visual-studio-marketplace/v/qczone.switch2idea?label=VS%20Marketplace&style=for-the-badge&logo=visual-studio-code)](https://marketplace.visualstudio.com/items?itemName=qczone.switch2idea) -[![Downloads](https://img.shields.io/visual-studio-marketplace/d/qczone.switch2idea?style=for-the-badge&logo=visual-studio-code)](https://marketplace.visualstudio.com/items?itemName=qczone.switch2idea) +[![Visual Studio Marketplace](https://img.shields.io/visual-studio-marketplace/v/qczone.switch2jetbrain?label=VS%20Marketplace&style=for-the-badge&logo=visual-studio-code)](https://marketplace.visualstudio.com/items?itemName=qczone.switch2jetbrain) +[![Downloads](https://img.shields.io/visual-studio-marketplace/d/qczone.switch2jetbrain?style=for-the-badge&logo=visual-studio-code)](https://marketplace.visualstudio.com/items?itemName=qczone.switch2jetbrain) [![License](https://img.shields.io/badge/license-MIT-blue.svg?style=for-the-badge)](LICENSE) ## 🔍 Project Overview A Cursor extension that enhances development efficiency by enabling smooth switching between Cursor and IDEA -![Switch2IDEA Demo](images/switch-show.gif) +![Switch2JETBRAIN Demo](images/switch-show.gif) ## 🌟 Features @@ -36,8 +36,8 @@ A Cursor extension that enhances development efficiency by enabling smooth switc ### Method 1: Install from Extension Marketplace -1. Click [here](https://marketplace.visualstudio.com/items?itemName=qczone.switch2idea) to install -2. Search for "Switch2IDEA" in the Cursor extension marketplace and install +1. Click [here](https://marketplace.visualstudio.com/items?itemName=qczone.switch2jetbrain) to install +2. Search for "Switch2JETBRAIN" in the Cursor extension marketplace and install ### Method 2: Local Installation @@ -52,18 +52,18 @@ A Cursor extension that enhances development efficiency by enabling smooth switc #### Open Project - Shortcut: `Alt+Shift+P` -- Context Menu: Right-click in file explorer → `Open Project in IDEA` +- Context Menu: Right-click in file explorer → `Open Project in Jetbrains` #### Open Current File - Shortcut: `Alt+Shift+O` - Context Menu: - - Right-click in editor → `Open File in IDEA` - - Right-click in file explorer → `Open File in IDEA` + - Right-click in editor → `Open File in Jetbrains` + - Right-click in file explorer → `Open File in Jetbrains` ### Configuration -Open Cursor settings, click `General` → `Editor` → `open editor settings` → `Extensions` → `Switch2IDEA` → `Idea Path` +Open Cursor settings, click `General` → `Editor` → `open editor settings` → `Extensions` → `Switch2JETBRAIN` → `Idea Path` - macOS: Automatically traverses common IDEA installation paths - Windows: Default `C:\Program Files\JetBrains\IntelliJ IDEA\bin\idea64.exe` @@ -84,7 +84,7 @@ Issues and Pull Requests are welcome to improve this extension. Please check the following steps: -1. Open Cursor settings, click `General` → `Editor` → `open editor settings` → `Extensions` → `Switch2IDEA` +1. Open Cursor settings, click `General` → `Editor` → `open editor settings` → `Extensions` → `Switch2JETBRAIN` 2. Verify that Idea Path is correctly configured to IDEA's executable path ### 2. Does it support jumping to other IDEs? @@ -97,7 +97,7 @@ You can configure IDE paths separately for each workspace: 1. Open Cursor settings, click `General` → `Editor` → `open editor settings` 2. Select the `Workspace` tab -3. Navigate to `Extensions` → `Switch2IDEA` → `ideaPath` +3. Navigate to `Extensions` → `Switch2JETBRAIN` → `ideaPath` 4. Enter the IDE path needed for that project Configuration examples: @@ -114,8 +114,8 @@ This project is licensed under the [MIT License](LICENSE) If you encounter issues or have suggestions, please provide feedback through: -- [Submit GitHub Issue](https://github.com/qczone/switch2idea/issues) +- [Submit GitHub Issue](https://github.com/qczone/switch2jetbrain/issues) ## 🌟 Star History -[![Star History Chart](https://api.star-history.com/svg?repos=qczone/switch2idea&type=Date)](https://star-history.com/#qczone/switch2idea&Date) \ No newline at end of file +[![Star History Chart](https://api.star-history.com/svg?repos=qczone/switch2jetbrain&type=Date)](https://star-history.com/#qczone/switch2jetbrain&Date) \ No newline at end of file diff --git a/README_zh.md b/README_zh.md index 7afceb7..f6191f9 100644 --- a/README_zh.md +++ b/README_zh.md @@ -1,18 +1,18 @@ -# Switch2IDEA +# Switch2JETBRAIN [English](README.md) > 💡 推荐在 IDEA 中配合 [Switch2Cursor](https://github.com/qczone/switch2cursor) 使用 -[![Visual Studio Marketplace](https://img.shields.io/visual-studio-marketplace/v/qczone.switch2idea?label=VS%20Marketplace&style=for-the-badge&logo=visual-studio-code)](https://marketplace.visualstudio.com/items?itemName=qczone.switch2idea) -[![Downloads](https://img.shields.io/visual-studio-marketplace/d/qczone.switch2idea?style=for-the-badge&logo=visual-studio-code)](https://marketplace.visualstudio.com/items?itemName=qczone.switch2idea) +[![Visual Studio Marketplace](https://img.shields.io/visual-studio-marketplace/v/qczone.switch2jetbrain?label=VS%20Marketplace&style=for-the-badge&logo=visual-studio-code)](https://marketplace.visualstudio.com/items?itemName=qczone.switch2jetbrain) +[![Downloads](https://img.shields.io/visual-studio-marketplace/d/qczone.switch2jetbrain?style=for-the-badge&logo=visual-studio-code)](https://marketplace.visualstudio.com/items?itemName=qczone.switch2jetbrain) [![License](https://img.shields.io/badge/license-MIT-blue.svg?style=for-the-badge)](LICENSE) ## 🔍 项目简介 一个提升开发效率的 Cursor 扩展,让你在 Cursor 和 IDEA 之间实现丝滑切换 -![Switch2IDEA演示](images/switch-show.gif) +![Switch2JETBRAIN演示](images/switch-show.gif) ## 🌟 功能特性 @@ -39,8 +39,8 @@ ### 方式一:通过扩展市场安装 -1. 点击 [这里](https://marketplace.visualstudio.com/items?itemName=qczone.switch2idea) 安装 -2. 在 Cursor 扩展市场中搜索 "Switch2IDEA" 并安装 +1. 点击 [这里](https://marketplace.visualstudio.com/items?itemName=qczone.switch2jetbrain) 安装 +2. 在 Cursor 扩展市场中搜索 "Switch2JETBRAIN" 并安装 ### 方式二:本地安装 @@ -55,18 +55,18 @@ #### 打开项目 - 快捷键:`Alt+Shift+P` -- 右键菜单:在文件浏览器中右键 → `Open Project in IDEA` +- 右键菜单:在文件浏览器中右键 → `Open Project in Jetbrains` #### 打开当前文件 - 快捷键:`Alt+Shift+O` - 右键菜单: - - 在编辑器中右键 → `Open File in IDEA` - - 在文件浏览器中右键 → `Open File in IDEA` + - 在编辑器中右键 → `Open File in Jetbrains` + - 在文件浏览器中右键 → `Open File in Jetbrains` ### 配置 -打开 Cursor 设置,点击 `General` → `Editor` → `open editor settings` → `Extensions` → `Switch2IDEA` → `Idea Path` +打开 Cursor 设置,点击 `General` → `Editor` → `open editor settings` → `Extensions` → `Switch2JETBRAIN` → `Idea Path` - macOS:自动遍历 IDEA 常用安装路径 - Windows:默认 `C:\Program Files\JetBrains\IntelliJ IDEA\bin\idea64.exe` @@ -87,7 +87,7 @@ 请按以下步骤检查: -1. 打开 Cursor 设置,点击 `General` → `Editor` → `open editor settings` → `Extensions` → `Switch2IDEA` +1. 打开 Cursor 设置,点击 `General` → `Editor` → `open editor settings` → `Extensions` → `Switch2JETBRAIN` 2. 确认 Idea Path 是否正确配置成 IDEA 的可执行文件路径 ### 2. 是否支持跳转到其他 IDE? @@ -100,7 +100,7 @@ 1. 打开 Cursor 设置,点击 `General` → `Editor` → `open editor settings` 2. 选择 `Workspace` 标签页 -3. 导航到 `Extensions` → `Switch2IDEA` → `ideaPath` +3. 导航到 `Extensions` → `Switch2JETBRAIN` → `ideaPath` 4. 输入该项目需要使用的 IDE 路径 示例配置: @@ -117,8 +117,8 @@ 如果遇到问题或有建议,请通过以下方式反馈: -- [提交 GitHub Issue](https://github.com/qczone/switch2idea/issues) +- [提交 GitHub Issue](https://github.com/qczone/switch2jetbrain/issues) ## 🌟 Star 历史 -[![Star History Chart](https://api.star-history.com/svg?repos=qczone/switch2idea&type=Date)](https://star-history.com/#qczone/switch2idea&Date) \ No newline at end of file +[![Star History Chart](https://api.star-history.com/svg?repos=qczone/switch2jetbrain&type=Date)](https://star-history.com/#qczone/switch2jetbrain&Date) \ No newline at end of file diff --git a/package.json b/package.json index 99f0a16..db15f79 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,13 @@ { - "name": "switch2idea", - "displayName": "Switch2IDEA", + "name": "switch2jetbrain", + "displayName": "Switch2JETBRAIN", "description": "Quickly switch between VS Code and IntelliJ IDEA, open current file in IDEA with the same position", "version": "1.0.3", "publisher": "qczone", "license": "MIT", "repository": { "type": "git", - "url": "https://github.com/qczone/switch2idea" + "url": "https://github.com/qczone/switch2jetbrain" }, "icon": "images/icon.png", "engines": { @@ -31,51 +31,71 @@ "contributes": { "commands": [ { - "command": "Switch2IDEA.openFileInIDEA", - "title": "Open File in IDEA" + "command": "Switch2JETBRAIN.openFileInJETBRAIN", + "title": "Open File in Jetbrains" }, { - "command": "Switch2IDEA.openProjectInIDEA", - "title": "Open Project in IDEA" + "command": "Switch2JETBRAIN.openProjectInJETBRAIN", + "title": "Open Project in Jetbrains" } ], "keybindings": [ { - "command": "Switch2IDEA.openFileInIDEA", + "command": "Switch2JETBRAIN.openFileInJETBRAIN", "key": "alt+shift+o", "mac": "alt+shift+o", "when": "editorTextFocus" }, { - "command": "Switch2IDEA.openProjectInIDEA", + "command": "Switch2JETBRAIN.openProjectInJETBRAIN", "key": "alt+shift+p", "mac": "alt+shift+p" } ], "configuration": { - "title": "Switch2IDEA", + "title": "Switch2JETBRAIN", "properties": { - "switch2idea.ideaPath": { + "switch2jetbrain.ideaPath": { "type": "string", "default": "", - "description": "IDEA executable path" + "description": "IDEA executable path (leave empty for auto-detection)" + }, + "switch2jetbrain.autoDetectProjectType": { + "type": "boolean", + "default": true, + "description": "Automatically detect project type and choose appropriate IDE" + }, + "switch2jetbrain.webstormPath": { + "type": "string", + "default": "", + "description": "WebStorm executable path (leave empty for auto-detection)" + }, + "switch2jetbrain.pycharmPath": { + "type": "string", + "default": "", + "description": "PyCharm executable path (leave empty for auto-detection)" + }, + "switch2jetbrain.golandPath": { + "type": "string", + "default": "", + "description": "GoLand executable path (leave empty for auto-detection)" } } }, "menus": { "editor/context": [ { - "command": "Switch2IDEA.openFileInIDEA", + "command": "Switch2JETBRAIN.openFileInJETBRAIN", "group": "navigation" } ], "explorer/context": [ { - "command": "Switch2IDEA.openFileInIDEA", + "command": "Switch2JETBRAIN.openFileInJETBRAIN", "group": "navigation" }, { - "command": "Switch2IDEA.openProjectInIDEA", + "command": "Switch2JETBRAIN.openProjectInJETBRAIN", "group": "navigation" } ] diff --git a/src/extension.ts b/src/extension.ts index 99734a2..6ae8f9f 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -2,29 +2,138 @@ import * as vscode from 'vscode'; import { exec } from 'child_process'; import * as os from 'os'; import * as fs from 'fs'; +import * as path from 'path'; -function getMacIdeaPath(): string { - const commonPaths = [ - '/Applications/IDEA.app', - '/Applications/IntelliJ IDEA.app', - '/Applications/IntelliJ IDEA CE.app', - '/Applications/IntelliJ IDEA Ultimate.app', - '/Applications/IntelliJ IDEA Community Edition.app', - `${os.homedir()}/Applications/IDEA.app`, - `${os.homedir()}/Applications/IntelliJ IDEA.app`, - `${os.homedir()}/Applications/IntelliJ IDEA CE.app`, - `${os.homedir()}/Applications/IntelliJ IDEA Ultimate.app`, - `${os.homedir()}/Applications/IntelliJ IDEA Community Edition.app`, - ]; - - // Iterate through all possible IDEA installation paths and return the first existing path - for (const path of commonPaths) { - if (fs.existsSync(path)) { - return path; +// 项目类型枚举 +enum ProjectType { + JAVA = 'java', + FRONTEND = 'frontend', + PYTHON = 'python', + GO = 'go', + UNKNOWN = 'unknown' +} + +// IDE类型枚举 +enum IdeType { + IDEA = 'idea', + WEBSTORM = 'webstorm', + PYCHARM = 'pycharm', + GOLAND = 'goland' +} + +// 检测项目类型 +function detectProjectType(workspacePath: string): ProjectType { + // 检查Java项目特征 + if (fs.existsSync(path.join(workspacePath, 'pom.xml')) || + fs.existsSync(path.join(workspacePath, 'build.gradle')) || + fs.existsSync(path.join(workspacePath, 'build.gradle.kts')) || + fs.existsSync(path.join(workspacePath, 'src', 'main', 'java')) || + fs.existsSync(path.join(workspacePath, 'src', 'main', 'kotlin'))) { + return ProjectType.JAVA; + } + + // 检查前端项目特征 + const packageJsonPath = path.join(workspacePath, 'package.json'); + if (fs.existsSync(packageJsonPath)) { + try { + const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); + const dependencies = { ...packageJson.dependencies, ...packageJson.devDependencies }; + + // 检查前端框架 + if (dependencies['react'] || dependencies['vue'] || dependencies['angular'] || + dependencies['@angular/core'] || dependencies['next'] || dependencies['nuxt'] || + dependencies['svelte'] || dependencies['@sveltejs/kit']) { + return ProjectType.FRONTEND; + } + + // 检查构建工具 + if (dependencies['webpack'] || dependencies['vite'] || dependencies['rollup'] || + dependencies['parcel'] || dependencies['esbuild']) { + return ProjectType.FRONTEND; + } + } catch (e) { + // 如果package.json解析失败,继续其他检查 } + return ProjectType.FRONTEND; + } + + // 检查Python项目特征 + if (fs.existsSync(path.join(workspacePath, 'requirements.txt')) || + fs.existsSync(path.join(workspacePath, 'setup.py')) || + fs.existsSync(path.join(workspacePath, 'pyproject.toml')) || + fs.existsSync(path.join(workspacePath, 'Pipfile')) || + fs.existsSync(path.join(workspacePath, 'poetry.lock')) || + fs.existsSync(path.join(workspacePath, 'environment.yml'))) { + return ProjectType.PYTHON; + } + + // 检查Go项目特征 + if (fs.existsSync(path.join(workspacePath, 'go.mod')) || + fs.existsSync(path.join(workspacePath, 'Gopkg.toml')) || + fs.existsSync(path.join(workspacePath, 'vendor'))) { + return ProjectType.GO; + } + + return ProjectType.UNKNOWN; +} + +// 获取Mac上不同IDE的路径 +function getMacIdePath(ideType: IdeType): string { + const idePaths: { [key in IdeType]: string[] } = { + [IdeType.IDEA]: [ + '/Applications/IntelliJ IDEA.app', + '/Applications/IntelliJ IDEA CE.app', + '/Applications/IntelliJ IDEA Ultimate.app', + '/Applications/IntelliJ IDEA Community Edition.app', + `${os.homedir()}/Applications/IntelliJ IDEA.app`, + `${os.homedir()}/Applications/IntelliJ IDEA CE.app`, + `${os.homedir()}/Applications/IntelliJ IDEA Ultimate.app`, + `${os.homedir()}/Applications/IntelliJ IDEA Community Edition.app` + ], + [IdeType.WEBSTORM]: [ + '/Applications/WebStorm.app', + `${os.homedir()}/Applications/WebStorm.app` + ], + [IdeType.PYCHARM]: [ + '/Applications/PyCharm.app', + '/Applications/PyCharm CE.app', + '/Applications/PyCharm Professional.app', + '/Applications/PyCharm Community Edition.app', + `${os.homedir()}/Applications/PyCharm.app`, + `${os.homedir()}/Applications/PyCharm CE.app`, + `${os.homedir()}/Applications/PyCharm Professional.app`, + `${os.homedir()}/Applications/PyCharm Community Edition.app` + ], + [IdeType.GOLAND]: [ + '/Applications/GoLand.app', + `${os.homedir()}/Applications/GoLand.app` + ] + }; + + for (const idePath of idePaths[ideType]) { + if (fs.existsSync(idePath)) { + return idePath; + } + } + + // 如果找不到指定的IDE,返回默认的IDEA + return idePaths[IdeType.IDEA][0]; +} + +// 根据项目类型选择IDE +function selectIdeForProject(projectType: ProjectType): IdeType { + switch (projectType) { + case ProjectType.JAVA: + return IdeType.IDEA; + case ProjectType.FRONTEND: + return IdeType.WEBSTORM; + case ProjectType.PYTHON: + return IdeType.PYCHARM; + case ProjectType.GO: + return IdeType.GOLAND; + default: + return IdeType.IDEA; } - // If no paths exist, return the default APP name - return 'IntelliJ IDEA'; } function executeCommand(command: string): Promise { @@ -48,8 +157,8 @@ function executeCommand(command: string): Promise { // Add error handling childProcess.on('error', (error: NodeJS.ErrnoException) => { if (error.code === 'EPIPE') { - console.log('Pipe communication disconnected, but this may not affect IDEA startup'); - resolve(); // Continue execution as IDEA may have started normally + console.log('Pipe communication disconnected, but this may not affect IDE startup'); + resolve(); // Continue execution as IDE may have started normally } else { reject(error); } @@ -57,11 +166,79 @@ function executeCommand(command: string): Promise { }); } -export function activate(context: vscode.ExtensionContext) { +// 获取IDE路径的通用函数 +function getIdePath(ideType: IdeType, config: vscode.WorkspaceConfiguration): string { + const autoDetect = config.get('autoDetectProjectType', true); + + if (!autoDetect) { + // 如果禁用自动检测,使用默认的IDEA路径 + return config.get('ideaPath') || getMacIdePath(IdeType.IDEA); + } + + // 根据IDE类型获取对应的配置路径 + const idePaths: { [key in IdeType]: string } = { + [IdeType.IDEA]: config.get('ideaPath') || '', + [IdeType.WEBSTORM]: config.get('webstormPath') || '', + [IdeType.PYCHARM]: config.get('pycharmPath') || '', + [IdeType.GOLAND]: config.get('golandPath') || '' + }; + + let idePath = idePaths[ideType]; + + if (!idePath) { + if (os.platform() === 'darwin') { + idePath = getMacIdePath(ideType); + } else if (os.platform() === 'win32') { + // Windows路径映射 + const windowsPaths: { [key in IdeType]: string } = { + [IdeType.IDEA]: 'C:\\Program Files\\JetBrains\\IntelliJ IDEA\\bin\\idea64.exe', + [IdeType.WEBSTORM]: 'C:\\Program Files\\JetBrains\\WebStorm\\bin\\webstorm64.exe', + [IdeType.PYCHARM]: 'C:\\Program Files\\JetBrains\\PyCharm\\bin\\pycharm64.exe', + [IdeType.GOLAND]: 'C:\\Program Files\\JetBrains\\GoLand\\bin\\goland64.exe' + }; + idePath = windowsPaths[ideType]; + } else { + // Linux路径映射 + const linuxPaths: { [key in IdeType]: string } = { + [IdeType.IDEA]: 'idea', + [IdeType.WEBSTORM]: 'webstorm', + [IdeType.PYCHARM]: 'pycharm', + [IdeType.GOLAND]: 'goland' + }; + idePath = linuxPaths[ideType]; + } + } + + return idePath; +} + +// 全局缓存项目类型和IDE类型 +let cachedProjectType: ProjectType = ProjectType.UNKNOWN; +let cachedIdeType: IdeType = IdeType.IDEA; +let isProjectTypeDetected = false; + +// 检测并缓存项目类型 +function detectAndCacheProjectType(): void { + if (isProjectTypeDetected) { + return; + } + + const workspaceFolders = vscode.workspace.workspaceFolders; + if (workspaceFolders && workspaceFolders.length > 0) { + cachedProjectType = detectProjectType(workspaceFolders[0].uri.fsPath); + cachedIdeType = selectIdeForProject(cachedProjectType); + console.log(`Project type detected: ${cachedProjectType}, using IDE: ${cachedIdeType}`); + } + isProjectTypeDetected = true; +} - console.log('Switch2IDEA is now active!'); +export function activate(context: vscode.ExtensionContext) { + console.log('Switch2JETBRAIN is now active!'); + + // 在激活时检测项目类型 + detectAndCacheProjectType(); - let openFileDisposable = vscode.commands.registerCommand('Switch2IDEA.openFileInIDEA', async (uri?: vscode.Uri) => { + let openFileDisposable = vscode.commands.registerCommand('Switch2JETBRAIN.openFileInJETBRAIN', async (uri?: vscode.Uri) => { let filePath: string; let line = 1; let column = 1; @@ -84,40 +261,33 @@ export function activate(context: vscode.ExtensionContext) { column = editor.selection.active.character; } - const config = vscode.workspace.getConfiguration('switch2idea'); - let ideaPath = config.get('ideaPath'); + // 使用缓存的项目类型和IDE类型 + const projectType = cachedProjectType; + const ideType = cachedIdeType; - if (!ideaPath) { - if (os.platform() === 'darwin') { - ideaPath = getMacIdeaPath(); - } else if (os.platform() === 'win32') { - ideaPath = 'C:\\Program Files\\JetBrains\\IntelliJ IDEA\\bin\\idea64.exe'; - } else { - ideaPath = 'idea'; - } - } + const config = vscode.workspace.getConfiguration('switch2jetbrain'); + const idePath = getIdePath(ideType, config); let command: string; if (os.platform() === 'darwin') { - const ideaUrl = `idea://open?file=${encodeURIComponent(filePath)}&line=${line}&column=${column}`; - // If IDEA is already open, using the 'idea' command will show two IDEA icons in the dock temporarily - // Using the 'open' command instead will prevent this issue - command = `open -a "${ideaPath}" "${ideaUrl}"`; + const ideUrl = `idea://open?file=${encodeURIComponent(filePath)}&line=${line}&column=${column}`; + command = `open -a "${idePath}" "${ideUrl}"`; } else { - command = `"${ideaPath}" --line ${line} --column ${column} "${filePath}"`; + command = `"${idePath}" --line ${line} --column ${column} "${filePath}"`; } + console.log(`Detected project type: ${projectType}, using IDE: ${ideType}`); console.log('Executing command:', command); try { await executeCommand(command); } catch (error) { const err = error as Error; - vscode.window.showErrorMessage(`Failed to open IDEA: ${err.message}`); + vscode.window.showErrorMessage(`Failed to open ${ideType}: ${err.message}`); } }); - let openProjectDisposable = vscode.commands.registerCommand('Switch2IDEA.openProjectInIDEA', async () => { + let openProjectDisposable = vscode.commands.registerCommand('Switch2JETBRAIN.openProjectInJETBRAIN', async () => { const workspaceFolders = vscode.workspace.workspaceFolders; if (!workspaceFolders || workspaceFolders.length === 0) { vscode.window.showErrorMessage('No workspace folder is opened!'); @@ -126,40 +296,42 @@ export function activate(context: vscode.ExtensionContext) { const projectPath = workspaceFolders[0].uri.fsPath; - const config = vscode.workspace.getConfiguration('switch2idea'); - let ideaPath = config.get('ideaPath'); + // 使用缓存的项目类型和IDE类型 + const projectType = cachedProjectType; + const ideType = cachedIdeType; - if (!ideaPath) { - if (os.platform() === 'darwin') { - const macIdeaPath = getMacIdeaPath(); - ideaPath = macIdeaPath || 'IntelliJ IDEA'; - } else if (os.platform() === 'win32') { - ideaPath = 'C:\\Program Files\\JetBrains\\IntelliJ IDEA\\bin\\idea64.exe'; - } else { - ideaPath = 'idea'; - } - } + const config = vscode.workspace.getConfiguration('switch2jetbrain'); + const idePath = getIdePath(ideType, config); let command: string; if (os.platform() === 'darwin') { - const ideaUrl = `idea://open?file=${encodeURIComponent(projectPath)}`; - command = `open -a "${ideaPath}" "${ideaUrl}"`; + const ideUrl = `idea://open?file=${encodeURIComponent(projectPath)}`; + command = `open -a "${idePath}" "${ideUrl}"`; } else { - command = `"${ideaPath}" "${projectPath}"`; + command = `"${idePath}" "${projectPath}"`; } + console.log(`Detected project type: ${projectType}, using IDE: ${ideType}`); console.log('Executing command:', command); try { await executeCommand(command); } catch (error) { const err = error as Error; - vscode.window.showErrorMessage(`Failed to open project in IDEA: ${err.message}`); + vscode.window.showErrorMessage(`Failed to open project in ${ideType}: ${err.message}`); } }); + // 监听工作区变化,重新检测项目类型 + const workspaceChangeDisposable = vscode.workspace.onDidChangeWorkspaceFolders(() => { + console.log('Workspace changed, re-detecting project type...'); + isProjectTypeDetected = false; + detectAndCacheProjectType(); + }); + context.subscriptions.push(openFileDisposable); context.subscriptions.push(openProjectDisposable); + context.subscriptions.push(workspaceChangeDisposable); } -export function deactivate() {} +export function deactivate() {} \ No newline at end of file diff --git a/src/test/extension.test.ts b/src/test/extension.test.ts index 9e7999e..95484ca 100644 --- a/src/test/extension.test.ts +++ b/src/test/extension.test.ts @@ -4,11 +4,11 @@ import * as os from 'os'; import * as path from 'path'; import * as fs from 'fs'; -suite('Switch2IDEA Extension Test Suite', () => { +suite('Switch2JETBRAIN Extension Test Suite', () => { // 在所有测试开始前激活扩展 suiteSetup(async () => { // 等待扩展激活 - const extension = vscode.extensions.getExtension('qczone.switch2idea'); + const extension = vscode.extensions.getExtension('qczone.switch2jetbrain'); if (extension) { if (!extension.isActive) { await extension.activate(); @@ -18,9 +18,9 @@ suite('Switch2IDEA Extension Test Suite', () => { test('Extension should be present', async () => { // 获取扩展并等待激活 - const extension = vscode.extensions.getExtension('qczone.switch2idea'); + const extension = vscode.extensions.getExtension('qczone.switch2jetbrain'); assert.ok(extension, 'Extension should be installed'); - + if (!extension.isActive) { await extension.activate(); } @@ -30,15 +30,18 @@ suite('Switch2IDEA Extension Test Suite', () => { test('Should register open in IDEA command', () => { const commands = vscode.commands.getCommands(true); return commands.then((cmds) => { - assert.ok(cmds.includes('Switch2IDEA.openInIDEA')); + assert.ok(cmds.includes('Switch2JETBRAIN.openFileInJETBRAIN')); }); }); test('Should have correct configuration', () => { - const config = vscode.workspace.getConfiguration('switch2idea'); + const config = vscode.workspace.getConfiguration('switch2jetbrain'); assert.ok(config.has('ideaPath')); - assert.ok(config.has('keyboardShortcut')); - assert.strictEqual(config.get('keyboardShortcut'), 'alt+shift+o'); + assert.ok(config.has('autoDetectProjectType')); + assert.ok(config.has('webstormPath')); + assert.ok(config.has('pycharmPath')); + assert.ok(config.has('golandPath')); + assert.strictEqual(config.get('autoDetectProjectType'), true); }); test('Should handle file path with spaces and special characters', async () => { @@ -46,17 +49,15 @@ suite('Switch2IDEA Extension Test Suite', () => { const tmpDir = os.tmpdir(); const testFileName = 'test file with spaces!.txt'; const testFilePath = path.join(tmpDir, testFileName); - + try { // Create test file fs.writeFileSync(testFilePath, 'test content'); // Open file const doc = await vscode.workspace.openTextDocument(testFilePath); - const editor = await vscode.window.showTextDocument(doc); - // Execute command - await vscode.commands.executeCommand('Switch2IDEA.openInIDEA'); + await vscode.commands.executeCommand('Switch2JETBRAIN.openFileInJETBRAIN'); // Verify command execution completed without errors // Note: We cannot verify if IDEA actually opened the file as it's an external process @@ -75,7 +76,7 @@ suite('Switch2IDEA Extension Test Suite', () => { // Create a temporary file const tmpDir = os.tmpdir(); const testFilePath = path.join(tmpDir, 'test.txt'); - + try { // Create multi-line test file const content = 'line1\nline2\nline3\nline4\n'; @@ -84,13 +85,13 @@ suite('Switch2IDEA Extension Test Suite', () => { // Open file and set cursor position const doc = await vscode.workspace.openTextDocument(testFilePath); const editor = await vscode.window.showTextDocument(doc); - + // Move cursor to line 3, column 2 const position = new vscode.Position(2, 1); editor.selection = new vscode.Selection(position, position); // Execute command - await vscode.commands.executeCommand('Switch2IDEA.openInIDEA'); + await vscode.commands.executeCommand('Switch2JETBRAIN.openFileInJETBRAIN'); // Verify command execution completed without errors assert.ok(true); @@ -106,15 +107,15 @@ suite('Switch2IDEA Extension Test Suite', () => { test('Should handle non-existent ideaPath gracefully', async () => { // Temporarily set a non-existent ideaPath - const config = vscode.workspace.getConfiguration('switch2idea'); + const config = vscode.workspace.getConfiguration('switch2jetbrain'); const originalPath = config.get('ideaPath'); - + try { await config.update('ideaPath', 'non-existent-path', vscode.ConfigurationTarget.Global); - + // Execute command - await vscode.commands.executeCommand('Switch2IDEA.openInIDEA'); - + await vscode.commands.executeCommand('Switch2JETBRAIN.openFileInJETBRAIN'); + // Command should complete without crashing assert.ok(true); } finally { @@ -122,4 +123,58 @@ suite('Switch2IDEA Extension Test Suite', () => { await config.update('ideaPath', originalPath, vscode.ConfigurationTarget.Global); } }); + + test('Should detect Java project type', async () => { + // Create a temporary directory with Java project structure + const tmpDir = os.tmpdir(); + const testProjectPath = path.join(tmpDir, 'java-test-project'); + + try { + // Create Java project structure + fs.mkdirSync(testProjectPath, { recursive: true }); + fs.mkdirSync(path.join(testProjectPath, 'src', 'main', 'java'), { recursive: true }); + fs.writeFileSync(path.join(testProjectPath, 'pom.xml'), ''); + + // Test that the extension can handle Java projects + await vscode.commands.executeCommand('Switch2JETBRAIN.openProjectInJETBRAIN'); + assert.ok(true); + } finally { + // Cleanup + try { + fs.rmSync(testProjectPath, { recursive: true, force: true }); + } catch (e) { + console.error('Failed to cleanup test project:', e); + } + } + }); + + test('Should detect frontend project type', async () => { + // Create a temporary directory with frontend project structure + const tmpDir = os.tmpdir(); + const testProjectPath = path.join(tmpDir, 'frontend-test-project'); + + try { + // Create frontend project structure + fs.mkdirSync(testProjectPath, { recursive: true }); + const packageJson = { + name: 'test-frontend', + dependencies: { + 'react': '^18.0.0', + 'webpack': '^5.0.0' + } + }; + fs.writeFileSync(path.join(testProjectPath, 'package.json'), JSON.stringify(packageJson, null, 2)); + + // Test that the extension can handle frontend projects + await vscode.commands.executeCommand('Switch2JETBRAIN.openProjectInJETBRAIN'); + assert.ok(true); + } finally { + // Cleanup + try { + fs.rmSync(testProjectPath, { recursive: true, force: true }); + } catch (e) { + console.error('Failed to cleanup test project:', e); + } + } + }); });