From 073978d3cabdfa2c3deb688fb4523b0548a48efb Mon Sep 17 00:00:00 2001
From: thzxx
Date: Sat, 15 Aug 2026 21:18:05 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20v0.6.2=20=E2=80=94=20sqlark=200.7.4=20?=
=?UTF-8?q?=E5=8D=87=E7=BA=A7(KVStore)=20+=2014=20=E9=A1=B9=E7=BC=BA?=
=?UTF-8?q?=E9=99=B7=E4=BF=AE=E5=A4=8D=20+=20=E5=A4=9A=E6=96=87=E4=BB=B6?=
=?UTF-8?q?=E6=90=9C=E7=B4=A2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- chore: 升级 @metona-team/metona-sqlark 0.4.4 → 0.7.4,存储后端迁移
KVStore 引擎(内存索引+快照/日志,OPFS 落盘,jsdom 回退 memory),
启动时自动删除旧 IndexedDB 库(aria-MarkLiteV2 / Dexie MarkLite),
不做向下兼容
- fix: 保存竞态 — 快照比对后才清 isModified,防止保存期间的新输入被
误清标记导致永不落盘(自动保存与手动保存均修复)
- fix: 另存为后标签重绑新路径(此前 Ctrl+S/自动保存仍写回旧文件),
并同步最近文件与快照持久化
- fix: tabSwitched 只依赖活动文件路径(此前每次击键都触发 IPC 并
重启主进程文件 watcher)
- fix: 主进程关闭兜底超时 5s→12s(长于 confirm 10s,防强杀丢编辑)
- fix: 外部修改检测覆盖非活动标签,banner 显示文件名,
标签有未保存修改时显式提示不再静默
- fix: 导入备份后 flush + closeDatabase 再 reload(防 OPFS 未落盘丢数据),
导入整体事务原子化(防半导入状态)
- fix: 文档大纲跳过代码块内标题;切换标签恢复光标位置
- fix: 首次启动主题跟随系统偏好(settings 无记录时 load 返回 null)
- fix: watcher error 恢复时重置 isSelfWriting,防外部修改通知被永久吞掉
- fix: 打开失败路径(最近文件/文件树/打开对话框)显式提示
- fix: 保存时保留原文件编码(UTF-16 LE/BE BOM 同编码写回)
- feat: 多文件搜索 — dir:search IPC + SearchPanel 弹层 + Ctrl+Shift+F,
文件夹内递归搜索(大小写/正则,结果定位到行)
- feat: 标签恢复时与磁盘 mtime 比对,自动同步磁盘最新内容
- test: 新增 outlineUtils(6) / searchInDir(7) / updateTabFilePath(2) 测试
- docs: README/DESIGN 同步 kv 后端与版本号 v0.6.2
---
DESIGN.md | 15 +-
README.md | 6 +-
docs/metona-sqlark-demo.html | 43 ++++-
docs/metona-sqlark-docs.html | 133 ++++++++++---
package.json | 5 +-
src/main/__tests__/searchInDir.test.ts | 71 +++++++
src/main/file-system.ts | 124 +++++++++++-
src/main/file-watcher.ts | 4 +
src/main/index.ts | 4 +-
src/main/ipc-handlers.ts | 20 +-
src/preload/index.ts | 2 +
src/renderer/App.tsx | 72 ++++++-
.../components/AboutDialog/AboutDialog.tsx | 2 +-
src/renderer/components/Editor/Editor.tsx | 12 +-
src/renderer/components/Icons.tsx | 19 ++
.../ModifiedBanner/ModifiedBanner.tsx | 5 +-
.../__tests__/outlineUtils.test.ts | 48 +++++
.../components/OutlinePanel/outlineUtils.ts | 35 +++-
.../components/SearchPanel/SearchPanel.tsx | 171 ++++++++++++++++
src/renderer/components/SearchPanel/index.ts | 1 +
src/renderer/components/Sidebar/Sidebar.tsx | 8 +
src/renderer/components/Toolbar/Toolbar.tsx | 26 ++-
.../__tests__/recentFiles.integration.test.ts | 5 +-
src/renderer/db/backupRepository.ts | 15 +-
src/renderer/db/schema.ts | 95 +++++++--
src/renderer/db/settingsRepository.ts | 12 +-
src/renderer/hooks/useAutoSave.ts | 15 +-
src/renderer/hooks/useFileOperations.ts | 32 ++-
src/renderer/hooks/useFileWatch.ts | 10 +-
src/renderer/hooks/useKeyboard.ts | 9 +-
src/renderer/hooks/useSettingsInit.ts | 12 +-
.../stores/__tests__/tabStore.test.ts | 26 +++
src/renderer/stores/tabStore.ts | 44 +++++
src/renderer/styles/global.css | 182 ++++++++++++++++++
src/renderer/types/ipc.ts | 4 +
src/shared/constants.ts | 2 +-
src/shared/ipc-channels.ts | 1 +
src/shared/types.ts | 24 +++
38 files changed, 1191 insertions(+), 123 deletions(-)
create mode 100644 src/main/__tests__/searchInDir.test.ts
create mode 100644 src/renderer/components/OutlinePanel/__tests__/outlineUtils.test.ts
create mode 100644 src/renderer/components/SearchPanel/SearchPanel.tsx
create mode 100644 src/renderer/components/SearchPanel/index.ts
diff --git a/DESIGN.md b/DESIGN.md
index c209e98..551d7d0 100644
--- a/DESIGN.md
+++ b/DESIGN.md
@@ -22,7 +22,7 @@ MarkLite 是一款轻量级的 Windows 本地 Markdown 编辑器桌面应用程
| 类型系统 | TypeScript | v5.6 | 全量类型安全 |
| 编辑器 | MetonaEditor | v0.4.0 | 零依赖 Markdown 编辑器,三模式视图 + 插件系统 |
| 状态管理 | Zustand | v5 | 轻量级状态管理 |
-| 持久化 | MetonaSqlark (IndexedDB) | v0.4.1 | 标签页状态 / 用户设置 / 最近文件(AriaEngine) |
+| 持久化 | MetonaSqlark | v0.7.4 | 标签页状态 / 用户设置 / 最近文件(AriaEngine + KVStore,OPFS 落盘;v0.6.2 起不再使用 IndexedDB,旧库启动时自动删除) |
| Markdown 解析 | MetonaEditor 内置解析器 | v0.4.0 | 零依赖,GFM + 脚注 + 数学公式 + mermaid |
| 代码高亮 | MetonaEditor 内置高亮器 | v0.4.0 | 零依赖,16 种语言 |
| Toast | @metona-team/metona-toast | v0.5.0 | 通知提示组件 |
@@ -162,11 +162,13 @@ interface SidebarState {
}
```
-## 4. 数据持久化 — IndexedDB
+## 4. 数据持久化 — MetonaSqlark (KVStore)
v0.5.0: 由 Dexie.js 迁移至 MetonaSqlark(AriaEngine:自研 LSM-Tree + WAL + MVCC 存储引擎,对标 SQLite)。
MetonaSqlark 的 create() 为异步,采用懒加载单例(getDb()),
表结构幂等创建(查表名后 defineTable),数据库名更换为 MarkLiteV2(旧 Dexie 数据已放弃)。
+v0.6.2: sqlark 升级 0.7.4,存储后端改用自研 KVStore(内存索引 + 快照/日志,OPFS 落盘);
+旧 IndexedDB 库在启动时自动删除,不做向下兼容。
### 4.1 数据库 Schema
@@ -175,11 +177,11 @@ MetonaSqlark 的 create() 为异步,采用懒加载单例(getDb()),
let dbPromise: Promise | null = null
export function getDb(): Promise {
if (!dbPromise) {
- dbPromise = MetonaSqlark.create({
+ dbPromise = create({
name: 'MarkLiteV2',
mode: 'aria', // AriaEngine: LSM-Tree + WAL + MVCC 快照隔离
- diskEngine: 'indexeddb', // 底层存储后端(indexeddb | opfs | memory)
- version: 1,
+ diskEngine: 'kv', // v0.6.2: 自研 KVStore 后端(OPFS 落盘;jsdom 测试回退 memory)
+ version: 0, // AriaEngine 忽略版本号
}).then(async (db) => {
if (!(await db.getTableNames()).includes('tabSnapshots')) {
await db.defineTable('tabSnapshots', { id: { type: 'string', primaryKey: true }, ... })
@@ -221,6 +223,7 @@ export function getDb(): Promise {
| `dir:openDialog` | 无 | `string \| null` | 打开文件夹选择对话框 |
| `dir:watch` | `dirPath` | `void` | 监听目录变化 |
| `dir:unwatch` | 无 | `void` | 停止监听目录变化 |
+| `dir:search` | `{ dirPath, query, caseSensitive?, useRegex? }` | `SearchInDirResult` | v0.6.2: 文件夹内多文件内容搜索 |
### 5.2 主进程 → 渲染进程(send)
@@ -405,7 +408,7 @@ npm run build:portable # 便携版(免安装)
|------|------|------|
| react / react-dom | ^18.3 | UI 框架 |
| zustand | ^5.0 | 状态管理 |
-| @metona-team/metona-sqlark | 0.4.1 | 前端关系型数据库(AriaEngine) |
+| @metona-team/metona-sqlark | 0.7.4 | 前端关系型数据库(AriaEngine + KVStore,OPFS) |
| nanoid | ^5.0 | 唯一 ID 生成 |
| @metona-team/metona-editor | 0.4.0 | Markdown 编辑器(内置解析器 + 高亮) |
| @metona-team/metona-toast | 0.5.0 | Toast 通知组件 |
diff --git a/README.md b/README.md
index f6dbb84..7af6ac6 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@
-
+
@@ -38,6 +38,7 @@
| 🔔 **文件监听** | 外部修改文件时自动提示,支持重新加载或忽略 |
| 💾 **文件保存** | 保存 / 另存为,支持 .md / .markdown / .txt 格式 |
| 🔍 **搜索替换** | Ctrl+F 搜索、Ctrl+H 替换,支持正则表达式、大小写敏感 |
+| 🔎 **多文件搜索** | Ctrl+Shift+F 在已打开文件夹内递归搜索内容,结果定位到行 |
| 📁 **文件树** | 侧边栏浏览项目目录,点击打开文件,目录变化自动刷新 |
| 📊 **Mermaid 图表** | 代码块中渲染 Mermaid 流程图 / 时序图 / 甘特图等 |
| 💾 **状态持久化** | 标签页状态、用户设置通过 MetonaSqlark(AriaEngine)持久化,关闭后可恢复 |
@@ -134,6 +135,7 @@ npm run test:coverage
| `Ctrl + Shift + S` | 另存为 |
| `Ctrl + F` | 搜索 |
| `Ctrl + H` | 搜索并替换 |
+| `Ctrl + Shift + F` | 多文件搜索(当前文件夹内) |
| `Ctrl + Z` / `Ctrl + Y` | 撤销 / 重做 |
| `Ctrl + B` / `Ctrl + I` | 粗体 / 斜体(编辑器内置) |
| `Ctrl + E` / `Ctrl + K` / `Ctrl + Q` | 行内代码 / 链接 / 引用(编辑器内置) |
@@ -149,7 +151,7 @@ npm run test:coverage
| 类型系统 | [TypeScript](https://www.typescriptlang.org/) v5.6 | 全量类型安全 |
| 编辑器 | [MetonaEditor](https://git.metona.cn/MetonaTeam/MetonaEditor) v0.4.1 | 内置解析器 + 高亮,三模式视图 + 浮动格式栏 + Zen 模式 + 插件系统 |
| 状态管理 | [Zustand](https://zustand-demo.pmnd.rs/) v5 | 轻量级状态管理 |
-| 持久化 | [MetonaSqlark](https://git.metona.cn/MetonaTeam/MetonaSqlark) v0.4.4 (IndexedDB, AriaEngine) | 标签页状态 & 用户设置持久化 |
+| 持久化 | [MetonaSqlark](https://git.metona.cn/MetonaTeam/MetonaSqlark) v0.7.4 (AriaEngine + KVStore/OPFS) | 标签页状态 & 用户设置持久化 |
| Markdown 解析 | MetonaEditor 内置解析器 | 零依赖:GFM / 脚注 / 数学公式 / Mermaid |
| 代码高亮 | MetonaEditor 内置高亮器 | 零依赖,16 种语言 |
| Toast | [@metona-team/metona-toast](https://git.metona.cn/MetonaTeam/-/packages/npm/@metona-team%2Fmetona-toast) v0.5.0 | 通知提示组件 |
diff --git a/docs/metona-sqlark-demo.html b/docs/metona-sqlark-demo.html
index 6e414d8..1259c4c 100644
--- a/docs/metona-sqlark-demo.html
+++ b/docs/metona-sqlark-demo.html
@@ -3,7 +3,7 @@
-🧪 在线演示 — MetonaSqlark v0.4.4
+🧪 在线演示 — MetonaSqlark v0.7.4