唯杰地图 logo唯杰地图
VJMAP
EN

execute-script

vjcad/references/command/execute-script.md 7.2 KB107 行
原文

本文回答:vjcad 提供两条内置脚本命令——EXECSTR(执行 CAD 命令脚本)和 EXECJS(执行 JavaScript 代码)。代码侧有两个层级:Engine.editor.automate(scriptString) 是裸命令喂行器(只认命令名行+点输入行),new vjcad.ExecuteStrCommand().executeString(script) 才支持 SET/$(VAR)/REPEAT 等语法糖。

一、Engine.editor.automate(script):裸命令喂行器

语义(源码 UD 类 + getPoint 自动化分支):

  • 主循环只执行命令名行:逐行 CommandRegistry.item(行) 查找,非命令行(含 SET、$(…)、垃圾文本、空行、注释)静默跳过——不报错、不执行。
  • 命令别名在脚本里无效:主循环只查 CommandRegistry.item,不经 CommandAliasManager 解析,所以 L / C / M 这类别名行同样被静默跳过(交互命令行 executerWithOp 才解析别名)。脚本里一律写全名 LINE / CIRCLE / MOVE。
  • 只有 getPoint 会消费脚本行:命令执行中每个点提示从 scriptRowStack 读下一非空行,跳过 ;/// 注释与空行;"x,y" 解析为坐标,单数字+useBasePoint 解析为相对偏移,命中 keywords 则按关键字,否则 Cancel 结束当前命令。
  • getString/getKeyword/getReal/getEntity 不读脚本行——命令走到这类提示时会回到交互模式等待真实输入,automate() 的 Promise 挂起不返回。
  • 顶层 getInteger/getCorner 同样不吃 automate:getInteger(opts) 挂起后 automate("42\n") 只是把 "42" 当命令名查表跳过,promise 永挂;getCorner 同理。这两类只能真实 UI 输入或派发 Escape 取消:命令进行中用 await Engine.editor.awaitDispatchEscapeEvent()(派发 Escape 并等待命令结束;Editor 上没有 dispatchEscapeKey,那是右键菜单的私有方法);不在命令里的顶层调用,awaitDispatchEscapeEvent 要么不派发、要么等不到命令结束,改为直接 document.dispatchEvent(new KeyboardEvent('keydown', { code: 'Escape' }))。vjcad 没有 vjmapext inputManager.resolve*Value 那样的程序化落地通道。
  • 空行≠回车:空行被点输入读取循环跳过。LINE/PLINE 这类需要 Enter 收尾的命令,靠下一条命令名行被当无效点读入→Cancel 收尾(已画段会提交)。所以两条 LINE 要写成 LINE p1 p2 LINE LINE p3 p4 <收尾行> 形态。
  • 脚本末尾不能留着待输入的命令:栈空时 getPoint 落回交互等待,automate() Promise 永不 resolve(静默挂死)。
// 可直接运行:两条 CIRCLE(圆心+半径两段自动完成,无需收尾行)
await Engine.editor.automate(`CIRCLE
5000,5000
30
CIRCLE
5200,5000
40
`);

// LINE 需要"下一条命令名"收尾——这里第一条 CIRCLE 行既给 LINE Cancel 收尾、
// 第二条 CIRCLE 行才真正启动画圆
await Engine.editor.automate(`LINE
5000,5000
5100,5000
CIRCLE
CIRCLE
6000,5000
20
`);

MCP 参考:vjcad/example/command/05executescript.js(⚠️ 示例里的矩形脚本以 LINE+空行收尾——最后一条 LINE 会等不到输入而挂起,且空行并不产生回车)。

二、ExecuteStrCommand.executeString(script):带语法糖的脚本

EXECSTR 命令类(导出为 vjcad.ExecuteStrCommand)内部用 GD 解析器把脚本编译成可执行行序列,再喂给 automate——SET/$(VAR)/%VAR%/$(expr)/REPEAT n…ENDREPEAT/GOTO/:label/IF … GOTO 都在这一层生效,裸 automate 里它们只是被静默跳过的普通行。

