feat: add diff view component

This commit is contained in:
2026-11-06 08:01:23 +07:00
parent f272f80d09
commit 7214c70ea7
11 changed files with 1067 additions and 35 deletions
+20 -6
View File
@@ -1,3 +1,4 @@
use std::sync::Arc;
use std::time::Duration;
use std::time::Instant;
@@ -54,9 +55,9 @@ struct AutohideState {
}
impl Autohide {
pub(crate) fn new(window: &mut Window, cx: &mut App) -> Self {
pub(crate) fn new(key: ElementId, window: &mut Window, cx: &mut App) -> Self {
let view = window.current_view();
let state = window.use_keyed_state("scrollbar-autohide", cx, |_, _| AutohideState {
let state = window.use_keyed_state(key, cx, |_, _| AutohideState {
last_activity: None,
hide_task: None,
});
@@ -195,6 +196,11 @@ impl ScrollArea {
}
}
/// Names keyed state under the scrollbar's own id.
pub fn scrollbar_state_key(name: &'static str, id: &ElementId) -> ElementId {
ElementId::NamedChild(Arc::new(id.clone()), SharedString::from(name))
}
/// Pure thumb geometry for an overlay scrollbar.
pub(crate) fn thumb_geometry(
viewport: Pixels,
@@ -247,11 +253,12 @@ impl RenderOnce for ScrollArea {
ScrollbarVisibility::Always => false,
ScrollbarVisibility::Autohide => true,
};
let id = self.id.clone();
wrapper.extend(std::iter::once(
canvas(|_, _, _| {}, {
let handle = handle.clone();
move |_, _, window, cx| {
paint_scrollbar(&handle, autohide, window, cx);
paint_scrollbar(&handle, &id, autohide, window, cx);
}
})
.absolute()
@@ -265,7 +272,13 @@ impl RenderOnce for ScrollArea {
}
/// Paints the overlay scrollbar thumb.
fn paint_scrollbar(handle: &ScrollHandle, autohide: bool, window: &mut Window, cx: &mut App) {
fn paint_scrollbar(
handle: &ScrollHandle,
key: &ElementId,
autohide: bool,
window: &mut Window,
cx: &mut App,
) {
let theme = cx.theme();
let view = window.current_view();
@@ -281,8 +294,9 @@ fn paint_scrollbar(handle: &ScrollHandle, autohide: bool, window: &mut Window, c
return;
}
let autohide_state = autohide.then(|| Autohide::new(window, cx));
let drag = window.use_keyed_state("scrollbar-thumb-drag", cx, |_, _| {
let autohide_state =
autohide.then(|| Autohide::new(scrollbar_state_key("autohide", key), window, cx));
let drag = window.use_keyed_state(scrollbar_state_key("thumb-drag", key), cx, |_, _| {
Option::<(Pixels, Pixels)>::None
});
let dragging = drag.read(cx).is_some();
+22 -15
View File
@@ -1,23 +1,15 @@
//! Overlay scrollbars for scroll surfaces, including gpui's virtualized
//! `uniform_list` and `list`. Render the scrollbar as a later child of a
//! `.relative()` container around the scrolled surface:
//!
//! ```
//! div().relative()
//! .child(uniform_list(...).track_scroll(&handle))
//! .child(Scrollbar::vertical(handle))
//! ```
//! Overlay scrollbars for scroll surfaces.
use std::rc::Rc;
use gpui::{
App, Bounds, DispatchPhase, IntoElement, ListState, MouseButton, MouseDownEvent,
App, Bounds, DispatchPhase, ElementId, IntoElement, ListState, MouseButton, MouseDownEvent,
MouseMoveEvent, MouseUpEvent, Pixels, Point, RenderOnce, ScrollEvent, ScrollHandle,
Styled as _, UniformListScrollHandle, Window, canvas, fill, point,
};
use gpui_native_theme::ActiveTheme as _;
use crate::scroll_area::{Autohide, thumb_geometry, thumb_style};
use crate::scroll_area::{Autohide, scrollbar_state_key, thumb_geometry, thumb_style};
/// Re-exported so callers only need the scrollbar module.
pub use crate::scroll_area::ScrollbarVisibility;
@@ -130,12 +122,13 @@ impl Axis {
}
}
/// An overlay scrollbar; the caller renders it over the scrolled surface.
/// An overlay scrollbar, the caller renders it over the scrolled surface.
#[derive(IntoElement)]
pub struct Scrollbar {
axis: Axis,
handle: Rc<dyn ScrollbarHandle>,
visibility: ScrollbarVisibility,
key: ElementId,
}
impl Scrollbar {
@@ -148,6 +141,7 @@ impl Scrollbar {
axis: Axis::Vertical,
handle: Rc::new(handle),
visibility: ScrollbarVisibility::default(),
key: ElementId::Name("scrollbar".into()),
}
}
@@ -160,6 +154,7 @@ impl Scrollbar {
axis: Axis::Horizontal,
handle: Rc::new(handle),
visibility: ScrollbarVisibility::default(),
key: ElementId::Name("scrollbar".into()),
}
}
@@ -168,6 +163,12 @@ impl Scrollbar {
self.visibility = visibility;
self
}
/// Names this scrollbar's state.
pub fn key(mut self, key: impl Into<ElementId>) -> Self {
self.key = key.into();
self
}
}
impl RenderOnce for Scrollbar {
@@ -176,7 +177,8 @@ impl RenderOnce for Scrollbar {
let handle = self.handle;
let axis = self.axis;
let visibility = self.visibility;
move |_, _, window, cx| paint_scrollbar(&handle, axis, visibility, window, cx)
let key = self.key;
move |_, _, window, cx| paint_scrollbar(&handle, axis, visibility, &key, window, cx)
})
.absolute()
.inset_0()
@@ -190,6 +192,7 @@ fn paint_scrollbar(
handle: &Rc<dyn ScrollbarHandle>,
axis: Axis,
visibility: ScrollbarVisibility,
key: &ElementId,
window: &mut Window,
cx: &mut App,
) {
@@ -214,7 +217,9 @@ fn paint_scrollbar(
ScrollbarVisibility::Always => false,
ScrollbarVisibility::Autohide => true,
};
let autohide_state = autohide.then(|| Autohide::new(window, cx));
let autohide_state =
autohide.then(|| Autohide::new(scrollbar_state_key("autohide", key), window, cx));
let track_length = viewport_along - inset * 2.0;
@@ -262,7 +267,9 @@ fn paint_scrollbar(
}
};
let drag = window.use_keyed_state("scrollbar-thumb-drag", cx, |_, _| Drag::None);
let drag = window.use_keyed_state(scrollbar_state_key("thumb-drag", key), cx, |_, _| {
Drag::None
});
let dragging = drag.read(cx).is_some();
let alpha = match &autohide_state {