Add `Buffer` component

Marshall Bowers created

Change summary

crates/gpui3/src/style_helpers.rs                  |   9 
crates/storybook2/src/stories/components.rs        |   1 
crates/storybook2/src/stories/components/buffer.rs |  46 ++
crates/storybook2/src/story_selector.rs            |   2 
crates/ui2/src/components.rs                       |   2 
crates/ui2/src/components/buffer.rs                | 238 +++++++++++
crates/ui2/src/components/list.rs                  |   4 
crates/ui2/src/components/panel.rs                 |   4 
crates/ui2/src/elements/avatar.rs                  |   2 
crates/ui2/src/elements/icon.rs                    |   2 
crates/ui2/src/elements/label.rs                   |   2 
crates/ui2/src/lib.rs                              |   2 
crates/ui2/src/prelude.rs                          |  20 
crates/ui2/src/static_data.rs                      | 346 ++++++++++++++++
14 files changed, 661 insertions(+), 19 deletions(-)

Detailed changes

crates/gpui3/src/style_helpers.rs 🔗

@@ -8,8 +8,13 @@ use smallvec::smallvec;
 pub trait StyleHelpers: Sized + Styled<Style = Style> {
     gpui3_macros::style_helpers!();
 
-    fn h(mut self, height: Length) -> Self {
-        self.declared_style().size.height = Some(height);
+    fn w<L: Into<Length>>(mut self, width: L) -> Self {
+        self.declared_style().size.width = Some(width.into());
+        self
+    }
+
+    fn h<L: Into<Length>>(mut self, height: L) -> Self {
+        self.declared_style().size.height = Some(height.into());
         self
     }
 

crates/storybook2/src/stories/components/buffer.rs 🔗

@@ -0,0 +1,46 @@
+use std::marker::PhantomData;
+
+use gpui3::rems;
+use ui::prelude::*;
+use ui::{
+    empty_buffer_example, hello_world_rust_buffer_example,
+    hello_world_rust_buffer_with_status_example, Buffer,
+};
+
+use crate::story::Story;
+
+#[derive(Element)]
+pub struct BufferStory<S: 'static + Send + Sync + Clone> {
+    state_type: PhantomData<S>,
+}
+
+impl<S: 'static + Send + Sync + Clone> BufferStory<S> {
+    pub fn new() -> Self {
+        Self {
+            state_type: PhantomData,
+        }
+    }
+
+    fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
+        let theme = theme(cx);
+
+        Story::container(cx)
+            .child(Story::title_for::<_, Buffer<S>>(cx))
+            .child(Story::label(cx, "Default"))
+            .child(div().w(rems(64.)).h_96().child(empty_buffer_example()))
+            .child(Story::label(cx, "Hello World (Rust)"))
+            .child(
+                div()
+                    .w(rems(64.))
+                    .h_96()
+                    .child(hello_world_rust_buffer_example(&theme)),
+            )
+            .child(Story::label(cx, "Hello World (Rust) with Status"))
+            .child(
+                div()
+                    .w(rems(64.))
+                    .h_96()
+                    .child(hello_world_rust_buffer_with_status_example(&theme)),
+            )
+    }
+}

crates/storybook2/src/story_selector.rs 🔗

@@ -33,6 +33,7 @@ impl ElementStory {
 #[strum(serialize_all = "snake_case")]
 pub enum ComponentStory {
     AssistantPanel,
+    Buffer,
     Panel,
 }
 
@@ -44,6 +45,7 @@ impl ComponentStory {
             Self::AssistantPanel => {
                 components::assistant_panel::AssistantPanelStory::new().into_any()
             }
+            Self::Buffer => components::buffer::BufferStory::new().into_any(),
             Self::Panel => components::panel::PanelStory::new().into_any(),
         }
     }

crates/ui2/src/components.rs 🔗

@@ -1,9 +1,11 @@
 mod assistant_panel;
+mod buffer;
 mod icon_button;
 mod list;
 mod panel;
 
 pub use assistant_panel::*;
+pub use buffer::*;
 pub use icon_button::*;
 pub use list::*;
 pub use panel::*;

crates/ui2/src/components/buffer.rs 🔗

