首页/新闻资讯/正文详情

xi-editor 插件开发起步:基于 Rust 的 sample-plugin 模板解析与安装实战

发布时间:2026/9/21 1:42:40 来源:云帆数科 栏目:资讯中心
xi-editor 插件开发起步:基于 Rust 的 sample-plugin 模板解析与安装实战
xi-editor 插件开发起步基于 Rust 的 sample-plugin 模板解析与安装实战【免费下载链接】xi-editorA modern editor with a backend written in Rust.项目地址: https://gitcode.com/gh_mirrors/xie/xi-editor本篇指南以 xi-editor后端由 Rust 编写的现代编辑器仓库中的 rust/sample-plugin 为蓝本完整讲解 Rust 插件的构成三要素——manifest 清单、Makefile 构建脚本与 Plugin trait 实现——以及它们在 xi-core 插件系统中的真实运行机制。读完本文你将掌握如何从零构建、安装一个 xi 插件并理解插件如何通过 RPC 读取与修改缓冲区内容。插件模板概览一个极简但完整的 Rust 插件sample-plugin 是仓库中刻意保持非常非常精简原文very, very barebones的 Rust 插件模板其定位是为想写 Rust 插件的开发者准备的模板intended as a template。它虽然简单却包含了插件的全部必要组成部分rust/sample-plugin/manifest.toml描述插件身份与可执行文件位置的清单文件rust/sample-plugin/Makefile负责编译与安装的构建脚本rust/sample-plugin/src/main.rs实现Plugintrait 的完整可运行代码rust/sample-plugin/Cargo.toml声明对xi-plugin-lib、xi-core-lib、xi-rope、xi-trace等核心 crate 的依赖。该插件目前只有一个值得注意的行为当插件激活且用户在文档中输入感叹号!时插件会把光标前一个单词自动转成大写。这个功能虽小却完整演示了监听编辑事件 → 读取缓冲区 → 构造 delta → 回写编辑的插件核心流程是理解 xi 插件 API 的绝佳入口。安装插件两条路径原文档给出的速记式安装命令是make install。为了让安装过程完全透明这里展开说明其背后的完整机制。手动安装理解目录约定无论是否使用 Makefile安装的本质都是把两样东西放到正确的位置manifest 清单必须放在$XI_CONFIG_DIR/plugins下的一个新目录中。也就是说对于名为sample-plugin的插件最终路径应为$XI_CONFIG_DIR/plugins/sample-plugin/manifest.toml。编译好的可执行文件必须放在该目录的bin/子目录下即$XI_CONFIG_DIR/plugins/sample-plugin/bin/xi-sample-plugin。这是默认位置manifest 中的exec_path可以改变它。这里$XI_CONFIG_DIR并非用户手工配置的环境变量而是由前端客户端在启动时通过client_startedRPC 的config_dir字段传给 xi-core 的路径。在 rust/core-lib/src/rpc.rs 中可以看到client_started的协议定义其参数中包含config_dir: OptionPathBufxi-core 收到该消息后见 rust/core-lib/src/core.rs即以此初始化配置管理并在 rust/core-lib/src/config.rs 与 rust/core-lib/src/config.rs 中将插件目录解析为config_dir/plugins。在 macOS 上$XI_CONFIG_DIR的默认位置是~/Library/Application Support/XiEditor因此插件默认应安装到~/Library/Application Support/XiEditor/plugins/下。使用 Makefile 一键安装sample-plugin 的 Makefile 将上述过程自动化支持 macOS 与 Linux# Makefile for installing the plugin on macOS and Linux # The official name of this plugin, displayed in menus etc PLUGIN_NAME sample-plugin # the name of the plugin binary; this is the same as the name in Cargo.toml PLUGIN_BIN xi-sample-plugin # On MacOS we just always assume that plugins are in the default location ifeq ($(shell uname -s), Darwin) XI_CONFIG_DIR ? $(HOME)/Library/Application\ Support/XiEditor endif XDG_CONFIG_HOME ? $(HOME)/.config XI_CONFIG_DIR ? $(XDG_CONFIG_HOME)/xi XI_PLUGIN_DIR ? $(XI_CONFIG_DIR)/plugins out/$(PLUGIN_NAME): $(PLUGIN_BIN) mkdir -p out/$(PLUGIN_NAME)/bin cp ../target/release/$(PLUGIN_BIN) out/$(PLUGIN_NAME)/bin cp manifest.toml out/$(PLUGIN_NAME)/manifest.toml .PHONY: $(PLUGIN_BIN) $(PLUGIN_BIN): cargo build --release install: manifest.toml out/$(PLUGIN_NAME) mkdir -p $(XI_PLUGIN_DIR) cp -r out/$(PLUGIN_NAME) $(XI_PLUGIN_DIR) clean: rm -rf out cargo clean .PHONY: clean install逐段拆解其工作原理路径变量XI_CONFIG_DIR的默认值因平台而异——DarwinmacOS下直接取~/Library/Application Support/XiEditor即 README 中提到的默认目录其他平台则遵循 XDG 规范取$XDG_CONFIG_HOME/xiXDG_CONFIG_HOME默认是~/.config。XI_PLUGIN_DIR即$XI_CONFIG_DIR/plugins是最终安装目标。三处?赋值保证用户可以通过命令行覆盖这些默认值。out/$(PLUGIN_NAME)目标先在out/sample-plugin/bin建目录然后把 workspace 根目录下编译产物../target/release/xi-sample-plugin和manifest.toml复制进去形成一个待安装的插件目录。注意它依赖$(PLUGIN_BIN)目标后者执行cargo build --release编译发生在仓库的 rust/Cargo.toml workspace 层面产物落在rust/target/release/。install目标创建$XI_PLUGIN_DIR并把out/sample-plugin整体复制进去最终得到$XI_PLUGIN_DIR/sample-plugin/{manifest.toml, bin/xi-sample-plugin}与 README 描述的手动目录结构完全一致。clean目标清理out/目录并执行cargo clean。manifest.toml 清单文件详解manifest清单是 xi-core 识别与加载插件的第一入口。sample-plugin 的清单文件内容如下# The plugin manifest describes the plugin and its capabilities. # At the very least it must contain these three fields: name sample-plugin version 0.0 exec_path ./bin/xi-sample-plugin如注释所言这三个字段是必填项字段含义name插件的唯一名称用于在目录/菜单中标识也作为 core 端PluginCatalog的 keyversion插件版本号exec_path插件可执行文件的路径./前缀表示相对 manifest 所在目录解析在 core 端清单由 rust/core-lib/src/plugins/manifest.rs 中的PluginDescription结构体反序列化而来其中exec_path经过特殊处理Windows 平台会自动补上.exe扩展名见 manifest.rs 的platform_exec_path反序列化函数。除了三个必填字段PluginDescription还支持更多可选元数据scope插件作用域枚举值为global接收多缓冲区事件、buffer_local单缓冲区默认值、single_invocation响应命令一次性启动activations触发插件运行的事件列表如autorun编辑器可用时总是运行、on_syntax指定语法激活时、on_command响应命令时commands插件提供的自定义命令描述含标题、参数、RPC 模板languages插件声明的语言定义列表。仓库中的 rust/syntect-plugin/manifest.toml 展示了这些可选字段的真实用法——语法高亮插件xi-syntect-plugin声明了scope global、activations [autorun]并附带了上百个[[languages]]条目如 Rust、Python、Go 等每个含name、extensions、scope以及可选的first_line_match正则。manifest 的加载与校验逻辑位于 rust/core-lib/src/plugins/catalog.rsfind_all_manifestscatalog.rs会扫描插件根目录若根目录本身存在manifest.toml则直接使用否则遍历其一级子目录查找各自目录下的manifest.toml——这正是 README 要求把 manifest 放进 plugins 下的新目录的原因load_manifestcatalog.rs解析 TOML 后若exec_path以./开头会将其相对于 manifest 所在目录做路径规范化canonicalize因此./bin/xi-sample-plugin实际指向plugins/sample-plugin/bin/xi-sample-plugin与安装步骤一一对应。插件主体实现 Plugin trait安装之后插件如何运行答案在 rust/sample-plugin/src/main.rs 中。整个程序的核心是两件事实现Plugintrait并调用mainloop进入事件循环。fn main() { let mut plugin SamplePlugin; mainloop(mut plugin).unwrap(); }mainloop来自xi-plugin-librust/plugin-lib/src/lib.rs其实现创建一个基于标准输入/输出的RpcLoop与Dispatcher把 stdin 上的 JSON-RPC 消息分发到Plugintrait 的回调方法上。也就是说xi-core 与插件进程之间通过 stdin/stdout 上的 RPC 通信插件独立于 core 进程运行——这正是 docs/docs/plugin.md 中描述的插件异步化、可用任何语言编写、慢插件不阻塞输入、崩溃插件不丢数据的设计哲学。sample-plugin 的 trait 实现main.rs覆盖了生命周期回调impl Plugin for SamplePlugin { type Cache ChunkCache; fn new_view(mut self, view: mut ViewSelf::Cache) { eprintln!(new view {}, view.get_id()); } fn did_close(mut self, view: ViewSelf::Cache) { eprintln!(close view {}, view.get_id()); } fn did_save(mut self, view: mut ViewSelf::Cache, _old: OptionPath) { eprintln!(saved view {}, view.get_id()); } fn config_changed(mut self, _view: mut ViewSelf::Cache, _changes: ConfigTable) {} fn update( mut self, view: mut ViewSelf::Cache, delta: OptionRopeDelta, _edit_type: String, _author: String, ) { //NOTE: example simple conditional edit. If this delta is //an insert of a single !, we capitalize the preceding word. if let Some(delta) delta { let (iv, _) delta.summary(); let text: String delta.as_simple_insert().map(String::from).unwrap_or_default(); if text ! { let _ self.capitalize_word(view, iv.end()); } } } }Plugintrait 的完整定义见 rust/plugin-lib/src/lib.rs除上述方法外还包含initialize插件初始化时拿到CoreProxy、language_changed、custom_command、idle配合View::schedule_idle()做增量后台分析、get_hover等钩子开发者可按需覆写。trait 关联类型type Cache: Cache决定缓冲区缓存的实现sample-plugin 使用ChunkCache按需分块拉取文档内容xi-plugin-lib 还提供了全量快照式的StateCache语法高亮插件即使用它高级用户也可自实现Cachetraitlib.rs。update方法演示了条件编辑的经典写法每次缓冲区发生编辑core 都会把RopeDelta编辑增量推送过来插件用delta.as_simple_insert()判断本次 delta 是否为简单插入若插入文本恰好是!则触发capitalize_word。深入 capitalize_word读取与写回缓冲区capitalize_wordmain.rs是模板中真正有业务逻辑的部分完整展示了使用ViewAPI 读取文档并构造编辑的过程fn capitalize_word(self, view: mut ViewChunkCache, end_offset: usize) - Result(), Error { //NOTE: this makes it clear to me that we need a better API for edits let line_nb view.line_of_offset(end_offset)?; let line_start view.offset_of_line(line_nb)?; let mut cur_utf8_ix 0; let mut word_start 0; for c in view.get_line(line_nb)?.chars() { if c.is_whitespace() { word_start cur_utf8_ix; } cur_utf8_ix c.len_utf8(); if line_start cur_utf8_ix end_offset { break; } } let new_text view.get_line(line_nb)?[word_start..end_offset - line_start].to_uppercase(); let buf_size view.get_buf_size(); let mut builder EditBuilder::new(buf_size); let iv Interval::new(line_start word_start, end_offset); builder.replace(iv, new_text.into()); view.edit(builder.build(), 0, false, true, sample.into()); Ok(()) }算法分三步定位line_of_offset得到光标所在行号offset_of_line得到该行的起始字节偏移从而把绝对偏移换算成行内坐标。扫描逐字符遍历该行注意按chars()迭代、用len_utf8()累加正确处理多字节 UTF-8记录最后一个空白字符后的位置作为word_start即光标前单词的起点。编辑取出[word_start, end_offset - line_start]区间文本转大写用xi_rope的EditBuilderrust/rope/src/delta.rs 中的增量构造器构造一个替换区间Interval::new(line_start word_start, end_offset)的RopeDelta最后通过view.edit(...)提交。View::edit的签名rust/plugin-lib/src/view.rs是edit(delta, priority, after_cursor, new_undo_group, author)。sample-plugin 传入的(delta, 0, false, true, sample)含义为优先级0、不强制把光标移到编辑之后、开启新的 undo 分组、作者标记为sample。该方法的底层实现将PluginEdit包含当前rev版本号与 delta封装为editRPC 通知发送给 corecore 负责把插件编辑与用户编辑做合并/冲突消解。View还提供了get_document、get_region、add_scopes语法作用域、update_annotations、add_status_item等能力完整清单见 rust/plugin-lib/src/view.rs。依赖与构建上下文rust/sample-plugin/Cargo.toml 声明了模板的依赖关系这也是任何 Rust 插件都要面对的基础设施[dependencies] serde 1.0 serde_derive 1.0 [dependencies.xi-plugin-lib] path ../plugin-lib [dependencies.xi-core-lib] path ../core-lib [dependencies.xi-rope] path ../rope [dependencies.xi-trace] path ../trace四个xi-*依赖均以相对路径指向同仓库的 cratexi-plugin-lib提供Plugin/View/Cache与事件循环xi-core-lib提供ConfigTable、插件 RPC 类型等源码中的use crate::xi_core::ConfigTable即源于此xi-rope提供RopeDelta、Interval与增量构造器xi-trace提供性能追踪。整个rust/目录是一个 Cargo workspace因此编译整个仓库或在 workspace 内构建该插件使用cargo build --release产物统一落在rust/target/release/下随后由 Makefile 的install目标搬运到插件目录。Makefile 头部注释也强调PLUGIN_BIN xi-sample-plugin必须与 Cargo.toml 的包名一致因为二进制文件名由 Cargo 按包名生成。从模板到真实插件参考实现若想从 sample-plugin 进一步探索仓库内还有两个成熟的插件可作参照rust/syntect-plugin基于 syntect 的语法高亮插件使用StateCache、add_scopes逐行推送高亮作用域其 manifest.toml 是 manifest 可选字段的最佳范本入口源码见 rust/syntect-plugin/src/main.rspython/ 目录下的多个 Python 插件如 python/echo_plugin.py、python/spellcheck.py印证了 xi插件可以用任何语言编写的定位。更宏观的插件架构理念异步 RPC、快照读、delta 写、多级作用域与触发机制记录在 docs/docs/plugin.md 中虽然该文注明部分实现细节已演进但其高层设计——插件通过 RPC 调用、不在前端或后端进程内提供语言绑定、慢插件不应干扰输入、崩溃插件不应导致数据丢失——仍然是理解 sample-plugin 所处体系的最佳背景。小结sample-plugin 麻雀虽小五脏俱全一个必填三字段的manifest.toml定义了插件的身份与入口一个跨平台Makefile把cargo build --release的产物按$XI_CONFIG_DIR/plugins/name/bin/约定安装到位一个约百行的main.rs通过Plugintrait 与mainloop接入 core 的 RPC 事件流并用ViewAPI 完成了读到编辑 → 识别感叹号 → 大写前词 → 回写 delta的完整闭环。以此为起点你可以把update换成自己的业务逻辑、把ChunkCache换成StateCache、在 manifest 中补上activations与commands一步步构建出真正属于自己的 xi-editor Rust 插件。【免费下载链接】xi-editorA modern editor with a backend written in Rust.项目地址: https://gitcode.com/gh_mirrors/xie/xi-editor创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

