@@ -28,9 +28,9 @@ use git::{repository::RepoPath, status::FileStatus, Commit, ToggleStaged};
use git::{ExpandCommitEditor, RestoreTrackedFiles, StageAll, TrashUntrackedFiles, UnstageAll};
use gpui::{
actions, anchored, deferred, percentage, uniform_list, Action, Animation, AnimationExt as _,
- ClickEvent, Corner, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, KeyContext,
- ListHorizontalSizingBehavior, ListSizingBehavior, Modifiers, ModifiersChangedEvent,
- MouseButton, MouseDownEvent, Point, PromptLevel, ScrollStrategy, Stateful, Subscription, Task,
+ Axis, ClickEvent, Corner, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable,
+ KeyContext, ListHorizontalSizingBehavior, ListSizingBehavior, Modifiers, ModifiersChangedEvent,
+ MouseButton, MouseDownEvent, Point, PromptLevel, ScrollStrategy, Subscription, Task,
Transformation, UniformListScrollHandle, WeakEntity,
};
use itertools::Itertools;
@@ -205,6 +205,21 @@ pub struct GitStatusEntry {
pub(crate) staging: StageStatus,
}
+impl GitStatusEntry {
+ fn display_name(&self) -> String {
+ self.worktree_path
+ .file_name()
+ .map(|name| name.to_string_lossy().into_owned())
+ .unwrap_or_else(|| self.worktree_path.to_string_lossy().into_owned())
+ }
+
+ fn parent_dir(&self) -> Option<String> {
+ self.worktree_path
+ .parent()
+ .map(|parent| parent.to_string_lossy().into_owned())
+ }
+}
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum TargetStatus {
Staged,
@@ -222,6 +237,61 @@ struct PendingOperation {
type RemoteOperations = Rc<RefCell<HashSet<u32>>>;
+// 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, |panel, mut cx| async move {
+ cx.background_executor()
+ .timer(SCROLLBAR_SHOW_INTERVAL)
+ .await;
+
+ if let Some(panel) = panel.upgrade() {
+ panel
+ .update(&mut 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 {
remote_operation_id: u32,
pending_remote_operations: RemoteOperations,
@@ -237,7 +307,8 @@ pub struct GitPanel {
single_tracked_entry: Option<GitStatusEntry>,
focus_handle: FocusHandle,
fs: Arc<dyn Fs>,
- hide_scrollbar_task: Option<Task<()>>,
+ horizontal_scrollbar: ScrollbarProperties,
+ vertical_scrollbar: ScrollbarProperties,
new_count: usize,
entry_count: usize,
new_staged_count: usize,
@@ -246,10 +317,9 @@ pub struct GitPanel {
pending_serialization: Task<Option<()>>,
pub(crate) project: Entity<Project>,
scroll_handle: UniformListScrollHandle,
- scrollbar_state: ScrollbarState,
+ max_width_item_index: Option<usize>,
selected_entry: Option<usize>,
marked_entries: Vec<usize>,
- show_scrollbar: bool,
tracked_count: usize,
tracked_staged_count: usize,
update_visible_entries_task: Task<()>,
@@ -316,7 +386,7 @@ impl GitPanel {
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_scrollbar(window, cx);
+ this.hide_scrollbars(window, cx);
})
.detach();
@@ -355,8 +425,23 @@ impl GitPanel {
)
.detach();
- let scrollbar_state =
- ScrollbarState::new(scroll_handle.clone()).parent_entity(&cx.entity());
+ 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 git_panel = Self {
pending_remote_operations: Default::default(),
@@ -371,7 +456,6 @@ impl GitPanel {
entries: Vec::new(),
focus_handle: cx.focus_handle(),
fs,
- hide_scrollbar_task: None,
new_count: 0,
new_staged_count: 0,
pending: Vec::new(),
@@ -381,10 +465,9 @@ impl GitPanel {
single_tracked_entry: None,
project,
scroll_handle,
- scrollbar_state,
+ max_width_item_index: None,
selected_entry: None,
marked_entries: Vec::new(),
- show_scrollbar: false,
tracked_count: 0,
tracked_staged_count: 0,
update_visible_entries_task: Task::ready(()),
@@ -393,12 +476,93 @@ impl GitPanel {
workspace,
modal_open: false,
entry_count: 0,
+ horizontal_scrollbar,
+ vertical_scrollbar,
};
git_panel.schedule_update(false, window, cx);
- git_panel.show_scrollbar = git_panel.should_show_scrollbar(cx);
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) -> Option<usize> {
fn binary_search<F>(mut low: usize, mut high: usize, is_target: F) -> Option<usize>
where
@@ -555,53 +719,6 @@ impl GitPanel {
}
}
- fn show_scrollbar(&self, cx: &mut Context<Self>) -> ShowScrollbar {
- GitPanelSettings::get_global(cx)
- .scrollbar
- .show
- .unwrap_or_else(|| EditorSettings::get_global(cx).scrollbar.show)
- }
-
- fn should_show_scrollbar(&self, cx: &mut Context<Self>) -> bool {
- let show = self.show_scrollbar(cx);
- match show {
- ShowScrollbar::Auto => true,
- ShowScrollbar::System => true,
- ShowScrollbar::Always => true,
- ShowScrollbar::Never => false,
- }
- }
-
- fn should_autohide_scrollbar(&self, cx: &mut Context<Self>) -> bool {
- let show = self.show_scrollbar(cx);
- 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 => true,
- }
- }
-
- fn hide_scrollbar(&mut self, window: &mut Window, cx: &mut Context<Self>) {
- const SCROLLBAR_SHOW_INTERVAL: Duration = Duration::from_secs(1);
- if !self.should_autohide_scrollbar(cx) {
- return;
- }
- self.hide_scrollbar_task = Some(cx.spawn_in(window, |panel, mut cx| async move {
- cx.background_executor()
- .timer(SCROLLBAR_SHOW_INTERVAL)
- .await;
- panel
- .update(&mut cx, |panel, cx| {
- panel.show_scrollbar = false;
- cx.notify();
- })
- .log_err();
- }))
- }
-
fn handle_modifiers_changed(
&mut self,
event: &ModifiersChangedEvent,
@@ -1972,12 +2089,13 @@ impl GitPanel {
cx.background_executor().timer(UPDATE_DEBOUNCE).await;
if let Some(git_panel) = handle.upgrade() {
git_panel
- .update_in(&mut cx, |git_panel, _, cx| {
+ .update_in(&mut cx, |git_panel, window, cx| {
if clear_pending {
git_panel.clear_pending();
}
git_panel.update_visible_entries(cx);
git_panel.update_editor_placeholder(cx);
+ git_panel.update_scrollbar_properties(window, cx);
})
.ok();
}
@@ -2038,6 +2156,7 @@ impl GitPanel {
let mut conflict_entries = Vec::new();
let mut last_staged = None;
let mut staged_count = 0;
+ let mut max_width_item: Option<(RepoPath, usize)> = None;
let Some(repo) = self.active_repository.as_ref() else {
// Just clear entries if no repository is active.
@@ -2083,6 +2202,21 @@ impl GitPanel {
last_staged = Some(entry.clone());
}
+ let width_estimate = Self::item_width_estimate(
+ entry.parent_dir().map(|s| s.len()).unwrap_or(0),
+ entry.display_name().len(),
+ );
+
+ match max_width_item.as_mut() {
+ Some((repo_path, estimate)) => {
+ if width_estimate > *estimate {
+ *repo_path = entry.repo_path.clone();
+ *estimate = width_estimate;
+ }
+ }
+ None => max_width_item = Some((entry.repo_path.clone(), width_estimate)),
+ }
+
if is_conflict {
conflict_entries.push(entry);
} else if is_new {
@@ -2155,6 +2289,15 @@ impl GitPanel {
.extend(new_entries.into_iter().map(GitListEntry::GitStatusEntry));
}
+ if let Some((repo_path, _)) = max_width_item {
+ self.max_width_item_index = self.entries.iter().position(|entry| match entry {
+ GitListEntry::GitStatusEntry(git_status_entry) => {
+ git_status_entry.repo_path == repo_path
+ }
+ GitListEntry::Header(_) => false,
+ });
+ }
+
self.update_counts(repo);
self.select_first_entry_if_none(cx);
@@ -2376,6 +2519,12 @@ impl GitPanel {
self.has_staged_changes()
}
+ // eventually we'll need to take depth into account here
+ // if we add a tree view
+ fn item_width_estimate(path: usize, file_name: usize) -> usize {
+ path + file_name
+ }
+
fn render_overflow_menu(&self, id: impl Into<ElementId>) -> impl IntoElement {
let focus_handle = self.focus_handle.clone();
PopoverMenu::new(id.into())
@@ -2795,58 +2944,108 @@ impl GitPanel {
)
}
- fn render_scrollbar(&self, cx: &mut Context<Self>) -> Option<Stateful<Div>> {
- let scroll_bar_style = self.show_scrollbar(cx);
- let show_container = matches!(scroll_bar_style, ShowScrollbar::Always);
-
- if !self.should_show_scrollbar(cx)
- || !(self.show_scrollbar || self.scrollbar_state.is_dragging())
- {
- return None;
- }
+ 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();
+ }
- Some(
- div()
- .id("git-panel-vertical-scroll")
- .occlude()
- .flex_none()
- .h_full()
- .cursor_default()
- .when(show_container, |this| this.pl_1().px_1p5())
- .when(!show_container, |this| {
- this.absolute().right_1().top_1().bottom_1().w(px(12.))
- })
- .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.scrollbar_state.is_dragging()
- && !this.focus_handle.contains_focused(window, cx)
- {
- this.hide_scrollbar(window, cx);
- cx.notify();
- }
+ }),
+ )
+ .on_scroll_wheel(cx.listener(|_, _, _, cx| {
+ cx.notify();
+ }))
+ .children(Scrollbar::vertical(
+ // percentage as f32..end_offset as f32,
+ self.vertical_scrollbar.state.clone(),
+ ))
+ }
- cx.stop_propagation();
- }),
- )
- .on_scroll_wheel(cx.listener(|_, _, _, cx| {
- cx.notify();
- }))
- .children(Scrollbar::vertical(
- // percentage as f32..end_offset as f32,
- self.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(
@@ -2900,54 +3099,147 @@ impl GitPanel {
) -> impl IntoElement {
let entry_count = self.entries.len();
- h_flex()
+ 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()
- .flex_grow()
.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(
- uniform_list(cx.entity().clone(), "entries", entry_count, {
- move |this, range, window, cx| {
- let mut items = Vec::with_capacity(range.end - range.start);
-
- for ix in range {
- match &this.entries.get(ix) {
- Some(GitListEntry::GitStatusEntry(entry)) => {
- items.push(this.render_entry(
- ix,
- entry,
- has_write_access,
- window,
- cx,
- ));
- }
- Some(GitListEntry::Header(header)) => {
- items.push(this.render_list_header(
- ix,
- header,
- has_write_access,
- window,
- cx,
- ));
+ h_flex()
+ .flex_1()
+ .size_full()
+ .relative()
+ .overflow_hidden()
+ .child(
+ uniform_list(cx.entity().clone(), "entries", entry_count, {
+ move |this, range, window, cx| {
+ let mut items = Vec::with_capacity(range.end - range.start);
+
+ for ix in range {
+ match &this.entries.get(ix) {
+ Some(GitListEntry::GitStatusEntry(entry)) => {
+ items.push(this.render_entry(
+ ix,
+ entry,
+ has_write_access,
+ window,
+ cx,
+ ));
+ }
+ Some(GitListEntry::Header(header)) => {
+ items.push(this.render_list_header(
+ ix,
+ header,
+ has_write_access,
+ window,
+ cx,
+ ));
+ }
+ None => {}
+ }
}
- None => {}
- }
- }
- items
- }
- })
- .size_full()
- .with_sizing_behavior(ListSizingBehavior::Auto)
- .with_horizontal_sizing_behavior(ListHorizontalSizingBehavior::Unconstrained)
- .track_scroll(self.scroll_handle.clone()),
- )
- .on_mouse_down(
- MouseButton::Right,
- cx.listener(move |this, event: &MouseDownEvent, window, cx| {
- this.deploy_panel_context_menu(event.position, window, cx)
- }),
+ items
+ }
+ })
+ .size_full()
+ .flex_grow()
+ .with_sizing_behavior(ListSizingBehavior::Auto)
+ .with_horizontal_sizing_behavior(
+ ListHorizontalSizingBehavior::Unconstrained,
+ )
+ .with_width_from_item(self.max_width_item_index)
+ .track_scroll(self.scroll_handle.clone()),
+ )
+ .on_mouse_down(
+ MouseButton::Right,
+ cx.listener(move |this, event: &MouseDownEvent, window, cx| {
+ 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,
+ ),
+ )
+ }),
)
- .children(self.render_scrollbar(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 {
@@ -3074,13 +3366,8 @@ impl GitPanel {
window: &Window,
cx: &Context<Self>,
) -> AnyElement {
- let display_name = entry
- .worktree_path
- .file_name()
- .map(|name| name.to_string_lossy().into_owned())
- .unwrap_or_else(|| entry.worktree_path.to_string_lossy().into_owned());
+ let display_name = entry.display_name();
- let worktree_path = entry.worktree_path.clone();
let selected = self.selected_entry == Some(ix);
let marked = self.marked_entries.contains(&ix);
let status_style = GitPanelSettings::get_global(cx).status_style;
@@ -3272,12 +3559,12 @@ impl GitPanel {
.child(
h_flex()
.items_center()
- .overflow_hidden()
- .when_some(worktree_path.parent(), |this, parent| {
- let parent_str = parent.to_string_lossy();
- if !parent_str.is_empty() {
+ .flex_1()
+ // .overflow_hidden()
+ .when_some(entry.parent_dir(), |this, parent| {
+ if !parent.is_empty() {
this.child(
- self.entry_label(format!("{}/", parent_str), path_color)
+ self.entry_label(format!("{}/", parent), path_color)
.when(status.is_deleted(), |this| this.strikethrough()),
)
} else {
@@ -3351,14 +3638,13 @@ 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_action(cx.listener(|this, &OpenSelected, cx| this.open_selected(&OpenSelected, cx)))
- .on_hover(cx.listener(|this, hovered, window, cx| {
+ .on_hover(cx.listener(move |this, hovered, window, cx| {
if *hovered {
- this.show_scrollbar = true;
- this.hide_scrollbar_task.take();
+ this.horizontal_scrollbar.show(cx);
+ this.vertical_scrollbar.show(cx);
cx.notify();
} else if !this.focus_handle.contains_focused(window, cx) {
- this.hide_scrollbar(window, cx);
+ this.hide_scrollbars(window, cx);
}
}))
.size_full()