快速上手
从零写一个书砚插件
本教程带你一步一步写出自己的第一个书砚扩展——「每日一句」侧边栏插件,会在侧边栏显示一句随机金句,鼓励码字的自己。
第 1 步:创建文件
在书砚安装目录的 plugins/ 下新建 daily_quote.py:
plugins/daily_quote.py
def get_info():
return {
'name': 'daily_quote',
'display_name': '📅 每日一句',
'version': '1.0.0',
'author': '你的名字',
'description': '侧边栏显示一句随机金句',
}
def activate(api):
# TODO: 在这里往侧边栏挂面板
pass
保存后重启书砚,打开任意项目 → 编辑器页面右下角的控制台应该会打印 [插件] ✓ daily_quote 已激活。
第 2 步:往侧边栏挂面板
侧边栏是一个 QTabWidget(就是「👤 人物 / 📍 地点 / ⚔️ 物品 / ⚠️ 敏感词」那一排),用 api.add_side_tab(widget, label) 就能加自己的 tab:
import random
from PySide2.QtWidgets import QWidget, QVBoxLayout, QLabel, QPushButton
QUOTES = [
"写作是把自己摊开的过程。",
"每天写一千字,坚持一年就是三十六万字。",
"不要等灵感,要等习惯。",
"写完比写好更重要。",
"读者要的不是完美,是真实。",
]
def activate(api):
# 1. 造面板
panel = QWidget()
layout = QVBoxLayout(panel)
quote_label = QLabel("点下面按钮抽一句~")
quote_label.setWordWrap(True)
quote_label.setStyleSheet("font-size: 16px; padding: 12px; color: #555;")
btn = QPushButton("🎲 换一句")
layout.addWidget(quote_label)
layout.addWidget(btn)
layout.addStretch()
# 2. 挂到侧边栏
api.add_side_tab(panel, "📅 金句")
# 3. 按钮逻辑(可以直接访问 api.db / api.project_id 等)
def refresh():
quote_label.setText(random.choice(QUOTES))
btn.clicked.connect(refresh)
refresh() # 初始化先显示一句
重启书砚,侧边栏最后一个 tab 就是「📅 金句」了!
第 3 步:加一个工具栏按钮
工具栏按钮走 api.add_toolbar_btn(label, slot);如果想加在已有菜单里,用 api.add_menu(parent, label, slot, shortcut=None)。parent 可以是字符串("文件" / "编辑" / "工具"),也可以是 QMenu 对象。
def activate(api):
# ... 上面的代码 ...
# 加工具栏按钮
api.add_toolbar_btn("🎲 金句", lambda: random.choice(QUOTES))
# 加菜单项(带快捷键)
api.add_menu("工具", "📅 显示金句",
lambda: api.toast(random.choice(QUOTES)),
shortcut="Ctrl+Shift+Q")
第 4 步:注册 Hook
Hook 让你的插件在某些事件发生时自动被通知,比如章节保存后、切换 tab 时、文本变化时。
def activate(api):
# ...
# 章节保存时弹个鼓励 toast
def on_saved(editor):
api.toast("本章保存啦!✅ " + random.choice(QUOTES))
api.on_chapter_saved(on_saved)
第 5 步:读写数据库和配置
插件通过 api.db 拿到完整的 Database 实例,可以用 api.project_id 拿到当前项目 ID。
def activate(api):
# 列出所有章节
chapters = api.list_chapters()
api.toast(f"当前项目共 {len(chapters)} 章")
# 搜索某个关键词
hits = api.search_text("张三")
for h in hits[:3]:
print(h['chapter_title'], h['context'])
# 存插件自己的配置(key 要加前缀防冲突)
api.set_config(f'daily_quote_fav_{api.project_id}',
"写作是把自己摊开的过程")
# 读回来
fav = api.get_config(f'daily_quote_fav_{api.project_id}', '')
第 6 步:打开章节 / 跳转位置
如果插件想主动让书砚打开某个章节或者跳到某个位置:
# 打开第 3 章
api.open_chapter(3)
# 打开第 3 章并跳到第 120 个字符
api.jump_to_offset(3, 120)
第 7 步:调用编辑器的 Markdown 方法
书砚的 NovelEditor 内置了 Markdown 快捷插入方法,插件可以直接调用:
def activate(api):
# 当章节保存时自动在开头加一条分割线
def on_saved(editor):
# 编辑器可能为 None
if not api.editor:
return
api.editor.md_hr() # 插入 --- 分割线
api.editor.md_h3() # 插入 ###
api.on_chapter_saved(on_saved)
第 8 步:禁用 / 卸载
如果你的插件提供了 deactivate(api) 函数,禁用或卸载时会被调用。适合做清理工作,比如从侧边栏移除自己的 tab:
def deactivate(api):
# 侧边栏 tab 会自动随 widget 销毁而关闭
# 这里主要清理 Hook、定时器等
print("[插件] daily_quote 已停用")
禁用 / 卸载 / 刷新都可以在 工具 → 扩展管理 对话框里完成。
安全警告:插件有完整的 Python 执行权限,可以读写任意文件、发起网络请求、执行系统命令。只从可信来源安装扩展!