公司动态
Rasa多光标机制揭秘:CrdRange数据结构与rangeDo批量操作实现原理
Rasa多光标机制揭秘CrdRange数据结构与rangeDo批量操作实现原理【免费下载链接】rasaExtremely modular text editor built in Haskell项目地址: https://gitcode.com/gh_mirrors/ras/rasaRasa 是一款用 Haskell 编写的极其模块化的文本编辑器它的多光标功能并非内建而是由独立扩展 rasa-ext-cursors 实现。本文将带你揭秘其背后的核心CrdRange数据结构如何表示光标以及rangeDo如何一行代码完成批量操作让你既懂原理又能快速上手。上图正是一次 Rasa 多光标编辑会话同一行上的多个CrdRange光标被同时反色高亮多个视口独立滚动——这一切都源于下面这套简洁的设计。为什么多光标值得揭秘 Rasa 的核心原则是能做成扩展的功能绝不写进内核。多光标、文件读写、按键绑定、终端渲染全都是扩展。这意味着理解rasa-ext-cursors这一个包就理解了 Rasa 扩展 API 的精髓扩展状态按缓冲区Buffer隔离存储每个缓冲区各自维护自己的光标列表所有操作都是可组合的BufAction通过事件监听系统驱动其他扩展如 rasa-ext-vim直接复用这些光标 API扩展开发入门可参考 docs/Building-An-Extension.md。CrdRange多光标的核心数据结构从 Coord 到 CrdRange 的三层抽象CrdRange定义在核心包 rasa/src/Rasa/Internal/Range.hs 中由两层泛型特化而来Coord坐标(行, 列)二元组零索引。Coord 0 0是第一个字符Coord 2 1是第三行第二列Range a b区间Range { _rStart, _rEnd }持有两个端点支持Bifunctor/Bitraversable可以对两端同时施加变换CrdRange Range Coord Coord两端点都是坐标时的特化即一个文本区间妙处在于Rasa 中的光标不是位置而是区间。每个光标至少覆盖一个字符这让删除光标下字符和选中替换用同一套数据结构表达无需区分插入点与选区。光标状态Cursors 包装列表多光标扩展的状态定义在 rasa-ext-cursors/src/Rasa/Ext/Cursors/Internal/Base.hsdata Cursors Cursors [CrdRange]默认值是单光标选中首字符Cursors [Range (Coord 0 0) (Coord 0 1)]。通过getBufExt/setBufExt按缓冲区存取天然实现每个缓冲区独立多光标。cleanRanges光标的净化流水线任何一组新区间在写入前都会经过cleanRangesBase.hs#L32-L43它串联四步保证合法性步骤作用sortnubreverse排序、去重保持稳定顺序clampRange把越界坐标夹紧到文本范围内ensureSize零宽度区间自动扩展为一个字符行首向右、否则向左结果写回缓冲区始终保证光标数量与位置合法这套设计让上层代码可以放心乱写区间非法状态永远落不了地。rangeDo一行代码实现批量操作批量遍历的三种姿势批量操作的灵魂就在 Base.hs#L59-L69rangeDo f getRanges mapM f -- 对每个区间执行动作收集结果 rangeDo_ f void . rangeDo f -- 忽略结果的版本 overEachRange f rangeDo f setRanges -- 用结果替换各区间rangeDo顺序地以每个光标为当前光标执行动作是插入、删除类操作的基石overEachRange把每个区间映射成新区间后整体写回是移动类操作的基石addRange往列表追加一个新区间即新增光标批量删除与插入处理同行连带影响单光标删除很简单多光标的难点在于同一行上的多个光标前面的删改会影响后面的列坐标。rasa-ext-cursors/src/Rasa/Ext/Cursors/Internal/Actions.hs 用moveSameLineRangesBy优雅解决delete rangeDo_ $ \r - do deleteRange r moveSameLineRangesBy r (negate $ sizeOfR r)每次删除一个区间的文本后只把同一行上位于其右侧的区间整体左移相应列数insertText则对称地右移。这样多光标同时打字、同时删除都不会互相错位。findNext所有光标同时跳转findNextActions.hs#L41-L48演示了rangeDosetRanges的组合拳对每个区间独立搜索下一个匹配位置生成新区间列表后一次性写回。moveRangesByN、moveRangesByC这类整体移动更是直接一行搞定overRanges . fmap . moveRangeByN。多光标如何渲染反向视频高亮 ✨光标在屏幕上的反色显示靠的是缓冲区级样式提供器Base.hs#L75-L80setStyleProvider void . addStyleProvider $ rangeDo setStyle where setStyle r return $ Span r (flair ReverseVideo)再次复用rangeDo对每个区间生成一个带ReverseVideo样式的Span渲染管线自动叠加。而扩展的注册入口 Cursors.hs#L28-L31 只用三行cursors onBufAdded_ $ \bufRef - bufDo_ bufRef setStyleProvider监听BufAdded事件新缓冲区一出现就自动挂上样式——零配置、全自动。实战vim 扩展如何驾驭多光标rasa-ext-vim/src/Rasa/Ext/Vim.hs 是这套 API 的最佳消费者w/WfindNext 让所有光标跳到下一个单词大写W用rangeDo_ addCursor为每个单词种一个新光标Vim.hs#L152-L159x/X直接调用delete批量删除所有光标下的字符r替换delete insertText (Y.singleton c)一行代码让所有光标同时换字;take 1只保留第一个区间瞬间从多光标切回单光标可见多光标 API 被设计成完全可组合的动词移动、插入、删除、查找、增删区间任意拼接即是新的编辑命令。快速上手 Rasa 多光标安装 Stack 后克隆仓库git clone https://gitcode.com/gh_mirrors/ras/rasa在 Rasa 仓库目录执行stack build stack exec rasa你的配置参考 rasa-example-config/app/Main.hs中引入cursors与vim两个扩展进入 Vim 扩展的 Normal 模式按W逐词添加光标按x观察批量删除效果扩展间的依赖与打包结构可浏览根目录 cabal.project 与 README.md。总结Rasa 的多光标机制只有寥寥数百行代码却堪称 Haskell 库设计的范本CrdRange用坐标区间统一表示光标配合cleanRanges净化流水线保证状态永远合法rangeDomapM之上的三行抽象把对每个光标做 X变成声明式的一行同行坐标联动moveSameLineRangesBy解决多光标编辑最棘手的坐标漂移问题事件驱动注册新缓冲区自动获得多光标能力理解了这一套你就掌握了 Rasa 一切皆扩展哲学的核心。源码入口rasa-ext-cursors、rasa-ext-vim、核心类型定义 rasa/src/Rasa/Internal/Range.hs。【免费下载链接】rasaExtremely modular text editor built in Haskell项目地址: https://gitcode.com/gh_mirrors/ras/rasa创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考