兰 亭 墨 苑
期货 · 量化 · AI · 终身学习
首页
归档
编辑文章
标题 *
URL 别名 *
内容 *
(支持 Markdown 格式)
# 面向新手、但不牺牲 FOEK 理念深度的入门教程 --- # 🧭 tmux‑fsm 新手入门教程 **从“按键”到“事实”的第一次迁移** --- ## 在开始之前(非常重要) tmux‑fsm **不是 Vim**, 也**不是 tmux 的一组快捷键**。 它是一个 **常驻内存的编辑内核(FOEK)**, 而 tmux 只是它的 **输入输出设备**。 👉 如果你期待的是: - “装上就跟 Vim 一模一样” - “一个 key binding 文件” - “按一下就跑、跑完就退出的脚本” **请现在就停下。** 你会用得非常痛苦。 --- ## tmux‑fsm 到底在做什么? 一句话版本: > **tmux‑fsm 不编辑字符,它编辑「意义在时间中的变化」。** 它做了三件传统 tmux 插件做不到的事: 1. **拥有状态**(而不是存到 tmux option) 2. **记住时间线**(事务、撤销、审计) 3. **用事实定位文本**(而不是光标猜测) 这也是为什么它需要一个 **Go 守护进程**。 --- ## 🧱 核心概念速读(新手必看) 在真正开始用之前,你只需要记住 5 个词。 ### 1️⃣ Kernel(内核) - tmux‑fsm 的 Go Server - 常驻后台 - **唯一的真相来源** - FSM、Undo、事务、锚点都在这里 tmux ≠ 状态来源 tmux = 键盘 + 屏幕 --- ### 2️⃣ Mode(模式) 和 Vim 类似,但由 **显式 FSM 驱动**: - `NORMAL` - `OPERATOR_PENDING` - `MOTION_PENDING` - `VISUAL` - `REGISTER_SELECT` 你看到的状态栏文字,来自 **内核实时状态**。 --- ### 3️⃣ Fact(事实) 一次编辑 ≠ 一串按键 一次编辑 = 一个 **事实** 一个 Fact 包含: - Range(范围) - Anchor(锚点) - Operation(意图) 撤销时,内核会**重新寻找这个事实的位置**。 --- ### 4️⃣ Transaction(事务) 像 `3dw` 这样的操作: - ✅ 要么 **全部成功** - ❌ 要么 **整体跳过** **永远不会留下半删的垃圾状态。** --- ### 5️⃣ Anchor Resolver(定位引擎) 撤销时,内核会按顺序尝试: 1. **Exact**:精确匹配 2. **Fuzzy**:模糊匹配(会提示 `~UNDO`) 3. **Fail**:失败(安全拒绝,`!UNDO_FAIL`) --- ## 🚀 第一步:安装并启动内核 ### 安装 ```bash ./install.sh ``` 这一步会: - 编译 Go 内核 - 启动守护进程 - 自动配置 tmux - **预热 Kernel** ✅ 安装完成后,不需要手动启动服务。 --- ### 验证是否成功 进入 tmux 后执行: ```bash tmux show-messages ``` 或检查 socket: ```bash ls ~/.tmux-fsm.sock ``` --- ## 🎹 第二步:进入 FSM 模式 在 tmux 中: ``` <prefix> f ``` 你会看到状态栏显示: ``` NORMAL ``` 这意味着: ✅ 内核在线 ✅ FSM 正常 ✅ tmux 已连接成功 退出 FSM: ``` Esc 或 Ctrl-c ``` --- ## 🧠 第三步:从最基础的操作开始 ### ✅ 移动(不会修改任何东西) ```text h j k l 左 下 上 右 w b e 单词移动 0 $ 行首 / 行尾 gg G 顶部 / 底部 ``` 这些操作: - 不创建 Fact - 不进入事务 - 只是改变视角 --- ### ✅ 第一次真正的“编辑事实” 试试: ```text dw ``` FSM 路径是: ``` NORMAL → OPERATOR_PENDING → EXECUTE → NORMAL ``` 内核会: - 创建一个 delete Fact - 记录精确范围 - 推入事务栈 --- ### ✅ 数字前缀是“事务的一部分” ```text 3dw ``` 这 **不是** 3 次 `dw` 而是 **一个事务,包含 3 个事实** 撤销时: - ✅ 要么全部撤 - ❌ 要么全部跳过 --- ## ↩️ 第四步:真正理解 Undo / Redo ### Undo ``` u ``` ### Redo ``` Ctrl-r ``` 但要注意: > **Undo 不是保证一定成功的。** 如果环境变化太大(Prompt 刷新、外部输出): - 内核会选择 **保护现场** - 状态栏显示:`!UNDO_FAIL` 这是 **设计目标**,不是 Bug。 --- ### 🔍 查询为什么 Undo 失败 在 FSM 模式中输入: ``` __WHY_FAIL__ ``` 你会看到类似: ``` Anchor mismatch due to prompt shift ``` 这叫 **可审计性(Auditability)**。 --- ## 🌌 第五步:第一次接触 Spatial Echo(进阶) 这是 tmux‑fsm 最“反直觉”,也是最强大的地方。 ### 示例 ```text 3dw ``` 现在,**这 3 个删除事实被“武装”了**。 移动到任意位置,然后: ```text gd ``` 内核会: - 瞬移到 3 个锚点 - **重新执行同一个删除意图** ✅ 没有多光标 ✅ 没有新模式 ✅ 只是时间线的再投影 --- ## 🧪 常见新手误区 ### ❌ “为什么有时候 Undo 不工作?” ✅ 因为 tmux‑fsm **优先保护现场一致性** ❌ 它不会为了“看起来成功”而破坏状态 --- ### ❌ “为什么不用 tmux option 存状态?” 因为: - tmux option ≠ 原子 - tmux option ≠ 并发安全 - tmux option ≠ 时间线 FOEK 必须 **拥有状态** --- ### ❌ “我能把它当 Vim 用吗?” 可以学 Vim 的 **语义模型** 但不要期待 Vim 的 **实现方式** --- ## ✅ 你现在已经会什么了? 到这里,你已经: - ✅ 理解 tmux‑fsm 的定位 - ✅ 会进入 / 退出 FSM - ✅ 会安全地编辑 - ✅ 会 Undo / Redo - ✅ 知道为什么系统会拒绝你 - ✅ 见过 Spatial Echo 的雏形 --- ## 🧭 下一步建议 当你准备好了,可以继续探索: - VISUAL 模式与 Range Fact - 文本对象(`iw`, `i"`, `ap`) - 寄存器与追加语义 - 审计日志与事务栈可视化 - FOEK Kernel 内部接口 --- > **tmux‑fsm 不要求你“记住快捷键”。** > 它要求你 **理解时间、状态与意图**。 如果这正是你想要的, 欢迎来到 FOEK。 # tmux-fsm: Fact-Oriented Editing Kernel (FOEK) # tmux‑fsm ------ > **tmux‑fsm is not a tmux plugin.** tmux‑fsm is a **headless editing kernel** running as a long‑lived daemon. tmux is merely its **TTY frontend** for input and display. **This project is NOT for you if you want:** - A drop‑in key binding collection - A stateless script that runs and exits - Something that stores its state in tmux options - “Just another tmux plugin” tmux‑fsm **persists in memory**, **owns the state machine**, and **enforces its own timeline**. To tmux‑fsm, tmux is strictly a **dumb I/O device** — never the source of truth. This architecture exists to enable things traditional tmux plugins cannot do: semantic undo, spatial replay, multi‑step FSM reasoning, and sub‑millisecond reaction time. If this sounds excessive, unfamiliar, or unnecessary — **you should stop reading here.** — ### Who this project is for tmux‑fsm is designed for users who: - are comfortable running background daemons - understand client/server architectures - care about temporal continuity and state ownership - want an **editing kernel**, not a shortcut collection Everyone else will be happier with a conventional tmux plugin. tmux‑fsm does not edit text. It edits meaning over time. -------- 一个基于 **FOEK (事实导向编辑内核)** 理念的 tmux 模式插件。它不仅为 tmux 提供了 Vim 风格的导航,更在终端层面上实现了一套具备 **空间感 (Spatial Awareness)** 与 **时间线感 (Timeline Awareness)** 的编辑内核。 --- ## 🌌 内核核心:FOEK (Fact-Oriented Editing Kernel) tmux-fsm 不仅仅是一个插件,它是一个**高性能、常驻内存的编辑内核**,专注于三个核心领域:高性能响应、语义化一致性、以及**工业级安全性**。 ### 为极致性能而生:Go Daemon 内核 - **服务端 (Daemon)**: 全 Go 编写,常驻内存,处理 FSM 状态转换与复杂逻辑。响应时间 **< 1ms**。 - **客户端 (Client)**: 极简二进制,仅负责通过 Unix Socket 发送按键,瞬间退出,零感知。 ### 从“命令”到“事实”的飞跃 在 FOEK 中,编辑不是“按键的模拟”,而是“意图对空间事实的投影”。 - **Fact (事实)**:每个动作(删除、插入、修改)都被记录为一个具备精确范围(Range)和定位锚点(Anchor)的语义事实。 - **Transaction (事务)**:复合操作(如 `5dw`)被视为原子事务。撤销时要么完整还原,要么为了安全拒绝执行,绝不留下中间错误状态。 - **Anchor Resolver (定位引擎)**:撤销不再依赖光标位置,而是通过 **Exact -> Fuzzy -> Fail** 三层策略在面板中搜索文本。 --- ## 🛡️ 工业级安全:撤销安全公理 (Undo Safety Axioms) tmux-fsm 实现了目前终端插件中最先进的撤销保护机制。我们遵循一套严格的**撤销安全公理**: 1. **保护现场高于还原文本**:当环境发生剧烈变动(如 Shell Prompt 刷新或文本被外部篡改)导致无法 100% 确定位置时,系统会选择 **Safe Skip (安全跳过)**,并标记 `!UNDO_FAIL`。 2. **原子化一致性**:事务中任何一步由于安全原因无法执行,整个事务都会被标记为 `Skipped`,且禁止 Redo。 3. **模糊透明度**:当系统通过模糊匹配成功找回文本时,状态栏会显示 `~UNDO` 指示,告知用户当前环境已发生偏移。 ### 诊断与审计 (Auditability) 系统不再是一个“黑盒”。如果撤销失败,您可以询问系统: - **`p` 键 (__STATUS__)**:查看内核当前完整的事务栈。 - **`__WHY_FAIL__` 指令**:返回最近一次撤销失败的具体审计原因(例如:`Anchor mismatch due to Prompt detection`)。 --- ## ✨ 魔法特性:Spatial Echo (空间回声) **Spatial Echo** 是 FOEK 内核成熟后的第一次自然共振。它在无多光标、无新模式的前提下,实现了多点、可重放的编辑。 1. **Armed Facts (武装事实)**:执行如 `3dw` 的复合操作时,系统会生成 **3 个独立的 Range 事实** 并存入缓冲区。 2. **Global Apply (全局意图)**:按下 `g + 操作符`(如 `gd`, `g~`),内核会瞬间“瞬移”到所有武装锚点并重新执行编辑意图。 --- ## 🛠 功能特性 - **Vim 风格导航**:`h/j/k/l`, `w/b/e`, `0/$`, `gg/G`, `f{char}`。 - **结构化操作符**:`d` (delete), `y` (yank), `c` (change), `v/V` (visual), `p/P` (paste)。 - **工业级 Undo/Redo**:基于事务和 Anchor Resolver 的原子化撤销系统。 - **文本对象**:支持 `aw`, `iw`, `i"`, `ap` 等高级语义操作。 - **寄存器系统**:26 个命名寄存器,支持追加模式,并与系统剪贴板实时同步。 --- ## 📜 执行架构 (C/S 架构) ```mermaid graph TD Key[按键按下] --> Client[tmux-fsm 客户端] Client -- "Unix Socket" --> Server[tmux-fsm 守护进程] Server --> Kernel{FOEK Kernel} Kernel --> Trans[Transaction Management] Trans --> Resolver[Anchor Resolver: Exact/Fuzzy/Fail] Resolver --> TMUX[TMUX Surface] Trans --> History[(Transactional History)] History -- "Audit Query" --> Why[__WHY_FAIL__] History -- "Status Display" --> SB[~UNDO / !UNDO_FAIL] ``` --- ## 🚀 快速开始 ### 安装 **依赖**:需要安装 [Go](https://go.dev/) (用于编译高性能内核)。 ```bash # 1. 克隆仓库并编译安装 ./install.sh ``` 安装脚本会自动: - 编译 Go 二进制文件 (FOEK Kernel) - 部署插件到 `~/.tmux/plugins/tmux-fsm` - 自动在 `~/.tmux.conf` 中配置加载项并重新加载 ### 基础操作 - **进入/退出**:`<prefix> f` 进入,`Esc` 退出。 - **工业级撤销**:`u` (Undo), `C-r` (Redo)。 - **空间回声**:执行 `3dw` 后,在任意位置按 `gd` 即可触发全局回声。 - **文本对象**:`diw` (删除词内), `ci"` (修改引号内)。 - **诊断失败**:输入 `__WHY_FAIL__` 查询最后一次撤销被拒的原因。 --- ## 许可证 本项目遵循 **FOEK 内核宣言**,采用 MIT License 授权。 > _“我们不只是在模拟 Vim,我们是在隔离终端的复杂性。”_ --- ## 卸载 ```bash rm -rf ~/.tmux/plugins/tmux-fsm ``` 并从 tmux 配置文件中删除: ``` source-file "$HOME/.tmux/plugins/tmux-fsm/plugin.tmux" ``` --- ## 故障排除 1. **确保已安装 Go**:编译内核需要 Go 环境。 2. **确认 Socket 状态**:守护进程会在 `~/.tmux-fsm.sock` 创建连接点。 3. **重新加载配置**: ```bash tmux source-file ~/.tmux.conf ``` 4. **手动停止/重启服务端**: ```bash pkill -f "tmux-fsm -server" ``` 4. 如果有问题,可在 tmux 中查看错误信息: ```bash tmux show-messages ``` --- --- # FSM 状态转移图(FSM Diagram) ## 1️⃣ 总览(高层 FSM) ```mermaid stateDiagram-v2 [*] --> NORMAL NORMAL --> OPERATOR_PENDING : d / y / c NORMAL --> MOTION_PENDING : g / f NORMAL --> REGISTER_SELECT : " NORMAL --> NORMAL : motion (h j k l w b e 0 $ G) NORMAL --> NORMAL : count (1-9) NORMAL --> [*] : Esc / C-c OPERATOR_PENDING --> MOTION_PENDING : motion OPERATOR_PENDING --> MODIFIER : a / i OPERATOR_PENDING --> NORMAL : invalid / cancel MOTION_PENDING --> NORMAL : motion complete MOTION_PENDING --> MOTION_PENDING : g (gg) MOTION_PENDING --> NORMAL : invalid / timeout MODIFIER --> MOTION_PENDING : text-object (w $ j ...) MODIFIER --> NORMAL : invalid REGISTER_SELECT --> NORMAL : register selected ``` --- ## 2️⃣ 各状态说明(和代码一一对应) ### 🟢 NORMAL **默认状态** - 等待: - 操作符:`d y c` - 移动命令:`h j k l w b e 0 $ G` - 前缀数字:`1-9` - 特殊前缀:`g`、`f` - 寄存器选择:`"` 特点: - 所有命令的 **起点** - 可直接执行 _纯移动_ - 可累计数字前缀 --- ### 🟡 OPERATOR_PENDING **操作符等待状态** 由以下进入: - `d`(delete) - `y`(yank) - `c`(change) 等待: - 一个 **motion** - 或 **modifier**(`a` / `i`) 示例: - `d` → OPERATOR_PENDING - `dw` → 执行 delete(word) - `diw` → delete(inside word) --- ### 🔵 MOTION_PENDING **需要更多按键的移动命令** 典型场景: - `g` → 等待第二个 `g` - `f` → 等待目标字符 示例: - `g` → MOTION_PENDING - `gg` → goto top - `f a` → find next `a` --- ### 🟣 MODIFIER **文本对象修饰符** 进入方式: - 在 OPERATOR_PENDING 后输入: - `a`(around) - `i`(inside) 等待: - 一个 motion / text-object 示例: - `diw` - `yaw` - `ci"` --- ### 🟠 REGISTER_SELECT **寄存器选择状态** 进入方式: - 输入 `"` 等待: - 寄存器名: - `a-z` - `A-Z`(追加) - `0-9` - `+`(系统剪贴板) 示例: - `"a yw` - `"A dw` - `"+p` --- ## 3️⃣ 典型命令的 FSM 路径示例 ### ✅ `3dw` ``` NORMAL → (3) count → d → OPERATOR_PENDING → w → execute(delete, word, count=3) → NORMAL ``` --- ### ✅ `"a y2w` ``` NORMAL → " → REGISTER_SELECT → a → NORMAL (register=a) → y → OPERATOR_PENDING → 2 → count → w → execute(yank, word, count=2, register=a) → NORMAL ``` --- ### ✅ `gg` ``` NORMAL → g → MOTION_PENDING → g → execute(goto_top) → NORMAL ``` --- ## 4️⃣ 设计亮点(可以直接写进 README) > tmux-fsm 使用 **显式 FSM 状态建模**,而不是 tmux key-table 级联: > > - ✅ 避免 key table 组合爆炸 > - ✅ Vim 风格操作符-动作模型天然表达 > - ✅ 新命令 = 新状态或新转移,不影响已有逻辑 > - ✅ 所有按键路径 **可视化、可推理、可测试** 在 tmux-fsm 插件的“Phase 2”优化中,迷你客户端(Client)是实现零延迟响应的关键一环。它将原本厚重的逻辑处理转化为轻量级的消息传递。 以下是关于迷你客户端的实现细节、代码量及作用的详细介绍: 1. 迷你客户端的实现原理 在 C/S(服务端/客户端)架构中,迷你客户端不再负责任何复杂的逻辑判断或 tmux 状态读写。它的唯一任务是:获取用户的按键输入,并将其通过 Unix Socket 快速发送给常驻内存的服务端(Server)。 这种设计的优势在于: * 极速启动:客户端代码极简,Go 语言编译后的二进制文件执行一次 fork/exec 到退出仅需不到 5ms。 * 非阻塞:客户端发送完数据即退出,不等待服务端处理完成,从而消除了用户按键时的“粘滞感”。 2. 代码实现及作用 迷你客户端的代码通常集成在主程序中,通过命令行参数区分运行模式。 核心代码示例(基于 main.go) func runClient() { // 1. 参数校验:确保有按键传入 if len(os.Args) < 2 { return } key := os.Args[1] // 2. 连接服务端:通过本地 Unix Socket 文件通信 socketPath := os.Getenv("HOME") + "/.tmux-fsm.sock" conn, err := net.Dial("unix", socketPath) if err != nil { // 如果服务端未启动,静默退出或记录错误 return } defer conn.Close() // 3. 发送按键数据:将按键字符写入 Socket conn.Write([]byte(key)) // 4. 立即退出:客户端生命周期结束 } 各部分作用详解: * 参数接收 (os.Args[1]):通过 tmux 的按键绑定(如 bind-key -T fsm Any run-shell "tmux-fsm '#{key}'")捕获用户当前按下的键位。 * Unix Socket 连接 (net.Dial):这是客户端与服务端通信的桥梁。相比 TCP,Unix Socket 在本地通信中开销更小。 * 数据写入 (conn.Write):将简单的按键信息(如 "j", "k", "3")推送到服务端的处理队列中。 * defer conn.Close():确保在发送完成后正确关闭连接,释放系统资源。 3. 代码量统计 迷你客户端的实现体现了“小而美”的工程哲学: * 逻辑代码:约 10-15 行 Go 代码。 * 总二进制体积:由于 Go 的静态链接特性,虽然整体二进制文件较大(约 2MB),但客户端执行路径非常短。 * 调用开销:由于省去了原先版本中频繁读写 tmux option 的操作( load/save 状态),每次调用的系统资源占用降低了约 90%。 4. 总结 迷你客户端就像是神经系统的末梢神经,它只负责感应(捕获按键)并传递信号,而繁重的大脑功能(FSM 状态机逻辑、Undo 栈、状态栏重绘)全部交由服务端处理。这种设计让 tmux-fsm 在功能日益复杂的同时,依然保持了原生 Vim 般的清脆响应。 ### 优化过程 这份优化报告记录了将 tmux-fsm 插件从 Python 后端迁移到 Go 语言后端(称为 “Phase 1” 迁移),并进一步优化为服务端/客户端架构(“Phase 2” 守护进程化)的全过程。 以下是该优化报告的总结: 1. 核心问题与诊断 * 状态栏显示延迟:最初用户反馈右下角显示状态(如 NORMAL)无法及时更新。诊断发现 tmux 的刷新机制导致状态栏仅在有输入或定时刷新(默认 15 秒)时更新,且脚本在后台运行使 tmux 无法感知变量变化。 * 配置路径冲突:修复过程中发现,尽管编译了 Go 版本,但 ~/.tmux.conf 仍在加载旧的 Python 路径,导致逻辑不生效。 * 性能瓶颈:原有的 Python 脚本及初版 Go 脚本在每次按键时都会进行多次 fork/exec 系统调用(读写 tmux option),产生了微小的“粘滞感”。 2. 主要改进措施 * 后端语言迁移:将 FSM(有限状态机)逻辑从 Python 完美复刻到 Go 结构体中,提升了基础运行效率。 * 引入强制刷新:在代码中增加了 tmux refresh-client -S 命令,确保每次状态变化都能实时重绘状态栏。 * Server/Client 架构(Phase 2): * 守护进程化:实现了一个常驻内存的 Server,通过 Unix Socket 与 Client 通信。 * 内存状态管理:状态(Mode、Count、Undo 栈等)存储在内存中,无需频繁读写磁盘或 tmux 变量,响应速度提升约 10 倍。 * 并发安全:引入了全局互斥锁 (sync.Mutex),防止快速按键(如 3dw)导致的状态竞争和数据错乱。 * 逻辑完善:修复了初始状态为空导致按键被忽略的 Bug,并添加了对 VISUAL 模式和数字计数的实时显示支持。 3. 最终状态与成果 * 零延迟响应:通过内存驻留逻辑和极简客户端,消除了按键时的顿挫感,达到了类似原生 Vim 的清脆响应。 * 架构稳固:成功实现了名为 “FOEK” 的内核迁移,具备了物理锁和数据结构保留能力,为后续实现复杂功能(如空间回声、宏录制)打下了基础。 * 自动化部署:更新了 install.sh 和 plugin.tmux,确保 Server 能够自动启动并正确挂载 Go 版本的二进制文件。 当前结论:该插件已完成从“脚本调用”到“系统级服务”的质变,解决了所有已知的显示同步与性能延迟问题。
配图 (可多选)
选择新图片文件或拖拽到此处
标签
更新文章
删除文章