159 lines
4.7 KiB
Rust
159 lines
4.7 KiB
Rust
use std::{num::NonZeroUsize, rc::Rc, sync::Arc};
|
|
|
|
use gpui::{
|
|
IntoElement, ParentElement, Refineable, Styled, div, list, prelude::FluentBuilder, px, rems,
|
|
};
|
|
|
|
use crate::app;
|
|
|
|
#[derive(gpui::IntoElement, Clone)]
|
|
pub(crate) struct CodeLine {
|
|
line_number: Option<NonZeroUsize>,
|
|
content: Option<gpui::SharedString>,
|
|
diff_marker: CodeLineMarker,
|
|
gutter_width: gpui::Pixels,
|
|
style: gpui::StyleRefinement,
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub(crate) enum CodeLineMarker {
|
|
Added,
|
|
Deleted,
|
|
Unchanged,
|
|
Placeholder,
|
|
}
|
|
#[derive(Clone)]
|
|
pub(crate) struct CodeViewState(gpui::ListState);
|
|
|
|
pub(crate) struct CodeView {
|
|
state: CodeViewState,
|
|
content: CodeViewContent,
|
|
}
|
|
|
|
pub(crate) struct CodeViewContent {
|
|
lines: Rc<[CodeLine]>,
|
|
}
|
|
|
|
pub(crate) fn code_view(state: CodeViewState, content: CodeViewContent) -> CodeView {
|
|
CodeView { state, content }
|
|
}
|
|
|
|
pub(crate) fn code_line(
|
|
line_index: Option<usize>,
|
|
content: Option<gpui::SharedString>,
|
|
marker: CodeLineMarker,
|
|
) -> CodeLine {
|
|
CodeLine {
|
|
line_number: line_index.map(|i| unsafe { NonZeroUsize::new_unchecked(i + 1) }),
|
|
content,
|
|
diff_marker: marker,
|
|
gutter_width: px(0.),
|
|
style: gpui::StyleRefinement::default(),
|
|
}
|
|
}
|
|
|
|
impl CodeViewContent {
|
|
pub(crate) fn new(lines: Vec<CodeLine>) -> Self {
|
|
Self {
|
|
lines: lines.into(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl CodeLine {
|
|
pub(crate) fn gutter_width(mut self, width: gpui::Pixels) -> Self {
|
|
self.gutter_width = width;
|
|
self
|
|
}
|
|
}
|
|
|
|
impl gpui::RenderOnce for CodeView {
|
|
fn render(self, window: &mut gpui::Window, cx: &mut gpui::App) -> impl gpui::IntoElement {
|
|
let digits = self
|
|
.content
|
|
.lines
|
|
.iter()
|
|
.rfind(|l| l.line_number.is_some())
|
|
.map(|l| l.line_number.unwrap().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 gutter_width = window
|
|
.text_system()
|
|
.ch_advance(font_id, font_size)
|
|
.unwrap_or(px(7.2))
|
|
* digits;
|
|
|
|
println!("gutter width {}", gutter_width);
|
|
|
|
list(self.state.0, move |i, _window, _app| {
|
|
let line = self.content.lines[i].clone();
|
|
div()
|
|
.flex()
|
|
.flex_row()
|
|
.items_start()
|
|
.w_full()
|
|
.child(line.gutter_width(gutter_width))
|
|
.into_any_element()
|
|
})
|
|
}
|
|
}
|
|
|
|
impl gpui::Styled for CodeLine {
|
|
#[doc = " Returns a reference to the style memory of this element."]
|
|
fn style(&mut self) -> &mut gpui::StyleRefinement {
|
|
&mut self.style
|
|
}
|
|
}
|
|
|
|
impl gpui::RenderOnce for CodeLine {
|
|
fn render(self, _window: &mut gpui::Window, cx: &mut gpui::App) -> impl IntoElement {
|
|
let theme = app::current_theme(cx);
|
|
|
|
let mut div = div()
|
|
.flex()
|
|
.flex_row()
|
|
.font_family("Menlo")
|
|
.text_color(theme.colors.text)
|
|
.text_xs()
|
|
.child(
|
|
div()
|
|
.bg(theme.colors.surface)
|
|
.w(self.gutter_width + px(16.))
|
|
.text_align(gpui::TextAlign::Right)
|
|
.px_2()
|
|
.when_some(self.line_number, |it, line_number| {
|
|
it.child(line_number.to_string())
|
|
})
|
|
.when(matches!(self.diff_marker, CodeLineMarker::Added), |it| {
|
|
it.bg(theme.colors.success_muted)
|
|
.text_color(theme.colors.success_fg)
|
|
.border_l_2()
|
|
.border_color(theme.colors.success_border)
|
|
})
|
|
.when(matches!(self.diff_marker, CodeLineMarker::Deleted), |it| {
|
|
it.bg(theme.colors.danger_muted)
|
|
.text_color(theme.colors.danger_fg)
|
|
.border_l_2()
|
|
.border_color(theme.colors.danger_border)
|
|
}),
|
|
)
|
|
.when_some(self.content, |it, content| {
|
|
it.child(div().px_2().w_full().min_w_0().child(content))
|
|
})
|
|
.when(matches!(self.diff_marker, CodeLineMarker::Added), |it| {
|
|
it.bg(theme.colors.success_muted)
|
|
})
|
|
.when(matches!(self.diff_marker, CodeLineMarker::Deleted), |it| {
|
|
it.bg(theme.colors.danger_muted)
|
|
});
|
|
|
|
div.style().refine(&self.style);
|
|
|
|
div
|
|
}
|
|
}
|