@@ -0,0 +1,238 @@
+use std::marker::PhantomData;
+
+use gpui3::{Hsla, WindowContext};
+
+use crate::prelude::*;
+use crate::{h_stack, theme, v_stack, Icon, IconElement};
+
+#[derive(Default, PartialEq, Copy, Clone)]
+pub struct PlayerCursor {
+    color: Hsla,
+    index: usize,
+}
+
+#[derive(Default, PartialEq, Clone)]
+pub struct HighlightedText {
+    pub text: String,
+    pub color: Hsla,
+}
+
+#[derive(Default, PartialEq, Clone)]
+pub struct HighlightedLine {
+    pub highlighted_texts: Vec<HighlightedText>,
+}
+
+#[derive(Default, PartialEq, Clone)]
+pub struct BufferRow {
+    pub line_number: usize,
+    pub code_action: bool,
+    pub current: bool,
+    pub line: Option<HighlightedLine>,
+    pub cursors: Option<Vec<PlayerCursor>>,
+    pub status: GitStatus,
+    pub show_line_number: bool,
+}
+
+#[derive(Clone)]
+pub struct BufferRows {
+    pub show_line_numbers: bool,
+    pub rows: Vec<BufferRow>,
+}
+
+impl Default for BufferRows {
+    fn default() -> Self {
+        Self {
+            show_line_numbers: true,
+            rows: vec![BufferRow {
+                line_number: 1,
+                code_action: false,
+                current: true,
+                line: None,
+                cursors: None,
+                status: GitStatus::None,
+                show_line_number: true,
+            }],
+        }
+    }
+}
+
+impl BufferRow {
+    pub fn new(line_number: usize) -> Self {
+        Self {
+            line_number,
+            code_action: false,
+            current: false,
+            line: None,
+            cursors: None,
+            status: GitStatus::None,
+            show_line_number: true,
+        }
+    }
+
+    pub fn set_line(mut self, line: Option<HighlightedLine>) -> Self {
+        self.line = line;
+        self
+    }
+
+    pub fn set_cursors(mut self, cursors: Option<Vec<PlayerCursor>>) -> Self {
+        self.cursors = cursors;
+        self
+    }
+
+    pub fn add_cursor(mut self, cursor: PlayerCursor) -> Self {
+        if let Some(cursors) = &mut self.cursors {
+            cursors.push(cursor);
+        } else {
+            self.cursors = Some(vec![cursor]);
+        }
+        self
+    }
+
+    pub fn set_status(mut self, status: GitStatus) -> Self {
+        self.status = status;
+        self
+    }
+
+    pub fn set_show_line_number(mut self, show_line_number: bool) -> Self {
+        self.show_line_number = show_line_number;
+        self
+    }
+
+    pub fn set_code_action(mut self, code_action: bool) -> Self {
+        self.code_action = code_action;
+        self
+    }
+
+    pub fn set_current(mut self, current: bool) -> Self {
+        self.current = current;
+        self
+    }
+}
+
+#[derive(Element, Clone)]
+pub struct Buffer<S: 'static + Send + Sync + Clone> {
+    state_type: PhantomData<S>,
+    scroll_state: ScrollState,
+    rows: Option<BufferRows>,
+    readonly: bool,
+    language: Option<String>,
+    title: Option<String>,
+    path: Option<String>,
+}
+
+impl<S: 'static + Send + Sync + Clone> Buffer<S> {
+    pub fn new() -> Self {
+        Self {
+            state_type: PhantomData,
+            scroll_state: ScrollState::default(),
+            rows: Some(BufferRows::default()),
+            readonly: false,
+            language: None,
+            title: Some("untitled".to_string()),
+            path: None,
+        }
+    }
+
+    pub fn bind_scroll_state(&mut self, scroll_state: ScrollState) {
+        self.scroll_state = scroll_state;
+    }
+
+    pub fn set_title<T: Into<Option<String>>>(mut self, title: T) -> Self {
+        self.title = title.into();
+        self
+    }
+
+    pub fn set_path<P: Into<Option<String>>>(mut self, path: P) -> Self {
+        self.path = path.into();
+        self
+    }
+
+    pub fn set_readonly(mut self, readonly: bool) -> Self {
+        self.readonly = readonly;
+        self
+    }
+
+    pub fn set_rows<R: Into<Option<BufferRows>>>(mut self, rows: R) -> Self {
+        self.rows = rows.into();
+        self
+    }
+
+    pub fn set_language<L: Into<Option<String>>>(mut self, language: L) -> Self {
+        self.language = language.into();
+        self
+    }
+
+    fn render_row(row: BufferRow, cx: &WindowContext) -> impl Element<State = S> {
+        let theme = theme(cx);
+        let system_color = SystemColor::new();
+
+        let line_background = if row.current {
+            theme.middle.base.default.background
+        } else {
+            system_color.transparent
+        };
+
+        let line_number_color = if row.current {
+            HighlightColor::Default.hsla(&theme)
+        } else {
+            HighlightColor::Comment.hsla(&theme)
+        };
+
+        h_stack()
+            .fill(line_background)
+            .w_full()
+            .gap_2()
+            .px_1()
+            .child(
+                h_stack()
+                    .w_4()
+                    .h_full()
+                    .px_0p5()
+                    .when(row.code_action, |c| {
+                        div().child(IconElement::new(Icon::Bolt))
+                    }),
+            )
+            .when(row.show_line_number, |this| {
+                this.child(
+                    h_stack().justify_end().px_0p5().w_3().child(
+                        div()
+                            .text_color(line_number_color)
+                            .child(row.line_number.to_string()),
+                    ),
+                )
+            })
+            .child(div().mx_0p5().w_1().h_full().fill(row.status.hsla(cx)))
+            .children(row.line.map(|line| {
+                div()
+                    .flex()
+                    .children(line.highlighted_texts.iter().map(|highlighted_text| {
+                        div()
+                            .text_color(highlighted_text.color)
+                            .child(highlighted_text.text.clone())
+                    }))
+            }))
+    }
+
+    fn render_rows(&self, cx: &WindowContext) -> Vec<impl Element<State = S>> {
+        match &self.rows {
+            Some(rows) => rows
+                .rows
+                .iter()
+                .map(|row| Self::render_row(row.clone(), cx))
+                .collect(),
+            None => vec![],
+        }
+    }
+
+    fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
+        let theme = theme(cx);
+        let rows = self.render_rows(cx);
+
+        v_stack()
+            .flex_1()
+            .w_full()
+            .h_full()
+            .fill(theme.highest.base.default.background)
+            .children(rows)
+    }
+}

