vscode-extension.ts 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. // electron/modules/vscode-extension.ts - VS Code 插件安装模块
  2. import { BrowserWindow } from 'electron'
  3. import { execa } from 'execa'
  4. import { getVscodeCliPath } from './utils'
  5. import logger from './logger'
  6. /**
  7. * 发送状态到渲染进程
  8. */
  9. function sendToRenderer(channel: string, data: unknown): void {
  10. const windows = BrowserWindow.getAllWindows()
  11. windows.forEach((win) => {
  12. win.webContents.send(channel, data)
  13. })
  14. }
  15. /**
  16. * 安装 VS Code 插件
  17. * 供 IPC handler 和 installer.ts 复用
  18. * @param extensionId 插件 ID
  19. * @returns 安装结果
  20. */
  21. export async function installVscodeExtension(extensionId: string): Promise<{ success: boolean; error?: string }> {
  22. try {
  23. const codePath = await getVscodeCliPath()
  24. const fullCommand = `${codePath} --install-extension ${extensionId}`
  25. logger.installInfo(`开始安装 VS Code 插件: ${extensionId},使用 CLI: ${codePath}`)
  26. // 使用 install-status 事件发送日志,这样可以被 App.vue 中的监听器捕获
  27. sendToRenderer('install-status', {
  28. software: 'vscode',
  29. message: `正在安装 VS Code 插件: ${extensionId}...`,
  30. progress: 30,
  31. i18nKey: 'log.vscodeExtInstalling',
  32. i18nParams: { extensionId }
  33. })
  34. // 发送执行命令的日志
  35. sendToRenderer('install-status', {
  36. software: 'vscode',
  37. message: `执行命令: ${fullCommand}`,
  38. progress: 40,
  39. i18nKey: 'log.executingCommand',
  40. i18nParams: { command: fullCommand }
  41. })
  42. const result = await execa(codePath, ['--install-extension', extensionId], {
  43. encoding: 'utf8',
  44. stdout: 'pipe',
  45. stderr: 'pipe'
  46. })
  47. // 记录命令输出
  48. if (result.stdout) {
  49. logger.installInfo(`VS Code 插件安装输出: ${result.stdout}`)
  50. sendToRenderer('install-status', {
  51. software: 'vscode',
  52. message: `code 输出: ${result.stdout}`,
  53. progress: 80,
  54. i18nKey: 'log.vscodeExtOutput',
  55. i18nParams: { output: result.stdout }
  56. })
  57. }
  58. logger.installInfo(`VS Code 插件安装成功: ${extensionId}`)
  59. sendToRenderer('install-status', {
  60. software: 'vscode',
  61. message: `✅ VS Code 插件安装成功: ${extensionId}`,
  62. progress: 100,
  63. i18nKey: 'log.vscodeExtInstallSuccess',
  64. i18nParams: { extensionId }
  65. })
  66. return { success: true }
  67. } catch (error) {
  68. const execaError = error as { message?: string; stderr?: string; shortMessage?: string }
  69. // 过滤乱码字符,只保留可读字符(ASCII 可打印字符和中文)
  70. let errorMessage = execaError.shortMessage || execaError.message || '未知错误'
  71. if (execaError.stderr) {
  72. const stderrClean = execaError.stderr.replace(/[^\x20-\x7E\u4e00-\u9fa5\n\r]/g, '').trim()
  73. if (stderrClean) {
  74. errorMessage = stderrClean
  75. }
  76. }
  77. // 从错误消息中也过滤乱码
  78. errorMessage = errorMessage.replace(/[^\x20-\x7E\u4e00-\u9fa5\n\r:.\-_/\\]/g, '').trim()
  79. logger.installError(`VS Code 插件安装失败: ${extensionId}`, error)
  80. // 发送错误到渲染进程的安装日志
  81. sendToRenderer('install-status', {
  82. software: 'vscode',
  83. message: `❌ VS Code 插件安装失败: ${errorMessage}`,
  84. progress: 0,
  85. i18nKey: 'log.vscodeExtInstallFailed',
  86. i18nParams: { extensionId, error: errorMessage }
  87. })
  88. return { success: false, error: errorMessage }
  89. }
  90. }