ModuForge Core
ModuForge Core 是一个基于 Rust 实现的文档编辑器核心库,提供了灵活的文档模型和状态管理。
核心概念
1. 文档模型 (Document Model)
文档模型是 ModuForge 的核心,它定义了文档的结构和行为。主要包含以下几个关键组件:
1.1 节点类型 (NodeType)
节点类型定义了:
- 节点的基本属性(名称、描述、分组)
- 节点的属性约束
- 节点的内容结构规则
- 节点支持的标记类型
1.2 节点规范 (NodeSpec)
节点规范用于配置节点类型的行为和约束。
2. 内容匹配系统 (Content Matching System)
内容匹配系统负责验证和构建文档结构,确保文档内容符合预定义的规则。
2.1 内容匹配规则 (ContentMatch)
内容匹配规则定义了:
- 允许的节点序列
- 节点的重复规则
- 节点的可选性
2.2 内容表达式语法
支持以下内容表达式:
*
- 零个或多个节点+
- 一个或多个节点?
- 零个或一个节点|
- 节点类型选择- 空格分隔的序列
例如:
"DW+" // 一个或多个 DW 节点
"DW*" // 零个或多个 DW 节点
"DW djgc" // DW 节点后跟 djgc 节点
3. 状态流转系统 (State Transition System)
3.1 状态定义
3.2 状态转换流程
- 初始化状态
let state = create.await?;
- 状态转换规则
- 每个操作都会产生新的状态
- 状态转换必须保持文档一致性
- 状态转换必须记录在历史中
- 状态转换必须经过插件验证
- 状态验证
- 文档结构验证
- 插件状态验证
- 事务过滤验证
3.3 核心 apply_transaction 方法
apply_transaction
是状态转换系统的核心方法,负责处理事务的应用和插件的交互。其执行流程如下:
+------------------+
| 开始 |
+------------------+
↓
+------------------+
| 事务过滤 |
+------------------+
↓
+----------+
|过滤失败? |
+----------+
↓
+----------+ +------------------+
| 是 | | 初始化事务 |
+----------+ | 列表和状态 |
↓ | 追踪 |
+------------------+ +------------------+
| 返回原始状态 | ↓
+------------------+ +------------------+
| 插件事务处理循环 |
+------------------+
↓
+------------------+
| 检查所有插件 |
+------------------+
↓
+------------------+
| 有新事务? |
+------------------+
↓
+----------+ +------------------+
| 是 | | 事务后处理 |
+----------+ +------------------+
↓ ↓
+------------------+ +------------------+
| 应用新事务 | | 遍历所有插件 |
+------------------+ +------------------+
↓ ↓
+------------------+ +------------------+
| 更新状态追踪 | | 执行插件后处理 |
+------------------+ +------------------+
↓ ↓
+------------------+ +------------------+
| 添加到事务列表 | | 更新插件状态 |
+------------------+ +------------------+
↓ ↓
+------------------+ +------------------+
| 结束 | | 结束 |
+------------------+ +------------------+
这个方法的主要特点:
-
事务过滤机制
- 在应用事务前进行过滤
- 支持插件自定义过滤规则
- 可以阻止不合法的事务
-
插件事务追加
- 支持插件追加新事务
- 维护事务处理顺序
- 防止循环依赖
-
状态追踪
- 记录每个插件的处理状态
- 追踪事务处理进度
- 确保状态一致性
-
事务后处理
- 允许插件进行清理工作
- 更新插件状态
- 维护系统一致性
4. 事务系统 (Transaction System)
4.1 事务定义
4.2 事务执行流程
- 事务开始
let tr = state.tr;
- 事务应用流程
// 1. 事务前处理
state.before_apply_transaction.await?;
// 2. 事务过滤
if !state.filter_transaction.await?
// 3. 应用事务
let mut new_state = state.apply_inner.await?;
// 4. 事务后处理
state.after_apply_transaction.await?;
- 事务类型
a. 简单事务
- 单个编辑操作
- 直接执行和回滚
- 不包含子事务
b. 复合事务
- 多个编辑操作
- 可以包含子事务
- 原子性保证
c. 插件事务
- 由插件产生的事务
- 可以修改或扩展原有事务
- 可以过滤事务执行
4.3 核心 apply 方法分析
apply
方法是状态转换的核心,它负责将事务应用到当前状态。主要流程如下:
- 事务前处理
pub async
- 事务过滤
pub async
- 事务应用
pub async
- 事务后处理
async
4.4 插件系统集成
插件系统通过以下方式与状态转换集成:
- 插件特征
- 状态字段特征
这种设计允许:
- 插件可以修改事务内容
- 插件可以过滤事务执行
- 插件可以在事务前后执行自定义逻辑
- 插件可以维护自己的状态
5. 执行流程
5.1 文档创建流程
- 初始化 Schema
let schema = compile?;
- 创建根节点
let root = schema.top_node_type.create_and_fill;
- 内容填充过程
- 检查内容匹配规则
- 创建缺失的必需节点
- 递归创建子节点
- 建立节点间的引用关系
5.2 内容验证流程
- 节点内容验证
node_type.check_content
- 属性验证
node_type.check_attrs
- 内容匹配验证
content_match.match_fragment
6. 示例
6.1 定义文档结构
let schema_spec = SchemaSpec ;
6.2 创建文档
let schema = compile?;
let id = get_id;
let nodes = schema.top_node_type.create_and_fill;
使用说明
-
首先定义文档的 Schema,包括:
- 节点类型定义
- 内容规则
- 属性约束
- 标记类型
-
使用 Schema 创建文档:
- 创建根节点
- 添加子节点
- 设置节点属性
- 应用标记
-
验证文档结构:
- 检查内容规则
- 验证属性
- 确保标记正确
注意事项
- 内容匹配规则必须是无歧义的
- 节点属性必须满足规范要求
- 标记类型必须在节点类型允许的范围内
- 文档结构必须符合预定义的规则
- 状态转换必须保持一致性
- 事务必须正确处理回滚
性能考虑
- 内容匹配使用 DFA 实现,确保高效的匹配过程
- 节点引用使用 ID 而不是直接引用,减少内存占用
- 使用缓存优化重复操作
- 延迟创建子节点,避免不必要的开销
- 状态转换使用不可变数据结构
- 事务使用增量更新策略