办公楼亚克力LED发光字制作安装施工组织设计与实操指南
办公楼亚克力LED发光字制作安装施工组织设计与实操指南

简介:办公楼亚克力LED发光字制作安装工程施工组织设计文档,面向施工管理人员、工程技术人员及项目负责人,针对已投入使用的办公楼楼顶安装发光字这一场景,完整提供了从工程说明、工程概况到工艺流程、施工要求、安全保证措施的实施… · 2026/9/21 1:42:40

RISC-V AI芯片开发:告别自研编译器,用现成工具链实现降维打击
RISC-V AI芯片开发:告别自研编译器,用现成工具链实现降维打击

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/21 1:42:40

高质量数据集建设与标准化:从数据治理到质量评估实战
高质量数据集建设与标准化:从数据治理到质量评估实战

简介:一份四十页PPT资源,聚焦高质量数据集建设与标准化情况,面向人工智能从业者、数据工程师、大模型训练及数据治理相关读者。内容从数据驱动的人工智能发展切入,回顾浅层学习、深度学习到大模型时期数据集规模与质量要求的演进&… · 2026/9/21 1:41:40

Python+torch实现PINN求解二维Helmholtz方程:从低频到高频的实战指南
Python+torch实现PINN求解二维Helmholtz方程:从低频到高频的实战指南

