添加 man 指令

This commit is contained in:
2025-10-07 15:54:16 +08:00
parent 91687fb8c3
commit 109a81923f
8 changed files with 211 additions and 0 deletions

View File

@ -0,0 +1,34 @@
from nonebot import get_plugin_config
import nonebot
import nonebot.adapters
import nonebot.adapters.console
import nonebot.adapters.discord
import nonebot.adapters.onebot
from pydantic import BaseModel
class IsAdminConfig(BaseModel):
admin_qq_group: list[int] = []
admin_qq_account: list[int] = []
admin_discord_channel: list[int] = []
admin_discord_account: list[int] = []
cfg = get_plugin_config(IsAdminConfig)
def is_admin(event: nonebot.adapters.Event):
if isinstance(event, nonebot.adapters.onebot.v11.MessageEvent):
if event.user_id in cfg.admin_qq_account:
return True
if isinstance(event, nonebot.adapters.onebot.v11.GroupMessageEvent):
if event.group_id in cfg.admin_qq_group:
return True
if isinstance(event, nonebot.adapters.discord.event.MessageEvent):
if event.channel_id in cfg.admin_discord_channel:
return True
if event.user_id in cfg.admin_discord_account:
return True
if isinstance(event, nonebot.adapters.console.event.Event):
return True
return False

View File

@ -2,3 +2,11 @@ from pathlib import Path
ASSETS_PATH = Path(__file__).resolve().parent.parent.parent / "assets" ASSETS_PATH = Path(__file__).resolve().parent.parent.parent / "assets"
FONTS_PATH = ASSETS_PATH / "fonts" FONTS_PATH = ASSETS_PATH / "fonts"
SRC_PATH = Path(__file__).resolve().parent.parent
DOCS_PATH = SRC_PATH / "docs"
DOCS_PATH_MAN1 = DOCS_PATH / "user"
DOCS_PATH_MAN3 = DOCS_PATH / "lib"
DOCS_PATH_MAN7 = DOCS_PATH / "concepts"
DOCS_PATH_MAN8 = DOCS_PATH / "sys"

40
konabot/docs/README.md Normal file
View File

@ -0,0 +1,40 @@
# 此方 Bot 的文档系统
此方 Bot 使用类 Linux 的 `man` 指令来管理文档。文档一般建议使用纯文本书写,带有相对良好的格式。
## 文件夹摆放规则
`docs` 目录下,有若干文档可以拿来阅读和输出。每个子文件夹里,文档文件使用名字不含空格的 txt 文件书写,其他后缀名的文件将会被忽略。所以,如果你希望有些文件只在代码库中可阅读,你可以使用 `.md` 格式。
### 1 - user
`docs/user` 目录下的文档是直接会给用户进行检索的文档,在直接使用 `man` 指令时,会搜索该文件夹的全部文件,以知晓所有有文档的指令。
### 3 - lib
`docs/lib` 目录下的文档主要给该项目的维护者进行阅读和使用,讲述的是本项目内置的一些函数的功能讲解(一般以便利为主要目的)以及一些项目安排上的要求。一般不会列举,除非用户指定要求列举该范围。
### 7 - concepts
`docs/concepts` 用来摆放任何的概念。任何的。一般不会列举,除非用户指定要求列举该范围。
### 8 - sys
`docs/sys` 用于摆放仅 MTTU 群可以使用的文档集合。在 MTTU 群内,该目录下的文档也会被索引,否则文档将不可阅读。
## 书写规范
无特殊要求,因为当用户进行 `man` 的时候,会将文档内的内容原封不动地展示出来。但是,你仍然可以模仿 Linux 下的 `man` 指令的格式进行书写。
```
指令介绍
man - 用于展示此方 BOT 使用手册的指令
格式
man [文档类型] <指令>
示例
`man` 查看所有有文档的指令清单
`man 喵` 查看指令「喵」的使用说明
……
```

View File

View File

1
konabot/docs/sys/out.txt Normal file
View File

@ -0,0 +1 @@
MAN what can I say!

24
konabot/docs/user/man.txt Normal file
View File

