feat: basic pr diff rendering
This commit is contained in:
@@ -1,108 +1,158 @@
|
||||
use std::{rc::Rc, sync::Arc};
|
||||
use std::{num::NonZeroUsize, rc::Rc, sync::Arc};
|
||||
|
||||
use gpui::{IntoElement, ParentElement, Styled, div, list, px, rems};
|
||||
use gpui::{
|
||||
IntoElement, ParentElement, Refineable, Styled, div, list, prelude::FluentBuilder, 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,
|
||||
pub(crate) struct CodeLine {
|
||||
line_number: Option<NonZeroUsize>,
|
||||
content: Option<gpui::SharedString>,
|
||||
diff_marker: CodeLineMarker,
|
||||
gutter_width: gpui::Pixels,
|
||||
style: gpui::StyleRefinement,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
enum DiffMarker {
|
||||
pub(crate) enum CodeLineMarker {
|
||||
Added,
|
||||
Deleted,
|
||||
Unchanged,
|
||||
Placeholder,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct CodeViewState(gpui::ListState);
|
||||
pub(crate) struct CodeViewState(gpui::ListState);
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Lines(Rc<Vec<Line>>);
|
||||
|
||||
struct CodeView {
|
||||
pub(crate) struct CodeView {
|
||||
state: CodeViewState,
|
||||
lines: Lines,
|
||||
content: CodeViewContent,
|
||||
}
|
||||
|
||||
pub(crate) fn line(
|
||||
line_number: usize,
|
||||
content: impl Into<Arc<str>>,
|
||||
diff_marker: DiffMarker,
|
||||
) -> Line {
|
||||
Line {
|
||||
line_number,
|
||||
diff_marker,
|
||||
content: gpui::SharedString::new(content),
|
||||
line_number_col_width: px(0.),
|
||||
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(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn code_view(state: CodeViewState, lines: Lines) -> CodeView {
|
||||
CodeView { state, lines }
|
||||
impl CodeViewContent {
|
||||
pub(crate) fn new(lines: Vec<CodeLine>) -> Self {
|
||||
Self {
|
||||
lines: lines.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromIterator<Line> for Lines {
|
||||
fn from_iter<T: IntoIterator<Item = Line>>(iter: T) -> Self {
|
||||
Lines(Rc::new(iter.into_iter().collect()))
|
||||
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
|
||||
.0
|
||||
.last()
|
||||
.map(|l| l.line_number.to_string().len())
|
||||
.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 line_number_col_width = window
|
||||
let gutter_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;
|
||||
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)
|
||||
.child(line.gutter_width(gutter_width))
|
||||
.into_any_element()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl gpui::RenderOnce for Line {
|
||||
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);
|
||||
|
||||
div()
|
||||
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.line_number_col_width)
|
||||
.w(self.gutter_width + px(16.))
|
||||
.text_align(gpui::TextAlign::Right)
|
||||
.child(self.line_number.to_string()),
|
||||
.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)
|
||||
}),
|
||||
)
|
||||
.child(self.content)
|
||||
.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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user