第 5 章 · 05 撤销重做与综合:一个能编辑保存的小编辑器


文档摘要

第 5 章 · 05 撤销重做与综合:一个能编辑保存的小编辑器 本节摘要:这是第 5 章的收尾节,讲两件事:撤销/重做的实现(命令模式的应用),以及把前四节组装成一个能编辑、保存、撤销的小编辑器。撤销的本质是「把每次编辑封装成可逆命令」——插入的反向是删除、删除的反向是重新插入。理解命令模式,你不仅会做编辑器撤销,更掌握了一门通用的软件设计模式。 内容来源:基于编辑器设计与设计模式整理的导读。 学习目标 阅读完本节,你应当能够: 说清撤销的本质:把每次编辑封装成可逆命令。 实现撤销栈/重做栈的双栈模型。 理解「命令模式」(command pattern)是通用设计模式。 把缓冲区、光标、模式、文件 IO、渲染、撤销组装成一个最小可用编辑器。

第 5 章 · 05 撤销重做与综合:一个能编辑保存的小编辑器

本节摘要:这是第 5 章的收尾节,讲两件事:撤销/重做的实现(命令模式的应用),以及把前四节组装成一个能编辑、保存、撤销的小编辑器。撤销的本质是「把每次编辑封装成可逆命令」——插入的反向是删除、删除的反向是重新插入。理解命令模式,你不仅会做编辑器撤销,更掌握了一门通用的软件设计模式。

内容来源:基于编辑器设计与设计模式整理的导读。

学习目标

阅读完本节,你应当能够:

  1. 说清撤销的本质:把每次编辑封装成可逆命令。
  2. 实现撤销栈/重做栈的双栈模型。
  3. 理解「命令模式」(command pattern)是通用设计模式。
  4. 把缓冲区、光标、模式、文件 IO、渲染、撤销组装成一个最小可用编辑器。

一、学习价值:命令模式是通用设计

撤销/重做不只为编辑器——它是「命令模式」的典型应用,这种模式用在任何需要「可逆操作」的场景:数据库事务回滚、图形编辑器、游戏、协同编辑。理解它,你掌握了一门通用设计模式。

二、子系统拆解:撤销的实现

命令封装

每次编辑封装成一个命令对象,含「执行」与「撤销」两个方法:

InsertCommand { pos, text }: do(): 在 pos 插入 text undo(): 在 pos 删除 len(text) 个字符 DeleteCommand { pos, text }: do(): 在 pos 删除 text undo(): 在 pos 重新插入 text(删掉的存起来)

双栈模型

维护两个栈:undo_stackredo_stack

执行命令: cmd.do(); undo_stack.push(cmd); 清空 redo_stack (新操作后, 重做历史失效) 撤销 (Ctrl+Z): cmd = undo_stack.pop(); cmd.undo(); redo_stack.push(cmd) 重做 (Ctrl+Y): cmd = redo_stack.pop(); cmd.do(); undo_stack.push(cmd)

注意点

  • 新操作清空 redo 栈:撤销几次后,一旦执行新操作,被撤销的历史就不能再重做了(否则与现状冲突)。
  • 粒度:一次「按键」太细(撤销一次只回退一个字符),一次「会话」太粗。常用粒度是「一次连续输入」或「一次命令」(如 dd 整体作为一个命令)。
  • 内存:撤销栈无限增长会占内存,实际编辑器有上限(如 1000 步)。

三、综合:最小可用编辑器

把前四节组装:

1. 启动: enter_raw_mode(); atexit(restore); 读文件到缓冲区 2. 主循环: render() # 清屏 + 画缓冲 + 移光标(04 节) key = read_key() # 读按键(04 节) if normal 模式: hjkl/gg/G/dd/... → 改光标或执行编辑命令(02 节) i/a/o → 切 insert elif insert 模式: 字符 → 插入缓冲(封装为 InsertCommand, 进 undo 栈)(01 节) Esc → 切 normal 退格 → 删除(封装 DeleteCommand) Ctrl+S → 原子保存(03 节) Ctrl+Z → undo; Ctrl+Y → redo(本节) Ctrl+Q → 退出

这是最小可用:能打开、编辑、保存、撤销。后续可扩展搜索替换(用第 4 章正则)、多缓冲、语法高亮。

本节要点回顾

  1. 撤销本质:每次编辑封装成可逆命令(do/undo 两方法)。
  2. 双栈模型:undo_stack 与 redo_stack;执行清 redo,撤销从 undo 弹到 redo,重做反之。
  3. 新操作清空 redo 栈(避免与现状冲突);粒度通常「一次命令」而非「一字符」。
  4. 命令模式是通用设计:编辑器、数据库、图形工具都用。
  5. 最小编辑器 = 缓冲 + 光标 + 模式 + IO + 渲染 + 撤销;后续可扩搜索/多缓冲/语法高亮。

推荐上手顺序

  1. 先实现「无撤销」的最小编辑器(前四节组装),能编辑保存。
  2. 加命令封装:每次插入/删除包成 Command 对象。
  3. 加 undo 栈,Ctrl+Z 弹栈执行 undo。
  4. 加 redo 栈,Ctrl+Y 重做;注意新操作清 redo。
  5. 测试:编辑→撤销→重做→新编辑→重做应失效。

至此第 5 章「造文本编辑器」全部讲完。本章让你造一个能打开、编辑、保存、撤销的小编辑器,并理解 Vim/Emacs 的设计智慧。下一章造 Git——理解版本控制的内部模型。


发布者: 作者: 灏天文库 转发
评论区 (0)
U