@ -0,0 +1,24 @@
指令介绍
man - 用于展示此方 BOT 使用手册的指令
格式
man 文档类型 [文档类型选项]
man [文档类型] <指令>
示例
`man` 查看所有有文档的指令清单
`man 3` 列举所有可读文档的库函数清单
`man 喵` 查看指令「喵」的使用说明
`man 8 out` 查看管理员指令「out」的使用说明
文档类型
文档类型用来区分同一指令在不同场景下的情景。你可以使用数字编号进行筛选。分为这些种类:
- 1 用户态指令,用于日常使用的指令
- 3 库函数指令,用于 Bot 开发用的函数查询
- 7 概念指令,用于概念解释
- 8 系统指令,仅管理员可用
文档类型选项
-p <page>
指定要列举的文档清单的页

View File

@ -0,0 +1,104 @@
from curses.ascii import isdigit
from pathlib import Path
import nonebot
import nonebot.adapters
import nonebot.adapters.discord
import nonebot.rule
from nonebot import on_command
from nonebot_plugin_alconna import Alconna, Args, UniMessage, on_alconna
from konabot.common.nb.is_admin import is_admin
from konabot.common.path import DOCS_PATH_MAN1, DOCS_PATH_MAN3, DOCS_PATH_MAN7, DOCS_PATH_MAN8
def search_man(section: int) -> dict[tuple[int, str], Path]:
base_path = {
1: DOCS_PATH_MAN1,
3: DOCS_PATH_MAN3,
7: DOCS_PATH_MAN7,
8: DOCS_PATH_MAN8,
}.get(section, DOCS_PATH_MAN1)
res: dict[tuple[int, str], Path] = {}
for fp in base_path.iterdir():
if fp.suffix != '.txt':
continue
name = fp.name.lower().removesuffix('.txt')
res[(section, name)] = fp
return res
man = on_alconna(Alconna(
'man',
Args['section', int | None],
Args['doc', str | None],
))
@man.handle()
async def _(
section: int | None,
doc: str | None,
event: nonebot.adapters.Event,
):
if doc is not None and section is None and all(isdigit(c) for c in doc):
section = int(doc)
doc = None
if section is not None and section not in {1, 3, 7, 8}:
await man.send(
UniMessage().text(f"你所指定的文档类型 {section} 不在可用范围内")
)
return
if doc is None:
# 检索模式
if section is None:
section_set = {1}
else:
section_set = {section}
if 1 in section_set and is_admin(event):
section_set.add(8)
mans: list[str] = []
for section in section_set:
mans += [f"{n}({s})" for s, n in search_man(section).keys()]
mans.sort()
await man.send(UniMessage().text(
(
"★此方 BOT 使用帮助★\n"
"使用 man <指令名> 查询某个指令的名字\n\n"
"可供查询的指令清单:"
)
+ ", ".join(mans)
+ "\n\n例如,使用 man man 来查询 man 指令的使用方法"
))
else:
# 查阅模式
if section is None:
section_set = {1}
else:
section_set = {section}
if 1 in section_set and is_admin(event):
section_set.add(8)
if 8 in section_set and not is_admin(event):
await man.send(UniMessage().text("你没有查看该指令类型的权限"))
return
mans_dict: dict[tuple[int, str], Path] = {}
for section in section_set:
mans_dict: dict[tuple[int, str], Path] = {**mans_dict, **search_man(section)}
mans_dict_2 = {key[1]: val for key, val in mans_dict.items()}
mans_fp = mans_dict_2.get(doc.lower())
if mans_fp is None:
await man.send(UniMessage().text("你所检索的指令不存在"))
return
mans_msg = mans_fp.read_text('utf-8', 'replace')
if isinstance(event, nonebot.adapters.discord.event.MessageEvent):
mans_msg = f'```\n{mans_msg}\n```'
await man.send(UniMessage().text(mans_msg))
help_deprecated = on_command('help', rule=nonebot.rule.to_me())
@help_deprecated.handle()
async def _():
await help_deprecated.send('请使用 man 指令来查询此方 bot 的帮助文档哦')