Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docs: 更新最佳实践的 Alconna 部分 #2443

Merged
merged 7 commits into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 23 additions & 5 deletions website/docs/best-practice/alconna/README.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ description: Alconna 命令解析拓展
slug: /best-practice/alconna/
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Alconna 插件

[`nonebot-plugin-alconna`](https://github.com/nonebot/plugin-alconna) 是一类提供了拓展响应规则的插件。
该插件使用 [Alconna](https://github.com/ArcletProject/Alconna) 作为命令解析器,
是一个简单、灵活、高效的命令参数解析器, 并且不局限于解析命令式字符串。
是一个简单、灵活、高效的命令参数解析器并且不局限于解析命令式字符串。

该插件提供了一类新的事件响应器辅助函数 `on_alconna`,以及 `AlconnaResult` 等依赖注入函数。

Expand All @@ -31,16 +34,31 @@ slug: /best-practice/alconna/

在**项目目录**下执行以下命令:

<Tabs groupId="install">
<TabItem value="cli" label="使用 nb-cli">

```shell
nb plugin install nonebot-plugin-alconna
```

</TabItem>
<TabItem value="pip" label="使用 pip">

```shell
pip install nonebot-plugin-alconna
```

</TabItem>

<TabItem value="pdm" label="使用 pdm">

```shell
pdm add nonebot-plugin-alconna
```

</TabItem>
</Tabs>

## 导入插件

由于 `nonebot-plugin-alconna` 作为插件,因此需要在使用前对其进行**加载**并**导入**其中的 `on_alconna` 来使用命令拓展。使用 `require` 方法可轻松完成这一过程,可参考 [跨插件访问](../../advanced/requiring.md) 一节进行了解。
Expand Down Expand Up @@ -87,7 +105,7 @@ async def got_location(location: str = ArgPlainText()):
```python {5-10,14-16,18-19}
from nonebot.rule import to_me
from arclet.alconna import Alconna, Args
from nonebot_plugin_alconna import Match, AlconnaMatcher, on_alconna
from nonebot_plugin_alconna import Match, on_alconna

weather = on_alconna(
Alconna("天气", Args["location?", str]),
Expand All @@ -98,9 +116,9 @@ weather.shortcut("天气预报", {"command": "天气"})


@weather.handle()
async def handle_function(matcher: AlconnaMatcher, location: Match[str]):
async def handle_function(location: Match[str]):
if location.available:
matcher.set_path_arg("location", location.result)
weather.set_path_arg("location", location.result)

@weather.got_path("location", prompt="请输入地名")
async def got_location(location: str):
Expand Down
112 changes: 98 additions & 14 deletions website/docs/best-practice/alconna/command.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ description: Alconna 基本介绍
# Alconna 命令解析

[Alconna](https://github.com/ArcletProject/Alconna) 作为命令解析器,
是一个简单、灵活、高效的命令参数解析器, 并且不局限于解析命令式字符串。
是一个简单、灵活、高效的命令参数解析器并且不局限于解析命令式字符串。

特点包括:
yanyongyu marked this conversation as resolved.
Show resolved Hide resolved

Expand All @@ -16,10 +16,94 @@ description: Alconna 基本介绍
- 自定义的帮助信息格式
- 多语言支持
- 易用的快捷命令创建与使用
- 可创建命令补全会话, 以实现多轮连续的补全提示
- 可创建命令补全会话以实现多轮连续的补全提示
- 可嵌套的多级子命令
- 正则匹配支持

## 命令示范

```python
import sys
from io import StringIO

from arclet.alconna import Alconna, Args, Field, Option, CommandMeta, MultiVar, Arparma
from nepattern import AnyString

alc = Alconna(
"exec",
Args["code", MultiVar(AnyString), Field(completion=lambda: "print(1+1)")] / "\n",
Option("纯文本"),
Option("无输出"),
Option("目标", Args["name", str, "res"]),
meta=CommandMeta("exec python code", example="exec\\nprint(1+1)"),
)

alc.shortcut(
"echo",
{"command": "exec 纯文本\nprint(\\'{*}\\')"},
)

alc.shortcut(
"sin(\d+)",
{"command": "exec 纯文本\nimport math\nprint(math.sin({0}*math.pi/180))"},
)


def exec_code(result: Arparma):
if result.find("纯文本"):
codes = list(result.code)
else:
codes = str(result.origin).split("\n")[1:]
output = result.query[str]("目标.name", "res")
if not codes:
return ""
lcs = {}
_stdout = StringIO()
_to = sys.stdout
sys.stdout = _stdout
try:
exec(
"def rc(__out: str):\n "
+ " ".join(_code + "\n" for _code in codes)
+ " return locals().get(__out)",
{**globals(), **locals()},
lcs,
)
code_res = lcs["rc"](output)
sys.stdout = _to
if result.find("无输出"):
return ""
if code_res is not None:
return f"{output}: {code_res}"
_out = _stdout.getvalue()
return f"输出: {_out}"
except Exception as e:
sys.stdout = _to
return str(e)
finally:
sys.stdout = _to

print(exec_code(alc.parse("echo 1234")))
print(exec_code(alc.parse("sin30")))
print(
exec_code(
alc.parse(
"""\
exec
print(
exec_code(
alc.parse(
"exec\\n"
"import sys;print(sys.version)"
)
)
)
"""
)
)
)
```

## 命令编写

### 命令头
Expand Down Expand Up @@ -115,7 +199,7 @@ alc = Alconna(
- `help_text`: 传入该组件的帮助信息
- `dest`: 被指定为解析完成时标注匹配结果的标识符,不传入时默认为选项或子命令的名称 (name)
- `requires`: 一段指定顺序的字符串列表,作为唯一的前置序列与命令嵌套替换
对于命令 `test foo bar baz qux <a:int>` 来讲,因为`foo bar baz` 仅需要判断是否相等, 所以可以这么编写:
对于命令 `test foo bar baz qux <a:int>` 来讲,因为`foo bar baz` 仅需要判断是否相等所以可以这么编写:

```python
Alconna("test", Option("qux", Args["a", int], requires=["foo", "bar", "baz"]))
Expand Down Expand Up @@ -263,7 +347,7 @@ args = Args["foo", BasePattern("@\d+")]

### 紧凑命令

`Alconna`, `Option` 与 `Subcommand` 可以设置 `compact=True` 使得解析命令时允许名称与后随参数之间没有分隔:
`Alconna``Option` 可以设置 `compact=True` 使得解析命令时允许名称与后随参数之间没有分隔:

```python
from arclet.alconna import Alconna, Option, CommandMeta, Args
Expand Down Expand Up @@ -390,14 +474,14 @@ class ShortcutArgs(TypedDict):

- `{%X}`: 如 `setu {%0}`,表示此处必须填入快捷指令后随的第 X 个参数。

例如,若快捷指令为 `涩图`, 配置为 `{"command": "setu {%0}"}`, 则指令 `涩图 1` 相当于 `setu 1`
例如,若快捷指令为 `涩图`配置为 `{"command": "setu {%0}"}`则指令 `涩图 1` 相当于 `setu 1`

- `{*}`: 表示此处填入所有后随参数,并且可以通过 `{*X}` 的方式指定组合参数之间的分隔符。
- `{X}`: 表示此处填入可能的正则匹配的组:
- 若 `command` 中存在匹配组 `(xxx)`,则 `{X}` 表示第 X 个匹配组的内容
- 若 `command` 中存储匹配组 `(?P<xxx>...)`, 则 `{X}` 表示名字为 X 的匹配结果
- 若 `command` 中存储匹配组 `(?P<xxx>...)`则 `{X}` 表示名字为 X 的匹配结果

除此之外, 通过内置选项 `--shortcut` 可以动态操作快捷指令。
除此之外通过内置选项 `--shortcut` 可以动态操作快捷指令。

例如:

Expand Down Expand Up @@ -444,17 +528,17 @@ alc.parse("test_fuzy")

`path` 支持如下:

- `main_args`, `options`, ...: 返回对应的属性
- `main_args``options`...: 返回对应的属性
- `args`: 返回 all_matched_args
- `main_args.xxx`, `options.xxx`, ...: 返回字典中 `xxx`键对应的值
- `main_args.xxx``options.xxx`...: 返回字典中 `xxx`键对应的值
- `args.xxx`: 返回 all_matched_args 中 `xxx`键对应的值
- `options.foo`, `foo`: 返回选项 `foo` 的解析结果 (OptionResult)
- `options.foo.value`, `foo.value`: 返回选项 `foo` 的解析值
- `options.foo.args`, `foo.args`: 返回选项 `foo` 的解析参数字典
- `options.foo.args.bar`, `foo.bar`: 返回选项 `foo` 的参数字典中 `bar` 键对应的值
- `options.foo``foo`: 返回选项 `foo` 的解析结果 (OptionResult)
- `options.foo.value``foo.value`: 返回选项 `foo` 的解析值
- `options.foo.args``foo.args`: 返回选项 `foo` 的解析参数字典
- `options.foo.args.bar``foo.bar`: 返回选项 `foo` 的参数字典中 `bar` 键对应的值
...

同样, `Arparma["foo.bar"]` 的表现与 `query()` 一致
同样`Arparma["foo.bar"]` 的表现与 `query()` 一致

## Duplication

Expand Down
11 changes: 2 additions & 9 deletions website/docs/best-practice/alconna/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,7 @@ description: 配置项
- **类型**: `bool`
- **默认值**: `False`

是否全局使用原始消息 (即未经过 to_me 等处理的), 该选项会影响到 Alconna 的匹配行为。

## alconna_use_param

- **类型**: `bool`
- **默认值**: `True`

是否使用特制的 Param 提供更好的依赖注入,该选项不会对使用依赖注入函数形式造成影响
是否全局使用原始消息 (即未经过 to_me 等处理的),该选项会影响到 Alconna 的匹配行为。

## alconna_use_command_sep

Expand All @@ -52,4 +45,4 @@ description: 配置项
- **类型**: `List[str]`
- **默认值**: `[]`

全局加载的扩展, 路径以 . 分隔, 如 foo.bar.baz:DemoExtension
全局加载的扩展路径以 . 分隔,如 `foo.bar.baz:DemoExtension`
Loading