Nathan
Mikayla 和我周末投入时间,Conrad 帮助我们合并结果后,我们终于为 GPUI 的核心视图相关特性设计了一个令人满意的版本。
在 GPUI 中,当你打开一个窗口时,你需要提供一个视图,用于指示该窗口应该显示什么。要实现一个视图,你需要在任何类型上实现 Render
特性,以描述它在屏幕上的显示方式。
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
特性类似的是 RenderOnce
,它通过移动对象来渲染对象。
pub trait RenderOnce: Sized {
type Element: IntoElement;
fn render(self) -> Self::Element;
}
通常,你可以使用此特性来实现可从其他元素组成的自定义 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
特性,例如,这对于将任意子项传递给父元素(如 div)很有用
// Note that you don't need to call `Button::render` here.
div().child(Button::new("button"))
Nate
美国的朋友们,感恩节快乐! 实际上,我们在加拿大十月份就庆祝感恩节了,所以我仍然在这里努力工作😄
我想谈谈 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 的早期阶段,因此仍然存在一些粗糙的边缘。
Kirill
本周,我专注于修复现有错误并推动 Zed 的工作区文件功能。 现在,设置中有一个 file_scan_exclusions
列表,默认情况下,它会从 Zed 中隐藏一堆类似 .DS_Store
的文件。
随着排除项的发布,工作区似乎只有一个悬而未决的问题,与排除项完全相反:gitignore 文件层次结构中的各种查找。
-
项目面板(文件树)已经处理了 gitignore 文件,将其灰显,并且仅当它们在文件树中“打开”时才(重新)加载 gitignore 目录。
-
项目搜索直到本周我才涵盖了这一部分,因此无法在 gitignore 文件中进行搜索。 在实现了排除项部分之后,启用这一部分相对简单,但是性能部分还剩下一些容易实现的成果。 任何普通的 node_modules 或 target 都可能会因短查询而产生大量结果,因此现在还不清楚从哪里开始划定基线。
-
文件查找器(打开文件面板)也不匹配 gitignore 文件路径,并且似乎是最后一个从这样做中受益匪浅的元素。 然而,这似乎是所有问题中最复杂的一个:目前,Zed 既不急于扫描 gitignore 目录,也不跟踪它们的 FS 事件:
node_modules
或target
目录可能比常规项目大得多,这似乎非常浪费。 实际上,我们之前做过类似的事情,这对许多用户的工作负载来说非常繁重。 “面板”本身是一个简单的输入字段,没有额外的过滤器,似乎最多可以添加“全部 gitignore 文件或无”切换,并且输入查询是一个模糊匹配字符串,这意味着 Zed 必须搜索所有 gitignore 目录根目录直到最后才能正确匹配结果。 很幸运能够提前达到最大匹配路径限制,但是如果平均体验是等待几秒钟才能产生少于 100 行包含路径的额外行,那就不够好了。 为某些 gitignore 目录添加额外的设置来包含它们似乎很复杂(我们已经有了排除项!)并且不够灵活。 我仍然犹豫不决,试图为该功能找到一个好的 UX。
最后,为了至少以某种方式帮助 Zed2,我参与了 Zed 每日构建的基础工作,帮助 Mikayla 为 gpui2 构建启动 Zed。