完善执行命令功能 90%

This commit is contained in:
fofolee 2022-04-10 00:38:56 +08:00
parent e86fb1b02a
commit 73c5dbacee
9 changed files with 200 additions and 140 deletions

View File

@ -255,10 +255,6 @@ let getSleepCodeByShell = ms => {
return cmd return cmd
} }
let modWindowHeight = height => {
$('#options').is(':hidden') && utools.setExpendHeight(height > 600 ? 600 : height);
}
// 屏蔽危险函数 // 屏蔽危险函数
getuToolsLite = () => { getuToolsLite = () => {
var utoolsLite = Object.assign({}, utools) var utoolsLite = Object.assign({}, utools)
@ -564,6 +560,16 @@ getCurrentFolderPathFix = () => {
return pwdFix.replace(/\\/g, '\\\\') return pwdFix.replace(/\\/g, '\\\\')
} }
getMatchedFilesFix = payload => {
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('$', '$$$'))
})
}
saveFile = (content, file) => { saveFile = (content, file) => {
if (file instanceof Object) { if (file instanceof Object) {
file = utools.showSaveDialog(file) file = utools.showSaveDialog(file)
@ -580,18 +586,16 @@ yuQueClient = axios.create({
} }
}); });
getSelectFile = hwnd => getSelectFile = hwnd => {
new Promise((reslove, reject) => { if (utools.isWindows()) {
if (utools.isWindows()) { var cmd = `powershell.exe -NoProfile "(New-Object -COM 'Shell.Application').Windows() | Where-Object { $_.HWND -eq ${hwnd} } | Select-Object -Expand Document | select @{ n='SelectItems'; e={$_.SelectedItems()} } | select -Expand SelectItems | select -Expand Path "`;
var cmd = `powershell.exe -NoProfile "(New-Object -COM 'Shell.Application').Windows() | Where-Object { $_.HWND -eq ${hwnd} } | Select-Object -Expand Document | select @{ n='SelectItems'; e={$_.SelectedItems()} } | select -Expand SelectItems | select -Expand Path "`; let result = child_process.execSync(cmd, {
child_process.exec(cmd, { encoding: "buffer",
encoding: "buffer" windowsHide: true
}, (err, stdout, stderr) => { })
if (err) reject(stderr) return iconv.decode(result, 'GBK').trim().replace(/\\/g, '/');
else reslove(iconv.decode(stdout, 'GBK').trim().replace(/\\/g, '/')); } else {
}) var cmd = `osascript -e 'tell application "Finder" to set selectedItems to selection as alias list
} else {
var cmd = `osascript -e 'tell application "Finder" to set selectedItems to selection as alias list
if selectedItems is {} then return if selectedItems is {} then return
set parentPath to do shell script "dirname " & quoted form of POSIX path of (item 1 of selectedItems) set parentPath to do shell script "dirname " & quoted form of POSIX path of (item 1 of selectedItems)
set pathData to "" set pathData to ""
@ -600,45 +604,16 @@ getSelectFile = hwnd =>
end repeat end repeat
' '
` `
child_process.exec(cmd, (err, stdout, stderr) => { let result = child_process.execSync(cmd, {
if (err) reject(stderr) encoding: "utf8",
else reslove(stdout.trim()); windowsHide: true
}); })
} console.log(result);
}) return result ? result.trim() : ""
clipboardReadText = () => {
return electron.clipboard.readText()
},
special = cmd => {
// 判断是否 windows 系统
if (cmd.includes('{{isWin}}')) {
let repl = utools.isWindows() ? 1 : 0;
cmd = cmd.replace(/\{\{isWin\}\}/mg, repl)
}
// 获取本机唯一ID
if (cmd.includes('{{LocalId}}')) {
let repl = utools.getNativeId();
cmd = cmd.replace(/\{\{LocalId\}\}/mg, repl)
}
// 获取浏览器当前链接
if (cmd.includes('{{BrowserUrl}}')) {
let repl = utools.getCurrentBrowserUrl();
cmd = cmd.replace(/\{\{BrowserUrl\}\}/mg, repl)
}
// 获取剪切板的文本
if (cmd.includes('{{ClipText}}')) {
let repl = clipboardReadText();
cmd = cmd.replace(/\{\{ClipText\}\}/mg, repl)
}
// 获取选中的文本
// if (cmd.includes('{{SelectText}}')) {
// let repl = getSelectText();
// cmd = cmd.replace(/\{\{SelectText\}\}/mg, repl)
// }
return cmd;
} }
}
clipboardReadText = () => electron.clipboard.readText()
runCodeFile = (cmd, option, terminal, callback) => { runCodeFile = (cmd, option, terminal, callback) => {
var bin = option.bin, var bin = option.bin,

View File

@ -108,10 +108,9 @@
<span v-for="cmd in commandInfo.features.cmds" :key="cmd"> <span v-for="cmd in commandInfo.features.cmds" :key="cmd">
<span v-if="typeof cmd === 'string'"> <span v-if="typeof cmd === 'string'">
<q-badge rounded :color="cmdBadgeColor()" <q-badge rounded :color="cmdBadgeColor()"
><q-icon ><q-icon class="q-mr-xs" :name="commandTypes.key.icon" />{{
class="q-mr-xs" getShortStrByByte(cmd)
:name="commandTypes.key.icon" }}</q-badge
/>{{ getShortStrByByte(cmd) }}</q-badge
> >
<q-tooltip> <q-tooltip>
<div class="text-subtitle2"> <div class="text-subtitle2">
@ -302,9 +301,11 @@ export default {
}, },
// //
runCommand() { runCommand() {
utools.redirect( let event = {
this.commandInfo.features.cmds.filter((x) => x.length)[0] type: "run",
); data: this.commandInfo.features.code,
};
this.$emit("commandChanged", event);
}, },
// / // /
toggleCommandActivated() { toggleCommandActivated() {

View File

@ -361,7 +361,7 @@ export default {
// action run text // action run text
this.quickcommandInfo.output = this.quickcommandInfo.output =
this.$refs.menu?.currentCommand.output || "text"; this.$refs.menu?.currentCommand.output || "text";
this.$refs.result.runCurrentCommand(this.quickcommandInfo); this.$refs.result.runCurrentCommand(_.cloneDeep(this.quickcommandInfo));
}, },
}, },
}; };

