example_editor_info.rs

 1//! `EditorInfo` โ€” a read-only View over an `ExampleEditor` entity.
 2//!
 3//! Demonstrates zero-wiring reactivity: just return the entity from `entity()`,
 4//! read from it in `render()`, and caching + invalidation happen automatically.
 5//! No observers, no subscriptions, no manual `cx.notify()`.
 6
 7use gpui::{App, Entity, IntoViewElement, Window, div, hsla, prelude::*, px};
 8
 9use crate::example_editor::ExampleEditor;
10use crate::example_render_log::RenderLog;
11
12#[derive(Hash, IntoViewElement)]
13pub struct EditorInfo {
14    editor: Entity<ExampleEditor>,
15    render_log: Entity<RenderLog>,
16}
17
18impl EditorInfo {
19    pub fn new(editor: Entity<ExampleEditor>, render_log: Entity<RenderLog>) -> Self {
20        Self { editor, render_log }
21    }
22}
23
24impl gpui::View for EditorInfo {
25    type Entity = ExampleEditor;
26
27    fn entity(&self) -> Option<Entity<ExampleEditor>> {
28        Some(self.editor.clone())
29    }
30
31    fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
32        self.render_log.update(cx, |log, _cx| log.log("EditorInfo"));
33
34        let editor = self.editor.read(cx);
35        let char_count = editor.content.len();
36        let cursor = editor.cursor;
37        let is_focused = editor.focus_handle.is_focused(window);
38
39        div()
40            .flex()
41            .gap(px(8.))
42            .text_xs()
43            .text_color(hsla(0., 0., 0.45, 1.))
44            .child(format!("{char_count} chars"))
45            .child("ยท")
46            .child(format!("cursor {cursor}"))
47            .child("ยท")
48            .child(if is_focused { "focused" } else { "unfocused" })
49    }
50}