diff --git a/plugin/preload.js b/plugin/preload.js index cde5c77..7ee0181 100644 --- a/plugin/preload.js +++ b/plugin/preload.js @@ -157,14 +157,13 @@ window.quickcommand = { }, // 载入在线资源 - loadRemoteScript: async function(url, forceUpdate = false) { + loadRemoteScript: async function(url) { if (!/^((ht|f)tps?):\/\/([\w\-]+(\.[\w\-]+)*\/)*[\w\-]+(\.[\w\-]+)*\/?(\?([\w\-\.,@?^=%&:\/~\+#]*)+)?/.test(url)) throw 'url 不合法' - let remote = url - let root = path.join(os.tmpdir(), 'qcRemoteScript') - if (!fs.existsSync(root)) fs.mkdirSync(root) - let local = path.join(root, require('crypto').createHash('md5').update(url).digest('hex')) - if (forceUpdate || !fs.existsSync(local)) await this.downloadFile(remote, local) - return require(local) + let local = getQuickcommandTempFile('js') + await this.downloadFile(url, local) + let source = require(local) + fs.unlinkSync(local) + return source }, // 唤醒 uTools @@ -187,7 +186,7 @@ window.quickcommand = { // 运行vbs脚本 if (process.platform == 'win32') quickcommand.runVbs = function(script) { return new Promise((reslove, reject) => { - var tempfile = path.join(os.tmpdir(), 'TempVBSScript.vbs') + var tempfile = getQuickcommandTempFile('vbs', 'TempVBSScript') fs.writeFile(tempfile, iconv.encode(script, 'gbk'), err => { child_process.exec(`cscript.exe /nologo "${tempfile}"`, { encoding: "buffer" @@ -258,7 +257,7 @@ window.pluginInfo = () => { let getSleepCodeByShell = ms => { var cmd, tempFilePath if (utools.isWindows()) { - tempFilePath = getQuickcommandTempFile('vbs') + tempFilePath = getQuickcommandTempFile('vbs', 'SleepVBSScript') cmd = `echo set ws=CreateObject("Wscript.Shell") > ${tempFilePath} && echo Wscript.sleep ${ms} >> ${tempFilePath} && cscript /nologo ${tempFilePath}` } else { cmd = `sleep ${ms / 1000}` @@ -316,8 +315,16 @@ window.getUtoolsPlugins = () => { return plugins; } -window.getQuickcommandTempFile = ext => { - return path.join(os.tmpdir(), `quickcommandTempFile.${ext}`) +window.getQuickcommandTempFile = (ext, name, dir = 'quickcommandTempDir') => { + if (!name) name = new Date().getTime() + (Math.random() * 10 ** 6).toFixed() + let tempDir = path.join(os.tmpdir(), dir) + if (!fs.existsSync(tempDir)) fs.mkdirSync(tempDir) + return path.join(tempDir, `${name}.${ext}`) +} + +window.delTempFile = (...args) => { + let tmpPath = path.join(os.tmpdir(), ...args) + if (fs.existsSync(tmpPath)) fs.unlinkSync(tmpPath) } window.getBase64Ico = filepath => { @@ -518,8 +525,8 @@ window.runCodeFile = (cmd, option, terminal, callback) => { ext = option.ext, charset = option.charset, scptarg = option.scptarg || ""; - let script = getQuickcommandTempFile(ext) - // 批处理和 powershell 默认编码为 GBK, 解决批处理的换行问题 + let script = getQuickcommandTempFile(ext, 'quickcommandTempScript') + // 批处理和 powershell 默认编码为 GBK, 解决批处理的换行问题 if (charset.scriptCode) cmd = iconv.encode(cmd.replace(/\n/g, '\r\n'), charset.scriptCode); fs.writeFileSync(script, cmd); // var argvs = [script] @@ -541,27 +548,27 @@ window.runCodeFile = (cmd, option, terminal, callback) => { // 在终端中输出 if (terminal) cmdline = getCommandToLaunchTerminal(cmdline) child = child_process.spawn(cmdline, { - encoding: 'buffer', - shell: true - }) - // var chunks = [], - // err_chunks = []; + encoding: 'buffer', + shell: true + }) + // var chunks = [], + // err_chunks = []; console.log('running: ' + cmdline); child.stdout.on('data', chunk => { if (charset.outputCode) chunk = iconv.decode(chunk, charset.outputCode) callback(chunk.toString(), null) - // chunks.push(chunk) + // chunks.push(chunk) }) child.stderr.on('data', stderr => { - if (charset.outputCode) stderr = iconv.decode(stderr, charset.outputCode) - callback(null, stderr.toString()) - // err_chunks.push(err_chunk) - }) - // child.on('close', code => { - // let stdout = chunks.join(""); - // let stderr = err_chunks.join(""); - // callback(stdout, stderr) - // }) + if (charset.outputCode) stderr = iconv.decode(stderr, charset.outputCode) + callback(null, stderr.toString()) + // err_chunks.push(err_chunk) + }) + // child.on('close', code => { + // let stdout = chunks.join(""); + // let stderr = err_chunks.join(""); + // callback(stdout, stderr) + // }) return child } @@ -599,7 +606,7 @@ window.quickcommandHttpServer = () => { req.on('end', () => { let parsedParams let params = data.join("").toString() - // 先尝试作为 json 解析 + // 先尝试作为 json 解析 try { parsedParams = JSON.parse(params) } catch (error) { diff --git a/src/components/CommandRunResult.vue b/src/components/CommandRunResult.vue index f5cc522..33ed484 100644 --- a/src/components/CommandRunResult.vue +++ b/src/components/CommandRunResult.vue @@ -69,6 +69,8 @@ export default { frameInitHeight: 0, childProcess: null, timeStamp: null, + urlReg: + /^((ht|f)tps?):\/\/([\w\-]+(\.[\w\-]+)*\/)*[\w\-]+(\.[\w\-]+)*\/?(\?([\w\-\.,@?^=%&:\/~\+#]*)+)?/, }; }, props: { @@ -102,15 +104,18 @@ export default { }, async fire(currentCommand) { currentCommand.cmd = this.assignSpecialVars(currentCommand.cmd); - this.enableHtml = currentCommand.output === "html"; + if (currentCommand.output === "html") { + this.enableHtml = true; + currentCommand.cmd = await this.cacheScript(currentCommand.cmd); + } let { hideWindow, outPlugin, action } = outputTypes[currentCommand.output]; // 需要隐藏的提前隐藏窗口 hideWindow && utools.hideMainWindow(); // 对于本身就没有输出的命令,无法确认命令是否执行完成,所以干脆提前退出插件 // 弊端就是如果勾选了隐藏后台就完全退出的话,会造成命令直接中断 - let quitBeforeShowResult = this.fromUtools && outPlugin; - quitBeforeShowResult && + let earlyExit = this.fromUtools && outPlugin; + earlyExit && setTimeout(() => { utools.outPlugin(); }, 500); @@ -118,19 +123,12 @@ export default { window.runCodeInSandbox( currentCommand.cmd, (stdout, stderr) => { - if (stderr) { - return quitBeforeShowResult - ? alert(stderr) - : this.showRunResult(stderr, false, action); - } - outPlugin - ? action(stdout.toString()) - : this.showRunResult(stdout, true); + this.handleResult(stdout, stderr, { outPlugin, action, earlyExit }); }, { enterData: this.$root.enterData } ); } else if (currentCommand.program === "html") { - this.showRunResult(currentCommand.cmd, true, action); + this.showRunResult(currentCommand.cmd, true); } else { let option = currentCommand.program === "custom" @@ -143,14 +141,7 @@ export default { option, currentCommand.output === "terminal", (stdout, stderr) => { - if (stderr) { - return quitBeforeShowResult - ? alert(stderr) - : this.showRunResult(stderr, false, action); - } - outPlugin - ? action(stdout.toString()) - : this.showRunResult(stdout, true); + this.handleResult(stdout, stderr, { outPlugin, action, earlyExit }); } ); // ctrl c 终止 @@ -235,6 +226,16 @@ export default { payload: await commandTypes[type]?.tempPayload?.(), }; }, + handleResult(stdout, stderr, options) { + if (stderr) { + return options.earlyExit + ? alert(stderr) + : this.showRunResult(stderr, false); + } + options.outPlugin + ? options.action(stdout.toString()) + : this.showRunResult(stdout, true); + }, // 显示运行结果 showRunResult(content, isSuccess) { this.isResultShow = true; @@ -278,6 +279,19 @@ export default { frameLoad(initHeight) { this.frameInitHeight = initHeight; }, + // 预先下载远程脚本 + async cacheScript(cmd) { + let html = quickcommand.htmlParse(cmd); + let scriptDoms = html.querySelectorAll("script"); + for (let i = 0; i < scriptDoms.length; i++) { + let src = scriptDoms[i].src; + if (!this.urlReg.test(src)) continue; + let dest = window.getQuickcommandTempFile("js", "remoteScript_" + i); + await quickcommand.downloadFile(src, dest); + scriptDoms[i].src = "file://" + dest; + } + return html.documentElement.innerHTML; + }, }, unmounted() { this.stopRun(); diff --git a/src/components/ResultArea.vue b/src/components/ResultArea.vue index 388ecf6..1d79685 100644 --- a/src/components/ResultArea.vue +++ b/src/components/ResultArea.vue @@ -82,10 +82,21 @@ export default { frameInit() { let cfw = this.$refs?.iframe?.contentWindow; if (!cfw) return; + let showError = (...args) => { + quickcommand.showMessageBox(args.join(" "), "error", 0); + }; + let showLog = (...args) => { + quickcommand.showMessageBox(args.join(" "), "success", 0); + }; let ctx = { quickcommand: _.cloneDeep(quickcommand), utools: _.cloneDeep(utools), parent: undefined, + console: { + log: showLog, + error: showError, + }, + onerror: (e) => showError(e), }; Object.assign(cfw, ctx); cfw.onload = () => { diff --git a/src/components/popup/IconPicker.vue b/src/components/popup/IconPicker.vue index b0ae250..da35fc2 100644 --- a/src/components/popup/IconPicker.vue +++ b/src/components/popup/IconPicker.vue @@ -177,7 +177,7 @@ export default { argvs: imgUrl, readfile: false, }); - let imgPath = window.getQuickcommandTempFile(imgInfo.ext); + let imgPath = window.getQuickcommandTempFile(imgInfo.ext, 'TempImgFile'); quickcommand .downloadFile(imgUrl, imgPath) .then(() => { diff --git a/src/components/quickcommandUI/QuickCommand.vue b/src/components/quickcommandUI/QuickCommand.vue index 6b2117d..ae07b4c 100644 --- a/src/components/quickcommandUI/QuickCommand.vue +++ b/src/components/quickcommandUI/QuickCommand.vue @@ -92,6 +92,15 @@ export default { message: message, timeout: time, position: "top", + actions: + time === 0 + ? [ + { + label: "确定", + color: "white", + }, + ] + : [], }); }, diff --git a/src/plugins/monaco/types/quickcommand.api.d.ts b/src/plugins/monaco/types/quickcommand.api.d.ts index 2c8c82d..edf94f9 100644 --- a/src/plugins/monaco/types/quickcommand.api.d.ts +++ b/src/plugins/monaco/types/quickcommand.api.d.ts @@ -138,7 +138,7 @@ interface quickcommandApi { * ``` * @param message 显示的消息内容 * @param icon 图标,默认为 success - * @param time 多少毫秒后消失,默认为 3000 + * @param time 多少毫秒后消失,默认为 3000,当设为 0 时则需要手动点击关闭 */ showMessageBox( message: string, @@ -352,18 +352,6 @@ interface quickcommandApi { */ simulatePaste(); - /** - * 读取剪贴板 - */ - readClipboard(): text; - - /** - * 写入剪贴板 - * - * @param text 要写入的文本 - */ - writeClipboard(text: string); - /** * 唤醒 uTools *