crates/ui2/src/components/list.rs 🔗

@@ -2,8 +2,8 @@ use std::marker::PhantomData;
 
 use gpui3::{div, Div, Hsla, WindowContext};
 
-use crate::theme::theme;
 use crate::prelude::*;
+use crate::theme::theme;
 use crate::{
     h_stack, token, v_stack, Avatar, Icon, IconColor, IconElement, IconSize, Label, LabelColor,
     LabelSize,
@@ -424,7 +424,7 @@ impl<S: 'static + Send + Sync + Clone> ListEntry<S> {
                     // .ml(rems(0.75 * self.indent_level as f32))
                     .children((0..self.indent_level).map(|_| {
                         div()
-                            // .w(token.list_indent_depth)
+                            .w(token.list_indent_depth)
                             .h_full()
                             .flex()
                             .justify_center()

crates/ui2/src/components/panel.rs 🔗

@@ -112,7 +112,7 @@ impl<S: 'static + Send + Sync> Panel<S> {
                 panel_base = v_stack()
                     .flex_initial()
                     .h_full()
-                    // .w(current_width)
+                    .w(current_width)
                     .w_64()
                     .fill(theme.middle.base.default.background)
                     .border_r()
@@ -122,7 +122,7 @@ impl<S: 'static + Send + Sync> Panel<S> {
                 panel_base = v_stack()
                     .flex_initial()
                     .h_full()
-                    // .w(current_width)
+                    .w(current_width)
                     .w_64()
                     .fill(theme.middle.base.default.background)
                     .border_l()

crates/ui2/src/elements/avatar.rs 🔗

@@ -2,8 +2,8 @@ use std::marker::PhantomData;
 
 use gpui3::{img, ArcCow};
 
-use crate::theme::theme;
 use crate::prelude::*;
+use crate::theme::theme;
 
 #[derive(Element, Clone)]
 pub struct Avatar<S: 'static + Send + Sync> {

crates/ui2/src/elements/icon.rs 🔗

@@ -4,8 +4,8 @@ use std::sync::Arc;
 use gpui3::{svg, Hsla};
 use strum::EnumIter;
 
-use crate::theme::{theme, Theme};
 use crate::prelude::*;
+use crate::theme::{theme, Theme};
 
 #[derive(Default, PartialEq, Copy, Clone)]
 pub enum IconSize {

crates/ui2/src/elements/label.rs 🔗

@@ -3,8 +3,8 @@ use std::marker::PhantomData;
 use gpui3::{Hsla, WindowContext};
 use smallvec::SmallVec;
 
-use crate::theme::theme;
 use crate::prelude::*;
+use crate::theme::theme;
 
 #[derive(Default, PartialEq, Copy, Clone)]
 pub enum LabelColor {

crates/ui2/src/lib.rs 🔗

@@ -5,6 +5,7 @@ mod components;
 mod element_ext;
 mod elements;
 pub mod prelude;
+mod static_data;
 mod theme;
 mod tokens;
 
@@ -13,6 +14,7 @@ pub use components::*;
 pub use element_ext::*;
 pub use elements::*;
 pub use prelude::*;
+pub use static_data::*;
 pub use tokens::*;
 
 pub use crate::theme::*;

crates/ui2/src/prelude.rs 🔗

@@ -48,28 +48,28 @@ impl HighlightColor {
             Self::Default => theme
                 .syntax
                 .get("primary")
-                .expect("no theme.syntax.primary")
-                .clone(),
+                .cloned()
+                .unwrap_or_else(|| rgb::<Hsla>(0xff00ff)),
             Self::Comment => theme
                 .syntax
                 .get("comment")
-                .expect("no theme.syntax.comment")
-                .clone(),
+                .cloned()
+                .unwrap_or_else(|| rgb::<Hsla>(0xff00ff)),
             Self::String => theme
                 .syntax
                 .get("string")
-                .expect("no theme.syntax.string")
-                .clone(),
+                .cloned()
+                .unwrap_or_else(|| rgb::<Hsla>(0xff00ff)),
             Self::Function => theme
                 .syntax
                 .get("function")
-                .expect("no theme.syntax.function")
-                .clone(),
+                .cloned()
+                .unwrap_or_else(|| rgb::<Hsla>(0xff00ff)),
             Self::Keyword => theme
                 .syntax
                 .get("keyword")
-                .expect("no theme.syntax.keyword")
-                .clone(),
+                .cloned()
+                .unwrap_or_else(|| rgb::<Hsla>(0xff00ff)),
         }
     }
 }

crates/ui2/src/static_data.rs 🔗

@@ -0,0 +1,346 @@
+use crate::{
+    Buffer, BufferRow, BufferRows, GitStatus, HighlightColor, HighlightedLine, HighlightedText,
+    Theme,
+};
+
+pub fn empty_buffer_example<S: 'static + Send + Sync + Clone>() -> Buffer<S> {
+    Buffer::new().set_rows(Some(BufferRows::default()))
+}
+
+pub fn hello_world_rust_buffer_example<S: 'static + Send + Sync + Clone>(
+    theme: &Theme,
+) -> Buffer<S> {
+    Buffer::new()
+        .set_title("hello_world.rs".to_string())
+        .set_path("src/hello_world.rs".to_string())
+        .set_language("rust".to_string())
+        .set_rows(Some(BufferRows {
+            show_line_numbers: true,
+            rows: hello_world_rust_buffer_rows(theme),
+        }))
+}
+
+pub fn hello_world_rust_buffer_rows(theme: &Theme) -> Vec<BufferRow> {
+    let show_line_number = true;
+
+    vec![
+        BufferRow {
+            line_number: 1,
+            code_action: false,
+            current: true,
+            line: Some(HighlightedLine {
+                highlighted_texts: vec![
+                    HighlightedText {
+                        text: "fn ".to_string(),
+                        color: HighlightColor::Keyword.hsla(&theme),
+                    },
+                    HighlightedText {
+                        text: "main".to_string(),
+                        color: HighlightColor::Function.hsla(&theme),
+                    },
+                    HighlightedText {
+                        text: "() {".to_string(),
+                        color: HighlightColor::Default.hsla(&theme),
+                    },
+                ],
+            }),
+            cursors: None,
+            status: GitStatus::None,
+            show_line_number,
+        },
+        BufferRow {
+            line_number: 2,
+            code_action: false,
+            current: false,
+            line: Some(HighlightedLine {
+                highlighted_texts: vec![HighlightedText {
+                    text: "    // Statements here are executed when the compiled binary is called."
+                        .to_string(),
+                    color: HighlightColor::Comment.hsla(&theme),
+                }],
+            }),
+            cursors: None,
+            status: GitStatus::None,
+            show_line_number,
+        },
+        BufferRow {
+            line_number: 3,
+            code_action: false,
+            current: false,
+            line: None,
+            cursors: None,
+            status: GitStatus::None,
+            show_line_number,
+        },
+        BufferRow {
+            line_number: 4,
+            code_action: false,
+            current: false,
+            line: Some(HighlightedLine {
+                highlighted_texts: vec![HighlightedText {
+                    text: "    // Print text to the console.".to_string(),
+                    color: HighlightColor::Comment.hsla(&theme),
+                }],
+            }),
+            cursors: None,
+            status: GitStatus::None,
+            show_line_number,
+        },
+        BufferRow {
+            line_number: 5,
+            code_action: false,
+            current: false,
+            line: Some(HighlightedLine {
+                highlighted_texts: vec![
+                    HighlightedText {
+                        text: "    println!(".to_string(),
+                        color: HighlightColor::Default.hsla(&theme),
+                    },
+                    HighlightedText {
+                        text: "\"Hello, world!\"".to_string(),
+                        color: HighlightColor::String.hsla(&theme),
+                    },
+                    HighlightedText {
+                        text: ");".to_string(),
+                        color: HighlightColor::Default.hsla(&theme),
+                    },
+                ],
+            }),
+            cursors: None,
+            status: GitStatus::None,
+            show_line_number,
+        },
+        BufferRow {
+            line_number: 6,
+            code_action: false,
+            current: false,
+            line: Some(HighlightedLine {
+                highlighted_texts: vec![HighlightedText {
+                    text: "}".to_string(),
+                    color: HighlightColor::Default.hsla(&theme),
+                }],
+            }),
+            cursors: None,
+            status: GitStatus::None,
+            show_line_number,
+        },
+    ]
+}
+
+pub fn hello_world_rust_buffer_with_status_example<S: 'static + Send + Sync + Clone>(
+    theme: &Theme,
+) -> Buffer<S> {
+    Buffer::new()
+        .set_title("hello_world.rs".to_string())
+        .set_path("src/hello_world.rs".to_string())
+        .set_language("rust".to_string())
+        .set_rows(Some(BufferRows {
+            show_line_numbers: true,
+            rows: hello_world_rust_with_status_buffer_rows(theme),
+        }))
+}
+
+pub fn hello_world_rust_with_status_buffer_rows(theme: &Theme) -> Vec<BufferRow> {
+    let show_line_number = true;
+
+    vec![
+        BufferRow {
+            line_number: 1,
+            code_action: false,
+            current: true,
+            line: Some(HighlightedLine {
+                highlighted_texts: vec![
+                    HighlightedText {
+                        text: "fn ".to_string(),
+                        color: HighlightColor::Keyword.hsla(&theme),
+                    },
+                    HighlightedText {
+                        text: "main".to_string(),
+                        color: HighlightColor::Function.hsla(&theme),
+                    },
+                    HighlightedText {
+                        text: "() {".to_string(),
+                        color: HighlightColor::Default.hsla(&theme),
+                    },
+                ],
+            }),
+            cursors: None,
+            status: GitStatus::None,
+            show_line_number,
+        },
+        BufferRow {
+            line_number: 2,
+            code_action: false,
+            current: false,
+            line: Some(HighlightedLine {
+                highlighted_texts: vec![HighlightedText {
+                    text: "// Statements here are executed when the compiled binary is called."
+                        .to_string(),
+                    color: HighlightColor::Comment.hsla(&theme),
+                }],
+            }),
+            cursors: None,
+            status: GitStatus::Modified,
+            show_line_number,
+        },
+        BufferRow {
+            line_number: 3,
+            code_action: false,
+            current: false,
+            line: None,
+            cursors: None,
+            status: GitStatus::None,
+            show_line_number,
+        },
+        BufferRow {
+            line_number: 4,
+            code_action: false,
+            current: false,
+            line: Some(HighlightedLine {
+                highlighted_texts: vec![HighlightedText {
+                    text: "    // Print text to the console.".to_string(),
+                    color: HighlightColor::Comment.hsla(&theme),
+                }],
+            }),
+            cursors: None,
+            status: GitStatus::None,
+            show_line_number,
+        },
+        BufferRow {
+            line_number: 5,
+            code_action: false,
+            current: false,
+            line: Some(HighlightedLine {
+                highlighted_texts: vec![
+                    HighlightedText {
+                        text: "    println!(".to_string(),
+                        color: HighlightColor::Default.hsla(&theme),
+                    },
+                    HighlightedText {
+                        text: "\"Hello, world!\"".to_string(),
+                        color: HighlightColor::String.hsla(&theme),
+                    },
+                    HighlightedText {
+                        text: ");".to_string(),
+                        color: HighlightColor::Default.hsla(&theme),
+                    },
+                ],
+            }),
+            cursors: None,
+            status: GitStatus::None,
+            show_line_number,
+        },
+        BufferRow {
+            line_number: 6,
+            code_action: false,
+            current: false,
+            line: Some(HighlightedLine {
+                highlighted_texts: vec![HighlightedText {
+                    text: "}".to_string(),
+                    color: HighlightColor::Default.hsla(&theme),
+                }],
+            }),
+            cursors: None,
+            status: GitStatus::None,
+            show_line_number,
+        },
+        BufferRow {
+            line_number: 7,
+            code_action: false,
+            current: false,
+            line: Some(HighlightedLine {
+                highlighted_texts: vec![HighlightedText {
+                    text: "".to_string(),
+                    color: HighlightColor::Default.hsla(&theme),
+                }],
+            }),
+            cursors: None,
+            status: GitStatus::Created,
+            show_line_number,
+        },
+        BufferRow {
+            line_number: 8,
+            code_action: false,
+            current: false,
+            line: Some(HighlightedLine {
+                highlighted_texts: vec![HighlightedText {
+                    text: "// Marshall and Nate were here".to_string(),
+                    color: HighlightColor::Comment.hsla(&theme),
+                }],
+            }),
+            cursors: None,
+            status: GitStatus::Created,
+            show_line_number,
+        },
+    ]
+}
+
+pub fn terminal_buffer<S: 'static + Send + Sync + Clone>(theme: &Theme) -> Buffer<S> {
+    Buffer::new()
+        .set_title("zed — fish".to_string())
+        .set_rows(Some(BufferRows {
+            show_line_numbers: false,
+            rows: terminal_buffer_rows(theme),
+        }))
+}
+
+pub fn terminal_buffer_rows(theme: &Theme) -> Vec<BufferRow> {
+    let show_line_number = false;
+
+    vec![
+        BufferRow {
+            line_number: 1,
+            code_action: false,
+            current: false,
+            line: Some(HighlightedLine {
+                highlighted_texts: vec![
+                    HighlightedText {
+                        text: "maxdeviant ".to_string(),
+                        color: HighlightColor::Keyword.hsla(&theme),
+                    },
+                    HighlightedText {
+                        text: "in ".to_string(),
+                        color: HighlightColor::Default.hsla(&theme),
+                    },
+                    HighlightedText {
+                        text: "profaned-capital ".to_string(),
+                        color: HighlightColor::Function.hsla(&theme),
+                    },
+                    HighlightedText {
+                        text: "in ".to_string(),
+                        color: HighlightColor::Default.hsla(&theme),
+                    },
+                    HighlightedText {
+                        text: "~/p/zed ".to_string(),
+                        color: HighlightColor::Function.hsla(&theme),
+                    },
+                    HighlightedText {
+                        text: "on ".to_string(),
+                        color: HighlightColor::Default.hsla(&theme),
+                    },
+                    HighlightedText {
+                        text: " gpui2-ui ".to_string(),
+                        color: HighlightColor::Keyword.hsla(&theme),
+                    },
+                ],
+            }),
+            cursors: None,
+            status: GitStatus::None,
+            show_line_number,
+        },
+        BufferRow {
+            line_number: 2,
+            code_action: false,
+            current: false,
+            line: Some(HighlightedLine {
+                highlighted_texts: vec![HighlightedText {
+                    text: "λ ".to_string(),
+                    color: HighlightColor::String.hsla(&theme),
+                }],
+            }),
+            cursors: None,
+            status: GitStatus::None,
+            show_line_number,
+        },
+    ]
+}