diff --git a/plugin/lib/getQuickcommandTempFile.js b/plugin/lib/getQuickcommandFile.js similarity index 52% rename from plugin/lib/getQuickcommandTempFile.js rename to plugin/lib/getQuickcommandFile.js index d30b27f..e6c7e80 100644 --- a/plugin/lib/getQuickcommandTempFile.js +++ b/plugin/lib/getQuickcommandFile.js @@ -9,4 +9,13 @@ const getQuickcommandTempFile = (ext, name, dir = "quickcommandTempDir") => { return path.join(tempDir, `${name}.${ext}`); }; -module.exports = getQuickcommandTempFile; +const getQuickcommandFolderFile = (name, ext) => { + const quickcommandPath = path.join( + window.utools.getPath("userData"), + "quickcommand" + ); + if (!fs.existsSync(quickcommandPath)) fs.mkdirSync(quickcommandPath); + return path.join(quickcommandPath, `${name}.${ext}`); +}; + +module.exports = { getQuickcommandTempFile, getQuickcommandFolderFile }; diff --git a/plugin/lib/quickcommand.js b/plugin/lib/quickcommand.js index 6ffafdd..d6c4a9b 100644 --- a/plugin/lib/quickcommand.js +++ b/plugin/lib/quickcommand.js @@ -6,7 +6,10 @@ const iconv = require("iconv-lite"); const path = require("path"); const axios = require("axios"); -const getQuickcommandTempFile = require("./getQuickcommandTempFile"); +const systemDialog = require("./systemDialog"); + +const { getQuickcommandTempFile } = require("./getQuickcommandFile"); + const getCommandToLaunchTerminal = require("./getCommandToLaunchTerminal"); const ctlKey = window.utools.isMacOs() ? "command" : "control"; @@ -262,6 +265,7 @@ if (process.platform === "win32") { }); }); }; + quickcommand.showSystemTextArea = systemDialog.showSystemTextArea; } if (process.platform === "darwin") { @@ -296,17 +300,18 @@ window.runPythonCommand = (py) => { } }; -// 在终端中执行 if (process.platform !== "linux") { + // 在终端中执行 quickcommand.runInTerminal = function (cmdline, dir) { let command = getCommandToLaunchTerminal(cmdline, dir); child_process.exec(command); }; + // 系统级弹窗 + quickcommand.showSystemMessageBox = systemDialog.showSystemMessageBox; + quickcommand.showSystemInputBox = systemDialog.showSystemInputBox; + quickcommand.showSystemConfirmBox = systemDialog.showSystemConfirmBox; + quickcommand.showSystemSelectList = systemDialog.showSystemSelectList; + quickcommand.showSystemButtonBox = systemDialog.showSystemButtonBox; } -quickcommand.showSystemMessageBox = function (title, content) { - window.utools.showNotification(title + "\n" + content); - console.log(title + "\n" + content); -}; - module.exports = quickcommand; diff --git a/plugin/lib/systemDialog.js b/plugin/lib/systemDialog.js new file mode 100644 index 0000000..b0e1ef0 --- /dev/null +++ b/plugin/lib/systemDialog.js @@ -0,0 +1,425 @@ +const fs = require("fs"); +const path = require("path"); +const { getQuickcommandFolderFile } = require("./getQuickcommandFile"); + +const getQuickcommandIconPath = () => { + try { + const iconPath = getQuickcommandFolderFile("logo", "png"); + if (!fs.existsSync(iconPath)) { + fs.copyFileSync(path.join(__dirname, "..", "logo.png"), iconPath); + } + return iconPath; + } catch (error) { + console.error(error); + return null; + } +}; + +const showSystemMessageBox = async function (content, title = "") { + const iconPath = getQuickcommandIconPath(); + if (window.utools.isMacOs()) { + let iconParam = "note"; + if (iconPath) { + const posixPath = iconPath.replace(/\\/g, "/"); + iconParam = `alias POSIX file "${posixPath}"`; + } + const script = `display dialog "${content}" with title "${title}" buttons {"确定"} default button "确定" with icon ${iconParam}`; + await this.runAppleScript(script); + } else if (window.utools.isWindows()) { + const csharpScript = ` + using System.Windows.Forms; + using System.Drawing; + using System.IO; + class Program { + static void Main() { + Form form = new Form(); + ${ + iconPath + ? `using (var bmp = new Bitmap("${iconPath}")) + { + form.Icon = Icon.FromHandle(bmp.GetHicon()); + }` + : "" + } + MessageBox.Show(form, "${content}", "${title}", + MessageBoxButtons.OK, + MessageBoxIcon.Information); + form.Dispose(); + } + }`; + await this.runCsharp(csharpScript); + } +}; + +// 系统级输入框 +const showSystemInputBox = async function (placeholders, title = "") { + if (!Array.isArray(placeholders)) { + placeholders = [placeholders]; + } + + const iconPath = getQuickcommandIconPath(); + if (window.utools.isMacOs()) { + let iconParam = "note"; + if (iconPath) { + const posixPath = iconPath.replace(/\\/g, "/"); + iconParam = `alias POSIX file "${posixPath}"`; + } + + const results = []; + for (let i = 0; i < placeholders.length; i++) { + const isLast = i === placeholders.length - 1; + const buttons = isLast ? '{"取消", "确定"}' : '{"取消", "继续"}'; + const defaultButton = isLast ? '"确定"' : '"继续"'; + const script = `display dialog "${placeholders[i]}" with title "${title}" default answer "" buttons ${buttons} default button ${defaultButton} with icon ${iconParam}`; + const result = await this.runAppleScript(script); + const buttonClicked = isLast ? "确定" : "继续"; + if (!result.includes(`button returned:${buttonClicked}`)) { + return null; + } + const text = result.match(/text returned:(.+)/)[1]; + results.push(text); + } + return results; + } else if (window.utools.isWindows()) { + const csharpScript = ` + using System.Windows.Forms; + using System.Drawing; + using System.IO; + class Program { + static void Main() { + Form form = new Form(); + form.Text = "${title}"; + form.ClientSize = new Size(300, ${50 + placeholders.length * 70}); + form.FormBorderStyle = FormBorderStyle.FixedDialog; + form.StartPosition = FormStartPosition.CenterScreen; + form.MaximizeBox = false; + form.MinimizeBox = false; + ${ + iconPath + ? `using (var bmp = new Bitmap("${iconPath}")) + { + form.Icon = Icon.FromHandle(bmp.GetHicon()); + }` + : "" + } + + ${placeholders + .map( + (placeholder, index) => ` + Label label${index} = new Label(); + label${index}.Text = "${placeholder}"; + label${index}.SetBounds(10, ${10 + index * 70}, 280, 20); + form.Controls.Add(label${index}); + + TextBox textBox${index} = new TextBox(); + textBox${index}.SetBounds(10, ${35 + index * 70}, 280, 20); + form.Controls.Add(textBox${index});` + ) + .join("\n")} + + Button okButton = new Button(); + okButton.Text = "确定"; + okButton.DialogResult = DialogResult.OK; + okButton.SetBounds(120, ${20 + placeholders.length * 70}, 75, 23); + form.Controls.Add(okButton); + + Button cancelButton = new Button(); + cancelButton.Text = "取消"; + cancelButton.DialogResult = DialogResult.Cancel; + cancelButton.SetBounds(210, ${ + 20 + placeholders.length * 70 + }, 75, 23); + form.Controls.Add(cancelButton); + + form.AcceptButton = okButton; + form.CancelButton = cancelButton; + + if (form.ShowDialog() == DialogResult.OK) { + ${placeholders + .map((_, index) => `Console.WriteLine(textBox${index}.Text);`) + .join("\n ")} + } + form.Dispose(); + } + }`; + const result = await this.runCsharp(csharpScript); + const lines = result.trim().split("\n"); + return lines.length > 0 && lines[0] !== "" ? lines : null; + } +}; + +// 系统级确认框 +const showSystemConfirmBox = async function (content, title = "") { + const iconPath = getQuickcommandIconPath(); + if (window.utools.isMacOs()) { + let iconParam = "note"; + if (iconPath) { + const posixPath = iconPath.replace(/\\/g, "/"); + iconParam = `alias POSIX file "${posixPath}"`; + } + const script = `display dialog "${content}" with title "${title}" buttons {"取消", "确定"} default button "确定" with icon ${iconParam}`; + const result = await this.runAppleScript(script); + return result.includes("button returned:确定"); + } else if (window.utools.isWindows()) { + const csharpScript = ` + using System.Windows.Forms; + using System.Drawing; + using System.IO; + class Program { + static void Main() { + Form form = new Form(); + ${ + iconPath + ? `using (var bmp = new Bitmap("${iconPath}")) + { + form.Icon = Icon.FromHandle(bmp.GetHicon()); + }` + : "" + } + DialogResult result = MessageBox.Show(form, "${content}", "${title}", + MessageBoxButtons.OKCancel, + MessageBoxIcon.Question); + Console.WriteLine(result == DialogResult.OK); + form.Dispose(); + } + }`; + const result = await this.runCsharp(csharpScript); + return result.trim() === "True"; + } +}; + +// 系统级选择框 +const showSystemSelectList = async function (items, title = "") { + const iconPath = getQuickcommandIconPath(); + if (window.utools.isMacOs()) { + const itemList = items.map((item) => `"${item}"`).join(", "); + const script = `choose from list {${itemList}} with title "${title}" with prompt "请选择:" default items {"${items[0]}"}`; + const result = await this.runAppleScript(script); + if (result.includes("false")) return null; + const text = result.trim(); + const id = items.findIndex((item) => item === text); + return { id, text }; + } else if (window.utools.isWindows()) { + const csharpScript = ` + using System.Windows.Forms; + using System.Drawing; + using System.IO; + class Program { + static void Main() { + Form form = new Form(); + ListBox listBox = new ListBox(); + Button okButton = new Button(); + Button cancelButton = new Button(); + + form.Text = "${title}"; + form.ClientSize = new Size(300, 250); + form.FormBorderStyle = FormBorderStyle.FixedDialog; + form.StartPosition = FormStartPosition.CenterScreen; + form.MaximizeBox = false; + form.MinimizeBox = false; + ${ + iconPath + ? `using (var bmp = new Bitmap("${iconPath}")) + { + form.Icon = Icon.FromHandle(bmp.GetHicon()); + }` + : "" + } + + listBox.SetBounds(10, 10, 280, 180); + ${items + .map((item, index) => `listBox.Items.Add("${item}");`) + .join("\n ")} + listBox.SelectedIndex = 0; + form.Controls.Add(listBox); + + okButton.Text = "确定"; + okButton.DialogResult = DialogResult.OK; + okButton.SetBounds(120, 200, 75, 23); + form.Controls.Add(okButton); + + cancelButton.Text = "取消"; + cancelButton.DialogResult = DialogResult.Cancel; + cancelButton.SetBounds(210, 200, 75, 23); + form.Controls.Add(cancelButton); + + if (form.ShowDialog() == DialogResult.OK && listBox.SelectedItem != null) { + Console.WriteLine($"{listBox.SelectedIndex}|{listBox.SelectedItem}"); + } + form.Dispose(); + } + }`; + const result = await this.runCsharp(csharpScript); + if (result.trim()) { + const [id, text] = result.trim().split("|"); + return { id: parseInt(id), text }; + } + return null; + } +}; + +// 系统级按钮组弹窗 +const showSystemButtonBox = async function (buttons, content, title = "") { + const iconPath = getQuickcommandIconPath(); + if (window.utools.isMacOs()) { + let iconParam = "note"; + if (iconPath) { + const posixPath = iconPath.replace(/\\/g, "/"); + iconParam = `alias POSIX file "${posixPath}"`; + } + const buttonList = buttons.map((btn) => `"${btn}"`).join(", "); + const script = `display dialog "${content}" with title "${title}" buttons {${buttonList}} default button "${buttons[0]}" with icon ${iconParam}`; + const result = await this.runAppleScript(script); + const match = result.match(/button returned:(.+)/); + if (match) { + const text = match[1]; + const id = buttons.findIndex((btn) => btn === text); + return { id, text }; + } + return null; + } else if (window.utools.isWindows()) { + const csharpScript = ` + using System.Windows.Forms; + using System.Drawing; + using System.IO; + class Program { + static void Main() { + Form form = new Form(); + Label label = new Label(); + FlowLayoutPanel buttonPanel = new FlowLayoutPanel(); + + form.Text = "${title}"; + form.ClientSize = new Size(400, 150); + form.FormBorderStyle = FormBorderStyle.FixedDialog; + form.StartPosition = FormStartPosition.CenterScreen; + form.MaximizeBox = false; + form.MinimizeBox = false; + ${ + iconPath + ? `using (var bmp = new Bitmap("${iconPath}")) + { + form.Icon = Icon.FromHandle(bmp.GetHicon()); + }` + : "" + } + + label.Text = "${content}"; + label.SetBounds(10, 10, 380, 40); + label.AutoSize = true; + form.Controls.Add(label); + + buttonPanel.SetBounds(10, 60, 380, 40); + buttonPanel.FlowDirection = FlowDirection.RightToLeft; + buttonPanel.WrapContents = false; + form.Controls.Add(buttonPanel); + + ${buttons + .map( + (btn, index) => ` + Button button${index} = new Button(); + button${index}.Text = "${btn}"; + button${index}.DialogResult = DialogResult.OK; + button${index}.Tag = "${index}"; + button${index}.SetBounds(0, 0, 80, 30); + buttonPanel.Controls.Add(button${index});` + ) + .join("\n")} + + DialogResult result = form.ShowDialog(); + if (result == DialogResult.OK) { + foreach (Button btn in buttonPanel.Controls) { + if (btn.DialogResult == result) { + Console.WriteLine($"{btn.Tag}|{btn.Text}"); + break; + } + } + } + form.Dispose(); + } + }`; + const result = await this.runCsharp(csharpScript); + if (result.trim()) { + const [id, text] = result.trim().split("|"); + return { id: parseInt(id), text }; + } + return null; + } +}; + +// 系统级文本区域弹窗 +const showSystemTextArea = async function ( + placeholder = "", + defaultText = "", + title = "" +) { + const iconPath = getQuickcommandIconPath(); + if (window.utools.isWindows()) { + const csharpScript = ` + using System.Windows.Forms; + using System.Drawing; + using System.IO; + class Program { + static void Main() { + Form form = new Form(); + TextBox textBox = new TextBox(); + Button okButton = new Button(); + Button cancelButton = new Button(); + Label label = new Label(); + + form.Text = "${title}"; + form.ClientSize = new Size(400, 300); + form.FormBorderStyle = FormBorderStyle.FixedDialog; + form.StartPosition = FormStartPosition.CenterScreen; + form.MaximizeBox = false; + form.MinimizeBox = false; + ${ + iconPath + ? `using (var bmp = new Bitmap("${iconPath}")) + { + form.Icon = Icon.FromHandle(bmp.GetHicon()); + }` + : "" + } + + label.Text = "${placeholder}"; + label.SetBounds(10, 10, 380, 20); + form.Controls.Add(label); + + textBox.Multiline = true; + textBox.ScrollBars = ScrollBars.Vertical; + textBox.SetBounds(10, 40, 380, 180); + textBox.Text = "${defaultText}"; + form.Controls.Add(textBox); + + okButton.Text = "确定"; + okButton.DialogResult = DialogResult.OK; + okButton.SetBounds(220, 230, 75, 23); + form.Controls.Add(okButton); + + cancelButton.Text = "取消"; + cancelButton.DialogResult = DialogResult.Cancel; + cancelButton.SetBounds(310, 230, 75, 23); + form.Controls.Add(cancelButton); + + form.AcceptButton = okButton; + form.CancelButton = cancelButton; + + if (form.ShowDialog() == DialogResult.OK) { + Console.WriteLine(textBox.Text); + } + form.Dispose(); + } + }`; + const result = await this.runCsharp(csharpScript); + return result.trim() || null; + } +}; + +module.exports = { + showSystemMessageBox, + showSystemInputBox, + showSystemConfirmBox, + showSystemSelectList, + showSystemButtonBox, + showSystemTextArea, +}; diff --git a/plugin/preload.js b/plugin/preload.js index e98a674..62309b3 100644 --- a/plugin/preload.js +++ b/plugin/preload.js @@ -41,8 +41,8 @@ window.convertFilePathToUtoolsPayload = convertFilePathToUtoolsPayload; window.getuToolsLite = require("./lib/utoolsLite"); window.quickcommand = require("./lib/quickcommand"); window.quickcomposer = require("./lib/quickcomposer"); -window.getQuickcommandTempFile = require("./lib/getQuickcommandTempFile"); window.showUb = require("./lib/showDocs"); +window.getQuickcommandTempFile = require("./lib/getQuickcommandFile").getQuickcommandTempFile; window.getSharedQcById = async (id) => { const url = "https://qc.qaz.ink/home/quick/script/getScript"; diff --git a/src/plugins/monaco/types/quickcommand.api.d.ts b/src/plugins/monaco/types/quickcommand.api.d.ts index bf02d33..a188d7d 100644 --- a/src/plugins/monaco/types/quickcommand.api.d.ts +++ b/src/plugins/monaco/types/quickcommand.api.d.ts @@ -485,6 +485,118 @@ interface quickcommandApi { */ all(): Array<{ id: string; value: string; isNative: boolean }>; }; + + /** + * 显示一个系统级消息框(不支持Linux) + * + * ```js + * quickcommand.showSystemMessageBox("这是一条消息", "标题") + * ``` + * + * @param content 消息内容 + * @param title 标题,默认为空 + */ + showSystemMessageBox(content: string, title?: string): Promise; + + /** + * 显示一个系统级输入框组,返回所有输入框的值(不支持Linux) + * + * ```js + * // 单个输入框 + * quickcommand.showSystemInputBox("请输入:", "标题").then(results => { + * console.log(results[0]) // 第一个输入框的值 + * }) + * + * // 多个输入框 + * quickcommand.showSystemInputBox(["姓名:", "年龄:", "地址:"], "个人信息").then(results => { + * console.log(results) // ["张三", "25", "北京"] + * }) + * ``` + * + * @param placeholders 输入框的提示文本,可以是单个字符串或字符串数组 + * @param title 标题,默认为空 + */ + showSystemInputBox( + placeholders: string | string[], + title?: string + ): Promise; + + /** + * 显示一个系统级确认框,返回是否点击了确认(不支持Linux) + * + * ```js + * quickcommand.showSystemConfirmBox("确定要删除吗?", "确认删除").then(confirmed => { + * if (confirmed) { + * console.log("用户点击了确定") + * } + * }) + * ``` + * + * @param content 确认内容 + * @param title 标题,默认为空 + */ + showSystemConfirmBox(content: string, title?: string): Promise; + + /** + * 显示一个系统级选择列表,返回选择的项的索引和文本(不支持Linux) + * + * ```js + * quickcommand.showSystemSelectList(["选项1", "选项2", "选项3"], "请选择").then(result => { + * if (result) { + * console.log(`选择了第${result.id + 1}个选项:${result.text}`) + * } + * }) + * ``` + * + * @param items 选项列表 + * @param title 标题,默认为空 + */ + showSystemSelectList( + items: string[], + title?: string + ): Promise<{ id: number; text: string } | null>; + + /** + * 显示一个系统级按钮组对话框,返回点击的按钮的索引和文本(不支持Linux) + * + * ```js + * quickcommand.showSystemButtonBox(["保存", "不保存", "取消"], "是否保存更改?", "保存确认").then(result => { + * if (result) { + * console.log(`点击了第${result.id + 1}个按钮:${result.text}`) + * } + * }) + * ``` + * + * @param buttons 按钮文本数组 + * @param content 对话框内容 + * @param title 标题,默认为空 + */ + showSystemButtonBox( + buttons: string[], + content: string, + title?: string + ): Promise<{ id: number; text: string } | null>; + + /** + * 显示一个系统级多行文本输入框(仅Windows支持) + * + * ```js + * quickcommand.showSystemTextArea("请输入多行文本:", "默认内容", "文本编辑").then(text => { + * if (text) { + * console.log("输入的文本:", text) + * } + * }) + * ``` + * + * @param placeholder 提示文本,默认为空 + * @param defaultText 默认文本,默认为空 + * @param title 标题,默认为空 + */ + showSystemTextArea( + placeholder?: string, + defaultText?: string, + title?: string + ): Promise; } declare var quickcommand: quickcommandApi;