内森
在 Mikayla 和我周末投入时间,以及 Conrad 帮助我们合并结果后,我们终于为 GPUI 的核心视图相关 trait 找到了一个令人满意的设计。
在 GPUI 中,当你打开一个窗口时,你会提供一个 视图,它指示该窗口应该显示什么。要实现一个视图,你需要在一个类型上实现 Render trait,以描述它如何在屏幕上显示。
pub trait Render: 'static + Sized {
type Rendered: RenderOnce + 'static; // We can delete this type in Rust 1.75
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Rendered;
}例如,你可以像这样制作一个简单的 TaskList 视图。
use gpui::{prelude::*, Div, div};
struct TaskList {
title: SharedString,
tasks: Vec<Task>
}
struct Task {
title: SharedString,
completed: SharedString,
}
impl Render for TaskList {
type Rendered = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Rendered {
// In reality this would need more styling.
// This example is focused on data flow.
div()
.child(self.title.clone())
.children(self.tasks.iter().map(|task| {
div()
.flex()
.flex_row()
.child(checkbox(task.completed))
.child(task.title.clone())
}))
}
}Render trait 的一个兄弟是 RenderOnce,它通过移动对象来渲染。
pub trait RenderOnce: Sized {
type Element: IntoElement;
fn render(self) -> Self::Element;
}通常,你会使用这个 trait 来实现可以由其他元素组合而成的自定义 UI 元素,例如:
#[derive(IntoElement)]
struct Button {
title: SharedString,
icon_path: Option<SharedString>,
on_click: ClickListener,
}
impl RenderOnce for Button {
type Rendered = Div;
fn render(self, cx: &mut WindowContext) -> Self::Rendered {
div()
.flex()
.flex_row()
.child(self.title.clone())
.children(self
.icon_path
.clone().map(|path| svg(path)))
}
}请注意 Button 上的 #[derive(IntoElement)] 属性宏。这会自动派生 IntoElement trait,这对于将任意子元素传递给父元素(如 div)非常有用。
// Note that you don't need to call `Button::render` here.
div().child(Button::new("button"))内特
祝美国的朋友们感恩节快乐!我们加拿大其实在十月庆祝感恩节,所以我还在努力工作 😄
我想谈谈 UI 缩放以及它如何融入我们编写 gpui2 UI 的方式。
我们采用了 rem 单位和 px,以便更容易地缩放 UI 元素。rem 是一种测量单位,它相对于 CSS 中根元素的字体大小。
在 gpui2 中,我们同样将 1 rem 的大小视为 ui_font_size 的大小,这是我们添加到应用程序中的一个新设置。它默认为 16 (16px),这是大多数浏览器中的默认字体大小,并且可以很好地划分到基于 4 的网格中。
许多 UI 库和设计系统都使用基于 4 的网格,因为尺寸的自然演变易于使用。
一个元素可能有:- 4 像素的内边距 - 4 像素的边框半径 - 12 或 16 像素的字体大小 - 如果它包含多个元素,它们之间可能间隔 4 像素
这使我们可以在构建时像使用像素一样,但通过更改 ui_font_size 设置来放大或缩小 UI。
然而,我们仍有一些问题需要解决。0.25px 到底意味着什么?当你进入非常小的 UI 尺寸时,你会开始遇到我们仍在解决的问题。

上面是 ui_font_size 设置为 14px、16px 和 20px 的示例。UI 缩放可以独立于 buffer_font_size 进行设置,因此你可以拥有一个带有小字体大小的大 UI,或者反之。
Zed 的可伸缩 UI 仍处于早期阶段,因此仍有一些粗糙之处。
基里尔
本周,我专注于修复现有错误并推动 Zed 的工作树文件功能。现在,设置中有一个 file_scan_exclusions 列表,默认情况下会隐藏 Zed 中的许多 .DS_Store-like 文件。
随着排除项的发布,工作树似乎只剩下一个突出的问题,这与排除项恰好相反:在 gitignore 文件层次结构中的各种查找。
-
项目面板(文件树)已经处理了 gitignore 文件,将它们灰显,并且只有当它们在文件树中“打开”时才(重新)加载 gitignore 目录。
-
项目搜索无法在 gitignore 文件中搜索,直到本周我解决了这部分。在实现了排除部分之后,这部分相对容易启用,但性能部分还有一些唾手可得的改进。任何普通的 node_modules 或 target 都可能因短查询而结果过多,因此目前尚不清楚此处应如何划定基线。
-
文件查找器(打开文件面板)也不会匹配 gitignore 文件路径,这似乎是最后一个会因此而大幅受益的元素。然而,这似乎是所有问题中最复杂的一个:目前,Zed 既不急切扫描 gitignore 目录,也不跟踪它们的 FS 事件:
node_modules或target目录可能比常规项目大得多,这似乎非常浪费。事实上,我们以前做过类似的事情,这对许多用户的工作负载来说是相当繁重的。这个“面板”本身是一个简单的输入字段,没有额外的过滤器,似乎最多只能添加一个“所有 gitignore 文件或不包含任何文件”的切换,并且由于输入查询是一个模糊匹配字符串,这意味着 Zed 必须搜索所有 gitignore 目录的根目录直到末尾才能正确匹配结果。如果能早早达到最大匹配路径限制,那将是幸运的,但如果平均体验是等待几秒钟才能生成不到 100 条额外路径行,那就不够好了。为某些 gitignore 目录添加额外设置以包含它们似乎很复杂(我们已经有排除项了!),而且不够灵活。我仍在不确定中权衡利弊,试图为该功能找到一个好的用户体验。
最后,为了至少以某种方式帮助 Zed2,我参与了 Zed 夜间发布的基础工作,帮助 Mikayla 为基于 gpui2 构建的 Zed 启动工作。