fix: allow file tree to scroll
This commit is contained in:
@@ -120,6 +120,13 @@ impl DiffViewState {
|
|||||||
) {
|
) {
|
||||||
self.0.borrow_mut().new_side_highlights = Some(highlights);
|
self.0.borrow_mut().new_side_highlights = Some(highlights);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn scroll_to_diff_line(&mut self, line_i: util::diff::DiffLineIndex) {
|
||||||
|
self.0
|
||||||
|
.borrow_mut()
|
||||||
|
.list_state
|
||||||
|
.scroll_to_reveal_item(line_i.into());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl gpui::RenderOnce for DiffView {
|
impl gpui::RenderOnce for DiffView {
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
use std::{cell::RefCell, collections::HashSet, rc::Rc, sync::Arc};
|
use std::{cell::RefCell, collections::HashSet, rc::Rc, sync::Arc};
|
||||||
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
InteractiveElement, IntoElement, ParentElement, StatefulInteractiveElement, Styled, div, list,
|
InteractiveElement, IntoElement, ListHorizontalSizingBehavior, ListSizingBehavior,
|
||||||
prelude::FluentBuilder, px,
|
ParentElement, StatefulInteractiveElement, Styled, UniformListScrollHandle, div,
|
||||||
|
prelude::FluentBuilder, px, uniform_list,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -11,10 +12,7 @@ use crate::{
|
|||||||
font_icon::{FontIcon, font_icon},
|
font_icon::{FontIcon, font_icon},
|
||||||
text::text,
|
text::text,
|
||||||
},
|
},
|
||||||
util::{
|
util::{self, file::FileTreeItemKind},
|
||||||
self,
|
|
||||||
file::{FileTreeItem, FileTreeItemKind},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(gpui::IntoElement)]
|
#[derive(gpui::IntoElement)]
|
||||||
@@ -36,10 +34,11 @@ pub(crate) struct Item {
|
|||||||
pub(crate) struct FileTreeState(Rc<RefCell<FileTreeStateInner>>);
|
pub(crate) struct FileTreeState(Rc<RefCell<FileTreeStateInner>>);
|
||||||
|
|
||||||
struct FileTreeStateInner {
|
struct FileTreeStateInner {
|
||||||
list_state: gpui::ListState,
|
scroll_handle: UniformListScrollHandle,
|
||||||
collapsed_dirs: HashSet<Arc<str>>,
|
collapsed_dirs: HashSet<Arc<str>>,
|
||||||
visible_items: Vec<usize>,
|
visible_items: Vec<usize>,
|
||||||
highlighted_items: HashSet<usize>,
|
highlighted_items: HashSet<usize>,
|
||||||
|
max_width_item_index: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn file_tree(
|
pub(crate) fn file_tree(
|
||||||
@@ -56,17 +55,18 @@ pub(crate) fn file_tree(
|
|||||||
impl FileTreeState {
|
impl FileTreeState {
|
||||||
pub(crate) fn new() -> Self {
|
pub(crate) fn new() -> Self {
|
||||||
Self(Rc::new(RefCell::new(FileTreeStateInner {
|
Self(Rc::new(RefCell::new(FileTreeStateInner {
|
||||||
list_state: gpui::ListState::new(0, gpui::ListAlignment::Top, px(50.)),
|
scroll_handle: UniformListScrollHandle::new(),
|
||||||
collapsed_dirs: HashSet::new(),
|
collapsed_dirs: HashSet::new(),
|
||||||
visible_items: Vec::new(),
|
visible_items: Vec::new(),
|
||||||
highlighted_items: HashSet::new(),
|
highlighted_items: HashSet::new(),
|
||||||
|
max_width_item_index: None,
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn reset(&self, items: &[util::file::FileTreeItem]) {
|
pub(crate) fn reset(&self, items: &[util::file::FileTreeItem]) {
|
||||||
let mut state = self.0.borrow_mut();
|
let mut state = self.0.borrow_mut();
|
||||||
state.list_state.reset(items.len());
|
|
||||||
state.visible_items = (0..items.len()).collect::<Vec<_>>();
|
state.visible_items = (0..items.len()).collect::<Vec<_>>();
|
||||||
|
state.update_max_width_item_index(items);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn highlight_item(&mut self, index: usize) {
|
pub(crate) fn highlight_item(&mut self, index: usize) {
|
||||||
@@ -104,7 +104,21 @@ impl FileTreeState {
|
|||||||
state.visible_items.push(i);
|
state.visible_items.push(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
state.list_state.reset(state.visible_items.len());
|
state.update_max_width_item_index(items);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FileTreeStateInner {
|
||||||
|
fn update_max_width_item_index(&mut self, items: &[util::file::FileTreeItem]) {
|
||||||
|
self.max_width_item_index = self
|
||||||
|
.visible_items
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.max_by_key(|(_, item_i)| {
|
||||||
|
let item = &items[**item_i];
|
||||||
|
item.level.saturating_mul(2) + item.name.chars().count()
|
||||||
|
})
|
||||||
|
.map(|(visible_i, _)| visible_i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,28 +138,41 @@ impl gpui::RenderOnce for FileTree {
|
|||||||
_window: &mut gpui::Window,
|
_window: &mut gpui::Window,
|
||||||
_cx: &mut gpui::App,
|
_cx: &mut gpui::App,
|
||||||
) -> impl gpui::prelude::IntoElement {
|
) -> impl gpui::prelude::IntoElement {
|
||||||
let list_state = self.state.0.borrow().list_state.clone();
|
let state = self.state.0.borrow();
|
||||||
|
let item_count = state.visible_items.len();
|
||||||
|
let scroll_handle = state.scroll_handle.clone();
|
||||||
|
let max_width_item_index = state.max_width_item_index;
|
||||||
|
drop(state);
|
||||||
|
|
||||||
list(list_state, move |i, window, cx| {
|
uniform_list("file-tree", item_count, move |range, window, cx| {
|
||||||
let state = self.state.0.borrow();
|
range
|
||||||
let item_index = state.visible_items[i];
|
.map(|i| {
|
||||||
let on_item_click = self.on_item_click.as_ref().map(Rc::clone);
|
let item_index = self.state.0.borrow().visible_items[i];
|
||||||
|
let on_item_click = self.on_item_click.as_ref().map(Rc::clone);
|
||||||
|
|
||||||
let item = (self.item)(item_index, window, cx);
|
let item = (self.item)(item_index, window, cx);
|
||||||
let item = Item {
|
let state = self.state.0.borrow();
|
||||||
is_expanded: !state.collapsed_dirs.contains(&item.full_path),
|
let item = Item {
|
||||||
is_highlighed: state.highlighted_items.contains(&item_index),
|
is_expanded: !state.collapsed_dirs.contains(&item.full_path),
|
||||||
item,
|
is_highlighed: state.highlighted_items.contains(&item_index),
|
||||||
on_click: Box::new(move |window, cx| {
|
item,
|
||||||
if let Some(f) = &on_item_click {
|
on_click: Box::new(move |window, cx| {
|
||||||
f(&i, window, cx);
|
if let Some(f) = &on_item_click {
|
||||||
}
|
f(&item_index, window, cx);
|
||||||
}),
|
}
|
||||||
};
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
item.into_any_element()
|
item.into_any_element()
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
})
|
})
|
||||||
.size_full()
|
.h_full()
|
||||||
|
.min_w_full()
|
||||||
|
.with_sizing_behavior(ListSizingBehavior::Infer)
|
||||||
|
.with_horizontal_sizing_behavior(ListHorizontalSizingBehavior::Unconstrained)
|
||||||
|
.with_width_from_item(max_width_item_index)
|
||||||
|
.track_scroll(scroll_handle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,7 +181,7 @@ impl gpui::RenderOnce for Item {
|
|||||||
let theme = app::current_theme(cx);
|
let theme = app::current_theme(cx);
|
||||||
div()
|
div()
|
||||||
.id(gpui::SharedString::new(self.item.full_path))
|
.id(gpui::SharedString::new(self.item.full_path))
|
||||||
.w_full()
|
.min_w_full()
|
||||||
.flex()
|
.flex()
|
||||||
.flex_row()
|
.flex_row()
|
||||||
.items_center()
|
.items_center()
|
||||||
@@ -162,7 +189,6 @@ impl gpui::RenderOnce for Item {
|
|||||||
.pr_2()
|
.pr_2()
|
||||||
.py_0p5()
|
.py_0p5()
|
||||||
.pl(px(8. + (8 * self.item.level) as f32))
|
.pl(px(8. + (8 * self.item.level) as f32))
|
||||||
.rounded_sm()
|
|
||||||
.hover(|it| {
|
.hover(|it| {
|
||||||
if self.is_highlighed {
|
if self.is_highlighed {
|
||||||
it
|
it
|
||||||
@@ -191,6 +217,11 @@ impl gpui::RenderOnce for Item {
|
|||||||
it.bg(theme.colors.accent_muted)
|
it.bg(theme.colors.accent_muted)
|
||||||
.text_color(theme.colors.accent_fg)
|
.text_color(theme.colors.accent_fg)
|
||||||
})
|
})
|
||||||
.child(text(gpui::SharedString::new(self.item.name)).text_sm())
|
.child(
|
||||||
|
text(gpui::SharedString::new(self.item.name))
|
||||||
|
.text_sm()
|
||||||
|
.whitespace_nowrap()
|
||||||
|
.flex_shrink_0(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user