await new vjcad.ExecuteStrCommand().executeString(`SET Y=8000
REPEAT 3
CIRCLE
9000,$(Y)
$(10*2)
ENDREPEAT
`);
// REPEAT 3 展开三次 → CIRCLE +3;$(Y)→8000、$(10*2)→20

⚠️ REPEAT 展开的是原样的行序列——块内若放 LINE 这类需收尾命令,块首的 LINE 行会沦为上一轮 LINE 的 Cancel 输入,循环只产出 1 条。块内用自完成命令(CIRCLE/RECTANG 等两点即完的)才稳。

语法表(ExecuteStrCommand 层):

元素 含义
; 或 // 开头 注释(解析器与 automate 两层都会跳过)
SET VAR=value 变量赋值(值先经 $(…)/%…% 展开,可解析成数字则存数字)
$(VAR) / %VAR% 引用变量
$(expr) 表达式:$(100+50*2)、$(PI)、$(CLAYER)、$(CECOLOR)、$(LASTPOINT_X/Y)
REPEAT n … ENDREPEAT 循环展开(n 可写表达式,嵌套 REPEAT 支持)
GOTO :label / IF cond GOTO :label 跳转/条件跳转(:label 行定义标签)
空行 编译为 "" 行进入 automate,再被点输入跳过——不是回车

二、EXECSTR:弹脚本编辑对话框

await Engine.editor.executerWithOp('EXECSTR');

会弹出脚本输入对话框,用户在里面写脚本然后执行。MCP 参考:vjcad/example/command/05executescript.js(⚠️ 示例里打印的 EXECUTESTR 是过期名,真实注册名 EXECSTR;EXECJS 同理)。

三、EXECJS:弹 JS 代码对话框,跑一段 JS

await Engine.editor.executerWithOp('EXECJS');

执行上下文(vjcad@1.0.16 源码):ExecuteJsCommand.executeCode 把 window.vjcad 的全部导出按名字注入 AsyncFunction 参数——即所有 vjcad 顶层导出都可用,如 Engine、Point2D、LineEnt、CircleEnt、ArcEnt、PolylineEnt、TextEnt、MTextEnt、writeMessage、message、regen 等。

⚠️ 官方示例 06executejs.js 自述的 doc / log / executeCommand / addEntity 四个全局在 vjcad@1.0.16 源码中并不存在(它们不是包导出);等价写法是 Engine.currentDoc、message.info(...)/writeMessage(...)、Engine.editor.executerWithOp('CMD')、Engine.addEntities(ent)。示例模板里 addEntity(circle) / executeCommand(...) 的写法在对话框里会 ReferenceError。

MCP 参考:vjcad/example/command/06executejs.js。

四、对比 automate vs executerWithOp

想做的 用
跑一段已有的命令脚本 Engine.editor.automate(scriptString)
跑一条命令(字符串名) Engine.editor.executerWithOp('CMDNAME')
弹给用户编辑脚本 / JS Engine.editor.executerWithOp('EXECSTR') / 'EXECJS'

反例

  • 给 automate 传含 SET/$(…)/REPEAT 的脚本:这些行在 automate 层全部静默跳过——$(R) 喂给点输入会得到 NaN→Cancel。要用 new vjcad.ExecuteStrCommand().executeString(...)。
  • 脚本以"还在等输入的命令"结尾:栈空 → getPoint 落回交互等待 → automate() 挂起。收尾用一条自完成命令(如 CIRCLE 两段即完)或让下一条命令名吃掉它。
  • 脚本里写中文标点:100,50 不是合法参数(应是英文 ,)。
  • automate 无法喂 getString/getKeyword/getReal/getEntity 类输入——命令走到这类提示会静默转交互、Promise 不返回。只能驱动纯点输入链路的命令。

参考(官方文档 MCP)

  • 文档:vjcad/doc/command/index.md
  • 示例:vjcad/example/command/05executescript.js、vjcad/example/command/06executejs.js