- 使用方法
+ 使用方法
- 点击左侧的工具箱标签,在对应工具箱中拖出块,在工作区中进行拼接。
+ 点击编程标签页左侧的工具箱标签,在对应工具箱中拖出块,在工作区中进行拼接完成图形化编程。
- 点击此按钮加载默认示例
+ 点此按钮加载示例
+ (会覆盖当前工作区)
+ 暂存与回复
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
- tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
- veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
- commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
- velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
- cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
- est laborum.
+ 点击下方工具栏的“暂存”按钮可将当前设计暂存到浏览器中,点击“恢复”按钮可恢复上次暂存的设计。
+
+ 已存在暂存的设计时,刷新页面或重新打开页面时会自动恢复上次暂存的设计。
+
+
+ 配置与导入导出
+
+
+ 点击下方工具栏的“导入导出”按钮或点击“配置”标签,可进行参数配置、设计文件的导入导出、以及
+ NoneBot 工程的导出操作。
+
+
+ 导出设计文件将生成一个 JSON 文件并下载到本地;导入设计文件需要选择已导出的
+ JSON 文件上传。
+
+
+ 导出 NoneBot
+ 工程将生成一个压缩文件并下载到本地,使用时需要先进行解压,在项目根目录运行对应平台的脚本
+ ( Windows 平台为./install.ps1
和 ./run.ps1
;
+ Linux 平台为 bash ./install.sh
和
+ bash ./run.sh
+ )进行环境配置与运行。
+
+
+
+
+ 详细使用文档正在编写中。
diff --git a/packages/app/src/default.ts b/packages/app/src/default.ts
index f1658a7..df37045 100644
--- a/packages/app/src/default.ts
+++ b/packages/app/src/default.ts
@@ -1,76 +1,276 @@
-export const startBlocks = {
- blocks: {
- languageVersion: 0,
- blocks: [
+export const demoProject = {
+ version: "v1",
+ data: {
+ workspaceComments: [
{
- type: "nonebot_on_command",
- id: "!WdCO9=B,k2IY0/Su4|I",
- x: 150,
- y: 210,
- fields: { COMMAND: "save", TOME: true },
- inputs: {
- HANDLE: {
- block: {
- type: "variables_set",
- id: "9_AQ_@)mWU$=2GkYbT-d",
- fields: { VAR: { id: "VSvr3AeHEP),5NB5v$+;" } },
- inputs: {
- VALUE: {
- block: {
- type: "store_load_json",
- id: "3~H`IY?A(%(Bb+8/wL3c",
- fields: { FILE: "save.json" },
+ height: 79.33334350585938,
+ width: 401.33331298828125,
+ id: ").5C,33iYe,Es5QP^CZS",
+ x: 490,
+ y: 50,
+ text: '消息处理对整条纯文本消息进行响应\n发送内容为 "ping" 会得到回复 "pong"',
+ },
+ {
+ height: 143.99996948242188,
+ width: 480.00006103515625,
+ id: "^qq4*u=7LW8i@`p}MbNT",
+ x: 970,
+ y: 350,
+ text: '命令处理只处理以命令起始符和命令字符串起始的消息\n命令起始符可在配置选项卡中设置,默认为 "/"\n选择了空命令起始符时可直接匹配以命令字符串起始的消息\n本例中可相应消息如 "/save 1" "/save 2"\n每次调用会返回上一次的参数,首次为 "None",第二次为 "1"',
+ },
+ {
+ height: 92,
+ width: 483.33331298828125,
+ id: "[NvN:*-?JE3}m5R}jIm7",
+ x: 970,
+ y: 510,
+ text: "文件存储支持可以将文本或字典存入本地文件\n或从本地文件读出到对应的变量中",
+ },
+ {
+ height: 104.66668701171875,
+ width: 402,
+ id: "W;2zsU/+VlY54WQsR)5V",
+ x: 490,
+ y: 570,
+ text: "跨平台命令解析预处理由 alconna 插件提供支持\n可以自由配置固定字符串或多种数据类型的命令参数列表\n并在处理流程中取得对应的命令参数使用",
+ },
+ {
+ height: 82.666748046875,
+ width: 401.99993896484375,
+ id: "^dl/_H.6Ei@c8]zhc)MI",
+ x: 490,
+ y: 150,
+ text: "网络请求支持可以构建GET或POST网络请求\n需要正确配置返回内容的数据类型以支持后续处理",
+ },
+ {
+ height: 58.00006103515625,
+ width: 389.99981689453125,
+ id: "6ILVtb0f/4J2QpMw?W?u",
+ x: 970,
+ y: 810,
+ text: "定时任务支持可以根据设定时间重复指定的处理操作",
+ },
+ ],
+ blocks: {
+ languageVersion: 0,
+ blocks: [
+ {
+ type: "nonebot_on_command",
+ id: "!WdCO9=B,k2IY0/Su4|I",
+ x: 970,
+ y: 50,
+ fields: { COMMAND: "save", TOME: true },
+ inputs: {
+ HANDLE: {
+ block: {
+ type: "variables_set",
+ id: "9_AQ_@)mWU$=2GkYbT-d",
+ fields: { VAR: { id: "VSvr3AeHEP),5NB5v$+;" } },
+ inputs: {
+ VALUE: {
+ block: {
+ type: "store_load_json",
+ id: "3~H`IY?A(%(Bb+8/wL3c",
+ fields: { FILE: "save.json" },
+ },
},
},
- },
- next: {
- block: {
- type: "variables_set",
- id: "gc.{0S@R!yzBky.dRf/T",
- fields: { VAR: { id: "dS|cq^n0{Ep#B]f*RtAH" } },
- inputs: {
- VALUE: {
+ next: {
+ block: {
+ type: "variables_set",
+ id: "gc.{0S@R!yzBky.dRf/T",
+ fields: { VAR: { id: "dS|cq^n0{Ep#B]f*RtAH" } },
+ inputs: {
+ VALUE: {
+ block: {
+ type: "dicts_get",
+ id: "R5``m]FzB+yBPW1W2`]$",
+ fields: { KEY: "last" },
+ inputs: {
+ DICT: {
+ block: {
+ type: "variables_get",
+ id: "[Ws*B$JWgLY]BeT`^_=]",
+ fields: { VAR: { id: "VSvr3AeHEP),5NB5v$+;" } },
+ },
+ },
+ },
+ },
+ },
+ },
+ next: {
block: {
- type: "dicts_get",
- id: "R5``m]FzB+yBPW1W2`]$",
- fields: { KEY: "last" },
+ type: "nonebot_send",
+ id: "2VEO#b:zwo|#8!@y%P}q",
+ fields: { FINISH: false },
inputs: {
- DICT: {
+ MESSAGE: {
block: {
- type: "variables_get",
- id: "[Ws*B$JWgLY]BeT`^_=]",
- fields: { VAR: { id: "VSvr3AeHEP),5NB5v$+;" } },
+ type: "text_join",
+ id: "~Va]uDcID[2P5@n3z{pe",
+ extraState: { itemCount: 2 },
+ inputs: {
+ ADD0: {
+ block: {
+ type: "text",
+ id: "3Aw,]xK/YxeE+S`=:}vc",
+ fields: { TEXT: "last: " },
+ },
+ },
+ ADD1: {
+ block: {
+ type: "variables_get",
+ id: "hF5`vj~{OC2uF+^}Q8yk",
+ fields: {
+ VAR: { id: "dS|cq^n0{Ep#B]f*RtAH" },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ next: {
+ block: {
+ type: "dicts_set",
+ id: "B3Wx%a7x=Pp95taY%.*K",
+ fields: { KEY: "last" },
+ inputs: {
+ DICT: {
+ block: {
+ type: "variables_get",
+ id: "7iF8)`YtA.s.-@v_dYNo",
+ fields: {
+ VAR: { id: "VSvr3AeHEP),5NB5v$+;" },
+ },
+ },
+ },
+ VALUE: {
+ block: {
+ type: "nonebot_param_text",
+ id: "{eYrM|C4so41hXY4~MtD",
+ },
+ },
+ },
+ next: {
+ block: {
+ type: "store_save_json",
+ id: "sOck!o^D;xHPwNdX0v;s",
+ fields: { FILE: "save.json" },
+ inputs: {
+ DICT: {
+ block: {
+ type: "variables_get",
+ id: "Z8a4Wo4ae#)plFG}S:6B",
+ fields: {
+ VAR: { id: "VSvr3AeHEP),5NB5v$+;" },
+ },
+ },
+ },
+ },
+ },
},
},
},
},
},
},
- next: {
+ },
+ },
+ },
+ },
+ },
+ {
+ type: "nonebot_on_message",
+ id: "rJ[.=4k)POkDVT?Wz%zD",
+ x: 70,
+ y: 50,
+ fields: { TOME: false },
+ inputs: {
+ HANDLE: {
+ block: {
+ type: "controls_if",
+ id: "SBBb-4DL]Ofg,o5,lix9",
+ extraState: { elseIfCount: 2 },
+ inputs: {
+ IF0: {
+ block: {
+ type: "logic_compare",
+ id: "3KiI-ePNeWs/tZ.xUQd*",
+ fields: { OP: "EQ" },
+ inputs: {
+ A: {
+ block: {
+ type: "nonebot_param_text",
+ id: "}:vuF-QZzN6NL{}`jW87",
+ },
+ },
+ B: {
+ block: {
+ type: "text",
+ id: ":R-~fjy%Xs,HExpeH$jd",
+ fields: { TEXT: "ping" },
+ },
+ },
+ },
+ },
+ },
+ DO0: {
block: {
type: "nonebot_send",
- id: "2VEO#b:zwo|#8!@y%P}q",
- fields: { FINISH: false },
+ id: "zyjiCMiE87Wm_gt~i6dj",
+ fields: { FINISH: true },
inputs: {
MESSAGE: {
block: {
- type: "text_join",
- id: "~Va]uDcID[2P5@n3z{pe",
- extraState: { itemCount: 2 },
+ type: "text",
+ id: "NpK-srq00|eB:+v#I5t?",
+ fields: { TEXT: "pong" },
+ },
+ },
+ },
+ },
+ },
+ IF1: {
+ block: {
+ type: "logic_compare",
+ id: "!Q{^KS]tk}knY$0loSbK",
+ fields: { OP: "EQ" },
+ inputs: {
+ A: {
+ block: {
+ type: "nonebot_param_text",
+ id: "R3^-rcLn~gkf#eJO//|S",
+ },
+ },
+ B: {
+ block: {
+ type: "text",
+ id: "L44H6xsB#jzeNUodNS3*",
+ fields: { TEXT: "plugin" },
+ },
+ },
+ },
+ },
+ },
+ DO1: {
+ block: {
+ type: "variables_set",
+ id: "}8cI$-ju]d/4jbudI(%?",
+ fields: { VAR: { id: "i7%fQRO5s:HNPn!Egg/!" } },
+ inputs: {
+ VALUE: {
+ block: {
+ type: "request_get",
+ id: "i%$0*PV*Q}aD.4uiq,Xk",
+ fields: { TYPE: "list", TIMEOUT: 60 },
inputs: {
- ADD0: {
+ URL: {
block: {
type: "text",
- id: "3Aw,]xK/YxeE+S`=:}vc",
- fields: { TEXT: "last: " },
- },
- },
- ADD1: {
- block: {
- type: "variables_get",
- id: "hF5`vj~{OC2uF+^}Q8yk",
+ id: "ju`#!lmdA,,j~GxD)LdV",
fields: {
- VAR: { id: "dS|cq^n0{Ep#B]f*RtAH" },
+ TEXT: "https://registry.nonebot.dev/plugins.json",
},
},
},
@@ -80,37 +280,90 @@ export const startBlocks = {
},
next: {
block: {
- type: "dicts_set",
- id: "B3Wx%a7x=Pp95taY%.*K",
- fields: { KEY: "last" },
+ type: "nonebot_send",
+ id: "I]HVejYi1XMiH7@L#%fa",
+ fields: { FINISH: true },
inputs: {
- DICT: {
- block: {
- type: "variables_get",
- id: "7iF8)`YtA.s.-@v_dYNo",
- fields: { VAR: { id: "VSvr3AeHEP),5NB5v$+;" } },
- },
- },
- VALUE: {
+ MESSAGE: {
block: {
- type: "nonebot_param_text",
- id: "{eYrM|C4so41hXY4~MtD",
+ type: "text_join",
+ id: "TBv3^GAlbgL-)1DGdyI`",
+ extraState: { itemCount: 2 },
+ inputs: {
+ ADD0: {
+ block: {
+ type: "text",
+ id: "Nr4jVV3k@]@q._B7$O+_",
+ fields: { TEXT: "当前插件数量为:" },
+ },
+ },
+ ADD1: {
+ block: {
+ type: "lists_length",
+ id: "e8GR1^[w[S5c,=vs`nU(",
+ inputs: {
+ VALUE: {
+ block: {
+ type: "variables_get",
+ id: "@^l~%MD,Wm9RLJ|N%Ys4",
+ fields: {
+ VAR: {
+ id: "i7%fQRO5s:HNPn!Egg/!",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
},
},
},
- next: {
- block: {
- type: "store_save_json",
- id: "sOck!o^D;xHPwNdX0v;s",
- fields: { FILE: "save.json" },
- inputs: {
- DICT: {
- block: {
- type: "variables_get",
- id: "Z8a4Wo4ae#)plFG}S:6B",
- fields: {
- VAR: { id: "VSvr3AeHEP),5NB5v$+;" },
- },
+ },
+ },
+ },
+ },
+ IF2: {
+ block: {
+ type: "logic_compare",
+ id: "o|dYI,`Cy)u6gPCrP]!r",
+ fields: { OP: "EQ" },
+ inputs: {
+ A: {
+ block: {
+ type: "nonebot_param_text",
+ id: "2_xq)Q*KP{j0d0ZG1y`Z",
+ },
+ },
+ B: {
+ block: {
+ type: "text",
+ id: "S:8I/+[}C@_cjY*@_dhE",
+ fields: { TEXT: "random" },
+ },
+ },
+ },
+ },
+ },
+ DO2: {
+ block: {
+ type: "nonebot_send",
+ id: "[QQQ:Wu;b)hi|C_=p[T(",
+ fields: { FINISH: false },
+ inputs: {
+ MESSAGE: {
+ block: {
+ type: "text_join",
+ id: "NXK(kC#{y^-Wvr2a0_+;",
+ extraState: { itemCount: 1 },
+ inputs: {
+ ADD0: {
+ block: {
+ type: "variables_get",
+ id: "-f7]+j)Y],;g0.nxr[Kr",
+ fields: {
+ VAR: { id: "dm}-^1M|xx~4#6g~~7e#" },
},
},
},
@@ -125,52 +378,94 @@ export const startBlocks = {
},
},
},
- },
- {
- type: "nonebot_on_message",
- id: "rJ[.=4k)POkDVT?Wz%zD",
- x: 150,
- y: 30,
- fields: { TOME: false },
- inputs: {
- HANDLE: {
- block: {
- type: "controls_if",
- id: "SBBb-4DL]Ofg,o5,lix9",
- inputs: {
- IF0: {
- block: {
- type: "logic_compare",
- id: "3KiI-ePNeWs/tZ.xUQd*",
- fields: { OP: "EQ" },
- inputs: {
- A: {
- block: {
- type: "nonebot_param_text",
- id: "}:vuF-QZzN6NL{}`jW87",
+ {
+ type: "nonebot_on_alconna",
+ id: "|Fu4X1(2DR;,y_a_tXuZ",
+ x: 70,
+ y: 610,
+ extraState: { itemCount: 3 },
+ fields: { COMMAND: "command", TOME: true },
+ inputs: {
+ ARG0: {
+ block: {
+ type: "alconna_const",
+ id: "F]W)`U.)2h|Wy@y[#X1A",
+ fields: { TEXT: "test" },
+ },
+ },
+ ARG1: {
+ block: {
+ type: "alconna_arg",
+ id: "86},)_bY]o`5w*GGsg+o",
+ fields: { NAME: "name", TYPE: "str" },
+ },
+ },
+ ARG2: {
+ block: {
+ type: "alconna_arg",
+ id: "}qB@y=xly_6U~?~cTvl7",
+ fields: { NAME: "number", TYPE: "int" },
+ },
+ },
+ HANDLE: {
+ block: {
+ type: "nonebot_send",
+ id: "IG0GrnVygzO2N+qv~Wav",
+ fields: { FINISH: false },
+ inputs: {
+ MESSAGE: {
+ block: {
+ type: "text_join",
+ id: "BYK7GDru]?*p60E0ED!}",
+ extraState: { itemCount: 2 },
+ inputs: {
+ ADD0: {
+ block: {
+ type: "text",
+ id: "Lz;^)x7Ry)aC`;jz(n_[",
+ fields: { TEXT: "参数name为:" },
+ },
},
- },
- B: {
- block: {
- type: "text",
- id: ":R-~fjy%Xs,HExpeH$jd",
- fields: { TEXT: "ping" },
+ ADD1: {
+ block: {
+ type: "alconna_arg_get",
+ id: "kjv.p]ZKq?$Ay!@|(GZz",
+ extraState: { name: "name" },
+ fields: { NAME: "name" },
+ },
},
},
},
},
},
- DO0: {
+ next: {
block: {
type: "nonebot_send",
- id: "zyjiCMiE87Wm_gt~i6dj",
- fields: { FINISH: true },
+ id: "Df,m4`}7lCDAVw=}TxLl",
+ fields: { FINISH: false },
inputs: {
MESSAGE: {
block: {
- type: "text",
- id: "NpK-srq00|eB:+v#I5t?",
- fields: { TEXT: "pong" },
+ type: "text_join",
+ id: ",ujwQq~#eb/c(q9#mKnW",
+ extraState: { itemCount: 2 },
+ inputs: {
+ ADD0: {
+ block: {
+ type: "text",
+ id: "TJ?2:7Q!R$=_eUyD;M8m",
+ fields: { TEXT: "参数number为:" },
+ },
+ },
+ ADD1: {
+ block: {
+ type: "alconna_arg_get",
+ id: "[u:Is_2hXiJap%JWvgl2",
+ extraState: { name: "number" },
+ fields: { NAME: "number" },
+ },
+ },
+ },
},
},
},
@@ -180,11 +475,60 @@ export const startBlocks = {
},
},
},
- },
+ {
+ type: "scheduler_add",
+ id: "6djmI(1,`~eAj}g=@PXr",
+ x: 970,
+ y: 650,
+ inputs: {
+ TIME: {
+ block: {
+ type: "scheduler_time_interval",
+ id: "XCCX[EaW9yKIF;Ck|waX",
+ fields: { NUMBER: 10, UNIT: "seconds" },
+ },
+ },
+ ID: {
+ block: {
+ type: "text",
+ id: "@JgyG!7m]+3d#@1GPRaA",
+ fields: { TEXT: "refresh_number" },
+ },
+ },
+ HANDLE: {
+ block: {
+ type: "variables_set",
+ id: "iRc7.8GkpN=ZE){MYOG9",
+ fields: { VAR: { id: "dm}-^1M|xx~4#6g~~7e#" } },
+ inputs: {
+ VALUE: {
+ block: {
+ type: "math_random_float",
+ id: "$oMB|U7+QU_qfCwi,J$j",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ ],
+ },
+ variables: [
+ { name: "data_dict", id: "VSvr3AeHEP),5NB5v$+;" },
+ { name: "last_param", id: "dS|cq^n0{Ep#B]f*RtAH" },
+ { name: "plugin_data", id: "i7%fQRO5s:HNPn!Egg/!" },
+ { name: "plugin_data2", id: "`a{F^Z`6/mb_37*,mPgL" },
+ { name: "random_number", id: "dm}-^1M|xx~4#6g~~7e#" },
],
},
- variables: [
- { name: "data_dict", id: "VSvr3AeHEP),5NB5v$+;" },
- { name: "last_param", id: "dS|cq^n0{Ep#B]f*RtAH" },
- ],
+ config: {
+ name: "app_demo",
+ preset: { name: "console", description: "控制台机器人" },
+ port: 8080,
+ platform: ["windows", "linux"],
+ commandStart: ["/", ""],
+ superusers: ["User"],
+ kwargs: {},
+ },
};
diff --git a/packages/app/src/generators/helper.ts b/packages/app/src/generators/helper.ts
new file mode 100644
index 0000000..b5f85c2
--- /dev/null
+++ b/packages/app/src/generators/helper.ts
@@ -0,0 +1,29 @@
+import { PythonGenerator } from "blockly/python";
+import * as Blockly from "blockly/core";
+
+export function getGlobalStatement(
+ block: Blockly.Block,
+ generator: PythonGenerator,
+) {
+ const globals = [];
+ const workspace = block.workspace;
+ const usedVariables = Blockly.Variables.allUsedVarModels(workspace) || [];
+ for (const variable of usedVariables) {
+ const varName = variable.name;
+ globals.push(generator.getVariableName(varName));
+ }
+ // Add developer variables.
+ const devVarList = Blockly.Variables.allDeveloperVariables(workspace);
+ for (let i = 0; i < devVarList.length; i++) {
+ globals.push(
+ generator.nameDB_!.getName(
+ devVarList[i],
+ Blockly.Names.NameType.DEVELOPER_VARIABLE,
+ ),
+ );
+ }
+ const globalString = globals.length
+ ? "global " + globals.join(", ") + "\n"
+ : "";
+ return globalString;
+}
diff --git a/packages/app/src/generators/nonebot_alconna.ts b/packages/app/src/generators/nonebot_alconna.ts
index 2845928..c493751 100644
--- a/packages/app/src/generators/nonebot_alconna.ts
+++ b/packages/app/src/generators/nonebot_alconna.ts
@@ -3,6 +3,7 @@ import * as Blockly from "blockly/core";
import { AlconnaBlock, AlconnaArgGetBlock } from "@/blocks/nonebot_alconna";
import { getAlconnaArg } from "@/blocks/fields/alconna_helper";
+import { getGlobalStatement } from "./helper";
export const forBlock = Object.create(null);
@@ -11,8 +12,10 @@ forBlock["nonebot_on_alconna"] = function (
generator: PythonGenerator,
) {
const command = block.getFieldValue("COMMAND");
- const checkbox_tome = block.getFieldValue("TOME") === "TRUE";
- const statement_handle =
+ const tomeCheckbox = block.getFieldValue("TOME") === "TRUE";
+ const globalStatement =
+ generator.INDENT + getGlobalStatement(block, generator);
+ const handleStatement =
generator.statementToCode(block, "HANDLE") || generator.PASS;
// generator["definitions_"]["from nonebot.adapters import Bot"] = "from nonebot.adapters import Bot";
// generator["definitions_"]["from nonebot.adapters import Event"] = "from nonebot.adapters import Event";
@@ -20,38 +23,32 @@ forBlock["nonebot_on_alconna"] = function (
"from nonebot.matcher import Matcher";
generator["definitions_"]["from nonebot_plugin_alconna import on_alconna"] =
"from nonebot_plugin_alconna import on_alconna";
- let tome_statement = "";
- if (checkbox_tome) {
+ let tomeStatement = "";
+ if (tomeCheckbox) {
generator["definitions_"]["from nonebot.rule import to_me"] =
"from nonebot.rule import to_me";
- tome_statement = ", rule=to_me()";
+ tomeStatement = ", rule=to_me()";
}
let args: String[] = [];
- let args_matcher = "";
- let args_function = "";
+ let argsMatcher = "";
+ let argsFunction = "";
for (let n = 0; n < block.itemCount_; n++) {
const block_type = block
.getInput("ARG" + String(n))
?.connection?.targetConnection?.getSourceBlock().type;
- const arg_code = generator.valueToCode(
- block,
- "ARG" + String(n),
- Order.NONE,
- );
+ const argCode = generator.valueToCode(block, "ARG" + String(n), Order.NONE);
if (block_type === "alconna_const") {
- args_matcher += ` ${arg_code}`;
+ argsMatcher += ` ${argCode}`;
} else if (block_type === "alconna_arg") {
- args_matcher += ` {${arg_code}}`;
- args_function += `, ${arg_code}`;
+ argsMatcher += ` {${argCode}}`;
+ argsFunction += `, ${argCode}`;
// get name before `: type`
- args.push(arg_code.split(":")[0]);
+ args.push(argCode.split(":")[0]);
}
}
- let code = `@on_alconna("${command}${args_matcher}"${tome_statement}).handle()\n`;
+ let code = `@on_alconna("${command}${argsMatcher}"${tomeStatement}).handle()\n`;
// code += `async def _(matcher: Matcher, bot: Bot, event: Event, message: Annotated[Message, CommandArg()]):\n`;
- code += `async def _(matcher: Matcher${args_function}):\n`;
- code += statement_handle;
- code += "\n";
+ code += `async def _(matcher: Matcher${argsFunction}):\n${globalStatement}${handleStatement}\n`;
return code;
};
@@ -80,18 +77,24 @@ forBlock["alconna_arg_get"] = function (
generator: PythonGenerator,
) {
// This generator will also update the dropdown list
- let name_real = block.getFieldValue("NAME");
+ let name = block.getFieldValue("NAME");
const args = getAlconnaArg(block);
let options = new Array();
+ // If the block is not initialized, it is reloading from saved
+ // Should rebuild the dropdown list and set the name to the saved name `block.name_`
if (!block.isInitialized_ && block.name_ !== "") {
- // Read from saved
- name_real = block.name_;
+ name = block.name_;
block.isInitialized_ = true;
- if (args.indexOf(name_real) !== -1) {
- options.push([name_real, name_real]);
+ // Make sure the selected value is the first one of the dropdown list
+ // Due to the dynamic dropdowns are not responding to set value calls correctly
+ // https://github.com/google/blockly/issues/3099
+ // This will also cause warnings in console:
+ // `Cannot set the dropdown's value to an unavailable option.`
+ if (args.indexOf(name) !== -1) {
+ options.push([name, name]);
}
args.forEach((arg) => {
- if (arg !== name_real) {
+ if (arg !== name) {
options.push([arg, arg]);
}
});
@@ -101,9 +104,11 @@ forBlock["alconna_arg_get"] = function (
?.appendField("获取参数")
.appendField(new Blockly.FieldDropdown(options), "NAME");
} else {
+ // If the block is initialized, update the saved name and rebuild the dropdown list
args.forEach((arg) => {
options.push([arg, arg]);
});
+ block.name_ = name;
}
if (args.length === 0) {
this.removeInput("PARAMS");
@@ -113,15 +118,15 @@ forBlock["alconna_arg_get"] = function (
.appendField(new Blockly.FieldDropdown([["-", ""]]), "NAME");
return ["", Order.ATOMIC];
}
- if (!args.find((arg) => arg === name_real)) {
+ if (!args.find((arg) => arg === name)) {
this.removeInput("PARAMS");
this.setWarningText("");
this.appendDummyInput("PARAMS")
?.appendField("获取参数")
.appendField(new Blockly.FieldDropdown(options), "NAME");
}
- if (name_real) {
- return [generator.getVariableName("arg_" + name_real), Order.NONE];
+ if (name) {
+ return [generator.getVariableName("arg_" + name), Order.NONE];
}
return ["", Order.ATOMIC];
};
diff --git a/packages/app/src/generators/nonebot_basic.ts b/packages/app/src/generators/nonebot_basic.ts
index 846aa65..d3ecf05 100644
--- a/packages/app/src/generators/nonebot_basic.ts
+++ b/packages/app/src/generators/nonebot_basic.ts
@@ -1,14 +1,18 @@
import { PythonGenerator, Order } from "blockly/python";
import * as Blockly from "blockly/core";
+import { getGlobalStatement } from "./helper";
+
export const forBlock = Object.create(null);
forBlock["nonebot_on_message"] = function (
block: Blockly.Block,
generator: PythonGenerator,
) {
- const checkbox_tome = block.getFieldValue("TOME") === "TRUE";
- const statements_handle =
+ const tomeCheckbox = block.getFieldValue("TOME") === "TRUE";
+ const globalStatement =
+ generator.INDENT + getGlobalStatement(block, generator);
+ const handleStatement =
generator.statementToCode(block, "HANDLE") || generator.PASS;
generator["definitions_"]["from typing import Annotated"] =
"from typing import Annotated";
@@ -22,17 +26,15 @@ forBlock["nonebot_on_message"] = function (
"from nonebot.params import EventMessage";
generator["definitions_"]["from nonebot.plugin import on_message"] =
"from nonebot.plugin import on_message";
- let tome_statement = "";
- if (checkbox_tome) {
+ let tomeStatement = "";
+ if (tomeCheckbox) {
generator["definitions_"]["from nonebot.rule import to_me"] =
"from nonebot.rule import to_me";
- tome_statement = "rule=to_me()";
+ tomeStatement = "rule=to_me()";
}
- let code = `@on_message(${tome_statement}).handle()\n`;
+ let code = `@on_message(${tomeStatement}).handle()\n`;
// code += `async def _(matcher: Matcher, bot: Bot, event: Event, message: Annotated[Message, EventMessage()]):\n`;
- code += `async def _(matcher: Matcher, message: Annotated[Message, EventMessage()]):\n`;
- code += statements_handle;
- code += "\n";
+ code += `async def _(matcher: Matcher, message: Annotated[Message, EventMessage()]):\n${globalStatement}${handleStatement}\n`;
return code;
};
@@ -40,9 +42,11 @@ forBlock["nonebot_on_command"] = function (
block: Blockly.Block,
generator: PythonGenerator,
) {
- const text_command = block.getFieldValue("COMMAND");
- const checkbox_tome = block.getFieldValue("TOME") === "TRUE";
- const statements_handle =
+ const commandText = block.getFieldValue("COMMAND");
+ const tomeCheckbox = block.getFieldValue("TOME") === "TRUE";
+ const globalStatement =
+ generator.INDENT + getGlobalStatement(block, generator);
+ const handleStatement =
generator.statementToCode(block, "HANDLE") || generator.PASS;
generator["definitions_"]["from typing import Annotated"] =
"from typing import Annotated";
@@ -57,16 +61,14 @@ forBlock["nonebot_on_command"] = function (
generator["definitions_"]["from nonebot.plugin import on_command"] =
"from nonebot.plugin import on_command";
let tome_statement = "";
- if (checkbox_tome) {
+ if (tomeCheckbox) {
generator["definitions_"]["from nonebot.rule import to_me"] =
"from nonebot.rule import to_me";
tome_statement = ", rule=to_me()";
}
- let code = `@on_command("${text_command}"${tome_statement}).handle()\n`;
+ let code = `@on_command("${commandText}"${tome_statement}).handle()\n`;
// code += `async def _(matcher: Matcher, bot: Bot, event: Event, message: Annotated[Message, CommandArg()]):\n`;
- code += `async def _(matcher: Matcher, message: Annotated[Message, CommandArg()]):\n`;
- code += statements_handle;
- code += "\n";
+ code += `async def _(matcher: Matcher, message: Annotated[Message, CommandArg()]):\n${globalStatement}${handleStatement}\n`;
return code;
};
diff --git a/packages/app/src/generators/nonebot_matcher.ts b/packages/app/src/generators/nonebot_matcher.ts
deleted file mode 100644
index 96fc24c..0000000
--- a/packages/app/src/generators/nonebot_matcher.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import { Order } from "blockly/python";
-import * as Blockly from "blockly/core";
-
-export const forBlock = Object.create(null);
-
-forBlock["nonebot_on_command"] = function (
- block: Blockly.Block,
- generator: Blockly.CodeGenerator,
-) {
- const text_cmd = block.getFieldValue("CMD");
- const checkbox_to_me = block.getFieldValue("TO_ME") === "TRUE";
- let to_me_statement = "";
- generator["definitions_"]["from nonebot.plugin import on_command"] =
- "from nonebot.plugin import on_command";
- if (checkbox_to_me) {
- generator["definitions_"]["from nonebot.rule import to_me"] =
- "from nonebot.rule import to_me";
- to_me_statement = ", rule=to_me()";
- }
- let code = `on_command("${text_cmd}"${to_me_statement})`;
- return [code, Order.NONE];
-};
diff --git a/packages/app/src/generators/nonebot_request.ts b/packages/app/src/generators/nonebot_request.ts
index 3db0bb6..a136410 100644
--- a/packages/app/src/generators/nonebot_request.ts
+++ b/packages/app/src/generators/nonebot_request.ts
@@ -34,6 +34,9 @@ if not isinstance(driver, HTTPClientMixin): \n\
if (type === "dict") {
generator["definitions_"]["import json"] = "import json";
code = `json.loads(${content} or "{}")`;
+ } else if (type === "list") {
+ generator["definitions_"]["import json"] = "import json";
+ code = `json.loads(${content} or "[]")`;
}
return [code, Order.ATOMIC];
};
@@ -42,6 +45,37 @@ forBlock["request_post"] = function (
block: Blockly.Block,
generator: PythonGenerator,
) {
- const code = `\n`;
+ const url = generator.valueToCode(block, "URL", Order.ATOMIC);
+ const json = generator.valueToCode(block, "JSON", Order.ATOMIC) || "None";
+ const params = generator.valueToCode(block, "PARAMS", Order.ATOMIC) || "None";
+ const headers =
+ generator.valueToCode(block, "HEADERS", Order.ATOMIC) || "None";
+ const type = block.getFieldValue("TYPE");
+ const timeout = block.getFieldValue("TIMEOUT");
+ if (url === "" || url === "None") {
+ return ["None", Order.ATOMIC];
+ }
+ generator["definitions_"]["from nonebot import get_driver"] =
+ "from nonebot import get_driver";
+ generator["definitions_"]["from nonebot.drivers import Request"] =
+ "from nonebot.drivers import Request";
+ generator["definitions_"]["from nonebot.drivers import HTTPClientMixin"] =
+ "from nonebot.drivers import HTTPClientMixin";
+ generator["definitions_"]["nonebot_request_driver"] =
+ 'driver = get_driver() \n\
+ if not isinstance(driver, HTTPClientMixin): \n\
+ raise RuntimeError( \n\
+ f"Current driver {driver} does not support http client requests!" \n\
+ )';
+ const request = `Request("POST", ${url}, json=${json}, params=${params}, headers=${headers}, timeout=${timeout})`;
+ const content = `(await driver.request(${request})).content`;
+ let code = content;
+ if (type === "dict") {
+ generator["definitions_"]["import json"] = "import json";
+ code = `json.loads(${content} or "{}")`;
+ } else if (type === "list") {
+ generator["definitions_"]["import json"] = "import json";
+ code = `json.loads(${content} or "[]")`;
+ }
return [code, Order.ATOMIC];
};
diff --git a/packages/app/src/generators/nonebot_scheduler.ts b/packages/app/src/generators/nonebot_scheduler.ts
index b25cee9..5da83f0 100644
--- a/packages/app/src/generators/nonebot_scheduler.ts
+++ b/packages/app/src/generators/nonebot_scheduler.ts
@@ -1,28 +1,27 @@
import { PythonGenerator, Order } from "blockly/python";
import * as Blockly from "blockly/core";
+import { getGlobalStatement } from "./helper";
+
export const forBlock = Object.create(null);
forBlock["scheduler_add"] = function (
block: Blockly.Block,
generator: PythonGenerator,
) {
- const value_time = generator.valueToCode(block, "TIME", Order.ATOMIC);
- const value_id = generator.valueToCode(block, "ID", Order.ATOMIC);
- if (
- value_time === "" ||
- value_time === "None" ||
- value_id === "" ||
- value_id === "None"
- ) {
+ const time = generator.valueToCode(block, "TIME", Order.ATOMIC);
+ const id = generator.valueToCode(block, "ID", Order.ATOMIC);
+ if (time === "" || time === "None" || id === "" || id === "None") {
return "";
}
generator["definitions_"][
"from nonebot_plugin_apscheduler import scheduler"
] = "from nonebot_plugin_apscheduler import scheduler";
- const statement_handle =
+ const globalStatement =
+ generator.INDENT + getGlobalStatement(block, generator);
+ const handleStatement =
generator.statementToCode(block, "HANDLE") || generator.PASS;
- const code = `@scheduler.scheduled_job(${value_time}, id=${value_id})\nasync def _():\n${statement_handle}\n`;
+ const code = `@scheduler.scheduled_job(${time}, id=${id})\nasync def _():\n${globalStatement}${handleStatement}\n`;
return code;
};
@@ -30,11 +29,11 @@ forBlock["scheduler_remove"] = function (
block: Blockly.Block,
generator: PythonGenerator,
) {
- const value_id = generator.valueToCode(block, "ID", Order.ATOMIC);
+ const id = generator.valueToCode(block, "ID", Order.ATOMIC);
generator["definitions_"][
"from nonebot_plugin_apscheduler import scheduler"
] = "from nonebot_plugin_apscheduler import scheduler";
- const code = `scheduler.remove_job(${value_id})\n`;
+ const code = `scheduler.remove_job(${id})\n`;
return code;
};
diff --git a/packages/app/src/workspace.ts b/packages/app/src/workspace.ts
index 3e76b32..e7c3ca3 100644
--- a/packages/app/src/workspace.ts
+++ b/packages/app/src/workspace.ts
@@ -11,7 +11,7 @@ const version = "v1";
export const workspaceStore = reactive({
workspace: ref(),
- startBlocks: ref(),
+ demoProject: ref(),
});
export const optionsStore = reactive({
@@ -54,14 +54,107 @@ export const outputsStore = reactive({
snackbarMsg: "" as string,
snackbarTimeout: 2500 as number,
snackbarColor: "green" as string,
- export: {
- name: "app" as string,
- preset: { name: "console", description: "控制台机器人" },
- port: 8080 as number,
- platform: ["windows", "linux"] as string[],
- },
});
+export const exportConfig = reactive({
+ name: "app" as string,
+ preset: { name: "console", description: "控制台机器人" },
+ port: 8080 as number,
+ platform: ["windows", "linux"] as string[],
+ commandStart: ["/"] as string[],
+ superusers: [] as string[],
+ kwargs: {} as Record