View File

@ -165,13 +165,8 @@
<q-item v-bind="scope.itemProps"> <q-item v-bind="scope.itemProps">
<q-item-section> <q-item-section>
<q-item-label v-html="scope.opt.label" /> <q-item-label v-html="scope.opt.label" />
<q-tooltip v-if="!scope.opt.type"> <q-tooltip v-if="scope.opt.tooltip">
注意需要自行在变量两边加上引号"{{ scope.opt.label }}" {{ scope.opt.tooltip }}
</q-tooltip>
<q-tooltip v-else>
需要自行对json进行处理如json.loads(r"""{{
scope.opt.label
}}""")
</q-tooltip> </q-tooltip>
<q-item-label caption>{{ scope.opt.desc }}</q-item-label> <q-item-label caption>{{ scope.opt.desc }}</q-item-label>
</q-item-section> </q-item-section>
@ -337,7 +332,7 @@ export default {
this.cmdMatch = `/${this.cmdMatch}/`; this.cmdMatch = `/${this.cmdMatch}/`;
}, },
insertSpecialVar(text) { insertSpecialVar(text) {
this.$parent.$refs.editor.repacleEditorSelection(text); this.$parent.$refs.editor.repacleEditorSelection(`'${text}'`);
}, },
// //
SaveMenuData() { SaveMenuData() {

View File

@ -44,6 +44,7 @@
<script> <script>
import outputTypes from "../js/options/outputTypes.js"; import outputTypes from "../js/options/outputTypes.js";
import specialVars from "../js/options/specialVars.js";
export default { export default {
data() { data() {
@ -67,8 +68,8 @@ export default {
methods: { methods: {
// //
async runCurrentCommand(currentCommand) { async runCurrentCommand(currentCommand) {
currentCommand.cmd = window.special(currentCommand.cmd); currentCommand.cmd = this.assignSpecialVars(currentCommand.cmd);
currentCommand.cmd = await this.replaceTempInputVals(currentCommand.cmd); // currentCommand.cmd = await this.replaceTempInputVars(currentCommand.cmd);
let { hideWindow, outPlugin, action } = let { hideWindow, outPlugin, action } =
outputTypes[currentCommand.output]; outputTypes[currentCommand.output];
// //
@ -102,14 +103,24 @@ export default {
); );
} }
}, },
//
assignSpecialVars(cmd) {
let spVars = _.filter(specialVars, (sp) => sp.repl);
_.forIn(spVars, (val, key) => {
if (cmd.includes(val.label.slice(0, 12))) {
cmd = cmd.replace(val.match, (x) => val.repl(x));
}
});
return cmd;
},
// //
async replaceTempInputVals(cmd) { async replaceTempInputVars(cmd) {
let tempInputVals = []; let tempInputVals = [];
let needInputVal = [ let needInputVal = [
"input", "input",
"subinput", "subinput",
"pwd", "pwd",
"SelectFile", // "SelectFile",
"WindowInfo", "WindowInfo",
"MatchedFiles", "MatchedFiles",
]; ];

View File

@ -2,6 +2,50 @@
* 所有的匹配类型 * 所有的匹配类型
*/ */
const jsonSample = [
"关键词",
{
"type": "img",
"label": "图片匹配"
},
{
"type": "files",
"label": "文件匹配",
"fileType": "file",
"match": "/aaa/",
"minLength": 1,
"maxLength": 99
},
{
"type": "regex",
"label": "文本正则匹配",
"match": "/bbb/i",
"minLength": 1,
"maxLength": 99
},
{
"type": "over",
"label": "无匹配时",
"exclude": "/ccc/i",
"minLength": 1,
"maxLength": 99
},
{
"type": "window",
"label": "窗口动作",
"match": {
"app": [
"ddd.app",
"eee.exe"
],
"title": "/fff/",
"class": [
"ggg"
]
}
}
]
const commandTypes = { const commandTypes = {
key: { key: {
name: "key", name: "key",
@ -10,9 +54,9 @@ const commandTypes = {
matchLabel: "关键词", matchLabel: "关键词",
desc: "在主输入框输入对应关键字进入插件,最通用的一种模式,关键字可以设置多个", desc: "在主输入框输入对应关键字进入插件,最通用的一种模式,关键字可以设置多个",
valueType: "array", valueType: "array",
disabledSpecialVars: /{{input}}|{{SelectFile}}|{{pwd}}|{{WindowInfo}}|{{MatchedFiles}}/g, disabledSpecialVars: /{{input}}|{{SelectFile}}|{{pwd}}|{{WindowInfo.*?}}|{{MatchedFiles.*?}}/g,
matchToCmds: (rules, desc) => rules, matchToCmds: (rules, desc) => rules,
verify: (rules) => rules.length > 0 || "关键词不能为空", verify: (rules) => !_.isEmpty(rules) || "关键词不能为空",
}, },
regex: { regex: {
name: "regex", name: "regex",
@ -21,7 +65,7 @@ const commandTypes = {
icon: "rule", icon: "rule",
desc: "匹配主输入框或超级面板选中的文本,可以获取输入框文本或选中文本作为变量", desc: "匹配主输入框或超级面板选中的文本,可以获取输入框文本或选中文本作为变量",
valueType: "regex", valueType: "regex",
disabledSpecialVars: /{{SelectFile}}|{{WindowInfo}}|{{pwd}}|{{MatchedFiles}}/g, disabledSpecialVars: /{{SelectFile}}|{{WindowInfo.*?}}|{{pwd}}|{{MatchedFiles.*?}}/g,
matchToCmds: (rules, desc) => [{ matchToCmds: (rules, desc) => [{
label: desc, label: desc,
type: "regex", type: "regex",
@ -37,7 +81,7 @@ const commandTypes = {
icon: "emergency", icon: "emergency",
desc: "匹配主输入框的所有文本,但只有在该文本未设置对应的插件或功能时才生效", desc: "匹配主输入框的所有文本,但只有在该文本未设置对应的插件或功能时才生效",
valueType: null, valueType: null,
disabledSpecialVars: /{{SelectFile}}|{{WindowInfo}}|{{pwd}}|{{MatchedFiles}}/g, disabledSpecialVars: /{{SelectFile}}|{{WindowInfo.*?}}|{{pwd}}|{{MatchedFiles.*?}}/g,
matchToCmds: (rules, desc) => [{ matchToCmds: (rules, desc) => [{
label: desc, label: desc,
type: "over", type: "over",
@ -52,7 +96,7 @@ const commandTypes = {
icon: "widgets", icon: "widgets",
desc: "匹配呼出uTools前或唤出超级面板时的活动窗口可以获取窗口的信息或文件夹路径作为变量", desc: "匹配呼出uTools前或唤出超级面板时的活动窗口可以获取窗口的信息或文件夹路径作为变量",
valueType: "array", valueType: "array",
disabledSpecialVars: /{{input}}|{{MatchedFiles}}/g, disabledSpecialVars: /{{input}}|{{MatchedFiles.*?}}/g,
matchToCmds: (rules, desc) => [{ matchToCmds: (rules, desc) => [{
type: "window", type: "window",
label: desc, label: desc,
@ -60,7 +104,7 @@ const commandTypes = {
"app": rules "app": rules
} }
}], }],
verify: rules => rules.length > 0 || "进程名不能为空" verify: rules => !_.isEmpty(rules) || "进程名不能为空"
}, },
img: { img: {
name: "img", name: "img",
@ -69,7 +113,7 @@ const commandTypes = {
icon: "panorama", icon: "panorama",
desc: "匹配主输入框或超级面板选中的图片,并返回图片的 base64", desc: "匹配主输入框或超级面板选中的图片,并返回图片的 base64",
valueType: null, valueType: null,
disabledSpecialVars: /{{input}}|{{SelectFile}}|{{pwd}}|{{WindowInfo}}|{{MatchedFiles}}/g, disabledSpecialVars: /{{input}}|{{SelectFile}}|{{pwd}}|{{WindowInfo.*?}}|{{MatchedFiles.*?}}/g,
matchToCmds: (rules, desc) => [{ matchToCmds: (rules, desc) => [{
label: desc, label: desc,
type: "img", type: "img",
@ -83,7 +127,7 @@ const commandTypes = {
icon: "description", icon: "description",
desc: "匹配主输入框或超级面板选中的文件,可以获取复制及选中的文件信息作为变量", desc: "匹配主输入框或超级面板选中的文件,可以获取复制及选中的文件信息作为变量",
valueType: "regex", valueType: "regex",
disabledSpecialVars: /{{input}}|{{SelectFile}}|{{pwd}}|{{WindowInfo}}/g, disabledSpecialVars: /{{input}}|{{SelectFile}}|{{pwd}}|{{WindowInfo.*?}}/g,
matchToCmds: (rules, desc) => [{ matchToCmds: (rules, desc) => [{
type: "files", type: "files",
label: desc, label: desc,
@ -110,50 +154,8 @@ const commandTypes = {
return "专业模式json配置错误" return "专业模式json配置错误"
} }
}, },
jsonSample: [ jsonSample: jsonSample
"关键词",
{
"type": "img",
"label": "图片匹配"
},
{
"type": "files",
"label": "文件匹配",
"fileType": "file",
"match": "/aaa/",
"minLength": 1,
"maxLength": 99
},
{
"type": "regex",
"label": "文本正则匹配",
"match": "/bbb/i",
"minLength": 1,
"maxLength": 99
},
{
"type": "over",
"label": "无匹配时",
"exclude": "/ccc/i",
"minLength": 1,
"maxLength": 99
},
{
"type": "window",
"label": "窗口动作",
"match": {
"app": [
"ddd.app",
"eee.exe"
],
"title": "/fff/",
"class": [
"ggg"
]
}
}
]
} }
} }
export default commandTypes export default commandTypes

View File

@ -2,65 +2,126 @@
* 所有的特殊变量 * 所有的特殊变量
*/ */
let escapeItem = item => {
if (typeof item === 'number') return item
item = typeof item === 'object' ? JSON.stringify(item) : item.replace('\\', '\\\\')
return item.replace('$', '$$$')
}
let parseTheFirstLayerOfObjects = obj => {
let matched = /{{(\w+)(\[(\d+)\]){0,1}\.(\w+)}}/.exec(obj);
return matched ? {
obj: matched[1],
index: matched[3],
prop: matched[4],
} : {};
}
let handlingJsonVar = (jsonVar, srcObj) => {
try {
let parsed = parseTheFirstLayerOfObjects(jsonVar);
if (!parsed.obj) return escapeItem(srcObj)
else if (!parsed.index) return escapeItem(srcObj[parsed.prop])
else return escapeItem(srcObj[parsed.index][parsed.prop])
} catch {
return ""
}
}
const specialVars = { const specialVars = {
isWin: {
name: "isWin",
label: "{{isWin}}",
desc: "是否为 windows 系统,返回 0 或 1",
disabledType: [],
match: /{{isWin}}/mg,
repl: () => utools.isWindows() ? 1 : 0
},
LocalId: { LocalId: {
name: "LocalId", name: "LocalId",
label: "{{LocalId}}", label: "{{LocalId}}",
desc: "本机唯一ID" desc: "本机唯一ID",
disabledType: [],
match: /{{LocalId}}/mg,
repl: () => utools.getNativeId()
}, },
BrowserUrl: { BrowserUrl: {
name: "BrowserUrl", name: "BrowserUrl",
label: "{{BrowserUrl}}", label: "{{BrowserUrl}}",
desc: "浏览器当前链接" disabledType: [],
desc: "浏览器当前链接",
match: /{{BrowserUrl}}/mg,
repl: () => utools.getCurrentBrowserUrl()
}, },
ClipText: { ClipText: {
name: "ClipText", name: "ClipText",
label: "{{ClipText}}", label: "{{ClipText}}",
desc: "剪贴板内容" disabledType: [],
desc: "剪贴板内容",
match: /{{ClipText}}/mg,
repl: () => window.clipboardReadText()
}, },
subinput: { subinput: {
name: "subinput", name: "subinput",
label: "{{subinput}}", label: "{{subinput}}",
desc: "子输入框的文本" disabledType: [],
tooltip: `可以自定义占位符,如{{subinput:请输入}}`,
desc: "子输入框的文本",
match: /{{subinput(:.+?){0,1}}}/mg,
}, },
input: { input: {
name: "input", name: "input",
label: "{{input}}", label: "{{input}}",
desc: "主输入框的文本" desc: "主输入框的文本",
match: /{{input}}/mg,
repl: () => quickcommand.enterData.payload
}, },
pwd: { pwd: {
name: "pwd", name: "pwd",
label: "{{pwd}}", label: "{{pwd}}",
desc: "文件管理器当前目录" desc: "文件管理器当前目录",
match: /{{pwd}}/mg,
repl: () => window.getCurrentFolderPathFix()
}, },
WindowInfo: { WindowInfo: {
name: "WindowInfo", name: "WindowInfo",
label: "{{WindowInfo}}", label: "{{WindowInfo}}",
desc: "当前窗口信息JSON格式字符串", desc: "当前窗口信息JSON格式字符串",
type: "json" tooltip: `可以选择性读取其中的某一个属性,如{{WindowInfo.id}}`,
type: "json",
match: /{{WindowInfo(\.\w{1,7}){0,1}}}/mg,
repl: jsonVar => handlingJsonVar(jsonVar, quickcommand.enterData.payload)
}, },
SelectFile: { SelectFile: {
name: "SelectFile", name: "SelectFile",
label: "{{SelectFile}}", label: "{{SelectFile}}",
desc: "文件管理器选中的文件不支持Linux" desc: "文件管理器选中的文件不支持Linux",
match: /{{SelectFile}}/mg,
repl: () => window.getSelectFile(quickcommand.enterData.payload.id)
}, },
MatchedFiles: { MatchedFiles: {
name: "MatchedFiles", name: "MatchedFiles",
label: "{{MatchedFiles}}", label: "{{MatchedFiles}}",
tooltip: `可以选择性读取其中的某一个属性,如{{MatchedFiles[0].path}}`,
desc: "匹配的文件JSON格式字符串", desc: "匹配的文件JSON格式字符串",
type: "json" type: "json",
match: /{{MatchedFiles(\[\d+\]){0,1}(\.\w{1,11}){0,1}}}/mg,
repl: jsonVar => handlingJsonVar(jsonVar, quickcommand.enterData.payload)
}, },
type: { type: {
name: "type", name: "type",
label: "{{type}}", label: "{{type}}",
desc: "专业模式的type" desc: "专业模式的type",
match: /{{type}}/mg,
repl: () => quickcommand.enterData.type
}, },
payload: { payload: {
name: "payload", name: "payload",
label: "{{payload}}", label: "{{payload}}",
desc: "专业模式的payload,JSON格式字符串", desc: "专业模式的payload",
type: "json" match: /{{payload}}/mg,
repl: () => escapeItem(quickcommand.enterData.payload)
} }
} }
export default specialVars export default specialVars

View File

@ -29,7 +29,7 @@ export default {
}, },
methods: { methods: {
runCurrentCommand() { runCurrentCommand() {
this.$refs.result.runCurrentCommand(this.currentCommand); this.$refs.result.runCurrentCommand(_.cloneDeep(this.currentCommand));
}, },
}, },
}; };

View File

@ -187,6 +187,10 @@
></CommandEditor> ></CommandEditor>
</q-card> </q-card>
</q-dialog> </q-dialog>
<CommandRunResult
:action="{ type: 'inPlugin' }"
ref="result"
></CommandRunResult>
</div> </div>
</template> </template>
@ -195,6 +199,7 @@ import { defineAsyncComponent } from "vue";
import quickcommandParser from "../js/common/quickcommandParser.js"; import quickcommandParser from "../js/common/quickcommandParser.js";
import CommandCard from "components/CommandCard"; import CommandCard from "components/CommandCard";
import ConfigurationMenu from "components/ConfigurationMenu.vue"; import ConfigurationMenu from "components/ConfigurationMenu.vue";
import CommandRunResult from "components/CommandRunResult.vue";
import importAll from "../js/common/importAll.js"; import importAll from "../js/common/importAll.js";
const CommandEditor = defineAsyncComponent(() => const CommandEditor = defineAsyncComponent(() =>
@ -209,6 +214,7 @@ export default {
CommandCard, CommandCard,
ConfigurationMenu, ConfigurationMenu,
CommandEditor, CommandEditor,
CommandRunResult,
}, },
data() { data() {
return { return {
@ -352,10 +358,19 @@ export default {
return; return;
case "edit": case "edit":
this.editCommand(event.data); this.editCommand(event.data);
return;
case "run":
this.runCommand(event.data);
return;
default: default:
return; return;
} }
}, },
runCommand(code) {
this.$refs.result.runCurrentCommand(
_.cloneDeep(this.allQuickCommands[code])
);
},
// //
enableCommand(code) { enableCommand(code) {
this.$utools.whole.setFeature( this.$utools.whole.setFeature(