第一次把PINN跑通的时候,说实话没有太多成就感,因为在二维Helmholtz方程上它表现得相当一般。当方程里的波数k从7提到15,普通多层感知机的解就开始“摆烂”,损失曲线降不下去,数值解和解析解差得离谱。折腾一段时间后我… · 2026/9/21 2:22:47

AI桌面助手自动执行与权限管理实战:安全与效率如何平衡
AI桌面助手自动执行与权限管理实战:安全与效率如何平衡

"允许访问这个文件夹吗?"2026年,几乎所有主流AI桌面助手首次启动时都会弹出这句授权请求。对比2023年那个"只会写诗聊天"的AI,你手里的桌面助手如今会读文件、改配置、运行命令、批量删除重复文件,甚至自己写… · 2026/9/21 2:22:47

极摩客迷你主机本地AI部署指南:从内存核显到Ollama实战
极摩客迷你主机本地AI部署指南:从内存核显到Ollama实战

最近身边折腾本地 AI 的朋友明显多了,以前找我配电脑都是先问显卡显存、电源瓦数,最近画风全变了:上来就问能不能在自己家里跑 DeepSeek,聊天记录不想出本机,公司文档想整理成私有知识库,还有人想把本地模型… · 2026/9/21 2:22:47

ESD保护版图设计核心细节:从电流路径到镇流电阻的实战指南
ESD保护版图设计核心细节:从电流路径到镇流电阻的实战指南

