支持运行代码,编辑器加强

This commit is contained in:
fofolee 2020-06-14 10:34:13 +08:00
parent 0e26010751
commit 92986837ec

View File

@ -1,10 +1,10 @@
getCustomFts = () => { let getCustomFts = () => {
var db = utools.db.get("customFts"), var db = utools.db.get("customFts"),
customFts = db ? db.data : {}; customFts = db ? db.data : {};
return customFts; return customFts;
} }
putCustomFts = (code, pushData) => { let putCustomFts = (code, pushData) => {
var db = utools.db.get("customFts"); var db = utools.db.get("customFts");
if (db) { if (db) {
var rev = db._rev var rev = db._rev
@ -19,15 +19,14 @@ putCustomFts = (code, pushData) => {
} }
// 导入 // 导入
importCommand = () => { let importCommand = () => {
var options = { var options = {
filters: [{ name: 'json', extensions: ['json'] }, ] filters: [{ name: 'json', extensions: ['json'] }, ]
} }
var file = window.openFolder(options)[0]; var file = openFileInDialog(options, true)
if (file) { if (file) {
var data = readFile(file)
try { try {
var pushData = JSON.parse(data); var pushData = JSON.parse(file.data);
} catch (error) { } catch (error) {
Swal.fire({ Swal.fire({
icon: 'error', icon: 'error',
@ -59,7 +58,7 @@ importCommand = () => {
} }
} }
exportAll = () => { let exportAll = () => {
json = utools.db.get('customFts').data, json = utools.db.get('customFts').data,
options = { options = {
title: '选择保存位置', title: '选择保存位置',
@ -72,7 +71,7 @@ window.saveFile(options, JSON.stringify(json));
} }
clearAll = () => { let clearAll = () => {
Swal.fire({ Swal.fire({
text: '将会清空所有命令,请确认!', text: '将会清空所有命令,请确认!',
icon: 'warning', icon: 'warning',
@ -90,7 +89,7 @@ clearAll = () => {
}) })
} }
programs = { let programs = {
shell: { shell: {
bin: 'bash', bin: 'bash',
argv: '', argv: '',
@ -111,13 +110,13 @@ programs = {
bin: 'powershell', bin: 'powershell',
argv: '-NoProfile -File', argv: '-NoProfile -File',
ext: 'ps1', ext: 'ps1',
codec: isWin ? 'gbk' : '' codec: utools.isWindows() ? 'gbk' : ''
}, },
python: { python: {
bin: 'python', bin: 'python',
argv: '-u', argv: '-u',
ext: 'py', ext: 'py',
codec: isWin ? 'gbk' : '' codec: utools.isWindows() ? 'gbk' : ''
}, },
javascript: { javascript: {
bin: 'node', bin: 'node',
@ -152,7 +151,7 @@ programs = {
} }
} }
showOptions = () => { let showOptions = () => {
$("#featureList").remove(); $("#featureList").remove();
var currentFts = utools.getFeatures(), var currentFts = utools.getFeatures(),
customFts = getCustomFts(); customFts = getCustomFts();
@ -187,9 +186,9 @@ showOptions = () => {
<span class="text-switch"></span> <span class="text-switch"></span>
<span class="toggle-btn"></span> <span class="toggle-btn"></span>
</label> </label>
<span class="Btn editBtn" code="${features.code}"><img src="img/edit.png"></span> <span class="Btn editBtn" code="${features.code}"><img src="img/edit.svg"></span>
<span class="Btn exportBtn" code="${features.code}"><img src="img/export.png"></span> <span class="Btn exportBtn" code="${features.code}"><img src="img/export.svg"></span>
<span class="Btn delBtn" code="${features.code}"><img src="img/del.png"></span> <span class="Btn delBtn" code="${features.code}"><img src="img/del.svg"></span>
</td>` </td>`
}; };
featureList += `</tr></table><div class="foot"> featureList += `</tr></table><div class="foot">
@ -204,7 +203,7 @@ showOptions = () => {
$("#options").append(featureList); $("#options").append(featureList);
} }
showCustomize = () => { let showCustomize = () => {
$("#customize").remove(); $("#customize").remove();
let options = `<option>${Object.keys(programs).join('</option><option>')}</option>` let options = `<option>${Object.keys(programs).join('</option><option>')}</option>`
customWindow = `<div id="customize"> customWindow = `<div id="customize">
@ -272,7 +271,7 @@ showCustomize = () => {
<span id="addKey" class="robot footBtn">按键</span> <span id="addKey" class="robot footBtn">按键</span>
<select id="action" class="robot keys"> <select id="action" class="robot keys">
<option value="" style="display:none">预设动作</option> <option value="" style="display:none">预设动作</option>
<option value="await sleep">添加延时</option> <option value="sleep">添加延时</option>
<option value="open">打开文件</option> <option value="open">打开文件</option>
<option value="visit">打开网址</option> <option value="visit">打开网址</option>
<option value="locate">定位文件</option> <option value="locate">定位文件</option>
@ -294,29 +293,70 @@ showCustomize = () => {
<input type="text" id="customcodec" class="customscript" placeholder="输出编码"> <input type="text" id="customcodec" class="customscript" placeholder="输出编码">
</span> </span>
</p> </p>
<p><textarea id="cmd" placeholder="可以直接拖放脚本文件至此处"></textarea></p> <p><textarea id="cmd" placeholder="可以直接拖放脚本文件至此处, 支持VSCode快捷键\nAlt+Enter 全屏\nCtrl+B 运行\nCtrl+S 保存\nCtrl+Q 取消\nCtrl+F 搜索"></textarea></p>
<p> <p>
<button class="saveBtn">保存</button> <button class="cmdBtn save">保存</button>
<button class="cancelBtn">取消</button> <button class="cmdBtn run">运行</button>
<button class="cmdBtn cancel">取消</button>
</p>` </p>`
$("#options").append(customWindow) $("#options").append(customWindow)
$("#icon").attr('src', 'logo/simulation.png'); $("#icon").attr('src', 'logo/simulation.png');
getSpecialVars()
window.editor = CodeMirror.fromTextArea(document.getElementById("cmd"), { window.editor = CodeMirror.fromTextArea(document.getElementById("cmd"), {
lineNumbers: true, lineNumbers: true,
lineWrapping: true matchBrackets: true,
lineWrapping: true,
autoCloseBrackets: true,
styleActiveLine: true,
keyMap: "vscode",
theme: "mdn-like",
extraKeys: {
"Alt-Enter": cm => {
cm.setOption("fullScreen", !cm.getOption("fullScreen"));
},
"Ctrl-B": () => {
runQuickCommand()
},
"Ctrl-S": () => {
SaveQuickCommand()
},
"Ctrl-Q": () => {
quitQuickCommand()
},
"Ctrl-F": "findPersistent",
}
});
window.editor.on("cursorActivity", function () {
editor.showHint({
completeSingle: false
});
}); });
window.editor.setOption("mode", 'javascript'); window.editor.setOption("mode", 'javascript');
$("#customize").animate({ top: '0px' }); $("#customize").animate({ top: '0px' });
} }
// 获取特殊变量
let getSpecialVars = () => {
var specialVars = []
$("#vars option").each(i => {
var selector = $("#vars option").eq(i)
if (selector.css('display') != 'none') specialVars.push(selector.val())
})
localStorage['specialVars'] = specialVars
}
// 重置变量下拉框 // 重置变量下拉框
resetVars = () => { let resetVars = () => {
$('#vars').val(""); $('#vars').val("");
$("#vars").css({ 'color': '#999' }); $("#vars").css({ 'color': '#999' });
} }
// 检查输出选项 // 检查输出选项
outputCheck = () => { let outputCheck = () => {
var output = $("#output").val() var output = $("#output").val()
if (output == 'text' || output == 'html') { if (output == 'text' || output == 'html') {
$(".selectText").hide() $(".selectText").hide()
@ -326,7 +366,7 @@ outputCheck = () => {
} }
// 检查模式选项 // 检查模式选项
typeCheck = () => { let typeCheck = () => {
var type = $("#type").val(); var type = $("#type").val();
// $("#output, #program, #vars").prop("disabled", false); // $("#output, #program, #vars").prop("disabled", false);
// $('.varoutput').show() // $('.varoutput').show()
@ -343,7 +383,7 @@ typeCheck = () => {
$("#ruleWord").html("正&#12288;则"); $("#ruleWord").html("正&#12288;则");
$(".var.regex").show() $(".var.regex").show()
$(".var.window").hide() $(".var.window").hide()
$("#rule").prop("placeholder", '匹配的正则规则,如/\\w+/i'); $("#rule").prop("placeholder", '匹配的正则规则,如 /.*?\\.exe$/i');
break; break;
case 'window': case 'window':
$("#ruleWord").html("进&#12288;程"); $("#ruleWord").html("进&#12288;程");
@ -354,14 +394,45 @@ typeCheck = () => {
default: default:
break; break;
} }
getSpecialVars()
} }
clearAllFeatures = () => { let clearAllFeatures = () => {
for (var fts of utools.getFeatures()) { for (var fts of utools.getFeatures()) {
utools.removeFeature(fts.code) utools.removeFeature(fts.code)
} }
} }
let hasCustomIcon = () => {
var src = $("#icon").attr('src');
var iconame = $("#iconame").val();
return /data:image\/png;base64,/.test(src) || iconame
}
let programCheck = () => {
let mode = $('#program').val();
if (!hasCustomIcon()) $("#icon").attr('src', `logo/${mode}.png`);
switch (mode) {
case 'custom':
$('.customscript').show();
$('.simulation').hide();
$('.varoutput').show();
break;
case 'simulation':
$('.varoutput').hide();
$('.simulation').show();
$('.customscript').hide();
mode = 'javascript';
break;
default:
$('.customscript').hide();
$('.simulation').hide();
$('.varoutput').show();
break;
}
window.editor.setOption("mode", mode);
}
// 开关 // 开关
$("#options").on('change', 'input[type=checkbox]', function () { $("#options").on('change', 'input[type=checkbox]', function () {
var customFts = getCustomFts(), var customFts = getCustomFts(),
@ -391,11 +462,6 @@ $("#options").on('click', '.footBtn', function () {
} }
}) })
// 取消
$("#options").on('click', '.cancelBtn', function () {
$("#customize").animate({ top: '100%'});
})
// 编辑 // 编辑
$("#options").on('click', '.editBtn', function () { $("#options").on('click', '.editBtn', function () {
var code = $(this).attr('code'); var code = $(this).attr('code');
@ -424,9 +490,6 @@ $("#options").on('click', '.editBtn', function () {
$('#customext').show().val(data.customOptions.ext); $('#customext').show().val(data.customOptions.ext);
$('#customcodec').show().val(data.customOptions.codec); $('#customcodec').show().val(data.customOptions.codec);
} }
// mode == 'applescript' && (mode = 'shell');
// mode == 'cmd' && (mode = 'powershell');
// window.editor.setOption("mode", mode);
window.editor.setValue(data.cmd); window.editor.setValue(data.cmd);
resetVars(); resetVars();
typeCheck(); typeCheck();
@ -570,13 +633,14 @@ $("#options").on('click', '#icon, #iconame', function () {
extensions: ['png'] extensions: ['png']
}, ] }, ]
} }
let iconpath = window.openFolder(options)[0]; var file = openFileInDialog(options, false)
$("#iconame").val(basename(iconpath)); if (file) {
$("#icon").attr('src', iconpath); $("#iconame").val(file.name);
$("#icon").attr('src', file.path);
}
}) })
// 保存 let SaveQuickCommand = async () => {
$("#options").on('click', '.saveBtn', async function () {
var type = $('#type').val(); var type = $('#type').val();
var code = $("#code").val(); var code = $("#code").val();
if (!code) { if (!code) {
@ -613,7 +677,14 @@ $("#options").on('click', '.saveBtn', async function () {
title: '啊嘞?!', title: '啊嘞?!',
text: '显示文本或html输出时无法使用{{SelectText}}!', text: '显示文本或html输出时无法使用{{SelectText}}!',
}) })
} else { } else if (type == 'regex' && /^(|\/)\.[*+](|\/)$/.test($('#rule').val())) {
Swal.fire({
icon: 'error',
title: '啊嘞?!',
text: '正则匹配 .* 和 .+ 已被uTools禁用',
})
}
else {
var program = $('#program').val(), var program = $('#program').val(),
desc = $('#desc').val(), desc = $('#desc').val(),
iconame = $("#iconame").val(), iconame = $("#iconame").val(),
@ -700,40 +771,89 @@ $("#options").on('click', '.saveBtn', async function () {
$(`#${code}`).click(); $(`#${code}`).click();
} }
} }
})
hasCustomIcon = () => {
var src = $("#icon").attr('src');
var iconame = $("#iconame").val();
return /data:image\/png;base64,/.test(src) || iconame
} }
programCheck = () => { // 显示运行结果
let mode = $('#program').val(); let showResult = (content, raw, success) => {
if (!hasCustomIcon()) $("#icon").attr('src', `logo/${mode}.png`); var options
switch (mode) { var htmlEncode = value => {
case 'custom': return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;")
$('.customscript').show(); }
$('.simulation').hide(); var preView = () => {
$('.varoutput').show(); var result = $('#swal2-content').text()
var style = "text-align: left; padding: 0px 10px; white-space: pre-wrap; word-break: break-all;"
if (raw) result = htmlEncode(result)
$('#swal2-content').html(`<pre style="${style}">${result}</pre>`)
$('.swal2-popup').addClass('swal2-toast')
}
options = {
onBeforeOpen: preView,
icon: success ? "success" : "error",
text: content,
position: 'top',
width: 800,
showConfirmButton: false,
showClass: {
popup: 'fadeInDownWindow'
},
hideClass: {
popup: 'fadeOutUpWindow'
}
}
Swal.fire(options)
}
let runQuickCommand = () => {
var cmd = window.editor.getValue()
var program = $("#program").val()
var output = $("#output").val()
var terminal = false
var raw = true
switch (output) {
case "html":
raw = false
break; break;
case 'simulation': case "terminal":
$('.varoutput').hide(); terminal = true
$('.simulation').show();
$('.customscript').hide();
mode = 'javascript';
break; break;
default: case "ignore":
$('.customscript').hide(); if(program != "simulation") utools.hideMainWindow() // todo 模拟操作选择输出方式
$('.simulation').hide();
$('.varoutput').show();
break; break;
} }
if('applescript') mode = 'shell'; if (program == "simulation") {
if('cmd') mode = 'powershell'; runCodeInVm(cmd, (stdout, stderr) => {
window.editor.setOption("mode", mode); if (stderr) return showResult(stderr, raw, false)
showResult(stdout, raw, true)
});
} else {
var option = programs[program]
runCodeFile(cmd, option, terminal, (stdout, stderr) => {
if(terminal) return
if (stderr) return showResult(stderr, raw, false)
showResult(stdout, raw, true)
})
}
} }
let quitQuickCommand = () => {
$("#customize").animate({ top: '100%'});
}
// 运行
$("#options").on('click', '.cmdBtn.run', function () {
runQuickCommand()
})
// 取消
$("#options").on('click', '.cmdBtn.cancel', function () {
quitQuickCommand()
})
// 保存
$("#options").on('click', '.cmdBtn.save', function () {
SaveQuickCommand()
})
// 语言选项改变时 // 语言选项改变时
$("#options").on('change', '#program', function () { $("#options").on('change', '#program', function () {
programCheck() programCheck()
@ -755,7 +875,6 @@ $("#options").on('change', '#output', function () {
outputCheck(); outputCheck();
}) })
// 方式选项改变时 // 方式选项改变时
$("#options").on('change', '#type', function () { $("#options").on('change', '#type', function () {
resetVars(); resetVars();