← 返回博客

Zed 周刊:第 26 期

The current state of Zed under the GPUI2 port
GPUI2 移植后的 Zed 当前状态

内森

我们向 GPUI 2 的过渡仍在继续,并取得了良好进展。编辑器是我们最复杂的 UI 组件之一,几乎已完全移植。正如所料,当我们开始在应用程序中使用新框架时,它需要一些调整。

本周在文本输入和键盘事件处理方面取得了重大改进。下面是一个如何为包含项目列表的菜单视图实现一些简单键盘处理的草图。解释如下。

struct Menu {
    items: Vec<SharedString>,
    selected_index: usize,
}
 
actions!(MoveUp, MoveDown);
 
impl Render for Menu {
    fn render(&mut self, cx: &mut ViewContext<Self>) -> impl Component {
        div()
            .id("menu")
            .focusable()
            .key_context("menu")
            .on_action(Menu::move_up)
            .on_action(Menu::move_down)
            .children(self.items.iter().cloned().enumerate().map(|(ix, item)| {
                div()
                    .when(ix == self.selected_index, |div| {
                        div.bg(cx.theme().colors().selected)
                    })
                    .child(item)
            }))
    }
}
 
impl Menu {
    fn move_up(&mut self, _: &MoveUp, cx: &mut ViewContext<Self>) {
        if self.selected_index > 0 {
            self.selected_index -= 1;
            cx.notify();
        }
    }
 
    fn move_down(&mut self, _: &MoveUp, cx: &mut ViewContext<Self>) {
        if self.selected_index < self.items.len() - 1 {
            self.selected_index += 1;
            cx.notify();
        }
    }
}

为了使 Menu 结构成为一个视图,我们对其实现了 Render。然后,我们通过声明一个“menu”的 key_context,使此视图能够与键映射匹配键盘事件。这将导致我们匹配键映射中需要此上下文的绑定。然后,我们为 MoveUpMoveDown 操作添加侦听器,这些操作会改变 selected_index 并通知应用程序此视图已更改。

期待分享更多。

茱莉亚 (Julia)

本周早些时候,我一直在追查一些问题,这些问题是我们下载 NPM(用于安装 TSServer 等基于 Node 的语言服务器)时,服务器文件似乎安装到用户的主目录中,这时我偶然发现了一个更糟糕的问题。我们的 tsserver 集成完全中断了,这意味着 JS 和 TS 文件没有自动补全/诊断/代码操作等功能。

TypeScript 语言服务器本身并不原生支持我们依赖的语言服务器协议 (LSP)。这是因为 tsserver 实际上早于 LSP 规范本身。为了避免实现 tsserver 所说的定制协议,我们使用了一个社区项目,它围绕 tsserver 进行封装,充当支持 LSP 的编辑器和使用其自身协议的 tsserver 之间的中介。

使用现有项目的好处是,我们不必过多考虑细节,因为已经有人在做。这是代码共享和可重用库的核心原则,借助每个人都在做自己事情的网络效应,整体效率会更高。然而,为了使系统正常工作,各个项目必须能够进行必要的更改以改进,从而使整个系统受益。

这正是这里发生的事情;周三,这个封装项目发布了一个新版本,删除了我们遗憾地仍在使用的部分已弃用的命令行标志。一旦我弄清楚这一点,我就能够更新我们的使用方式,改进我们这边的一些正确性,然后服务器就恢复正常了!

教训是,无论何时依赖外部项目和代码,都必须始终注意即将发生的变化,特别是如果它是您无法合理地固定所依赖版本的一个组件。如果我们更早地意识到正在发生的事情,我们就能在弃用成为破坏性更改之前更新我们的使用方式。

基里尔

GPUI2 周围发生了很多事情,所以我所有从事相关工作的尝试看起来都没有什么影响力。因此,我决定继续改进我们的错误和功能,因为总有人要做。有趣的是,在此过程中,我确实发现了一些我可以帮助将旧事物移植到 GPUI2 的地方,我将尝试接下来进行这项工作。

到目前为止——两项主要工作

  • Prettier 及其相关错误——现在它更稳定了,减少了许多荒谬的错误并支持 NPM 工作区。很高兴看到对功能的反馈,并知道它现在应该能帮助很多人。

  • 诊断 UI 元素及其相关错误——我们之前的模型优雅地退化了,并且没有很好地为某些语言服务器返回文件诊断的“动态”方式做好准备。我修复了最明显的痛点,但还有更多问题需要处理。

当我寻找更好的方法来(不)显示 Git 排除文件中的诊断时,我得到了更多关于排除文件的搜索和索引如何工作的想法,我正在尝试现在追寻这些想法。

内特

gpui2 设计+组件的开发以及 Rust 语言的学习都在继续。我开始感觉自己对这门语言有了一定的掌握——至少足以让我不再需要不断地向别人寻求帮助,这感觉很好。

现在越来越多的人开始为 gpui2/zed2 重写 crates,我们迄今为止构建的组件正在迅速接受压力测试;我们正在寻找有效的工作模式,并发现存在差距的地方。

能够为 UI 组件创建“故事”以隔离测试它们,这使得迭代它们变得非常容易。这是一个所有可能的玩家颜色的“故事”示例

Player Colors
玩家颜色

目前,所有主题都实现了相同的玩家颜色集,但这种情况很快就会改变。

这是一个故事如何运作的非常粗略的例子

Player Colors Story Example
玩家颜色故事示例

在这种情况下,“故事组件”主要只是主题颜色,但你可以在那里渲染任何组件。

随着我们继续构建主题,能够拉起一个故事来检查特定状态下的情况真的很有用。

