#[command]Expand description
#[command(...)] 属性宏:声明式登记一个 matcher 门控的 handler,在 App::new
时经 inventory 自动收集。
把一个 async fn 注册成消息命令触发器。
保留原函数,并发出 <FN>_KEY 开关键、<FN>__nagisa_register 注册函数与一条
TriggerSpec 登记(详见 crate 级文档「触发器宏的共同展开形状」)。
§属性键
匹配器(三选一,互斥,必给其一):
- 前导位置参数
"签到", "sign", ..:字面量命令词(写在属性最前),编译成正则;至少一个。 regex = "^..$":原始正则字面量(展开期Matcher::regex(..).expect(..), 非法正则在该消费 crate 编译/启动时即暴露)。slots = <Type>:取一个#[derive(Slots)]类型的<Type as FromSlots>::matcher()作头匹配器。
行为:
mention_me(裸旗标):要求消息 @ 本机器人才触发。top(裸旗标):一级 top 观察者,永不被 waiter 拦截。priority = N:整数优先级(支持负数),越大越先。usage = "...":parse-miss 时回贴给用户的用法串(命令专属;#[event]拒绝此键)。
门控(原样搬运的表达式,宏对其内容零知识):
gate = <Rule expr>:任意Rule表达式,原样拼进门控槽。cooldown = <expr>:经Cooldown::from(<expr>).into_rule(..)物化,AND 进门控链最右 (权限/开关先判,冷却最后才盖戳)。
元数据(→ TriggerMeta,缺省由展开期回填):
id = "..."(缺省取函数名)、name = "..."(缺省取函数名)、description = "..."。can_disable = <bool>(缺省true)、default_enable = <bool>(缺省true)、hidden = <bool>(缺省false)。
命令体(参数)始终声明在 handler 形参上(args: Args<MyArgs>),而非属性里:
头写在属性、体写在形参,二者就近落在同一 handler。
§触发语义(命令不互斥)
dispatch 对每条消息逐个试所有命令的匹配器、命中即跑,不首中即停、不做「最具体优先」——
命令型 handler 之间互不阻断(只有 top 观察者与中断 waiter 的 block 能拦)。故两条匹配范围
重叠的命令会都触发。约定:命令作者自行保证匹配不重叠。
字面量命令词天然不必担心「前缀吃后缀」:它们编成 ^(?:词…)(?:\s|$),末尾的 (?:\s|$) 边界让
签到 不会命中 签到日历(CJK 无词边界,靠这个显式边界)。重叠风险主要来自 regex / 多命令
词人为撞车。
§约束
handler 必须是非泛型、无 self 接收者的 async fn(否则编译报错)。
§示例
ⓘ
// 字面量命令词 + 结构化参数:
#[command("echo", "复读", description = "复读一句话")]
async fn echo(ctx: &Context, args: Args<EchoArgs>) -> Result<()> { /* .. */ }
// 正则头 + @机器人 + 优先级 + 声明式门控:
#[command(regex = "^ping$", mention_me, priority = 10, gate = is_admin())]
async fn ping(ctx: &Context) -> Result<()> { /* .. */ }
// 用 #[derive(Slots)] 类型作头匹配器 + 冷却:
#[command(slots = ViewBoard, cooldown = 30)]
async fn view(ctx: &Context, slots: Slots<ViewBoard>) -> Result<()> { /* .. */ }