diff --git a/src/nonebot_plugin_alconna/matcher.py b/src/nonebot_plugin_alconna/matcher.py index 1254a4e..18ff57a 100644 --- a/src/nonebot_plugin_alconna/matcher.py +++ b/src/nonebot_plugin_alconna/matcher.py @@ -41,11 +41,11 @@ from .util import annotation from .pattern import patterns from .model import CompConfig, CommandModel -from .uniseg import Text, Segment, UniMessage from .uniseg.fallback import FallbackStrategy from .uniseg.template import UniMessageTemplate from .uniseg.message import current_send_wrapper from .extension import Extension, ExtensionExecutor +from .uniseg import Text, Segment, UniMessage, segment from .consts import ALCONNA_RESULT, ALCONNA_ARG_KEY, log from .params import ( CHECK, @@ -1188,6 +1188,11 @@ def from_model(cls, model: CommandModel): prefix=short.prefix, humanized=short.humanized, ) + if model.actions: + _globals = {**segment.__dict__, **globals()} + for act in model.actions: + func = act.gen_exec(_globals) + cmd.action(func) return cmd diff --git a/src/nonebot_plugin_alconna/model.py b/src/nonebot_plugin_alconna/model.py index 12234d2..97451a3 100644 --- a/src/nonebot_plugin_alconna/model.py +++ b/src/nonebot_plugin_alconna/model.py @@ -2,6 +2,7 @@ from typing import Any, Union, Generic, Literal, TypeVar, Optional, TypedDict from pydantic import Field, BaseModel +from arclet.alconna.action import Action from arclet.alconna import Empty, Alconna, Arparma from arclet.alconna.duplication import Duplication from nonebot.compat import PYDANTIC_V2, ConfigDict @@ -94,6 +95,7 @@ class OptionModel(BaseModel): name: str opt: Optional[str] = None default: Any = None + action: Optional[Union[Literal["store_true", "store_false", "count", "append"], Action]] = None class ShortcutModel(BaseModel): @@ -105,6 +107,20 @@ class ShortcutModel(BaseModel): humanized: Optional[str] = None +class ActionModel(BaseModel): + params: list[str] + code: str + + def gen_exec(self, _globals: dict): + code = f"async def _({', '.join(self.params)}):" + lines = self.code.splitlines() + for line in lines: + code += f" {line}" + _locals = {} + exec(code, _globals, _locals) + return _locals["_"] + + class CommandModel(BaseModel): command: str help: Optional[str] = None @@ -128,3 +144,4 @@ class CommandModel(BaseModel): options: list[OptionModel] = Field(default_factory=list) subcommands: list[SubcommandModel] = Field(default_factory=list) shortcuts: list[ShortcutModel] = Field(default_factory=list) + actions: list[ActionModel] = Field(default_factory=list) diff --git a/tests/test_koishi_command.py b/tests/test_koishi_command.py index 070ebb3..e7ed264 100644 --- a/tests/test_koishi_command.py +++ b/tests/test_koishi_command.py @@ -38,10 +38,6 @@ async def _(arp: Arparma): book1 = command_from_yaml(FILE).build() - @book1.handle() - async def _(arp: Arparma): - await book1.send(str(arp.options)) - async with app.test_matcher(book1) as ctx: # type: ignore adapter = get_adapter(Adapter) bot = ctx.create_bot(base=Bot, adapter=adapter) diff --git a/tests/test_koishi_command.yml b/tests/test_koishi_command.yml index 03a68fb..ccc6c0c 100644 --- a/tests/test_koishi_command.yml +++ b/tests/test_koishi_command.yml @@ -11,3 +11,8 @@ usage: book [-w | --anonymous] shortcuts: - key: 测试 args: ["--anonymous"] +actions: + - + params: ["options"] + code: | + return str(options) \ No newline at end of file