新主题的开发也在进行中。马歇尔在将主题调整到我想要的状态方面提供了巨大帮助。使用 Rust 的复杂性之一是,它对主题的格式/构建主题时必须提供的内容以及它是否可以在编译时可用非常严格。

因此,我们一直在构建一些系统来区分系统主题(完全用 Rust 构建并烘焙到应用程序中)、第三方默认主题(我们导入并动态构建为 Rust 文件以烘焙到应用程序中的外部主题)和最终用户主题(不会在构建时可用,需要动态反序列化并使其可用)。

部分工作使我们构建了一个正在开发的 VSCode 主题导入器(Marshall 在下面对此进行了更多介绍。)

有很多事情要谈,但也有很多事情要做,所以我就此打住。

我们非常高兴能很快将 Zed 在新的 gpui 上运行到大家手中,也同样很高兴大家能看到我们一直在 gpui 上所做的工作。

下次再见!

米凯拉

我一直在四处奔波,最终完善了对新 UI 框架的理解,并尝试用新框架重新引入大约 30,000 行测试和服务器代码。我还与 Max 合作,构建了一个自定义元素,用于高效显示统一元素大小列表,并正在努力在旧金山的 Aaron Schwartz Day 上发表我职业生涯的第一次演讲!下一个大目标:让 Zed 成为我们日常使用的工具 :D

约瑟夫

本周,我开始构建一个 AI 仪表板,以便我们可以查看用户与我们内置 AI 工具交互的频率。在遥测领域,我还更新了我们的文档,明确说明我们发送的事件类型以及每个事件中存储的数据。

另外,我们现在每周活跃安装量稳定超过 1000 次。

Weekly active installations
每周活跃安装量

如果一个安装当天发送了一个编辑器事件,则该安装被视为“活跃”。如果该安装在一周内至少活跃 3 天,则该安装被视为该周“活跃”。

我从 pre-alpha 时代就开始使用 Zed 了。那时,活跃用户可能只有 5-10 个,包括创始人,而 Zed 看起来像这样

Zed, circa July 5th, 2021
Zed,大约 2021 年 7 月 5 日

看着新用户勇敢地尝试不同的事物,这让人感到无比兴奋。在 Zed 成为适用于所有类型开发人员的通用可行编辑器之前,我们还有很多路要走,但对于那些一直积极使用 Zed,甚至只是偶尔尝试的人来说,您的支持对我们意义重大。看到 Zed 家族不断壮大,并见证这个编辑器变得比我们任何一个人都更强大,这 truly 令人鼓舞。

康拉德

我一直在努力让新 UI 框架的各个部分真正地将应用程序整合在一起!本周大部分时间都花在重建用于“跳转到行”的 ctrl-g 上。组件本身只需要几个小时,但作为第一个使用框架各个方面功能的乐趣在于发现所有“陷阱”,调试它们,并弄清楚我们想如何修复它们。

这包括从简单的疏忽(在当前聚焦的元素上调用“focus”不应该导致崩溃),到测试框架中微妙的并发错误(调用析构函数不应该导致你的测试死锁!)。

我期待着回到新的、改进的基础之上,让 Zed 变得更好。我们不再会像最近在场外活动中创造的那句短语一样,“以火腿的速度编码”。

马歇尔

除了与大家合作进行各种 GPUI 2 迁移工作外,本周我还花了一些时间继续改进我们的新主题系统。

简单介绍一下我们在 GPUI 2 中的当前主题流程,我们有一个 theme_importer CLI 工具,它可以摄取表示为 JSON 的 VS Code 主题,并将其作为表示为 Rust 源代码的 Zed 主题发出。然后这些主题被编译成二进制文件以进行分发。

以前我们发出的是一个完整的 Zed 主题,这意味着未由 VS Code 主题指定的颜色值会被默认 Zed 主题的值替换。虽然这是我们希望在运行时表现出的行为,但将默认值复制到每个主题中并不理想,并且很难看出哪些颜色来自主题本身,哪些来自默认主题。

我重新设计了我们的用户主题,将它们建模为在基本主题之上的叠加层。现在,每个主题只指定它需要从基本主题覆盖哪些值。然后在运行时,我们可以加载用户主题,将其应用到基本主题之上,并获得一个完整的 Zed 主题。这种机制也为加载不随 Zed 默认分发的主题奠定了基础。

我还花了一些时间来简化我们的主题导入过程。

theme_importer 依赖于包含主题定义的 theme2 crate,但 theme2 也包含由 theme_importer 发出的主题。这会造成一种循环依赖,其中发出主题中的编译错误会导致 theme_importer 编译失败。在迭代 theme_importer 时处理这个问题相当恼人,因此很明显我们需要一个更好的解决方案。

我得出的解决方案是使用 Cargo 特性来有条件地编译生成的主题。theme2 crate 定义了一个 importing-themes 特性,并且只在 importing-features 被禁用时才编译包含所有主题的 themes 模块。

#[cfg(not(feature = "importing-themes"))]
mod themes;

然后,在 theme_importerCargo.toml 中,我们设置 importing-themes 特性,以表明我们将要导入主题。

theme = { package = "theme2", path = "../theme2", features = ["importing-themes"] }

这使我们能够继续运行 theme_importer,即使 themes 模块处于无法编译的状态。


正在寻找更好的编辑器吗?

您今天就可以在 macOS、Windows 或 Linux 上试用 Zed。立即下载


我们正在招聘!

如果您对我们博客中涵盖的主题充满热情,请考虑加入我们的团队,帮助我们实现软件开发的未来。