!function () { // 暗黑模式 if (utools.isDarkColors()) { !$('#darkmode').length && $('head').append(` `) } else { $('#darkmode').length && $('#darkmode, #darkswal').remove() } // 禁用危险函数 let utoolsFull = utools if (!isDev()) utools = getuToolsLite() // 数据库前缀 const QC_PREFIX = 'qc_' const CFG_PREFIX = 'cfg_' // 数据库函数封装 let getDB = id => { let db = utoolsFull.db.get(id) return db ? db.data : {} } let putDB = (value, id) => { let db = utoolsFull.db.get(id); if (db) utoolsFull.db.put({ _id: id, data: value, _rev: db._rev }) else utoolsFull.db.put({ _id: id, data: value }); } let delDB = id => { return utoolsFull.db.remove(id) } let getDocs = key => { return utoolsFull.db.allDocs(key) } // 获取所有 qc,等效于 1.6 版本 getDB('customFts') let getAllQuickCommands = () => { let allQcs = {} getDocs(QC_PREFIX).forEach(x => allQcs[x.data.features.code] = x.data) return allQcs } // 进入插件 utools.onPluginEnter(async ({ code, type, payload }) => { if (isRunningAtFirstTime()) { showChangeLog() importDefaultCommands() oldVersionFix() } var handleEnter utools.onPluginOut(() => { // 暂存 codeRunner 的内容 if (code == "code") { var cmd = window.editor.getValue(); var program = $('#program').val(), scptarg = $('#scptarg').val(), customoptions; if (program == 'custom') customoptions = { custombin: $('#custombin').val(), customarg: $('#customarg').val(), customext: $('#customext').val(), customcodec: $('#customcodec').val() } putDB({ cmd: cmd, program: program, scptarg: scptarg, customoptions: customoptions }, CFG_PREFIX + 'codeHistory') } // 初始化 $("#options, #out").empty() $('body').children(':not(#wrapper)').remove() $('body').css({overflow: 'hidden'}) if (handleEnter) document.removeEventListener('keydown', handleEnter) }) // 配置页面 if (code == 'options') { utools.setExpendHeight(600); // $("#options").show(); showOptions(); } else if (code == 'code') { var file = "" // utools.setExpendHeight(600); if (type == 'files') file = payload[0].path showCodeEditor(file) } else { // console.log(new Date().getTime() - window.startTime); $('body').css({overflow: 'auto'}) utools.setExpendHeight(0); $("#options").hide(); var db = getDB(QC_PREFIX + code), cmd = db.cmd; if (db.program == "custom") { option = db.customOptions; } else if(db.program == "quickcommand"){ option = { mode: "quickcommand", enterData: { code, type, payload } }; }else{ option = programs[db.program]; } option.scptarg = db.scptarg cmd = special(cmd); // 正则 if (type == 'regex') cmd = cmd.replace(/\{\{input\}\}/mg, payload); // 文件 if (type == 'files' && cmd.includes('{{MatchedFiles')) { let MatchedFiles = payload let Matched = cmd.match(/\{\{MatchedFiles(\[\d+\]){0,1}(\.\w{1,11}){0,1}\}\}/g) Matched && Matched.forEach(m => { repl = eval(m.slice(2, -2)) typeof repl == 'object' ? (repl = JSON.stringify(repl)) : (repl = repl.replace('\\', '\\\\')) cmd = cmd.replace(m, repl.replace('$','$$$')) }) } // 窗口 var repl if (type == 'window') { // 获取选中的文件 if (cmd.includes('{{SelectFile}}')) { repl = await getSelectFile(payload.id); cmd = cmd.replace(/\{\{SelectFile\}\}/mg, repl) } // 获取资源管理器或访达当前目录 if (cmd.includes('{{pwd}}')) { repl = getCurrentFolderPathFix(); console.log(repl); cmd = cmd.replace(/\{\{pwd\}\}/mg, repl) console.log(cmd) } // 获取窗口信息 if (cmd.includes('{{WindowInfo')) { let WindowInfo = payload let Matched = cmd.match(/\{\{WindowInfo(\.\w{1,7}){0,1}\}\}/g) Matched && Matched.forEach(m => { repl = eval(m.slice(2, -2)) typeof repl == 'object' && (repl = JSON.stringify(repl)) cmd = cmd.replace(m, repl) }) } } // 无输出的批处理 // if (db.output == 'ignore' && option.ext == 'bat') option.bin = 'explorer'; if (db.hasSubInput) { // 启动子命令输入 // 清空输出 // $("#out").empty(); var rule = String.raw`\{\{subinput(:.+?){0,1}\}\}` var matched = cmd.match(new RegExp(rule)) var placeholder = matched[1] || ':请输入' var subinput = ''; var setSubInput = () => { utools.setSubInput(({text}) => { subinput = text; }, placeholder.slice(1)); } handleEnter = (event) => { if (event.keyCode == 13) { $("#out").append(`
>> ${new Date()}
`); var cmdToRun = cmd.replace(new RegExp(rule, 'g'), subinput); runQuickCommand(cmdToRun, option, db.output, true); } }; setSubInput(); document.addEventListener('keydown', handleEnter); } else { runQuickCommand(cmd, option, db.output, false); } } }); let runQuickCommand = (cmd, option, output, autoScroll = false, autoHeight = true) => { // 不需要输出的,提前关闭窗口 if (['ignore', 'clip', 'send', 'notice', 'terminal'].indexOf(output) !== -1) { utools.hideMainWindow(); setTimeout(() => { utools.outPlugin(); }, 500); } var outputOpts = { type: output, autoScroll: autoScroll, autoHeight: autoHeight } if (option.mode) { // 内置环境 runCodeInVm(cmd, (stdout, stderr) => { if (cmd.includes("utools.setExpendHeight")) outputOpts.autoHeight = false switchQuickCommandResult(stdout, stderr, outputOpts) }, option.enterData) } else { var terminal = output == 'terminal' ? true : false outputOpts.scriptPath = getQuickCommandScriptFile(option.ext) // 执行脚本 runCodeFile(cmd, option, terminal, (stdout, stderr) => { switchQuickCommandResult(stdout, stderr, outputOpts) }) } } let switchQuickCommandResult = (stdout, stderr, outputOpts) => { var output = outputOpts.type, autoScroll = outputOpts.autoScroll, autoHeight = outputOpts.autoHeight; var outputAutoFix = (autoScroll, autoHeight) => { var outputHeight = $("#out").outerHeight() if (outputHeight > 600) outputHeight = 600 if (autoHeight && $('#options').is(':hidden')) utools.setExpendHeight(outputHeight); if (outputHeight == 600 && autoScroll) $(document).scrollTop($(document).height()); } if (stderr) { $("#out").addClass('error') // 报错 if (output == 'text' || output == 'html') { $("#out").append(stderr) outputAutoFix(autoScroll, autoHeight) } else { var index = utools.showMessageBox({ type: 'error', title: '啊嘞?!', message: stderr, buttons: outputOpts.scriptPath ? ['转至脚本目录', '退出'] : ['退出'] }) if (outputOpts.scriptPath && index == 0) { locate(outputOpts.scriptPath ); } copyTo(stderr); message("已复制报错信息"); utools.outPlugin(); } } else if (stdout) { $("#out").removeClass("error") // 有输出 switch (output) { case "text": $("#out").append(htmlEncode(stdout, true)) outputAutoFix(autoScroll, autoHeight) break; case "html": $("#out").append(stdout) outputAutoFix(autoScroll, autoHeight) break; case "clip": copyTo(stdout) break; case "send": send(stdout) break; case "notice": // 发送系统通知 message(stdout) break; case "ignore": case "nothing": break; default: break; } // } else { // // 无输出 // utools.outPlugin() } } // 替换上个版本弃用的功能 let oldVersionFix = () => { var customFts = getDB('customFts'); let ftsKeys = Object.keys(customFts); if (!ftsKeys.length) return; utools.showNotification('正在对老版本命令做兼容处理,如插件显示空白请稍候', 'warning') ftsKeys.forEach((x, i) => { let fts = customFts[x] // 旧版的 program if (fts.program == 'simulation') fts.program = 'quickcommand'; // 旧版的 sleep if (fts.cmd.includes('await sleep')) fts.cmd = fts.cmd.replace(/await sleep/g, 'quickcommand.sleep') // 旧版的 match.app let type = fts.features.cmds[0].type || 'key' if (type == 'window') { let windowMatch = fts.features.cmds[0].match console.log(windowMatch) if (windowMatch && (typeof windowMatch.app == 'string')) { console.log(fts); fts.features.cmds[0].match.app = windowMatch.app.split(',') } } // 不规范的 code let code = fts.features.code if (!/^(window|key|regex|files|default)_/.test(code)) { console.log(code); utoolsFull.removeFeature(code) let uid = Number(Math.random().toString().substr(3, 3) + (Date.now() + i * 10000)).toString(36) code = type + '_' + uid fts.features.code = code } // 每一个命令一个 id putDB(fts, QC_PREFIX + code) }) delDB('customFts') } let showChangeLog = () => { putDB(pluginInfo().version, CFG_PREFIX + 'version') utools.createBrowserWindow('./helps/CHANGELOG.html', {width: 1280, height: 920}) } let isRunningAtFirstTime = () => { var historyVersion = getDB(CFG_PREFIX + 'version') if (historyVersion instanceof Object) return 'init' if (pluginInfo().version > historyVersion) return 'update' return false } // 导入默认命令 let importDefaultCommands = () => { let defaultCommands = getDefaultCommands() Object.values(defaultCommands).forEach(d => { importCommand(d) }) } // 是否含有 quickcommand 键值 let isJsonQc = obj => { var keys = ["features", "program", "cmd", "output"] if (keys.filter(x => typeof obj[x] == 'undefined').length) return false return true } // 判断是否为可导入的快捷命令 let quickCommandParser = json => { try { var qc = JSON.parse(json) } catch (error) { return false } if (isJsonQc(qc)) return { single: true, qc: qc } else if (!Object.values(qc).filter(q => !isJsonQc(q)).length) return { single: false, qc: qc } else return false } // 导入 let importCommand = file => { var pushData, clipboardText = clipboardReadText() if (!file) pushData = quickCommandParser(clipboardText) if (!pushData) { var options = file ? { type: 'file', argvs: file } : { type: 'dialog', argvs: { filters: [{ name: 'json', extensions: ['json'] }] } } options.readfile = true var fileinfo = getFileInfo(options) if (!fileinfo) return pushData = quickCommandParser(fileinfo.data) if (!pushData) return false } // 单个命令导入 if (pushData.single) { var code = pushData.qc.features.code; putDB(pushData.qc, QC_PREFIX + code); return { tags: pushData.qc.tags, code: code } // 多个命令导入 } else { for (var code of Object.keys(pushData.qc)) { putDB(pushData.qc[code], QC_PREFIX + code); } return true } } // 全部导出 let exportAll = (copy = false) => { let allQcs = getAllQuickCommands() let options = { title: '选择保存位置', defaultPath: 'quickCommand', filters: [ { name: 'json', extensions: ['json'] }, ] }; if (!isDev()) Object.keys(allQcs).forEach(k => { if (k.includes('default_')) delete allQcs[k] }) let stringifyQcs = JSON.stringify(allQcs) if (copy) utools.copyText(stringifyQcs) else window.saveFile(stringifyQcs, options); } // 清空 let clearAll = () => { quickcommand.showConfirmBox('将会清空所有自定义命令,请确认!').then(x => { if (!x) return exportAll(true) getDocs(QC_PREFIX).map(x => x._id).forEach(y => delDB(y)) importDefaultCommands(); clearAllFeatures(); showOptions(); quickcommand.showMessageBox('清空完毕,为防止误操作,已将所有命令复制到剪贴板,可通过导入命令恢复') }) } // 环境 const programs = { shell: { bin: 'bash', argv: '', ext: 'sh', color: '#89e051' }, applescript: { bin: 'osascript', argv: '', ext: 'scpt', color: '#101F1F' }, cmd: { bin: '', argv: '', ext: 'bat', codec: 'gbk', color: '#C1F12E' }, powershell: { bin: 'powershell', argv: '-NoProfile -File', ext: 'ps1', codec: utools.isWindows() ? 'gbk' : '', color: '#012456' }, python: { bin: 'python', argv: '-u', ext: 'py', codec: utools.isWindows() ? 'gbk' : '', color: '#3572A5' }, javascript: { bin: 'node', argv: '', ext: 'js', color: '#f1e05a' }, ruby: { bin: 'ruby', argv: '', ext: 'rb', color: '#701516' }, php: { bin: 'php', argv: '', ext: 'php', color: '#4F5D95' }, c: { bin: 'gcc', argv: '-o', ext: 'c', codec: utools.isWindows() ? 'gbk' : '', color: '#555555' }, csharp: { bin: 'C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\csc.exe', argv: '/Nologo', ext: 'cs', codec: 'gbk', color: '#178600' }, lua: { bin: 'lua', argv: '', ext: 'lua', color: '#000080' }, perl: { bin: 'perl', argv: '', ext: 'pl', color: '#0298c3' }, custom: { bin: '', argv: '', ext: '', codec: '', color: '#438eff' } } let getCmdsType = cmds => { try { JSON.stringify(cmds) } catch (error) { return 'illegal' } if (cmds.length == 0) return 'null' if (cmds.length == 1) { let type = cmds[0].type if (!type) return 'key' if (type == 'window' || cmds[0].minNum) return type return 'professional' } let counts = cmds.filter(x => typeof x == 'string').length return counts == cmds.length ? 'key' : 'professional' } let showCommandByType = features => { let qcType = '' let cmds = features.cmds let type = getCmdsType(cmds) if (type == 'professional') { qcType = `
匹 配
关键字
说 明
环 境 标 签
变 量 输 出
脚 本 ﹢动作 ﹢按键 ?文档 格式化
${(readonly && !isDev()) ? '' : ''}
${result}`) $('.swal2-popup').addClass('swal2-toast') } var contlength = content.length if (contlength > maxlength) content = content.slice(0, maxlength - 100) + `\n\n...\n${contlength - maxlength - 100} 字省略\n...\n\n` + content.slice(contlength - 100) content += '\n' var outputchannel = $("#swal2-content > pre") if (outputchannel.is(":parent")) { outputchannel.append(htmlEncode(content, raw)) } else { options = { onBeforeOpen: preView, icon: success ? "success" : "error", text: content, position: position, width: 800, showConfirmButton: true, showClass: { popup: showClass }, hideClass: { popup: hideClass } } Swal.fire(options) } } let replaceTempInputVals = async cmd => { let tempInputVals = [] let specilaVals = ['input', 'subinput', 'pwd', 'SelectFile', 'WindowInfo', 'MatchedFiles'] specilaVals.forEach(x => { let m = cmd.match(new RegExp('{{' + x + '.*?}}', 'g')) m && m.forEach(y => tempInputVals.includes(y) || tempInputVals.push(y)) }) if (!tempInputVals.length) return cmd let inputs = await quickcommand.showInputBox(tempInputVals, '需要临时为以下变量赋值') tempInputVals.forEach((t, n) => { cmd = cmd.replace(new RegExp(t, 'g'), inputs[n]) }) return cmd } let runCurrentCommand = async () => { if ($("#customize").is(":parent")) { var cmd = window.editor.getValue() cmd = special(cmd) cmd = await replaceTempInputVals(cmd) var program = $("#program").val() var output = $("#output").val() var terminal = false var raw = true switch (output) { case "html": raw = false break; case "terminal": terminal = true break; case "ignore": utools.hideMainWindow() break; } if (program == "quickcommand") { runCodeInVm(cmd, (stdout, stderr) => { if (stderr) return showRunResult(stderr, raw, false) showRunResult(stdout, raw, true) }); } else { var option = programs[program] if (program == "custom") option = { "bin": $('#custombin').val(), "argv": $('#customarg').val(), "ext": $('#customext').val(), 'codec': $('#customcodec').val() } option.scptarg = $('#scptarg').val() runCodeFile(cmd, option, terminal, (stdout, stderr) => { if (terminal) return if (stderr) return showRunResult(stderr, raw, false) showRunResult(stdout, raw, true) }) } } } let killCurrentCommand = () => { } let quitCurrentCommand = () => { if ($("#customize").is(":parent") && $("#featureList").is(":parent")) { $("#customize").animate({ top: '100%' }); $("#customize").empty() if ($('#customize').data('returnShare')) getSharedQCFromYuQue() } } let highlightIfKnown = ext => { var lang = Object.keys(programs).filter(p => programs[p].ext == ext) if (lang.length) { if (lang[0] == 'python') getPythonMods() window.editor.setOption("mode", lang[0]) return lang[0] } } let showCodeEditor = file => { var customWindow = `