diff --git a/plugin/package-lock.json b/plugin/package-lock.json index 3ce7bdd..e3684c3 100644 --- a/plugin/package-lock.json +++ b/plugin/package-lock.json @@ -8,7 +8,8 @@ "axios": "^0.24.0", "iconv-lite": "^0.6.3", "lodash": "^4.17.21", - "ses": "^0.15.15" + "ses": "^0.15.15", + "tree-kill": "^1.2.2" } }, "node_modules/axios": { @@ -63,6 +64,14 @@ "version": "0.15.15", "resolved": "https://registry.npmmirror.com/ses/-/ses-0.15.15.tgz", "integrity": "sha512-sJM4HRlM3VouA3RhRmS7wG5MRQPqZZnc6O4BvAefU7yeM+qp8EUfGAWQ9iB/X5cNh3+m5N9lC7DEpyxQ+E4D+w==" + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "bin": { + "tree-kill": "cli.js" + } } }, "dependencies": { @@ -101,6 +110,11 @@ "version": "0.15.15", "resolved": "https://registry.npmmirror.com/ses/-/ses-0.15.15.tgz", "integrity": "sha512-sJM4HRlM3VouA3RhRmS7wG5MRQPqZZnc6O4BvAefU7yeM+qp8EUfGAWQ9iB/X5cNh3+m5N9lC7DEpyxQ+E4D+w==" + }, + "tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==" } } } diff --git a/plugin/package.json b/plugin/package.json index 694e0ef..b867a2e 100644 --- a/plugin/package.json +++ b/plugin/package.json @@ -3,6 +3,7 @@ "axios": "^0.24.0", "iconv-lite": "^0.6.3", "lodash": "^4.17.21", - "ses": "^0.15.15" + "ses": "^0.15.15", + "tree-kill": "^1.2.2" } } diff --git a/plugin/preload.js b/plugin/preload.js index 3d1655e..541db67 100644 --- a/plugin/preload.js +++ b/plugin/preload.js @@ -8,6 +8,7 @@ const axios = require('axios'); const http = require('http'); const url = require('url') const nodeFns = require("./lib/nodeFns") +const kill = require('tree-kill') require('ses') window._ = require("lodash") @@ -97,8 +98,8 @@ window.quickcommand = { }, // 关闭进程 - kill: function(pid, signal = 'SIGTERM') { - process.kill(pid, signal) + kill: function(pid, signal = 'SIGTERM', cb) { + kill(pid, signal, cb) }, // dom 解析 @@ -211,22 +212,22 @@ if (process.platform !== 'linux') quickcommand.runInTerminal = function(cmdline, } let getCommandToLaunchTerminal = (cmdline, dir) => { - let cd = '' - if (utools.isWindows()) { - let appPath = path.join(utools.getPath('home'), '/AppData/Local/Microsoft/WindowsApps/') - // 直接 existsSync wt.exe 无效 - if (fs.existsSync(appPath) && fs.readdirSync(appPath).includes('wt.exe')) { - cmdline = cmdline.replace(/"/g, `\\"`) - if (dir) cd = `-d "${dir.replace(/\\/g, '/')}"` - command = `${appPath}wt.exe ${cd} cmd /k "${cmdline}"` - } else { - cmdline = cmdline.replace(/"/g, `^"`) - if (dir) cd = `cd /d "${dir.replace(/\\/g, '/')}" &&` - command = `${cd} start "" cmd /k "${cmdline}"` - } - } else { + let cd = '' + if (utools.isWindows()) { + let appPath = path.join(utools.getPath('home'), '/AppData/Local/Microsoft/WindowsApps/') + // 直接 existsSync wt.exe 无效 + if (fs.existsSync(appPath) && fs.readdirSync(appPath).includes('wt.exe')) { cmdline = cmdline.replace(/"/g, `\\"`) - if (dir) cd = `cd ${dir.replace(/ /g, `\\\\ `)} &&` + if (dir) cd = `-d "${dir.replace(/\\/g, '/')}"` + command = `${appPath}wt.exe ${cd} cmd /k "${cmdline}"` + } else { + cmdline = cmdline.replace(/"/g, `^"`) + if (dir) cd = `cd /d "${dir.replace(/\\/g, '/')}" &&` + command = `${cd} start "" cmd /k "${cmdline}"` + } + } else { + cmdline = cmdline.replace(/"/g, `\\"`) + if (dir) cd = `cd ${dir.replace(/ /g, `\\\\ `)} &&` if (fs.existsSync('/Applications/iTerm.app')) { command = `osascript -e 'tell application "iTerm" create window with default profile @@ -606,6 +607,7 @@ window.runCodeFile = (cmd, option, terminal, callback) => { // let stderr = err_chunks.join(""); // callback(stdout, stderr) // }) + return child } let httpServer @@ -666,4 +668,4 @@ window.quickcommandHttpServer = () => { run, stop } -} \ No newline at end of file +} diff --git a/src/components/CommandRunResult.vue b/src/components/CommandRunResult.vue index 1ef33cd..ba549d8 100644 --- a/src/components/CommandRunResult.vue +++ b/src/components/CommandRunResult.vue @@ -59,6 +59,7 @@ export default { history: [], historyIdx: null, enableHtml: false, + child: null, }; }, props: { @@ -122,7 +123,7 @@ export default { : this.$root.programs[currentCommand.program]; option.scptarg = currentCommand.scptarg || ""; option.charset = currentCommand.charset || {}; - window.runCodeFile( + this.child = window.runCodeFile( currentCommand.cmd, option, currentCommand.output === "terminal", @@ -237,6 +238,9 @@ export default { }, stopRun() { this.runResult = ""; + if (!!this.child) { + quickcommand.kill(this.child.pid); + } if (!!this.listener) { this.subInputValue = ""; utools.removeSubInput(); diff --git a/src/plugins/monaco/types/quickcommand.api.d.ts b/src/plugins/monaco/types/quickcommand.api.d.ts index 9c6765c..44e382b 100644 --- a/src/plugins/monaco/types/quickcommand.api.d.ts +++ b/src/plugins/monaco/types/quickcommand.api.d.ts @@ -256,11 +256,15 @@ interface quickcommandApi { loadRemoteScript(url: string): Promise; /** - * 将 signal 发送给 pid 标识的进程 , 默认为关闭进程,同process.kill + * 将 signal 发送给 pid 标识的进程 , 默认为关闭进程 + * + * 不同于process.kill,会将该进程启用的所有子进程也杀死 + * * @param pid 进程 ID * @param signal 进程信号,默认为SIGTERM + * @param callback 失败时的回调 */ - kill(pid: number, signal?: number | string): void; + kill(pid: number, signal?: string | number, callback?: (error?: Error) => void): void; /** * windows 下运行 VBS 脚本并返回运行结果