use std::{rc::Rc, sync::Arc}; use gpui::{IntoElement, ParentElement, Styled, div, list, px, rems}; use crate::app; #[derive(gpui::IntoElement, Clone)] pub(crate) struct Line { line_number_col_width: gpui::Pixels, line_number: usize, content: gpui::SharedString, diff_marker: DiffMarker, } #[derive(Clone)] enum DiffMarker { Added, Deleted, Unchanged, } #[derive(Clone)] struct CodeViewState(gpui::ListState); #[derive(Clone)] struct Lines(Rc>); struct CodeView { state: CodeViewState, lines: Lines, } pub(crate) fn line( line_number: usize, content: impl Into>, diff_marker: DiffMarker, ) -> Line { Line { line_number, diff_marker, content: gpui::SharedString::new(content), line_number_col_width: px(0.), } } pub(crate) fn code_view(state: CodeViewState, lines: Lines) -> CodeView { CodeView { state, lines } } impl FromIterator for Lines { fn from_iter>(iter: T) -> Self { Lines(Rc::new(iter.into_iter().collect())) } } impl gpui::RenderOnce for CodeView { fn render(self, window: &mut gpui::Window, cx: &mut gpui::App) -> impl gpui::IntoElement { let digits = self .lines .0 .last() .map(|l| l.line_number.to_string().len()) .unwrap_or(0); let text_style = window.text_style(); let font_size = text_style.font_size.to_pixels(window.rem_size()); let font_id = window.text_system().resolve_font(&gpui::font("Menlo")); let line_number_col_width = window .text_system() .ch_advance(font_id, font_size) .unwrap_or(px(7.2)) * digits; list(self.state.0, move |i, _window, _app| { let mut line = self.lines.0[i].clone(); line.line_number_col_width = line_number_col_width; div() .flex() .flex_row() .items_start() .w_full() .child(line) .into_any_element() }) } } impl gpui::RenderOnce for Line { fn render(self, _window: &mut gpui::Window, cx: &mut gpui::App) -> impl IntoElement { let theme = app::current_theme(cx); div() .flex() .flex_row() .font_family("Menlo") .text_color(theme.colors.text) .child( div() .bg(theme.colors.surface) .w(self.line_number_col_width) .text_align(gpui::TextAlign::Right) .child(self.line_number.to_string()), ) .child(self.content) } }