WIP
This commit is contained in:
parent
d705585a2e
commit
c28d873a2f
34 changed files with 1295 additions and 2348 deletions
|
@ -13,10 +13,7 @@ use agent_settings::AgentSettings;
|
|||
use anyhow::Context as _;
|
||||
use askpass::AskPassDelegate;
|
||||
use db::kvp::KEY_VALUE_STORE;
|
||||
use editor::{
|
||||
Editor, EditorElement, EditorMode, EditorSettings, MultiBuffer, ShowScrollbar,
|
||||
scroll::ScrollbarAutoHide,
|
||||
};
|
||||
use editor::{Editor, EditorElement, EditorMode, MultiBuffer};
|
||||
use futures::StreamExt as _;
|
||||
use git::blame::ParsedCommitMessage;
|
||||
use git::repository::{
|
||||
|
@ -31,7 +28,7 @@ use git::{
|
|||
UnstageAll,
|
||||
};
|
||||
use gpui::{
|
||||
Action, Animation, AnimationExt as _, AsyncApp, AsyncWindowContext, Axis, ClickEvent, Corner,
|
||||
Action, Animation, AnimationExt as _, AsyncApp, AsyncWindowContext, ClickEvent, Corner,
|
||||
DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, KeyContext,
|
||||
ListHorizontalSizingBehavior, ListSizingBehavior, MouseButton, MouseDownEvent, Point,
|
||||
PromptLevel, ScrollStrategy, Subscription, Task, Transformation, UniformListScrollHandle,
|
||||
|
@ -63,9 +60,10 @@ use std::{collections::HashSet, sync::Arc, time::Duration, usize};
|
|||
use strum::{IntoEnumIterator, VariantNames};
|
||||
use time::OffsetDateTime;
|
||||
use ui::{
|
||||
Checkbox, ContextMenu, ElevationIndex, IconPosition, Label, LabelSize, PopoverMenu, Scrollbar,
|
||||
ScrollbarState, SplitButton, Tooltip, prelude::*,
|
||||
Checkbox, ContextMenu, ElevationIndex, IconPosition, Label, LabelSize, PopoverMenu,
|
||||
SplitButton, Tooltip, prelude::*,
|
||||
};
|
||||
use ui::{ScrollAxes, Scrollbars, WithScrollbar};
|
||||
use util::{ResultExt, TryFutureExt, maybe};
|
||||
use workspace::SERIALIZATION_THROTTLE_TIME;
|
||||
|
||||
|
@ -276,61 +274,6 @@ struct PendingOperation {
|
|||
op_id: usize,
|
||||
}
|
||||
|
||||
// computed state related to how to render scrollbars
|
||||
// one per axis
|
||||
// on render we just read this off the panel
|
||||
// we update it when
|
||||
// - settings change
|
||||
// - on focus in, on focus out, on hover, etc.
|
||||
#[derive(Debug)]
|
||||
struct ScrollbarProperties {
|
||||
axis: Axis,
|
||||
show_scrollbar: bool,
|
||||
show_track: bool,
|
||||
auto_hide: bool,
|
||||
hide_task: Option<Task<()>>,
|
||||
state: ScrollbarState,
|
||||
}
|
||||
|
||||
impl ScrollbarProperties {
|
||||
// Shows the scrollbar and cancels any pending hide task
|
||||
fn show(&mut self, cx: &mut Context<GitPanel>) {
|
||||
if !self.auto_hide {
|
||||
return;
|
||||
}
|
||||
self.show_scrollbar = true;
|
||||
self.hide_task.take();
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn hide(&mut self, window: &mut Window, cx: &mut Context<GitPanel>) {
|
||||
const SCROLLBAR_SHOW_INTERVAL: Duration = Duration::from_secs(1);
|
||||
|
||||
if !self.auto_hide {
|
||||
return;
|
||||
}
|
||||
|
||||
let axis = self.axis;
|
||||
self.hide_task = Some(cx.spawn_in(window, async move |panel, cx| {
|
||||
cx.background_executor()
|
||||
.timer(SCROLLBAR_SHOW_INTERVAL)
|
||||
.await;
|
||||
|
||||
if let Some(panel) = panel.upgrade() {
|
||||
panel
|
||||
.update(cx, |panel, cx| {
|
||||
match axis {
|
||||
Axis::Vertical => panel.vertical_scrollbar.show_scrollbar = false,
|
||||
Axis::Horizontal => panel.horizontal_scrollbar.show_scrollbar = false,
|
||||
}
|
||||
cx.notify();
|
||||
})
|
||||
.log_err();
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GitPanel {
|
||||
pub(crate) active_repository: Option<Entity<Repository>>,
|
||||
pub(crate) commit_editor: Entity<Editor>,
|
||||
|
@ -343,8 +286,6 @@ pub struct GitPanel {
|
|||
single_tracked_entry: Option<GitStatusEntry>,
|
||||
focus_handle: FocusHandle,
|
||||
fs: Arc<dyn Fs>,
|
||||
horizontal_scrollbar: ScrollbarProperties,
|
||||
vertical_scrollbar: ScrollbarProperties,
|
||||
new_count: usize,
|
||||
entry_count: usize,
|
||||
new_staged_count: usize,
|
||||
|
@ -429,10 +370,6 @@ impl GitPanel {
|
|||
let git_panel = cx.new(|cx| {
|
||||
let focus_handle = cx.focus_handle();
|
||||
cx.on_focus(&focus_handle, window, Self::focus_in).detach();
|
||||
cx.on_focus_out(&focus_handle, window, |this, _, window, cx| {
|
||||
this.hide_scrollbars(window, cx);
|
||||
})
|
||||
.detach();
|
||||
|
||||
let mut was_sort_by_path = GitPanelSettings::get_global(cx).sort_by_path;
|
||||
cx.observe_global::<SettingsStore>(move |this, cx| {
|
||||
|
@ -457,24 +394,6 @@ impl GitPanel {
|
|||
|
||||
let scroll_handle = UniformListScrollHandle::new();
|
||||
|
||||
let vertical_scrollbar = ScrollbarProperties {
|
||||
axis: Axis::Vertical,
|
||||
state: ScrollbarState::new(scroll_handle.clone()).parent_entity(&cx.entity()),
|
||||
show_scrollbar: false,
|
||||
show_track: false,
|
||||
auto_hide: false,
|
||||
hide_task: None,
|
||||
};
|
||||
|
||||
let horizontal_scrollbar = ScrollbarProperties {
|
||||
axis: Axis::Horizontal,
|
||||
state: ScrollbarState::new(scroll_handle.clone()).parent_entity(&cx.entity()),
|
||||
show_scrollbar: false,
|
||||
show_track: false,
|
||||
auto_hide: false,
|
||||
hide_task: None,
|
||||
};
|
||||
|
||||
let mut assistant_enabled = AgentSettings::get_global(cx).enabled;
|
||||
let mut was_ai_disabled = DisableAiSettings::get_global(cx).disable_ai;
|
||||
let _settings_subscription = cx.observe_global::<SettingsStore>(move |_, cx| {
|
||||
|
@ -555,8 +474,6 @@ impl GitPanel {
|
|||
workspace: workspace.weak_handle(),
|
||||
modal_open: false,
|
||||
entry_count: 0,
|
||||
horizontal_scrollbar,
|
||||
vertical_scrollbar,
|
||||
bulk_staging: None,
|
||||
_settings_subscription,
|
||||
};
|
||||
|
@ -568,86 +485,6 @@ impl GitPanel {
|
|||
git_panel
|
||||
}
|
||||
|
||||
fn hide_scrollbars(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||
self.horizontal_scrollbar.hide(window, cx);
|
||||
self.vertical_scrollbar.hide(window, cx);
|
||||
}
|
||||
|
||||
fn update_scrollbar_properties(&mut self, _window: &mut Window, cx: &mut Context<Self>) {
|
||||
// TODO: This PR should have defined Editor's `scrollbar.axis`
|
||||
// as an Option<ScrollbarAxis>, not a ScrollbarAxes as it would allow you to
|
||||
// `.unwrap_or(EditorSettings::get_global(cx).scrollbar.show)`.
|
||||
//
|
||||
// Once this is fixed we can extend the GitPanelSettings with a `scrollbar.axis`
|
||||
// so we can show each axis based on the settings.
|
||||
//
|
||||
// We should fix this. PR: https://github.com/zed-industries/zed/pull/19495
|
||||
|
||||
let show_setting = GitPanelSettings::get_global(cx)
|
||||
.scrollbar
|
||||
.show
|
||||
.unwrap_or(EditorSettings::get_global(cx).scrollbar.show);
|
||||
|
||||
let scroll_handle = self.scroll_handle.0.borrow();
|
||||
|
||||
let autohide = |show: ShowScrollbar, cx: &mut Context<Self>| match show {
|
||||
ShowScrollbar::Auto => true,
|
||||
ShowScrollbar::System => cx
|
||||
.try_global::<ScrollbarAutoHide>()
|
||||
.map_or_else(|| cx.should_auto_hide_scrollbars(), |autohide| autohide.0),
|
||||
ShowScrollbar::Always => false,
|
||||
ShowScrollbar::Never => false,
|
||||
};
|
||||
|
||||
let longest_item_width = scroll_handle.last_item_size.and_then(|size| {
|
||||
(size.contents.width > size.item.width).then_some(size.contents.width)
|
||||
});
|
||||
|
||||
// is there an item long enough that we should show a horizontal scrollbar?
|
||||
let item_wider_than_container = if let Some(longest_item_width) = longest_item_width {
|
||||
longest_item_width > px(scroll_handle.base_handle.bounds().size.width.0)
|
||||
} else {
|
||||
true
|
||||
};
|
||||
|
||||
let show_horizontal = match (show_setting, item_wider_than_container) {
|
||||
(_, false) => false,
|
||||
(ShowScrollbar::Auto | ShowScrollbar::System | ShowScrollbar::Always, true) => true,
|
||||
(ShowScrollbar::Never, true) => false,
|
||||
};
|
||||
|
||||
let show_vertical = match show_setting {
|
||||
ShowScrollbar::Auto | ShowScrollbar::System | ShowScrollbar::Always => true,
|
||||
ShowScrollbar::Never => false,
|
||||
};
|
||||
|
||||
let show_horizontal_track =
|
||||
show_horizontal && matches!(show_setting, ShowScrollbar::Always);
|
||||
|
||||
// TODO: we probably should hide the scroll track when the list doesn't need to scroll
|
||||
let show_vertical_track = show_vertical && matches!(show_setting, ShowScrollbar::Always);
|
||||
|
||||
self.vertical_scrollbar = ScrollbarProperties {
|
||||
axis: self.vertical_scrollbar.axis,
|
||||
state: self.vertical_scrollbar.state.clone(),
|
||||
show_scrollbar: show_vertical,
|
||||
show_track: show_vertical_track,
|
||||
auto_hide: autohide(show_setting, cx),
|
||||
hide_task: None,
|
||||
};
|
||||
|
||||
self.horizontal_scrollbar = ScrollbarProperties {
|
||||
axis: self.horizontal_scrollbar.axis,
|
||||
state: self.horizontal_scrollbar.state.clone(),
|
||||
show_scrollbar: show_horizontal,
|
||||
show_track: show_horizontal_track,
|
||||
auto_hide: autohide(show_setting, cx),
|
||||
hide_task: None,
|
||||
};
|
||||
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
pub fn entry_by_path(&self, path: &RepoPath, cx: &App) -> Option<usize> {
|
||||
if GitPanelSettings::get_global(cx).sort_by_path {
|
||||
return self
|
||||
|
@ -2508,12 +2345,11 @@ impl GitPanel {
|
|||
cx.background_executor().timer(UPDATE_DEBOUNCE).await;
|
||||
if let Some(git_panel) = handle.upgrade() {
|
||||
git_panel
|
||||
.update_in(cx, |git_panel, window, cx| {
|
||||
.update(cx, |git_panel, cx| {
|
||||
if clear_pending {
|
||||
git_panel.clear_pending();
|
||||
}
|
||||
git_panel.update_visible_entries(cx);
|
||||
git_panel.update_scrollbar_properties(window, cx);
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
|
@ -3630,110 +3466,6 @@ impl GitPanel {
|
|||
)
|
||||
}
|
||||
|
||||
fn render_vertical_scrollbar(
|
||||
&self,
|
||||
show_horizontal_scrollbar_container: bool,
|
||||
cx: &mut Context<Self>,
|
||||
) -> impl IntoElement {
|
||||
div()
|
||||
.id("git-panel-vertical-scroll")
|
||||
.occlude()
|
||||
.flex_none()
|
||||
.h_full()
|
||||
.cursor_default()
|
||||
.absolute()
|
||||
.right_0()
|
||||
.top_0()
|
||||
.bottom_0()
|
||||
.w(px(12.))
|
||||
.when(show_horizontal_scrollbar_container, |this| {
|
||||
this.pb_neg_3p5()
|
||||
})
|
||||
.on_mouse_move(cx.listener(|_, _, _, cx| {
|
||||
cx.notify();
|
||||
cx.stop_propagation()
|
||||
}))
|
||||
.on_hover(|_, _, cx| {
|
||||
cx.stop_propagation();
|
||||
})
|
||||
.on_any_mouse_down(|_, _, cx| {
|
||||
cx.stop_propagation();
|
||||
})
|
||||
.on_mouse_up(
|
||||
MouseButton::Left,
|
||||
cx.listener(|this, _, window, cx| {
|
||||
if !this.vertical_scrollbar.state.is_dragging()
|
||||
&& !this.focus_handle.contains_focused(window, cx)
|
||||
{
|
||||
this.vertical_scrollbar.hide(window, cx);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
cx.stop_propagation();
|
||||
}),
|
||||
)
|
||||
.on_scroll_wheel(cx.listener(|_, _, _, cx| {
|
||||
cx.notify();
|
||||
}))
|
||||
.children(Scrollbar::vertical(
|
||||
// percentage as f32..end_offset as f32,
|
||||
self.vertical_scrollbar.state.clone(),
|
||||
))
|
||||
}
|
||||
|
||||
/// Renders the horizontal scrollbar.
|
||||
///
|
||||
/// The right offset is used to determine how far to the right the
|
||||
/// scrollbar should extend to, useful for ensuring it doesn't collide
|
||||
/// with the vertical scrollbar when visible.
|
||||
fn render_horizontal_scrollbar(
|
||||
&self,
|
||||
right_offset: Pixels,
|
||||
cx: &mut Context<Self>,
|
||||
) -> impl IntoElement {
|
||||
div()
|
||||
.id("git-panel-horizontal-scroll")
|
||||
.occlude()
|
||||
.flex_none()
|
||||
.w_full()
|
||||
.cursor_default()
|
||||
.absolute()
|
||||
.bottom_neg_px()
|
||||
.left_0()
|
||||
.right_0()
|
||||
.pr(right_offset)
|
||||
.on_mouse_move(cx.listener(|_, _, _, cx| {
|
||||
cx.notify();
|
||||
cx.stop_propagation()
|
||||
}))
|
||||
.on_hover(|_, _, cx| {
|
||||
cx.stop_propagation();
|
||||
})
|
||||
.on_any_mouse_down(|_, _, cx| {
|
||||
cx.stop_propagation();
|
||||
})
|
||||
.on_mouse_up(
|
||||
MouseButton::Left,
|
||||
cx.listener(|this, _, window, cx| {
|
||||
if !this.horizontal_scrollbar.state.is_dragging()
|
||||
&& !this.focus_handle.contains_focused(window, cx)
|
||||
{
|
||||
this.horizontal_scrollbar.hide(window, cx);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
cx.stop_propagation();
|
||||
}),
|
||||
)
|
||||
.on_scroll_wheel(cx.listener(|_, _, _, cx| {
|
||||
cx.notify();
|
||||
}))
|
||||
.children(Scrollbar::horizontal(
|
||||
// percentage as f32..end_offset as f32,
|
||||
self.horizontal_scrollbar.state.clone(),
|
||||
))
|
||||
}
|
||||
|
||||
fn render_buffer_header_controls(
|
||||
&self,
|
||||
entity: &Entity<Self>,
|
||||
|
@ -3781,35 +3513,19 @@ impl GitPanel {
|
|||
fn render_entries(
|
||||
&self,
|
||||
has_write_access: bool,
|
||||
_: &Window,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> impl IntoElement {
|
||||
let entry_count = self.entries.len();
|
||||
|
||||
let scroll_track_size = px(16.);
|
||||
|
||||
let h_scroll_offset = if self.vertical_scrollbar.show_scrollbar {
|
||||
// magic number
|
||||
px(3.)
|
||||
} else {
|
||||
px(0.)
|
||||
};
|
||||
|
||||
v_flex()
|
||||
.flex_1()
|
||||
.size_full()
|
||||
.overflow_hidden()
|
||||
.relative()
|
||||
// Show a border on the top and bottom of the container when
|
||||
// the vertical scrollbar container is visible so we don't have a
|
||||
// floating left border in the panel.
|
||||
.when(self.vertical_scrollbar.show_track, |this| {
|
||||
this.border_t_1()
|
||||
.border_b_1()
|
||||
.border_color(cx.theme().colors().border)
|
||||
})
|
||||
.child(
|
||||
h_flex()
|
||||
.id("git-panel-entries-container")
|
||||
.flex_1()
|
||||
.size_full()
|
||||
.relative()
|
||||
|
@ -3848,15 +3564,6 @@ impl GitPanel {
|
|||
items
|
||||
}),
|
||||
)
|
||||
.when(
|
||||
!self.horizontal_scrollbar.show_track
|
||||
&& self.horizontal_scrollbar.show_scrollbar,
|
||||
|this| {
|
||||
// when not showing the horizontal scrollbar track, make sure we don't
|
||||
// obscure the last entry
|
||||
this.pb(scroll_track_size)
|
||||
},
|
||||
)
|
||||
.size_full()
|
||||
.flex_grow()
|
||||
.with_sizing_behavior(ListSizingBehavior::Auto)
|
||||
|
@ -3872,72 +3579,14 @@ impl GitPanel {
|
|||
this.deploy_panel_context_menu(event.position, window, cx)
|
||||
}),
|
||||
)
|
||||
.when(self.vertical_scrollbar.show_track, |this| {
|
||||
this.child(
|
||||
v_flex()
|
||||
.h_full()
|
||||
.flex_none()
|
||||
.w(scroll_track_size)
|
||||
.bg(cx.theme().colors().panel_background)
|
||||
.child(
|
||||
div()
|
||||
.size_full()
|
||||
.flex_1()
|
||||
.border_l_1()
|
||||
.border_color(cx.theme().colors().border),
|
||||
),
|
||||
)
|
||||
})
|
||||
.when(self.vertical_scrollbar.show_scrollbar, |this| {
|
||||
this.child(
|
||||
self.render_vertical_scrollbar(
|
||||
self.horizontal_scrollbar.show_track,
|
||||
cx,
|
||||
),
|
||||
)
|
||||
}),
|
||||
.custom_scrollbars(
|
||||
Scrollbars::for_settings::<GitPanelSettings>()
|
||||
.tracked_scroll_handle(self.scroll_handle.clone())
|
||||
.with_track_along(ScrollAxes::Horizontal),
|
||||
window,
|
||||
cx,
|
||||
),
|
||||
)
|
||||
.when(self.horizontal_scrollbar.show_track, |this| {
|
||||
this.child(
|
||||
h_flex()
|
||||
.w_full()
|
||||
.h(scroll_track_size)
|
||||
.flex_none()
|
||||
.relative()
|
||||
.child(
|
||||
div()
|
||||
.w_full()
|
||||
.flex_1()
|
||||
// for some reason the horizontal scrollbar is 1px
|
||||
// taller than the vertical scrollbar??
|
||||
.h(scroll_track_size - px(1.))
|
||||
.bg(cx.theme().colors().panel_background)
|
||||
.border_t_1()
|
||||
.border_color(cx.theme().colors().border),
|
||||
)
|
||||
.when(self.vertical_scrollbar.show_track, |this| {
|
||||
this.child(
|
||||
div()
|
||||
.flex_none()
|
||||
// -1px prevents a missing pixel between the two container borders
|
||||
.w(scroll_track_size - px(1.))
|
||||
.h_full(),
|
||||
)
|
||||
.child(
|
||||
// HACK: Fill the missing 1px 🥲
|
||||
div()
|
||||
.absolute()
|
||||
.right(scroll_track_size - px(1.))
|
||||
.bottom(scroll_track_size - px(1.))
|
||||
.size_px()
|
||||
.bg(cx.theme().colors().border),
|
||||
)
|
||||
}),
|
||||
)
|
||||
})
|
||||
.when(self.horizontal_scrollbar.show_scrollbar, |this| {
|
||||
this.child(self.render_horizontal_scrollbar(h_scroll_offset, cx))
|
||||
})
|
||||
}
|
||||
|
||||
fn entry_label(&self, label: impl Into<SharedString>, color: Color) -> Label {
|
||||
|
@ -4446,15 +4095,6 @@ impl Render for GitPanel {
|
|||
.when(has_write_access && has_co_authors, |git_panel| {
|
||||
git_panel.on_action(cx.listener(Self::toggle_fill_co_authors))
|
||||
})
|
||||
.on_hover(cx.listener(move |this, hovered, window, cx| {
|
||||
if *hovered {
|
||||
this.horizontal_scrollbar.show(cx);
|
||||
this.vertical_scrollbar.show(cx);
|
||||
cx.notify();
|
||||
} else if !this.focus_handle.contains_focused(window, cx) {
|
||||
this.hide_scrollbars(window, cx);
|
||||
}
|
||||
}))
|
||||
.size_full()
|
||||
.overflow_hidden()
|
||||
.bg(cx.theme().colors().panel_background)
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use editor::ShowScrollbar;
|
||||
use editor::EditorSettings;
|
||||
use gpui::Pixels;
|
||||
use schemars::JsonSchema;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsSources};
|
||||
use ui::scrollbars::{ScrollbarVisibilitySetting, ShowScrollbar};
|
||||
use workspace::dock::DockPosition;
|
||||
|
||||
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
|
||||
|
@ -89,6 +90,22 @@ pub struct GitPanelSettings {
|
|||
pub collapse_untracked_diff: bool,
|
||||
}
|
||||
|
||||
impl ScrollbarVisibilitySetting for GitPanelSettings {
|
||||
fn scrollbar_visibility(&self, cx: &ui::App) -> ShowScrollbar {
|
||||
// TODO: This PR should have defined Editor's `scrollbar.axis`
|
||||
// as an Option<ScrollbarAxis>, not a ScrollbarAxes as it would allow you to
|
||||
// `.unwrap_or(EditorSettings::get_global(cx).scrollbar.show)`.
|
||||
//
|
||||
// Once this is fixed we can extend the GitPanelSettings with a `scrollbar.axis`
|
||||
// so we can show each axis based on the settings.
|
||||
//
|
||||
// We should fix this. PR: https://github.com/zed-industries/zed/pull/19495
|
||||
self.scrollbar
|
||||
.show
|
||||
.unwrap_or_else(|| EditorSettings::get_global(cx).scrollbar.show)
|
||||
}
|
||||
}
|
||||
|
||||
impl Settings for GitPanelSettings {
|
||||
const KEY: Option<&'static str> = Some("git_panel");
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue