gpui-kit Base 无样式源代码编辑器 Editor 完整指南:语言规则、快捷键、搜索与高亮扩展
【免费下载链接】gpui-kitRust GUI components for building fantastic cross-platform desktop application by using GPUI.项目地址: https://gitcode.com/GitHub_Trending/gp/gpui-kit
Editor是 gpui-kit Base 层提供的无样式源代码编辑控件,它建立在共享文本编辑引擎之上,为语言、行号槽(gutter)、折叠(folding)、空白字符显示、文本装饰、语法高亮、内置搜索、诊断与 LSP 扩展提供了统一入口。阅读本文后,你将能够在自己的 GPUI 应用中直接嵌入一个可编辑源码的编辑器,配置语言编辑规则(自动闭合、智能缩进),启用行号与折叠,打开内置搜索面板,并通过 decoration 与 highlighter 扩展点接入自定义高亮和视觉方案。单行值应使用 Input,普通多行文本使用 Textarea。
Editor 的定位:一个共享引擎、三种输入形态
从源码结构看,Base 的输入体系在 crates/base/src/input 下按base、editor、textarea三个子模块组织。Editor对应的核心类型定义在 crates/base/src/input/editor/mod.rs:
pub type EditorState = InputBaseState<EditorMode>;也就是说,EditorState就是共享编辑引擎InputBaseState在「代码编辑器」这个 mode 下的别名。同一引擎只有代码编辑形态会暴露语言、行号、折叠、缩进参考线、诊断、装饰和 LSP provider;普通Input与Textarea永远不会暴露这些能力。EditorMode在InputModeKind中声明了MULTI_LINE = true与CODE_EDITOR = true(见 mod.rs),并挂载了EditorExtras,用于承载 hover 定义弹层、装饰集合、语义 token、文档色块、内联补全和上下文菜单等代码编辑专属状态。
渲染端Editor只是一个持有Entity<EditorState>的轻量包装(mod.rs),通过RenderOnce把状态实体直接作为元素渲染,因此它本身不带任何样式——颜色、行号槽、折叠图标、覆盖层全部由应用层提供,这正是"无样式源代码编辑器"的含义。
语言编辑规则
Base 编辑器接受LanguageConfig,以及两个独立的编辑器偏好auto_close与smart_indent。它读取已注册的语言配置,但自身不加载任何解析器;解析器只存在于应用或 UI crate 层。
- Component 层在初始化时安装
LanguageProvider,提供内置语言名称、默认规则与语法提供者; - Base 使用者可通过
set_language_provider安装自己的语言服务,并通过set_language_config配置某个语言的编辑规则; - 直接使用 Base 时,从
gpui_kit::base::input导入与 Component 相同的配置类型。
详细配置字段与语言注册方式参见 语言编辑规则,这里结合 Base 源码补充底层实现要点。
LanguageConfig:声明式编辑规则
LanguageConfig定义在 crates/base/src/input/editor/language_config.rs,由四部分组成:
| 字段 | 含义 | 默认值(见Default实现) |
|---|---|---|
brackets | 结构性括号对,用于缩进判断与在定界符之间拆分 Enter | ()、[]、{} |
auto_closing_pairs | 自动闭合对及其禁用上下文 | 三个括号对 +""、'',均not_in [String, Comment] |
auto_close_before | 允许自动插入的后续字符集合 | ;:.,=}])> |
indentation_rules | 智能缩进的正则规则 | None |
其中brackets使用BracketPair::new("{", "}")这样的结构;auto_closing_pairs是可选的:取None时回退使用结构性brackets,取Some(vec![])则禁用所有自动配对(见 language_config.rs 的closing_pairs实现)。配对串支持多字符定界符,例如/*与*/。
not_in需要一个语法上下文提供者:如果没有安装提供者,Base 编辑器一律上报SyntaxContext::Code(language.rs)。样式化的编辑器在语言启用 Tree-sitter 语法时才会提供该上下文。
智能缩进与语法上下文
IndentationRules::new(increase, decrease)接受两个已编译的regex::Regex模式。按 Enter 时,increase模式匹配光标前的文本,decrease模式匹配光标后的文本(language_config.rs)。没有 increase 模式时,结构性开括号提供默认缩进(language_config.rs)。这些规则不会重排已有行或粘贴文本;Python 的语言默认值额外识别行尾冒号,未知语言只使用结构性括号。SyntaxContext是解析器无关的枚举(Code/String/Comment,见 highlighting.rs),供配对、跳过后置与缩进决策使用。
配置替换的语义
set_language_config(language, config, cx)会替换当前应用中该语言的配置,现有编辑器在下次编辑时立即生效(包括同一事件处理器内)。别名共享配置:python、py、pyi即使没有启用语法 feature 也指向同一语言。自定义语法注册优先于内置别名并保留原始大小写;未知语言使用LanguageConfig::default()(language.rs)。注意它不会改动auto_close与smart_indent两个独立偏好。
这套接口是 Monaco 风格语言配置的受支持子集,不是 Monaco JSON 或 Tree-sitter.scm文件的加载器;选区包围与自定义onEnterRules尚不在接口范围内。
快捷键与矩形列选
Base 与样式组件共享键盘和鼠标行为,默认快捷键在编辑器聚焦时生效。macOS 上 Option 即 Alt 修饰键;Linux 默认不绑定 Super/Win。各平台快捷键、多光标编辑与矩形列选细节参见 快捷键与矩形列选,要点速查如下:
| 操作 | macOS | Linux | Windows |
|---|---|---|---|
| 在上/下方添加光标 | Cmd+Option+Up / Down | Alt+Shift+Up / Down | Ctrl+Alt+Up / Down |
| 每个选区扩展一个字符 | Shift+Left / Right | Shift+Left / Right | Shift+Left / Right |
| 每个选区扩展一个单词 | Option+Shift+Left / Right | Ctrl+Shift+Left / Right | Ctrl+Shift+Left / Right |
| 鼠标添加光标 | Option+左键点击 | Alt+左键点击 | Alt+左键点击 |
| 矩形块选择 | Option+Shift+左键拖动 | Alt+Shift+左键拖动 | Alt+Shift+左键拖动 |
| 仅保留活动光标 | Escape | Escape | Escape |
Linux 还接受 Ctrl+Alt+左键拖动做矩形选择(与 Ghostty 一致)、Alt+Shift+Left / Right 做单词选择;Windows 额外接受 Alt+Shift+Left / Right 做字符选择。按住 Alt/Option 悬停在编辑器上会显示+十字光标;包含 Alt 的选择手势优先于 Ctrl/Cmd 点击的跳转定义。需要留意:Linux 桌面环境可能先于编辑器拦截组合键,其中 Ctrl+Alt+Up / Down 因部分桌面用于切换工作区而默认不绑定。
搜索
编辑器内置搜索面板。编辑器聚焦时按Ctrl-F(Windows/Linux)或Cmd-F(macOS)打开;Enter跳到下一个匹配,Shift+Enter跳到上一个,Escape关闭面板。编程式 API 如下:
// 打开查找面板(replace_mode = false) editor.update(cx, |state, cx| { state.open_search(false, cx); }); // 关闭面板 editor.update(cx, |state, cx| { state.close_search(cx); }); // 禁用搜索(Editor 默认启用) editor.update(cx, |state, cx| { state.set_searchable(false, cx); });open_search不是幂等操作:每次调用都会推进search_activation_revision,表现层据此重新聚焦搜索框并选中内容(与再次按下快捷键一致)。因此它应当从 action 或用户手势中调用,绝不能在渲染回调或每帧运行的 observer 里调用——那会在每一帧抢走焦点、导致无法输入(search.rs)。
搜索实现层面,SearchMatcher使用aho-corasick算法一次性构建多模式匹配器,默认大小写不敏感;相同查询重复提交不会重置当前激活匹配,保留上次查询会恢复到之前的匹配位置(search.rs 及单元测试identical_query_keeps_the_current_match)。只读编辑器仍然可以被搜索——替换 UI 会自动隐藏。详细行为参见 搜索。
导入与基本用法
use gpui_kit::base::input::{Editor, EditorState, TabSize};最小可运行示例:
let editor = cx.new(|cx| { EditorState::new(window, cx) .language("rust") .line_number(true) .folding(true) .tab_size(TabSize { tab_size: 4, hard_tabs: false }) .default_value("fn main() {\n println!(\"Hello\");\n}") }); Editor::new(&editor).language()指定的语言同时用于选择语法高亮;启用对应的 Cargo feature(如tree-sitter-rust、tree-sitter-markdown),或用tree-sitter-languages打包全部内置语法。
空白字符与装饰
通过show_whitespaces(true)显示空格、制表符等空白字符。通过create_decorations_collection创建随文本编辑自动跟踪范围的装饰集合:
let decorations = editor.update(cx, |state, cx| { state.create_decorations_collection(initial_decorations, cx) });返回的TextDecorationCollection必须在装饰仍需生效期间一直持有。其底层行为在 crates/base/src/input/editor/decorations.rs 有完整定义:
- 装饰范围使用指向
value()的 UTF-8 字节偏移; - 集合按插入顺序分层,重叠装饰设置同一
HighlightStyle属性时先创建的集合获胜; - 范围边界处的插入不会扩张范围,对应 Monaco 的
NeverGrowsWhenTypingAtEdges语义; - 范围会随编辑自动调整,无需在每次修改后重新设置(单元测试
decoration_ranges_follow_text_edits验证了插入、删除场景下的偏移计算); - 输入处于掩码(masked)状态时不渲染装饰;
- 集合的生命周期与所属
InputBaseState一致。
集合还支持set/append/clear/get_ranges操作,分别对应 Monaco 的IEditorDecorationsCollection同名方法(decorations.rs)。
高亮与语言功能
InputHighlighterFactory、InputHighlighter、诊断类型与 LSP provider trait 是提供给设计系统作者的底层扩展点,它们作用于共享的InputBaseState。普通文本输入框不会用到这些能力,样式化组件的应用应通过编辑器集成来配置它们。
关键扩展点定义在 crates/base/src/input/editor/highlighting.rs:
HighlightStyleResolver:把语义高亮名称解析为可渲染的 GPUIHighlightStyle。Base 刻意不感知具体语法主题,任何 UI crate 或应用都可以提供自己的 resolver;InputHighlighter:解析器无关的高亮接缝,实现方自己负责解析、增量状态与语言特有行为,Base 只索取样式区间与折叠候选(styles、fold_ranges、fold_ranges_for_edit,见 highlighting.rs);SyntaxContextProvider:按编辑器创建,为编辑决策(配对、跳过、缩进)提供SyntaxContext;InputEditorStyle:应用拥有的颜色与高亮 resolver,供编辑器绘制前景、光标、选区、诊断色与可选的行号槽背景、活动行背景、折叠图标渲染器(fold_icon_renderer)使用。
可运行展示使用syntect作为语法后端,并在 WASM 中选择兼容的fancy-regex后端。Syntect 只识别语法 scope;适配器把这些 scope 映射为语义名称,再由HighlightStyleResolver从应用主题解析颜色与字体样式。示例会在每次编辑后重新解析短代码;生产集成可以在InputHighlighter中保留增量解析状态以获得更好性能。
字体与表现
Editor没有独立的字体设置,而是使用环境文本样式。在外层元素设置font_family、text_size、字重与行高即可作用于编辑器(这些是每个元素都有的标准Styled方法):
Editor::new(&editor).text_sm() Editor::new(&editor) .font_family("JetBrains Mono") .text_size(px(15.))编辑器默认以等宽字体绘制代码;行高为字体大小的 1.5 倍,行号槽与行高会跟随字号变化。应用负责编辑器颜色、行号槽、折叠图标与覆盖层,通过InputEditorStyle、FoldIconRenderer与 provider trait 接入。现成的视觉方案参见gpui-componentEditor。
补充一点源码层面的实现事实:InputEditorStyle::resolved()会把未显式设置的透明颜色从当前语义主题调色板补齐(前景、光标、选区、背景、边框等),选区默认使用主题 accent 且透明度固定为 0.4,确保被选中的字形仍然可读(见 highlighting.rs 及配套单元测试)。
可运行示例
cargo run -p gpui-base-examples -- editor该命令从crates/base的 examples 目录(crates/base/examples)启动 Base 编辑器演示。样式化的完整编辑器体验(含主题、语法高亮、行号、折叠、搜索面板与只读/禁用外观控制)请参阅 gpui-component Editor 文档。
【免费下载链接】gpui-kitRust GUI components for building fantastic cross-platform desktop application by using GPUI.项目地址: https://gitcode.com/GitHub_Trending/gp/gpui-kit
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考