简介:面向集成电路设计与可靠性工程师的ESD(静电放电)保护专题文档,系统梳理静电放电对CMOS芯片的危害机理,并围绕接地栅NMOS(GGNMOS)器件物理分析,详解ESD保护结构的设计原理、版图… · 2026/9/21 2:22:47

CAN总线实战指南:STM32多节点实时通信系统搭建与避坑全记录
CAN总线实战指南:STM32多节点实时通信系统搭建与避坑全记录

简介:一份基于STM32的CAN总线多节点工业控制系统设计资料,面向具备嵌入式开发基础、熟悉STM32与C语言的软硬件工程师和工业自动化研发人员,目标是从零构建高可靠、可扩展的工业现场通信网络,实现电机控制、传感器采集、阀门执行和… · 2026/9/21 2:22:47

四大AI Agent实测:Claude Code、Codex CLI、OpenClaw、Hermes Agent怎么选?
四大AI Agent实测:Claude Code、Codex CLI、OpenClaw、Hermes Agent怎么选?

最近这半年,AI Agent 这个词几乎被聊烂了。我在技术群、同事饭局、线下 meetup 上,每周都要回答几次类似的问题:Claude Code 和 Codex CLI 到底哪个写代码更强?OpenClaw 和 Hermes Agent 又是什么来头,跟编程助手是一回… · 2026/9/21 2:21:47

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化
Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡… · 2026/9/21 0:02:39

Word表格编号全攻略:从列表编号到题注交叉引用
Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技… · 2026/9/21 0:02:39

从第一个站到第二个站:独立开发者的静态网站选型与落地实践
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&… · 2026/9/20 0:00:41

Claude Code 按智谱AI指南装完,ANTHROPIC_BASE_URL 改走 TaoToken 兼容通道行不行
Claude Code 按智谱AI指南装完,ANTHROPIC_BASE_URL 改走 TaoToken 兼容通道行不行

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/21 0:00:18

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程
agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程 【免费下载链接】agentic-awesome-skills AAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and … · 2026/9/21 0:00:18

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析
gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析 【免费下载链接】gin-vue-admin 🚀ViteVue3Gin拥有AI辅助的基础开发平台,企业级业务AI开发解决方案,内置mcp辅助服务,内置skills管理,… · 2026/9/21 0:00:18

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码