Compare commits
5 Commits
d726f9f781
...
b9d6f8b049
| Author | SHA1 | Date | |
|---|---|---|---|
| b9d6f8b049 | |||
| 7a7e58b3ee | |||
| e568a2dfaa | |||
| c714f554ac | |||
| 1bf08a3698 |
1
.idea/dictionaries/project.xml
generated
1
.idea/dictionaries/project.xml
generated
@@ -1,6 +1,7 @@
|
|||||||
<component name="ProjectDictionaryState">
|
<component name="ProjectDictionaryState">
|
||||||
<dictionary name="project">
|
<dictionary name="project">
|
||||||
<words>
|
<words>
|
||||||
|
<w>globalstorage</w>
|
||||||
<w>scrollarea</w>
|
<w>scrollarea</w>
|
||||||
</words>
|
</words>
|
||||||
</dictionary>
|
</dictionary>
|
||||||
|
|||||||
6
.idea/jsLinters/eslint.xml
generated
Normal file
6
.idea/jsLinters/eslint.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="EslintConfiguration">
|
||||||
|
<option name="fix-on-save" value="true" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
63
package-lock.json
generated
63
package-lock.json
generated
@@ -12,6 +12,7 @@
|
|||||||
"@electron-toolkit/preload": "^3.0.2",
|
"@electron-toolkit/preload": "^3.0.2",
|
||||||
"@electron-toolkit/utils": "^4.0.0",
|
"@electron-toolkit/utils": "^4.0.0",
|
||||||
"electron-updater": "^6.3.9",
|
"electron-updater": "^6.3.9",
|
||||||
|
"fast-xml-parser": "^5.5.9",
|
||||||
"highlight.js": "^11.11.1",
|
"highlight.js": "^11.11.1",
|
||||||
"load-json-file": "^7.0.1",
|
"load-json-file": "^7.0.1",
|
||||||
"make-dir": "^5.1.0",
|
"make-dir": "^5.1.0",
|
||||||
@@ -5708,6 +5709,41 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/fast-xml-builder": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmmirror.com/fast-xml-builder/-/fast-xml-builder-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/NaturalIntelligence"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"path-expression-matcher": "^1.1.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fast-xml-parser": {
|
||||||
|
"version": "5.5.9",
|
||||||
|
"resolved": "https://registry.npmmirror.com/fast-xml-parser/-/fast-xml-parser-5.5.9.tgz",
|
||||||
|
"integrity": "sha512-jldvxr1MC6rtiZKgrFnDSvT8xuH+eJqxqOBThUVjYrxssYTo1avZLGql5l0a0BAERR01CadYzZ83kVEkbyDg+g==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/NaturalIntelligence"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"fast-xml-builder": "^1.1.4",
|
||||||
|
"path-expression-matcher": "^1.2.0",
|
||||||
|
"strnum": "^2.2.2"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"fxparser": "src/cli/cli.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/fd-slicer": {
|
"node_modules/fd-slicer": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmmirror.com/fd-slicer/-/fd-slicer-1.1.0.tgz",
|
"resolved": "https://registry.npmmirror.com/fd-slicer/-/fd-slicer-1.1.0.tgz",
|
||||||
@@ -7597,6 +7633,21 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/path-expression-matcher": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/path-expression-matcher/-/path-expression-matcher-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-DwmPWeFn+tq7TiyJ2CxezCAirXjFxvaiD03npak3cRjlP9+OjTmSy1EpIrEbh+l6JgUundniloMLDQ/6VTdhLQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/NaturalIntelligence"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/path-is-absolute": {
|
"node_modules/path-is-absolute": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
"resolved": "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||||
@@ -8923,6 +8974,18 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/strnum": {
|
||||||
|
"version": "2.2.2",
|
||||||
|
"resolved": "https://registry.npmmirror.com/strnum/-/strnum-2.2.2.tgz",
|
||||||
|
"integrity": "sha512-DnR90I+jtXNSTXWdwrEy9FakW7UX+qUZg28gj5fk2vxxl7uS/3bpI4fjFYVmdK9etptYBPNkpahuQnEwhwECqA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/NaturalIntelligence"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/sumchecker": {
|
"node_modules/sumchecker": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmmirror.com/sumchecker/-/sumchecker-3.0.1.tgz",
|
"resolved": "https://registry.npmmirror.com/sumchecker/-/sumchecker-3.0.1.tgz",
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
"@electron-toolkit/preload": "^3.0.2",
|
"@electron-toolkit/preload": "^3.0.2",
|
||||||
"@electron-toolkit/utils": "^4.0.0",
|
"@electron-toolkit/utils": "^4.0.0",
|
||||||
"electron-updater": "^6.3.9",
|
"electron-updater": "^6.3.9",
|
||||||
|
"fast-xml-parser": "^5.5.9",
|
||||||
"highlight.js": "^11.11.1",
|
"highlight.js": "^11.11.1",
|
||||||
"load-json-file": "^7.0.1",
|
"load-json-file": "^7.0.1",
|
||||||
"make-dir": "^5.1.0",
|
"make-dir": "^5.1.0",
|
||||||
|
|||||||
111
src/main/code-launchpad/ide-projects.ts
Normal file
111
src/main/code-launchpad/ide-projects.ts
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
import path from 'path'
|
||||||
|
import fs from 'fs/promises'
|
||||||
|
import os from 'os'
|
||||||
|
import type { IdeProjectsDto } from '@my-type/ide-projects'
|
||||||
|
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'
|
||||||
|
|
||||||
|
const xmlParser = new XMLParser({ ignoreAttributes: false })
|
||||||
|
|
||||||
|
// VSCode 用来保存打开过的工作区的文件路径
|
||||||
|
const VSCODE_GLOBALSTORAGE_PATH = path.join(
|
||||||
|
os.homedir(),
|
||||||
|
'AppData/Roaming/Code/User/globalStorage/storage.json'
|
||||||
|
)
|
||||||
|
|
||||||
|
// JetBrains IDEs 的默认数据保存目录
|
||||||
|
// 每个 IDE 的每个版本都在该目录中拥有一个子目录
|
||||||
|
const JETBRAINS_IDES_DATA_PATH = path.join(os.homedir(), 'AppData/Roaming/JetBrains')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从 VSCode 的 GlobalStorage 中读取所有打开过的工作区,整理后返回。
|
||||||
|
*/
|
||||||
|
export async function getVscodeProjects(): Promise<IdeProjectsDto> {
|
||||||
|
const result: IdeProjectsDto = []
|
||||||
|
const data: VSCodeGlobalStorageJson = await loadJsonFile(VSCODE_GLOBALSTORAGE_PATH)
|
||||||
|
for (const workspace of Object.entries(data.profileAssociations.workspaces)) {
|
||||||
|
// VSCode 存储的工作区的一个示例:
|
||||||
|
// "vscode-remote://wsl%2Bubuntu-24.04/home/mango/pythonTest123": "__default__profile__"
|
||||||
|
// 目前不清楚值的具体含义,但显然值对我们没有帮助。
|
||||||
|
// 所以,将 path (项目路径)设置为键,然后取路径的最后一层目录为名称,构建数据并返回。
|
||||||
|
|
||||||
|
// JetBrains IDEs 的终端调用不支持 file:/// 命令,因此在此将协议名 file:/// 去除,方便用 JetBrains IDEs 打开它们。
|
||||||
|
// 还有一种协议名是 vscode-remote:// 将会保留,以作为 VSCode Remote 的标识
|
||||||
|
const path = decodeURIComponent(workspace[0]).replace('file:///', '')
|
||||||
|
const name = <string>path.split('/').at(-1)
|
||||||
|
result.push({ name, path, ide: ['VSC'] })
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getJetBrainsProjects(): Promise<IdeProjectsDto> {
|
||||||
|
const result: IdeProjectsDto = []
|
||||||
|
// 意外的是,JetBrains Toolbox 并不会自己保存 JetBrains IDEs 打开过的项目的历史记录,哪怕是在 Toolbox 中打开的。
|
||||||
|
// 据 AI 总结,工具箱的项目列表系读取已安装的所有 JetBrains IDE 的项目历史,并综合列出的。
|
||||||
|
// 所以,我们也要这么做。
|
||||||
|
const items = await fs.readdir(JETBRAINS_IDES_DATA_PATH, { withFileTypes: true })
|
||||||
|
const subDirs: string[] = []
|
||||||
|
// 只要目录,不要文件
|
||||||
|
for (const item of items) {
|
||||||
|
if (item.isDirectory()) {
|
||||||
|
subDirs.push(item.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建工具函数
|
||||||
|
const _ = (subDir: string): JetBrainsProductCode | null => {
|
||||||
|
// 获取枚举成员的变量名称
|
||||||
|
for (const ide in Object.keys(JetBrainsIDEDisplayNameEnum)) {
|
||||||
|
if (subDir.toLowerCase().includes(ide)) {
|
||||||
|
// 查找与之对应的产品代码并返回
|
||||||
|
// 由于已经做过判定,所以可得返回结果非空
|
||||||
|
return <JetBrainsProductCode>toProductCode(ide)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const subDir of subDirs) {
|
||||||
|
// 如果目录不受支持,直接排除
|
||||||
|
// 不受支持的表现之一就是目录名称中不包含工具箱支持的 IDE 的名称
|
||||||
|
const ide = _(subDir)
|
||||||
|
if (ide === null) continue
|
||||||
|
// 从目录中尝试读取 options/recentProjects.xml
|
||||||
|
const rpp = path.join(JETBRAINS_IDES_DATA_PATH, subDir, 'options/recentProjects.xml')
|
||||||
|
try {
|
||||||
|
// 从 xml 中解析数据
|
||||||
|
const data: JetBrainsIdeOptionsRecentProjects = xmlParser.parse(
|
||||||
|
await fs.readFile(rpp, 'utf-8')
|
||||||
|
)
|
||||||
|
for (const datum of data.application.component.option) {
|
||||||
|
for (const entry of datum.map.entry) {
|
||||||
|
const name = <string>entry.value.RecentProjectMetaInfo['@_frameTitle'].split(' – ').at(0)
|
||||||
|
const path = entry['@_key'].replace('$USER_HOME$', os.homedir())
|
||||||
|
// 认为包含此(安装/设置?)目录的是未保存的编辑,例如 light-edit 模式
|
||||||
|
// 正常来说不会在这样的目录下保存项目的……吧?而且俺寻思 IDE 用这种变量的话也不像是人为刻意保存到此目录。
|
||||||
|
if (path.includes('$APPLICATION_CONFIG_DIR$/')) continue
|
||||||
|
result.push({
|
||||||
|
name,
|
||||||
|
path,
|
||||||
|
ide: [ide]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// 忽略
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结合 {@link getVscodeProjects} 和 {@link getJetBrainsProjects} 的返回结果,
|
||||||
|
* 剔除重复项后,获取项目列表。
|
||||||
|
*/
|
||||||
|
export async function getProjects(): Promise<IdeProjectsDto> {
|
||||||
|
const result: IdeProjectsDto = []
|
||||||
|
return result
|
||||||
|
}
|
||||||
@@ -15,8 +15,8 @@ import {
|
|||||||
JetBrainsProductCode,
|
JetBrainsProductCode,
|
||||||
JetBrainsStateDto
|
JetBrainsStateDto
|
||||||
} from '@my-type/jetbrains-state-tools'
|
} from '@my-type/jetbrains-state-tools'
|
||||||
import { settingsManager } from './settings'
|
import { settingsManager } from '../settings'
|
||||||
import { codeLaunchpadIcon } from './resources'
|
import { codeLaunchpadIcon } from '../resources'
|
||||||
import { isNodeError } from '@my-type/node-error'
|
import { isNodeError } from '@my-type/node-error'
|
||||||
import { JetBrainsDataProductDto } from '@my-type/jetbrains-data-products'
|
import { JetBrainsDataProductDto } from '@my-type/jetbrains-data-products'
|
||||||
|
|
||||||
@@ -8,12 +8,17 @@ import {
|
|||||||
createCodeLaunchpadWindow,
|
createCodeLaunchpadWindow,
|
||||||
getIDEs,
|
getIDEs,
|
||||||
getIDEsVersion
|
getIDEsVersion
|
||||||
} from './code-launchpad'
|
} from './code-launchpad/ide-versions-check'
|
||||||
import { fanToolsIcon } from './resources'
|
import { fanToolsIcon } from './resources'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
|
import { getJetBrainsProjects, getVscodeProjects } from './code-launchpad/ide-projects'
|
||||||
|
|
||||||
let mainWindow: BrowserWindow | null = null
|
let mainWindow: BrowserWindow | null = null
|
||||||
|
// @ts-ignore 保存引用,禁用报错
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
let mainTray: Tray | null = null
|
let mainTray: Tray | null = null
|
||||||
|
// @ts-ignore 保存引用,禁用报错
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
let codeLaunchpadTray: Tray | null = null
|
let codeLaunchpadTray: Tray | null = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -88,7 +93,7 @@ function createTray(): Tray {
|
|||||||
// This method will be called when Electron has finished
|
// This method will be called when Electron has finished
|
||||||
// initialization and is ready to create browser windows.
|
// initialization and is ready to create browser windows.
|
||||||
// Some APIs can only be used after this event occurs.
|
// Some APIs can only be used after this event occurs.
|
||||||
app.whenReady().then(() => {
|
app.whenReady().then(async () => {
|
||||||
// Set app user model id for windows
|
// Set app user model id for windows
|
||||||
electronApp.setAppUserModelId('com.electron')
|
electronApp.setAppUserModelId('com.electron')
|
||||||
|
|
||||||
@@ -124,7 +129,9 @@ app.whenReady().then(() => {
|
|||||||
ipcMain.handle('codeLaunchpad:checkIDEs', checkIDEs)
|
ipcMain.handle('codeLaunchpad:checkIDEs', checkIDEs)
|
||||||
ipcMain.handle('codeLaunchpad:getIDEsVersion', getIDEsVersion)
|
ipcMain.handle('codeLaunchpad:getIDEsVersion', getIDEsVersion)
|
||||||
ipcMain.handle('codeLaunchpad:checkIDEsVersion', checkIDEsVersion)
|
ipcMain.handle('codeLaunchpad:checkIDEsVersion', checkIDEsVersion)
|
||||||
|
ipcMain.handle('codeLaunchpad:getVSCodeProjects', getVscodeProjects)
|
||||||
|
ipcMain.handle('codeLaunchpad:getJetBrainsProjects', getJetBrainsProjects)
|
||||||
|
|
||||||
checkIDEs()
|
await checkIDEs()
|
||||||
checkIDEsVersion()
|
await checkIDEsVersion()
|
||||||
})
|
})
|
||||||
|
|||||||
11
src/my-type/ide-projects.d.ts
vendored
Normal file
11
src/my-type/ide-projects.d.ts
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { JetBrainsProductCode } from '@my-type/jetbrains-state-tools'
|
||||||
|
|
||||||
|
type Ide = JetBrainsProductCode | 'VSC'
|
||||||
|
|
||||||
|
export interface IdeProjectDto {
|
||||||
|
name: string
|
||||||
|
path: string
|
||||||
|
ide: Ide[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export type IdeProjectsDto = IdeProjectDto[]
|
||||||
26
src/my-type/jetbrains-ide-options-recentProjects.d.ts
vendored
Normal file
26
src/my-type/jetbrains-ide-options-recentProjects.d.ts
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// 这些数据结构是由 XMLParser 解析成的 Javascript 对象,解析设置允许属性。
|
||||||
|
// 不完整,因为我也看不懂很多东西是干嘛用的,写完整了也用不到,所以把用到的定义一下就酱了
|
||||||
|
|
||||||
|
export interface RecentProjectMetaInfo {
|
||||||
|
option: []
|
||||||
|
frame: object
|
||||||
|
'@_frameTitle': string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface JetBrainsIdeOptionsRecentProjects {
|
||||||
|
application: {
|
||||||
|
component: {
|
||||||
|
option: [
|
||||||
|
{
|
||||||
|
map: {
|
||||||
|
entry: {
|
||||||
|
value: { RecentProjectMetaInfo: RecentProjectMetaInfo }
|
||||||
|
'@_key': string
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
'@_name': 'RecentProjectsManager'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,3 +25,21 @@ export enum JetBrainsIDEDisplayNameEnum {
|
|||||||
phpstorm = 'PhpStorm',
|
phpstorm = 'PhpStorm',
|
||||||
webstorm = 'WebStorm'
|
webstorm = 'WebStorm'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function toProductCode(anything: string): JetBrainsProductCode | null {
|
||||||
|
if ([JetBrainsIDEDisplayNameEnum.pycharm, 'pycharm'].includes(anything)) return 'PY'
|
||||||
|
if ([JetBrainsIDEDisplayNameEnum.idea, 'idea'].includes(anything)) return 'IU'
|
||||||
|
if ([JetBrainsIDEDisplayNameEnum.clion, 'clion'].includes(anything)) return 'CL'
|
||||||
|
if ([JetBrainsIDEDisplayNameEnum.phpstorm, 'phpstorm'].includes(anything)) return 'PS'
|
||||||
|
if ([JetBrainsIDEDisplayNameEnum.webstorm, 'webstorm'].includes(anything)) return 'WS'
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
export function toProductDisplayName(anything: string): string | null {
|
||||||
|
if (['PY', 'pycharm'].includes(anything)) return JetBrainsIDEDisplayNameEnum.pycharm
|
||||||
|
if (['IU', 'idea'].includes(anything)) return JetBrainsIDEDisplayNameEnum.idea
|
||||||
|
if (['CL', 'clion'].includes(anything)) return JetBrainsIDEDisplayNameEnum.clion
|
||||||
|
if (['PS', 'phpstorm'].includes(anything)) return JetBrainsIDEDisplayNameEnum.phpstorm
|
||||||
|
if (['WS', 'webstorm'].includes(anything)) return JetBrainsIDEDisplayNameEnum.webstorm
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|||||||
9
src/my-type/vscode-globalstorage-json.d.ts
vendored
Normal file
9
src/my-type/vscode-globalstorage-json.d.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export interface VSCodeGlobalStorageJson {
|
||||||
|
profileAssociations: {
|
||||||
|
/** 此键值对中项目越靠后,时间越新,我估计是的。<br/>
|
||||||
|
* key:远程开发链接为 `vscode-remote://`,本地文件(目录)为 `file:///`。<br/>
|
||||||
|
* value:难说到底有没有用,`__default__profile__`。
|
||||||
|
*/
|
||||||
|
workspaces: Record<string, string>
|
||||||
|
}
|
||||||
|
}
|
||||||
3
src/preload/index.d.ts
vendored
3
src/preload/index.d.ts
vendored
@@ -1,6 +1,7 @@
|
|||||||
import { ElectronAPI } from '@electron-toolkit/preload'
|
import { ElectronAPI } from '@electron-toolkit/preload'
|
||||||
import { settingsDto, checkIDEsResultDto } from '@my-type/settings'
|
import { settingsDto, checkIDEsResultDto } from '@my-type/settings'
|
||||||
import { checkIDEsVersionDto } from "../my-type/settings";
|
import { checkIDEsVersionDto } from "../my-type/settings";
|
||||||
|
import { IdeProjectsDto } from "../my-type/ide-projects";
|
||||||
|
|
||||||
// 此处只有签名
|
// 此处只有签名
|
||||||
|
|
||||||
@@ -18,6 +19,8 @@ declare global {
|
|||||||
_checkIDEs: () => Promise<checkIDEsResultDto>
|
_checkIDEs: () => Promise<checkIDEsResultDto>
|
||||||
_getIDEsVersion: () => Promise<checkIDEsVersionDto>
|
_getIDEsVersion: () => Promise<checkIDEsVersionDto>
|
||||||
_checkIDEsVersion: () => Promise<checkIDEsVersionDto>
|
_checkIDEsVersion: () => Promise<checkIDEsVersionDto>
|
||||||
|
_getVSCodeProjects: () => Promise<IdeProjectsDto>
|
||||||
|
_getJetBrainsProjects: () => Promise<IdeProjectsDto>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,9 @@ const codeLaunchpadApi = {
|
|||||||
_getIDEs: () => ipcRenderer.invoke('codeLaunchpad:getIDEs'),
|
_getIDEs: () => ipcRenderer.invoke('codeLaunchpad:getIDEs'),
|
||||||
_checkIDEs: () => ipcRenderer.invoke('codeLaunchpad:checkIDEs'),
|
_checkIDEs: () => ipcRenderer.invoke('codeLaunchpad:checkIDEs'),
|
||||||
_getIDEsVersion: () => ipcRenderer.invoke('codeLaunchpad:getIDEsVersion'),
|
_getIDEsVersion: () => ipcRenderer.invoke('codeLaunchpad:getIDEsVersion'),
|
||||||
_checkIDEsVersion: () => ipcRenderer.invoke('codeLaunchpad:checkIDEsVersion')
|
_checkIDEsVersion: () => ipcRenderer.invoke('codeLaunchpad:checkIDEsVersion'),
|
||||||
|
_getVSCodeProjects: () => ipcRenderer.invoke('codeLaunchpad:getVSCodeProjects'),
|
||||||
|
_getJetBrainsProjects: () => ipcRenderer.invoke('codeLaunchpad:getJetBrainsProjects')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use `contextBridge` APIs to expose Electron APIs to
|
// Use `contextBridge` APIs to expose Electron APIs to
|
||||||
|
|||||||
6
src/renderer/components.d.ts
vendored
6
src/renderer/components.d.ts
vendored
@@ -11,16 +11,18 @@ export {}
|
|||||||
/* prettier-ignore */
|
/* prettier-ignore */
|
||||||
declare module 'vue' {
|
declare module 'vue' {
|
||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
|
CoderBaseCard: typeof import('./src/components/CoderBaseCard.vue')['default']
|
||||||
CoderJson: typeof import('./src/components/CoderJson.vue')['default']
|
CoderJson: typeof import('./src/components/CoderJson.vue')['default']
|
||||||
|
CoderXml: typeof import('./src/components/CoderXml.vue')['default']
|
||||||
DetectedIDECard: typeof import('./src/components/DetectedIDECard.vue')['default']
|
DetectedIDECard: typeof import('./src/components/DetectedIDECard.vue')['default']
|
||||||
DetectedIDECardList: typeof import('./src/components/DetectedIDECardList.vue')['default']
|
DetectedIDECardList: typeof import('./src/components/DetectedIDECardList.vue')['default']
|
||||||
DetectedIDEVersionCard: typeof import('./src/components/DetectedIDEVersionCard.vue')['default']
|
|
||||||
DetectedIDEVersionCardList: typeof import('./src/components/DetectedIDEVersionCardList.vue')['default']
|
|
||||||
NAlert: typeof import('naive-ui')['NAlert']
|
NAlert: typeof import('naive-ui')['NAlert']
|
||||||
NButton: typeof import('naive-ui')['NButton']
|
NButton: typeof import('naive-ui')['NButton']
|
||||||
|
NButtonGroup: typeof import('naive-ui')['NButtonGroup']
|
||||||
NCard: typeof import('naive-ui')['NCard']
|
NCard: typeof import('naive-ui')['NCard']
|
||||||
NCode: typeof import('naive-ui')['NCode']
|
NCode: typeof import('naive-ui')['NCode']
|
||||||
NConfigProvider: typeof import('naive-ui')['NConfigProvider']
|
NConfigProvider: typeof import('naive-ui')['NConfigProvider']
|
||||||
|
NEllipsis: typeof import('naive-ui')['NEllipsis']
|
||||||
NEmpty: typeof import('naive-ui')['NEmpty']
|
NEmpty: typeof import('naive-ui')['NEmpty']
|
||||||
NFlex: typeof import('naive-ui')['NFlex']
|
NFlex: typeof import('naive-ui')['NFlex']
|
||||||
NFloatButton: typeof import('naive-ui')['NFloatButton']
|
NFloatButton: typeof import('naive-ui')['NFloatButton']
|
||||||
|
|||||||
@@ -3,9 +3,11 @@ import { darkTheme, dateZhCN, zhCN } from 'naive-ui'
|
|||||||
import hljs from 'highlight.js'
|
import hljs from 'highlight.js'
|
||||||
import javascript from 'highlight.js/lib/languages/javascript'
|
import javascript from 'highlight.js/lib/languages/javascript'
|
||||||
import json from 'highlight.js/lib/languages/json'
|
import json from 'highlight.js/lib/languages/json'
|
||||||
|
import xml from 'highlight.js/lib/languages/xml'
|
||||||
|
|
||||||
hljs.registerLanguage('javascript', javascript)
|
hljs.registerLanguage('javascript', javascript)
|
||||||
hljs.registerLanguage('json', json)
|
hljs.registerLanguage('json', json)
|
||||||
|
hljs.registerLanguage('xml', xml)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ function handleUpdateValue(key: string): void {
|
|||||||
<div class="codeLaunchpad-container">
|
<div class="codeLaunchpad-container">
|
||||||
<n-menu
|
<n-menu
|
||||||
v-model:value="activeKey"
|
v-model:value="activeKey"
|
||||||
|
class="codeLaunchpad-menu"
|
||||||
:options="codeLaunchpadMenuOptions"
|
:options="codeLaunchpadMenuOptions"
|
||||||
mode="horizontal"
|
mode="horizontal"
|
||||||
@update:value="handleUpdateValue"
|
@update:value="handleUpdateValue"
|
||||||
@@ -38,9 +39,15 @@ function handleUpdateValue(key: string): void {
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
div.codeLaunchpad-container {
|
div.codeLaunchpad-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex: 0 1;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
|
||||||
|
.codeLaunchpad-menu {
|
||||||
|
height: 40px;
|
||||||
|
min-height: 40px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
39
src/renderer/src/components-code-launchpad/ProjectCard.vue
Normal file
39
src/renderer/src/components-code-launchpad/ProjectCard.vue
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { IdeProjectDto } from '@my-type/ide-projects'
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import { toProductDisplayName } from '@my-type/jetbrains-state-tools'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
project: IdeProjectDto
|
||||||
|
}>()
|
||||||
|
|
||||||
|
// 计算属性,返回一个将显示在该卡片上的项目标签列表
|
||||||
|
const ideTags = computed(() => {
|
||||||
|
const tags: string[] = []
|
||||||
|
// 如果项目路径拥有 vscode-remote:// 协议,即是 VSCode Remote 项目
|
||||||
|
if (props.project.path.startsWith('vscode-remote://')) tags.push('VS Code 远程')
|
||||||
|
// 项目使用的 IDE
|
||||||
|
for (const ide of props.project.ide) {
|
||||||
|
// 不重复添加 VSCode
|
||||||
|
if (ide === 'VSC' && tags.length === 0) tags.push('VS Code')
|
||||||
|
if (ide !== 'VSC') tags.push(toProductDisplayName(ide) as string)
|
||||||
|
}
|
||||||
|
// 如果项目路径包含 wsl+ 或 wsl.,则认为是在 Windows Subsystem of Linux 中开发的项目
|
||||||
|
if (props.project.path.includes('wsl+') || props.project.path.includes('wsl.')) tags.push('WSL')
|
||||||
|
return tags
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<n-card>
|
||||||
|
<n-flex justify="left">
|
||||||
|
<n-h4>{{ project.name }}</n-h4>
|
||||||
|
<n-tag v-for="tag in ideTags" :key="tag" round :type="tag === 'WSL' ? 'primary' : 'info'">
|
||||||
|
{{ tag }}
|
||||||
|
</n-tag>
|
||||||
|
</n-flex>
|
||||||
|
<n-ellipsis>{{ project.path }}</n-ellipsis>
|
||||||
|
</n-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
104
src/renderer/src/components/CoderBaseCard.vue
Normal file
104
src/renderer/src/components/CoderBaseCard.vue
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, onMounted, ref } from 'vue'
|
||||||
|
import { useMessage } from 'naive-ui'
|
||||||
|
|
||||||
|
const message = useMessage()
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
cardTitle: string
|
||||||
|
defaultInput: string
|
||||||
|
// 人类友好格式的代码语言
|
||||||
|
codeLanguage1: 'json' | 'xml'
|
||||||
|
// 机器友好格式的代码语言
|
||||||
|
codeLanguage2: 'json' | 'xml'
|
||||||
|
// 转为人类友好格式
|
||||||
|
parser1: (input: string) => string
|
||||||
|
// 转为机器友好格式
|
||||||
|
parser2: (input: string) => string
|
||||||
|
// 转为人类友好格式别名
|
||||||
|
buttonText1?: string
|
||||||
|
// 转为机器友好格式别名
|
||||||
|
buttonText2?: string
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const codingHumanFriendly = ref(true)
|
||||||
|
const inputValue = ref(props.defaultInput)
|
||||||
|
const displayValue = ref('')
|
||||||
|
const errorTip = ref('')
|
||||||
|
|
||||||
|
function generate(humanFriendly: boolean, showSuccessMessage: boolean = true): void {
|
||||||
|
try {
|
||||||
|
displayValue.value = humanFriendly
|
||||||
|
? props.parser1(inputValue.value)
|
||||||
|
: props.parser2(inputValue.value)
|
||||||
|
errorTip.value = ''
|
||||||
|
// 页面挂载时不显示成功提示
|
||||||
|
if (showSuccessMessage) {
|
||||||
|
message.success('没抱错,所以应该成功辽~')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof SyntaxError) {
|
||||||
|
message.error(error.name)
|
||||||
|
displayValue.value = ''
|
||||||
|
errorTip.value = error.name + ': ' + error.message
|
||||||
|
} else {
|
||||||
|
// TODO 还有什么可能的错误?
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const codeLanguage = computed(() =>
|
||||||
|
codingHumanFriendly.value ? props.codeLanguage1 : props.codeLanguage2
|
||||||
|
)
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
generate(true, false)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<n-card class="default-card" :title="cardTitle">
|
||||||
|
<template #header-extra>
|
||||||
|
<n-flex align="center" justify="center">
|
||||||
|
<n-switch v-model:value="codingHumanFriendly" size="large">
|
||||||
|
<template #checked> {{ buttonText1 ? buttonText1 : '转换为人类友好格式' }} </template>
|
||||||
|
<template #unchecked> {{ buttonText2 ? buttonText2 : '转换为机器友好格式' }} </template>
|
||||||
|
</n-switch>
|
||||||
|
<n-button secondary type="primary" @click="() => generate(codingHumanFriendly)"
|
||||||
|
>生成</n-button
|
||||||
|
>
|
||||||
|
<n-button
|
||||||
|
secondary
|
||||||
|
type="warning"
|
||||||
|
@click="
|
||||||
|
() => {
|
||||||
|
inputValue = defaultInput
|
||||||
|
codingHumanFriendly = true
|
||||||
|
generate(true)
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>重置</n-button
|
||||||
|
>
|
||||||
|
<n-button secondary type="info">复制结果</n-button>
|
||||||
|
</n-flex>
|
||||||
|
</template>
|
||||||
|
<template #default>
|
||||||
|
<n-flex vertical>
|
||||||
|
<n-input v-model:value="inputValue" spellcheck="false" type="textarea" />
|
||||||
|
<div class="scrollarea code-area">
|
||||||
|
<n-code :code="displayValue" :language="codeLanguage" />
|
||||||
|
</div>
|
||||||
|
<n-alert v-if="errorTip !== ''" type="error">
|
||||||
|
{{ errorTip }}
|
||||||
|
</n-alert>
|
||||||
|
</n-flex>
|
||||||
|
</template>
|
||||||
|
</n-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
div.code-area {
|
||||||
|
max-height: 600px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,77 +1,16 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref } from 'vue'
|
import CoderBaseCard from '@renderer/components/CoderBaseCard.vue'
|
||||||
import { useMessage } from 'naive-ui'
|
|
||||||
|
|
||||||
const message = useMessage()
|
|
||||||
|
|
||||||
const defaultInput =
|
|
||||||
'{"name":"Code Space","author":1,"url":"https://code.mangofanfan.cn","users":[{"name":"MangoFanFanw","age":18,"male":true}]}'
|
|
||||||
|
|
||||||
const codingHumanFriendly = ref(true)
|
|
||||||
const inputValue = ref(defaultInput)
|
|
||||||
const displayValue = ref('')
|
|
||||||
const errorTip = ref('')
|
|
||||||
|
|
||||||
function generate(humanFriendly: boolean): void {
|
|
||||||
try {
|
|
||||||
displayValue.value = JSON.stringify(JSON.parse(inputValue.value), null, humanFriendly ? 4 : 0)
|
|
||||||
errorTip.value = ''
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof SyntaxError) {
|
|
||||||
message.error('JSON 解析错误,请复制完整并检查是否合法。')
|
|
||||||
displayValue.value = ''
|
|
||||||
errorTip.value = error.message
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
generate(true)
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<n-card class="default-card" title="json 格式化/压缩">
|
<CoderBaseCard
|
||||||
<template #header-extra>
|
card-title="json 格式化/压缩"
|
||||||
<n-flex align="center" justify="center">
|
default-input='{"name":"Code Space","author":1,"url":"https://code.mangofanfan.cn","users":[{"name":"MangoFanFanw","age":18,"male":true}]}'
|
||||||
<n-switch v-model:value="codingHumanFriendly" size="large">
|
code-language1="json"
|
||||||
<template #checked> 转换为人类友好格式 </template>
|
code-language2="json"
|
||||||
<template #unchecked> 转换为机器友好格式 </template>
|
:parser1="(code: string) => JSON.stringify(JSON.parse(code), null, 4)"
|
||||||
</n-switch>
|
:parser2="(code: string) => JSON.stringify(JSON.parse(code), null, 0)"
|
||||||
<n-button secondary type="primary" @click="() => generate(codingHumanFriendly)"
|
/>
|
||||||
>生成</n-button
|
|
||||||
>
|
|
||||||
<n-button
|
|
||||||
secondary
|
|
||||||
type="warning"
|
|
||||||
@click="
|
|
||||||
() => {
|
|
||||||
inputValue = defaultInput
|
|
||||||
codingHumanFriendly = true
|
|
||||||
generate(true)
|
|
||||||
}
|
|
||||||
"
|
|
||||||
>重置</n-button
|
|
||||||
>
|
|
||||||
<n-button secondary type="info">复制结果</n-button>
|
|
||||||
</n-flex>
|
|
||||||
</template>
|
|
||||||
<template #default>
|
|
||||||
<n-flex vertical>
|
|
||||||
<n-input v-model:value="inputValue" spellcheck="false" type="textarea" />
|
|
||||||
<div class="scrollarea code-area">
|
|
||||||
<n-code :code="displayValue" language="json" />
|
|
||||||
</div>
|
|
||||||
<n-alert v-if="errorTip !== ''" type="error">
|
|
||||||
{{ errorTip }}
|
|
||||||
</n-alert>
|
|
||||||
</n-flex>
|
|
||||||
</template>
|
|
||||||
</n-card>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped></style>
|
||||||
div.code-area {
|
|
||||||
max-height: 600px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
30
src/renderer/src/components/CoderXml.vue
Normal file
30
src/renderer/src/components/CoderXml.vue
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import CoderBaseCard from '@renderer/components/CoderBaseCard.vue'
|
||||||
|
import { XMLBuilder, XMLParser } from 'fast-xml-parser'
|
||||||
|
|
||||||
|
const xmlParser = new XMLParser({ ignoreAttributes: false })
|
||||||
|
const xmlBuilder = new XMLBuilder({ format: true, indentBy: ' ', ignoreAttributes: false })
|
||||||
|
|
||||||
|
function parser1(code: string): string {
|
||||||
|
return JSON.stringify(xmlParser.parse(code), null, 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
function parser2(code: string): string {
|
||||||
|
return xmlBuilder.build(JSON.parse(code))
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<CoderBaseCard
|
||||||
|
card-title="xml <=> json"
|
||||||
|
default-input='<?xml version="1.0" encoding="UTF-8"?><bookstore><book category="cooking"><title lang="en">Everyday Italian</title><author>Giada De Laurentiis</author><year>2005</year><price>30.00</price></book><book category="children"><title lang="en">Harry Potter</title><author>J K. Rowling</author><year>2005</year><price>29.99</price></book></bookstore>'
|
||||||
|
code-language1="json"
|
||||||
|
code-language2="xml"
|
||||||
|
:parser1
|
||||||
|
:parser2
|
||||||
|
button-text1="xml => json"
|
||||||
|
button-text2="json => xml"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
@@ -1,5 +1,53 @@
|
|||||||
<script setup lang="ts"></script>
|
<script setup lang="ts">
|
||||||
|
import ProjectCard from '@renderer/components-code-launchpad/ProjectCard.vue'
|
||||||
|
import { useProjects } from '@renderer/stores'
|
||||||
|
import { computed, onMounted, ref } from 'vue'
|
||||||
|
|
||||||
<template></template>
|
const projects = useProjects()
|
||||||
|
|
||||||
<style scoped></style>
|
const ide = ref<'VSCode' | 'JetBrains'>('VSCode')
|
||||||
|
|
||||||
|
// 此 switch-case 结构已经触及所有情况
|
||||||
|
// eslint-disable-next-line vue/return-in-computed-property
|
||||||
|
const reverseProjects = computed(() => {
|
||||||
|
switch (ide.value) {
|
||||||
|
case 'VSCode':
|
||||||
|
return projects.vscodeProjects.toReversed()
|
||||||
|
case 'JetBrains':
|
||||||
|
return projects.jetBrainsProjects.toReversed()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (projects.vscodeProjects.length === 0) {
|
||||||
|
projects.getVSCodeProjects()
|
||||||
|
}
|
||||||
|
if (projects.jetBrainsProjects.length === 0) {
|
||||||
|
projects.getJetBrainsProjects()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<n-button-group class="ide-button-group">
|
||||||
|
<n-button type="primary" secondary round @click="() => (ide = 'VSCode')">VS Code</n-button>
|
||||||
|
<n-button type="primary" secondary round @click="() => (ide = 'JetBrains')">JetBrains</n-button>
|
||||||
|
</n-button-group>
|
||||||
|
<n-flex size="small" vertical>
|
||||||
|
<div v-for="project of reverseProjects" :key="project.path" class="project-card">
|
||||||
|
<ProjectCard :project />
|
||||||
|
</div>
|
||||||
|
</n-flex>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.ide-button-group {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
margin-left: 10px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-card {
|
||||||
|
margin: 0 4px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import CoderJson from '@renderer/components/CoderJson.vue'
|
import CoderJson from '@renderer/components/CoderJson.vue'
|
||||||
|
import CoderXml from '@renderer/components/CoderXml.vue'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -10,6 +11,7 @@ import CoderJson from '@renderer/components/CoderJson.vue'
|
|||||||
</n-alert>
|
</n-alert>
|
||||||
|
|
||||||
<CoderJson />
|
<CoderJson />
|
||||||
|
<CoderXml />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import type {
|
|||||||
keyboardShortcut,
|
keyboardShortcut,
|
||||||
screenPosition
|
screenPosition
|
||||||
} from '@my-type/settings'
|
} from '@my-type/settings'
|
||||||
|
import { IdeProjectDto } from '@my-type/ide-projects'
|
||||||
|
|
||||||
export const useSettings = defineStore('settings', () => {
|
export const useSettings = defineStore('settings', () => {
|
||||||
const isStayInTray = ref(false)
|
const isStayInTray = ref(false)
|
||||||
@@ -101,3 +102,18 @@ export const useIDEs = defineStore('IDEs', () => {
|
|||||||
|
|
||||||
return { ides, versions, getIDEs, checkIDEs, getVersions, checkVersions }
|
return { ides, versions, getIDEs, checkIDEs, getVersions, checkVersions }
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const useProjects = defineStore('projects', () => {
|
||||||
|
const vscodeProjects = ref<IdeProjectDto[]>([])
|
||||||
|
const jetBrainsProjects = ref<IdeProjectDto[]>([])
|
||||||
|
|
||||||
|
async function getVSCodeProjects(): Promise<void> {
|
||||||
|
vscodeProjects.value = await window.codeLaunchpad._getVSCodeProjects()
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getJetBrainsProjects(): Promise<void> {
|
||||||
|
jetBrainsProjects.value = await window.codeLaunchpad._getJetBrainsProjects()
|
||||||
|
}
|
||||||
|
|
||||||
|
return { vscodeProjects, jetBrainsProjects, getVSCodeProjects, getJetBrainsProjects }
|
||||||
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user