From 6002ac14181467f8614cf68511fb136a61e20fd0 Mon Sep 17 00:00:00 2001 From: MangoFanFanw Date: Sun, 29 Mar 2026 00:26:49 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E5=90=AF=E5=8A=A8=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E5=8A=9F=E8=83=BD=E3=80=81=E6=8E=92=E6=9F=A5=E4=B8=80?= =?UTF-8?q?=E4=BA=9B=E7=81=B5=E5=BC=82=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/code-launchpad/ide-projects.ts | 48 ++++++++++- src/main/code-launchpad/ide-versions-check.ts | 39 ++++----- src/main/index.ts | 5 +- src/my-type/ide-icons.ts | 15 ++-- src/my-type/settings.d.ts | 10 ++- src/preload/index.d.ts | 1 + src/preload/index.ts | 4 +- src/renderer/components.d.ts | 1 + src/renderer/src/CodeLaunchpadApp.vue | 26 +++--- .../CodeLaunchpadButton.vue | 10 +++ .../components-code-launchpad/ProjectCard.vue | 85 +++++++++++++++++-- .../src/components/DetectedIDECard.vue | 6 +- .../src/components/DetectedIDECardList.vue | 4 +- .../src/pages-code-launchpad/Projects.vue | 29 +++++-- src/renderer/src/pages/CodeLaunchpadPage.vue | 6 +- .../src/pages/CodeLaunchpadPageIDEs.vue | 2 +- .../src/pages/CodeLaunchpadPageView.vue | 9 -- 17 files changed, 222 insertions(+), 78 deletions(-) diff --git a/src/main/code-launchpad/ide-projects.ts b/src/main/code-launchpad/ide-projects.ts index 94fc3ed..3d816dc 100644 --- a/src/main/code-launchpad/ide-projects.ts +++ b/src/main/code-launchpad/ide-projects.ts @@ -6,7 +6,13 @@ import { loadJsonFile } from 'load-json-file' import { XMLParser } from 'fast-xml-parser' import { VSCodeGlobalStorageJson } from '@my-type/vscode-globalstorage-json' import { JetBrainsIdeOptionsRecentProjects } from '@my-type/jetbrains-ide-options-recentProjects' -import { JetBrainsIDEDisplayNameEnum, JetBrainsProductCode, toProductCode } from '@my-type/jetbrains-state-tools' +import { + JetBrainsIDEDisplayNameEnum, + JetBrainsProductCode, + toProductCode +} from '@my-type/jetbrains-state-tools' +import { checkIDEsResultDto, IDECode } from '@my-type/settings' +import { spawn } from 'node:child_process' const xmlParser = new XMLParser({ ignoreAttributes: false }) @@ -24,6 +30,7 @@ const JETBRAINS_IDES_DATA_PATH = path.join(os.homedir(), 'AppData/Roaming/JetBra * 从 VSCode 的 GlobalStorage 中读取所有打开过的工作区,整理后返回。 */ export async function getVscodeProjects(): Promise { + console.log('查找 VSCode 项目中') const result: IdeProjectsDto = [] const data: VSCodeGlobalStorageJson = await loadJsonFile(VSCODE_GLOBALSTORAGE_PATH) for (const workspace of Object.entries(data.profileAssociations.workspaces)) { @@ -42,6 +49,7 @@ export async function getVscodeProjects(): Promise { } export async function getJetBrainsProjects(): Promise { + console.log('查找 JetBrains IDEs 项目中') const result: IdeProjectsDto = [] // 意外的是,JetBrains Toolbox 并不会自己保存 JetBrains IDEs 打开过的项目的历史记录,哪怕是在 Toolbox 中打开的。 // 据 AI 总结,工具箱的项目列表系读取已安装的所有 JetBrains IDE 的项目历史,并综合列出的。 @@ -109,3 +117,41 @@ export async function getProjects(): Promise { const result: IdeProjectsDto = [] return result } + +/** + * 使用指定 IDE 打开指定项目 + * @param ide IDE 代码 + * @param path 项目路径 + */ +export function openProject(ide: IDECode, path: string): boolean { + if (global.installedIDEs === null) return false + // 考虑到安全性问题,这里限制 IDE 代码,只有提供合法的 IDE 代码才能执行命令打开项目。 + for (const ideInfo of Object.values(global.installedIDEs as checkIDEsResultDto)) { + if (ideInfo !== null) { + if (ide === ideInfo.code) { + try { + const params: string[] = [] + // 如果是使用 VSCode 打开远程项目(WSL) + if (ide === 'VSC' && path.startsWith('vscode-remote://')) { + // 拼接正确命令 + params.push('--folder-uri', path) + } + // TODO 处理更多边界情况 + else { + params.push(path) + } + // 避免阻塞当前进程 + console.log(`打开项目:尝试执行:${ideInfo.command} ${params.join(' ')}`) + spawn(ideInfo.command, params, { detached: true, stdio: 'ignore', shell: true }) + return true + } catch (error) { + console.error(`使用 IDE ${ide} 打开 ${path} 时出现错误。`) + console.error(error) + return false + } + } + } + } + console.log(`打开项目:提供的 IDE 代号不合法:${ide} ${path}`) + return false +} diff --git a/src/main/code-launchpad/ide-versions-check.ts b/src/main/code-launchpad/ide-versions-check.ts index afa4ea1..51a76df 100644 --- a/src/main/code-launchpad/ide-versions-check.ts +++ b/src/main/code-launchpad/ide-versions-check.ts @@ -2,7 +2,8 @@ import type { checkIDEResultDto, checkIDEsResultDto, checkIDEsVersionDto, - checkIDEVersionDto + checkIDEVersionDto, + IDECode } from '@my-type/settings' import { execSync } from 'node:child_process' import { BrowserWindow, screen, shell, Tray } from 'electron' @@ -31,11 +32,7 @@ const JETBRAINS_TOOLBOX_STATE_JSON_PATH = path.join( * @param command IDE 的命令行别名,例如 `code`。 * @param code (JetBrains IDE)的产品代号;对于其他 IDE 为空字符串 */ -function checkIDE( - display: string, - command: string, - code: JetBrainsProductCode | '' = '' -): checkIDEResultDto | null { +function checkIDE(display: string, command: string, code: IDECode): checkIDEResultDto | null { try { const paths = execSync(`where.exe ${command}`).toString().split('\n').slice(0, -1) return { code, display: display, command: command, paths: paths } @@ -45,7 +42,7 @@ function checkIDE( } /** - * 检查 JerBrains IDEs 是否安装可用。 + * 检查 JetBrains IDEs 是否安装可用。 */ async function checkJetBrainsIDEs(): Promise { // 构建数据结构的辅助函数 @@ -58,11 +55,11 @@ async function checkJetBrainsIDEs(): Promise { } } const result: checkIDEsResultDto = { - pycharm: _('pycharm', 'PY'), - clion: _('clion', 'CL'), - webstorm: _('webstorm', 'WS'), - phpstorm: _('phpstorm', 'PS'), - idea: _('idea', 'IU') + PY: _('pycharm', 'PY'), + CL: _('clion', 'CL'), + WS: _('webstorm', 'WS'), + PS: _('phpstorm', 'PS'), + IU: _('idea', 'IU') } // 优先从 JBTState.json 查找 if (settingsManager._settings?.codeLaunchpadIDESearchPolicy.includes('JBTState.json')) { @@ -115,7 +112,7 @@ export async function getIDEs(): Promise { export async function checkIDEs(): Promise { console.log('在系统中查找已安装的 IDE ...') const vscodeIDEs = { - vscode: checkIDE('Visual Studio Code', 'code') + VSC: checkIDE('Visual Studio Code', 'code', 'VSC') } global.installedIDEs = { ...vscodeIDEs, ...(await checkJetBrainsIDEs()) } return global.installedIDEs @@ -135,7 +132,7 @@ async function checkVSCodeVersion(): Promise { console.error('获取 VSCode 版本列表时出现错误。错误提供如下。') console.error(error) } - return { code: '', install, latest, display: 'Visual Studio Code' } + return { code: 'VSC', install, latest, display: 'Visual Studio Code' } } /** @@ -152,11 +149,11 @@ export async function checkJetBrainsIDEsVersion(): Promise } } const result: checkIDEsVersionDto = { - pycharm: _('pycharm', 'PY'), - clion: _('clion', 'CL'), - webstorm: _('webstorm', 'WS'), - phpstorm: _('phpstorm', 'PS'), - idea: _('idea', 'IU') + PY: _('pycharm', 'PY'), + CL: _('clion', 'CL'), + WS: _('webstorm', 'WS'), + PS: _('phpstorm', 'PS'), + IU: _('idea', 'IU') } // 尝试从 JBTState.json 获取已安装的 JetBrains IDEs 的版本 @@ -227,8 +224,8 @@ export async function checkIDEsVersion(): Promise { let result: checkIDEsVersionDto = {} for (const ide in await getIDEs()) { switch (ide) { - case 'vscode': - result['vscode'] = await checkVSCodeVersion() + case 'VSC': + result['VSC'] = await checkVSCodeVersion() break } } diff --git a/src/main/index.ts b/src/main/index.ts index 34c8c68..10a66c1 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -11,7 +11,7 @@ import { } from './code-launchpad/ide-versions-check' import { fanToolsIcon } from './resources' import path from 'path' -import { getJetBrainsProjects, getVscodeProjects } from './code-launchpad/ide-projects' +import { getJetBrainsProjects, getVscodeProjects, openProject } from './code-launchpad/ide-projects' let mainWindow: BrowserWindow | null = null // @ts-ignore 保存引用,禁用报错 @@ -131,6 +131,9 @@ app.whenReady().then(async () => { ipcMain.handle('codeLaunchpad:checkIDEsVersion', checkIDEsVersion) ipcMain.handle('codeLaunchpad:getVSCodeProjects', getVscodeProjects) ipcMain.handle('codeLaunchpad:getJetBrainsProjects', getJetBrainsProjects) + ipcMain.handle('codeLaunchpad:openProject', (_, ide: string, path: string) => { + return openProject(ide, path) + }) await checkIDEs() await checkIDEsVersion() diff --git a/src/my-type/ide-icons.ts b/src/my-type/ide-icons.ts index 73448fa..357e910 100644 --- a/src/my-type/ide-icons.ts +++ b/src/my-type/ide-icons.ts @@ -12,6 +12,7 @@ import PyCharmIcon from '@renderer/assets/PyCharm_icon.svg?component' import WebStormIcon from '@renderer/assets/WebStorm_icon.svg?component' import { FunctionalComponent } from 'vue' +import { IDECode } from '@my-type/settings' function _( icon: FunctionalComponent, @@ -20,11 +21,11 @@ function _( return { icon, description } } -export const ideIcons = { - vscode: _(VSCodeIcon, '全能的代码编辑器'), - clion: _(CLionIcon, '强大的 C 和 C++ IDE'), - idea: _(IDEAIcon, '强大的 Java IDE'), - phpstorm: _(PhpStormIcon, '强大的 PHP IDE'), - pycharm: _(PyCharmIcon, '强大的 Python IDE'), - webstorm: _(WebStormIcon, '强大的 Web IDE') +export const ideIcons: Record = { + VSC: _(VSCodeIcon, '全能的代码编辑器'), + CL: _(CLionIcon, '强大的 C 和 C++ IDE'), + IU: _(IDEAIcon, '强大的 Java IDE'), + PS: _(PhpStormIcon, '强大的 PHP IDE'), + PY: _(PyCharmIcon, '强大的 Python IDE'), + WS: _(WebStormIcon, '强大的 Web IDE') } diff --git a/src/my-type/settings.d.ts b/src/my-type/settings.d.ts index 4f25261..b21ea60 100644 --- a/src/my-type/settings.d.ts +++ b/src/my-type/settings.d.ts @@ -18,22 +18,24 @@ export interface settingsDto { codeLaunchpadIDESearchPolicy: ideSearchPolicy[] } +export type IDECode = JetBrainsProductCode | 'VSC' + export interface checkIDEResultDto { // 仅针对 JetBrains 系列 IDEs 的产品代码,对于其他 IDE 统一为空字符串 - code: JetBrainsProductCode | '' + code: IDECode display: string command: string paths: string[] } -export type checkIDEsResultDto = Record +export type checkIDEsResultDto = Partial> export interface checkIDEVersionDto { // 仅针对 JetBrains 系列 IDEs 的产品代码,对于其他 IDE 统一为空字符串 - code: JetBrainsProductCode | '' + code: IDECode display: string install: string latest: string } -export type checkIDEsVersionDto = Record +export type checkIDEsVersionDto = Partial> diff --git a/src/preload/index.d.ts b/src/preload/index.d.ts index d4c0812..6426f3c 100644 --- a/src/preload/index.d.ts +++ b/src/preload/index.d.ts @@ -21,6 +21,7 @@ declare global { _checkIDEsVersion: () => Promise _getVSCodeProjects: () => Promise _getJetBrainsProjects: () => Promise + _openProject: (ide: string, path: string) => Promise } } } diff --git a/src/preload/index.ts b/src/preload/index.ts index da27fdc..14b1add 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -17,7 +17,9 @@ const codeLaunchpadApi = { _getIDEsVersion: () => ipcRenderer.invoke('codeLaunchpad:getIDEsVersion'), _checkIDEsVersion: () => ipcRenderer.invoke('codeLaunchpad:checkIDEsVersion'), _getVSCodeProjects: () => ipcRenderer.invoke('codeLaunchpad:getVSCodeProjects'), - _getJetBrainsProjects: () => ipcRenderer.invoke('codeLaunchpad:getJetBrainsProjects') + _getJetBrainsProjects: () => ipcRenderer.invoke('codeLaunchpad:getJetBrainsProjects'), + _openProject: (ide: string, path: string) => + ipcRenderer.invoke('codeLaunchpad:openProject', ide, path) } // Use `contextBridge` APIs to expose Electron APIs to diff --git a/src/renderer/components.d.ts b/src/renderer/components.d.ts index ac454ba..4bbf246 100644 --- a/src/renderer/components.d.ts +++ b/src/renderer/components.d.ts @@ -22,6 +22,7 @@ declare module 'vue' { NCard: typeof import('naive-ui')['NCard'] NCode: typeof import('naive-ui')['NCode'] NConfigProvider: typeof import('naive-ui')['NConfigProvider'] + NDropdown: typeof import('naive-ui')['NDropdown'] NEllipsis: typeof import('naive-ui')['NEllipsis'] NEmpty: typeof import('naive-ui')['NEmpty'] NFlex: typeof import('naive-ui')['NFlex'] diff --git a/src/renderer/src/CodeLaunchpadApp.vue b/src/renderer/src/CodeLaunchpadApp.vue index 69b88c9..4c64e75 100644 --- a/src/renderer/src/CodeLaunchpadApp.vue +++ b/src/renderer/src/CodeLaunchpadApp.vue @@ -23,19 +23,21 @@ function handleUpdateValue(key: string): void {