Start work on expanding and collapsing directories in project panel

Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Max Brunsfeld
2021-09-24 15:12:49 -07:00
co-authored by Nathan Sobo
parent 7eda614c4a
commit 443a7826bb
7 changed files with 559 additions and 160 deletions
+6 -6
View File
@@ -5,7 +5,7 @@ use crate::{
vector::{vec2f, Vector2F},
},
json::{self, json},
ElementBox, MutableAppContext,
ElementBox,
};
use json::ToJson;
use parking_lot::Mutex;
@@ -38,7 +38,7 @@ pub struct LayoutState {
pub struct UniformList<F>
where
F: Fn(Range<usize>, &mut Vec<ElementBox>, &mut MutableAppContext),
F: Fn(Range<usize>, &mut Vec<ElementBox>, &mut LayoutContext),
{
state: UniformListState,
item_count: usize,
@@ -47,7 +47,7 @@ where
impl<F> UniformList<F>
where
F: Fn(Range<usize>, &mut Vec<ElementBox>, &mut MutableAppContext),
F: Fn(Range<usize>, &mut Vec<ElementBox>, &mut LayoutContext),
{
pub fn new(state: UniformListState, item_count: usize, append_items: F) -> Self {
Self {
@@ -102,7 +102,7 @@ where
impl<F> Element for UniformList<F>
where
F: Fn(Range<usize>, &mut Vec<ElementBox>, &mut MutableAppContext),
F: Fn(Range<usize>, &mut Vec<ElementBox>, &mut LayoutContext),
{
type LayoutState = LayoutState;
type PaintState = ();
@@ -124,7 +124,7 @@ where
let mut scroll_max = 0.;
let mut items = Vec::new();
(self.append_items)(0..1, &mut items, cx.app);
(self.append_items)(0..1, &mut items, cx);
if let Some(first_item) = items.first_mut() {
let mut item_size = first_item.layout(item_constraint, cx);
item_size.set_x(size.x());
@@ -146,7 +146,7 @@ where
self.item_count,
start + (size.y() / item_height).ceil() as usize + 1,
);
(self.append_items)(start..end, &mut items, cx.app);
(self.append_items)(start..end, &mut items, cx);
for item in &mut items {
item.layout(item_constraint, cx);
}
+11 -1
View File
@@ -7,7 +7,7 @@ use crate::{
platform::Event,
text_layout::TextLayoutCache,
Action, AnyAction, AssetCache, ElementBox, Entity, FontSystem, ModelHandle, ReadModel,
ReadView, Scene, View, ViewHandle,
ReadView, Scene, UpdateView, View, ViewHandle,
};
use pathfinder_geometry::vector::{vec2f, Vector2F};
use serde_json::json;
@@ -264,6 +264,16 @@ impl<'a> ReadView for LayoutContext<'a> {
}
}
impl<'a> UpdateView for LayoutContext<'a> {
fn update_view<T, F, S>(&mut self, handle: &ViewHandle<T>, update: F) -> S
where
T: View,
F: FnOnce(&mut T, &mut crate::ViewContext<T>) -> S,
{
self.app.update_view(handle, update)
}
}
impl<'a> ReadModel for LayoutContext<'a> {
fn read_model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
self.app.read_model(handle)
+3 -3
View File
@@ -126,7 +126,7 @@ impl View for Select {
UniformList::new(
self.list_state.clone(),
self.item_count,
move |mut range, items, mut cx| {
move |mut range, items, cx| {
let handle = handle.upgrade(cx).unwrap();
let this = handle.read(cx);
let selected_item_ix = this.selected_item_ix;
@@ -134,9 +134,9 @@ impl View for Select {
items.extend(range.map(|ix| {
MouseEventHandler::new::<Item, _, _, _>(
(handle.id(), ix),
&mut cx,
cx,
|mouse_state, cx| {
(handle.read(*cx).render_item)(
(handle.read(cx).render_item)(
ix,
if ix == selected_item_ix {
ItemType::Selected
+40 -22
View File
@@ -278,29 +278,47 @@ pub async fn match_paths(
let start = max(tree_start, segment_start) - tree_start;
let end = min(tree_end, segment_end) - tree_start;
let entries = if include_ignored {
snapshot.files(start).take(end - start)
} else {
snapshot.visible_files(start).take(end - start)
};
let paths = entries.map(|entry| {
if let EntryKind::File(char_bag) = entry.kind {
PathMatchCandidate {
path: &entry.path,
char_bag,
if include_ignored {
let paths = snapshot.files(start).take(end - start).map(|entry| {
if let EntryKind::File(char_bag) = entry.kind {
PathMatchCandidate {
path: &entry.path,
char_bag,
}
} else {
unreachable!()
}
} else {
unreachable!()
}
});
matcher.match_paths(
snapshot.id(),
path_prefix,
paths,
results,
&cancel_flag,
);
});
matcher.match_paths(
snapshot.id(),
path_prefix,
paths,
results,
&cancel_flag,
);
} else {
let paths =
snapshot
.visible_files(start)
.take(end - start)
.map(|entry| {
if let EntryKind::File(char_bag) = entry.kind {
PathMatchCandidate {
path: &entry.path,
char_bag,
}
} else {
unreachable!()
}
});
matcher.match_paths(
snapshot.id(),
path_prefix,
paths,
results,
&cancel_flag,
);
};
}
if tree_end >= segment_end {
break;
+2 -1
View File
@@ -13,7 +13,7 @@ use zed::{
channel::ChannelList,
chat_panel, editor, file_finder,
fs::RealFs,
http, language, menus, rpc, settings, theme_selector,
http, language, menus, project_panel, rpc, settings, theme_selector,
user::UserStore,
workspace::{self, OpenNew, OpenParams, OpenPaths},
AppState,
@@ -55,6 +55,7 @@ fn main() {
editor::init(cx);
file_finder::init(cx);
chat_panel::init(cx);
project_panel::init(cx);
theme_selector::init(&app_state, cx);
cx.set_menus(menus::menus(&app_state.clone()));
+357 -68
View File
@@ -1,19 +1,41 @@
use crate::{
project::Project,
theme::Theme,
worktree::{self, Worktree},
Settings,
};
use crate::{project::Project, theme, Settings};
use gpui::{
elements::{Empty, Label, List, ListState, Orientation},
AppContext, Element, ElementBox, Entity, ModelHandle, View, ViewContext,
action,
elements::{Label, MouseEventHandler, UniformList, UniformListState},
Element, ElementBox, Entity, ModelHandle, MutableAppContext, ReadModel, View, ViewContext,
WeakViewHandle,
};
use postage::watch;
use std::ops::Range;
pub struct ProjectPanel {
project: ModelHandle<Project>,
list: ListState,
list: UniformListState,
visible_entries: Vec<Vec<usize>>,
expanded_dir_ids: Vec<Vec<usize>>,
settings: watch::Receiver<Settings>,
handle: WeakViewHandle<Self>,
}
#[derive(Debug, PartialEq, Eq)]
struct EntryDetails {
filename: String,
depth: usize,
is_dir: bool,
is_expanded: bool,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ProjectEntry {
worktree_ix: usize,
entry_id: usize,
}
action!(ToggleExpanded, ProjectEntry);
action!(Open, ProjectEntry);
pub fn init(cx: &mut MutableAppContext) {
cx.add_action(ProjectPanel::toggle_expanded);
}
pub enum Event {}
@@ -24,77 +46,139 @@ impl ProjectPanel {
settings: watch::Receiver<Settings>,
cx: &mut ViewContext<Self>,
) -> Self {
cx.observe(&project, |this, project, cx| {
let project = project.read(cx);
this.list.reset(Self::entry_count(project, cx));
cx.observe(&project, |this, _, cx| {
this.update_visible_entries(cx);
cx.notify();
})
.detach();
Self {
list: ListState::new(
{
let project = project.read(cx);
Self::entry_count(project, cx)
},
Orientation::Top,
1000.,
{
let project = project.clone();
let settings = settings.clone();
move |ix, cx| {
let project = project.read(cx);
Self::render_entry_at_index(project, ix, &settings.borrow().theme, cx)
}
},
),
let mut this = Self {
project,
settings,
}
list: Default::default(),
visible_entries: Default::default(),
expanded_dir_ids: Default::default(),
handle: cx.handle().downgrade(),
};
this.update_visible_entries(cx);
this
}
fn entry_count(project: &Project, cx: &AppContext) -> usize {
project
.worktrees()
.iter()
.map(|worktree| worktree.read(cx).visible_entry_count())
.sum()
fn toggle_expanded(&mut self, action: &ToggleExpanded, cx: &mut ViewContext<Self>) {
let ProjectEntry {
worktree_ix,
entry_id,
} = action.0;
let expanded_dir_ids = &mut self.expanded_dir_ids[worktree_ix];
match expanded_dir_ids.binary_search(&entry_id) {
Ok(ix) => {
expanded_dir_ids.remove(ix);
}
Err(ix) => {
expanded_dir_ids.insert(ix, entry_id);
}
}
self.update_visible_entries(cx);
}
fn render_entry_at_index(
project: &Project,
mut ix: usize,
theme: &Theme,
cx: &AppContext,
) -> ElementBox {
for worktree in project.worktrees() {
let worktree = worktree.read(cx);
let visible_entry_count = worktree.visible_entry_count();
if ix < visible_entry_count {
let entry = worktree.visible_entries(ix).next().unwrap();
return Self::render_entry(worktree, entry, theme, cx);
} else {
ix -= visible_entry_count;
fn update_visible_entries(&mut self, cx: &mut ViewContext<Self>) {
let worktrees = self.project.read(cx).worktrees();
self.visible_entries.clear();
for (worktree_ix, worktree) in worktrees.iter().enumerate() {
let snapshot = worktree.read(cx).snapshot();
if self.expanded_dir_ids.len() <= worktree_ix {
self.expanded_dir_ids
.push(vec![snapshot.root_entry().unwrap().id])
}
let expanded_dir_ids = &self.expanded_dir_ids[worktree_ix];
let mut visible_worktree_entries = Vec::new();
let mut entry_iter = snapshot.visible_entries(0);
while let Some(item) = entry_iter.item() {
visible_worktree_entries.push(entry_iter.ix());
if expanded_dir_ids.binary_search(&item.id).is_err() {
if entry_iter.advance_sibling() {
continue;
}
}
entry_iter.advance();
}
self.visible_entries.push(visible_worktree_entries);
}
}
fn append_visible_entries<C: ReadModel, T>(
&self,
range: Range<usize>,
items: &mut Vec<T>,
cx: &mut C,
mut render_item: impl FnMut(ProjectEntry, EntryDetails, &mut C) -> T,
) {
let worktrees = self.project.read(cx).worktrees().to_vec();
let mut total_ix = 0;
for (worktree_ix, visible_worktree_entries) in self.visible_entries.iter().enumerate() {
if total_ix >= range.end {
break;
}
if total_ix + visible_worktree_entries.len() <= range.start {
total_ix += visible_worktree_entries.len();
continue;
}
let expanded_entry_ids = &self.expanded_dir_ids[worktree_ix];
let snapshot = worktrees[worktree_ix].read(cx).snapshot();
let mut cursor = snapshot.visible_entries(0);
for ix in visible_worktree_entries[(range.start - total_ix)..]
.iter()
.copied()
{
cursor.advance_to_ix(ix);
if let Some(entry) = cursor.item() {
let details = EntryDetails {
filename: entry.path.file_name().map_or_else(
|| snapshot.root_name().to_string(),
|name| name.to_string_lossy().to_string(),
),
depth: entry.path.components().count(),
is_dir: entry.is_dir(),
is_expanded: expanded_entry_ids.binary_search(&entry.id).is_ok(),
};
let entry = ProjectEntry {
worktree_ix,
entry_id: entry.id,
};
items.push(render_item(entry, details, cx));
}
total_ix += 1;
}
}
Empty::new().boxed()
}
fn render_entry(
worktree: &Worktree,
entry: &worktree::Entry,
theme: &Theme,
_: &AppContext,
entry: ProjectEntry,
details: EntryDetails,
theme: &theme::ProjectPanel,
cx: &mut ViewContext<Self>,
) -> ElementBox {
let path = &entry.path;
let depth = path.iter().count() as f32;
Label::new(
path.file_name()
.map_or(String::new(), |s| s.to_string_lossy().to_string()),
theme.project_panel.entry.clone(),
let is_dir = details.is_dir;
MouseEventHandler::new::<Self, _, _, _>(
(entry.worktree_ix, entry.entry_id),
cx,
|state, cx| {
Label::new(details.filename, theme.entry.clone())
.contained()
.with_margin_left(details.depth as f32 * 20.)
.boxed()
},
)
.contained()
.with_margin_left(depth * 20.)
.on_click(move |cx| {
if is_dir {
cx.dispatch_action(ToggleExpanded(entry))
} else {
cx.dispatch_action(Open(entry))
}
})
.boxed()
}
}
@@ -105,14 +189,219 @@ impl View for ProjectPanel {
}
fn render(&mut self, _: &mut gpui::RenderContext<'_, Self>) -> gpui::ElementBox {
let theme = &self.settings.borrow().theme.project_panel;
List::new(self.list.clone())
.contained()
.with_style(theme.container)
.boxed()
let settings = self.settings.clone();
let handle = self.handle.clone();
UniformList::new(
self.list.clone(),
self.visible_entries.len(),
move |range, items, cx| {
let theme = &settings.borrow().theme.project_panel;
let this = handle.upgrade(cx).unwrap();
this.update(cx.app, |this, cx| {
this.append_visible_entries(range, items, cx, |entry, details, cx| {
Self::render_entry(entry, details, theme, cx)
});
})
},
)
.contained()
.with_style(self.settings.borrow().theme.project_panel.container)
.boxed()
}
}
impl Entity for ProjectPanel {
type Event = Event;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test::test_app_state;
use gpui::{TestAppContext, ViewHandle};
use serde_json::json;
use std::{collections::HashSet, path::Path};
#[gpui::test]
async fn test_visible_list(mut cx: gpui::TestAppContext) {
let app_state = cx.update(test_app_state);
let settings = app_state.settings.clone();
let fs = app_state.fs.as_fake();
fs.insert_tree(
"/root1",
json!({
".dockerignore": "",
".git": {
"HEAD": "",
},
"a": {
"0": { "q": "", "r": "", "s": "" },
"1": { "t": "", "u": "" },
"2": { "v": "", "w": "", "x": "", "y": "" },
},
"b": {
"3": { "Q": "" },
"4": { "R": "", "S": "", "T": "", "U": "" },
},
"c": {
"5": {},
"6": { "V": "", "W": "" },
"7": { "X": "" },
"8": { "Y": {}, "Z": "" }
}
}),
)
.await;
let project = cx.add_model(|_| Project::new(&app_state));
let worktree = project
.update(&mut cx, |project, cx| {
project.add_local_worktree("/root1".as_ref(), cx)
})
.await
.unwrap();
worktree
.read_with(&cx, |t, _| t.as_local().unwrap().scan_complete())
.await;
let (_, panel) = cx.add_window(|cx| ProjectPanel::new(project, settings, cx));
assert_eq!(
visible_entry_details(&panel, 0..50, &mut cx),
&[
EntryDetails {
filename: "root1".to_string(),
depth: 0,
is_dir: true,
is_expanded: true,
},
EntryDetails {
filename: ".dockerignore".to_string(),
depth: 1,
is_dir: false,
is_expanded: false,
},
EntryDetails {
filename: "a".to_string(),
depth: 1,
is_dir: true,
is_expanded: false,
},
EntryDetails {
filename: "b".to_string(),
depth: 1,
is_dir: true,
is_expanded: false,
},
EntryDetails {
filename: "c".to_string(),
depth: 1,
is_dir: true,
is_expanded: false,
},
]
);
toggle_expand_dir(&panel, "root1/b", &mut cx);
assert_eq!(
visible_entry_details(&panel, 0..50, &mut cx),
&[
EntryDetails {
filename: "root1".to_string(),
depth: 0,
is_dir: true,
is_expanded: true,
},
EntryDetails {
filename: ".dockerignore".to_string(),
depth: 1,
is_dir: false,
is_expanded: false,
},
EntryDetails {
filename: "a".to_string(),
depth: 1,
is_dir: true,
is_expanded: false,
},
EntryDetails {
filename: "b".to_string(),
depth: 1,
is_dir: true,
is_expanded: true,
},
EntryDetails {
filename: "3".to_string(),
depth: 2,
is_dir: true,
is_expanded: false,
},
EntryDetails {
filename: "4".to_string(),
depth: 2,
is_dir: true,
is_expanded: false,
},
EntryDetails {
filename: "c".to_string(),
depth: 1,
is_dir: true,
is_expanded: false,
},
]
);
fn toggle_expand_dir(
panel: &ViewHandle<ProjectPanel>,
path: impl AsRef<Path>,
cx: &mut TestAppContext,
) {
let path = path.as_ref();
panel.update(cx, |panel, cx| {
for (worktree_ix, worktree) in panel.project.read(cx).worktrees().iter().enumerate()
{
let worktree = worktree.read(cx);
if let Ok(relative_path) = path.strip_prefix(worktree.root_name()) {
let entry_id = worktree.entry_for_path(relative_path).unwrap().id;
panel.toggle_expanded(
&ToggleExpanded(ProjectEntry {
worktree_ix,
entry_id,
}),
cx,
);
return;
}
}
panic!("no worktree for path {:?}", path);
});
}
fn visible_entry_details(
panel: &ViewHandle<ProjectPanel>,
range: Range<usize>,
cx: &mut TestAppContext,
) -> Vec<EntryDetails> {
let mut result = Vec::new();
let mut project_entries = HashSet::new();
panel.update(cx, |panel, cx| {
panel.append_visible_entries(
range,
&mut result,
cx,
|project_entry, details, _| {
assert!(
project_entries.insert(project_entry),
"duplicate project entry {:?} {:?}",
project_entry,
details
);
details
},
);
});
result
}
}
}
+140 -59
View File
@@ -1482,16 +1482,16 @@ impl Snapshot {
self.entries_by_path.summary().visible_file_count
}
pub fn files(&self, start: usize) -> EntryIter {
EntryIter::files(self, start)
pub fn files(&self, start: usize) -> EntryIter<FileCount> {
EntryIter::new(self, start)
}
pub fn visible_entries(&self, start: usize) -> EntryIter {
EntryIter::visible(self, start)
pub fn visible_entries(&self, start: usize) -> EntryIter<VisibleCountAndPath> {
EntryIter::new(self, start)
}
pub fn visible_files(&self, start: usize) -> EntryIter {
EntryIter::visible_files(self, start)
pub fn visible_files(&self, start: usize) -> EntryIter<VisibleFileCount> {
EntryIter::new(self, start)
}
pub fn paths(&self) -> impl Iterator<Item = &Arc<Path>> {
@@ -1514,7 +1514,7 @@ impl Snapshot {
&self.root_name
}
fn entry_for_path(&self, path: impl AsRef<Path>) -> Option<&Entry> {
pub fn entry_for_path(&self, path: impl AsRef<Path>) -> Option<&Entry> {
let mut cursor = self.entries_by_path.cursor::<_, ()>();
if cursor.seek(&PathSearch::Exact(path.as_ref()), Bias::Left, &()) {
cursor.item()
@@ -2065,33 +2065,111 @@ impl<'a: 'b, 'b> sum_tree::Dimension<'a, EntrySummary> for PathSearch<'b> {
}
}
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Ord, PartialOrd)]
#[derive(Clone, Default, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct FileCount(usize);
#[derive(Clone, Default, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct VisibleFileCount(usize);
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct VisibleCountAndPath<'a> {
count: Option<usize>,
path: PathSearch<'a>,
}
impl<'a> sum_tree::Dimension<'a, EntrySummary> for FileCount {
fn add_summary(&mut self, summary: &'a EntrySummary, _: &()) {
self.0 += summary.file_count;
}
}
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct VisibleCount(usize);
impl<'a> sum_tree::Dimension<'a, EntrySummary> for VisibleCount {
fn add_summary(&mut self, summary: &'a EntrySummary, _: &()) {
self.0 += summary.visible_count;
}
}
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct VisibleFileCount(usize);
impl<'a> sum_tree::Dimension<'a, EntrySummary> for VisibleFileCount {
fn add_summary(&mut self, summary: &'a EntrySummary, _: &()) {
self.0 += summary.visible_file_count;
}
}
impl<'a> sum_tree::Dimension<'a, EntrySummary> for VisibleCountAndPath<'a> {
fn add_summary(&mut self, summary: &'a EntrySummary, _: &()) {
if let Some(count) = self.count.as_mut() {
*count += summary.visible_count;
} else {
unreachable!()
}
self.path = PathSearch::Exact(summary.max_path.as_ref());
}
}
impl<'a> Ord for VisibleCountAndPath<'a> {
fn cmp(&self, other: &Self) -> cmp::Ordering {
if let Some(count) = self.count {
count.cmp(&other.count.unwrap())
} else {
self.path.cmp(&other.path)
}
}
}
impl<'a> PartialOrd for VisibleCountAndPath<'a> {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl From<usize> for FileCount {
fn from(count: usize) -> Self {
Self(count)
}
}
impl From<usize> for VisibleFileCount {
fn from(count: usize) -> Self {
Self(count)
}
}
impl<'a> From<usize> for VisibleCountAndPath<'a> {
fn from(count: usize) -> Self {
Self {
count: Some(count),
path: PathSearch::default(),
}
}
}
impl Deref for FileCount {
type Target = usize;
fn deref(&self) -> &usize {
&self.0
}
}
impl Deref for VisibleFileCount {
type Target = usize;
fn deref(&self) -> &usize {
&self.0
}
}
impl<'a> Deref for VisibleCountAndPath<'a> {
type Target = usize;
fn deref(&self) -> &usize {
self.count.as_ref().unwrap()
}
}
impl<'a> Default for VisibleCountAndPath<'a> {
fn default() -> Self {
Self {
count: Some(0),
path: Default::default(),
}
}
}
struct BackgroundScanner {
fs: Arc<dyn Fs>,
snapshot: Arc<Mutex<Snapshot>>,
@@ -2584,63 +2662,66 @@ impl WorktreeHandle for ModelHandle<Worktree> {
}
}
pub enum EntryIter<'a> {
Files(Cursor<'a, Entry, FileCount, ()>),
Visible(Cursor<'a, Entry, VisibleCount, ()>),
VisibleFiles(Cursor<'a, Entry, VisibleFileCount, ()>),
pub struct EntryIter<'a, Dim> {
cursor: Cursor<'a, Entry, Dim, ()>,
}
impl<'a> EntryIter<'a> {
fn files(snapshot: &'a Snapshot, start: usize) -> Self {
impl<'a, Dim> EntryIter<'a, Dim>
where
Dim: sum_tree::SeekDimension<'a, EntrySummary> + From<usize> + Deref<Target = usize>,
{
fn new(snapshot: &'a Snapshot, start: usize) -> Self {
let mut cursor = snapshot.entries_by_path.cursor();
cursor.seek(&FileCount(start), Bias::Right, &());
Self::Files(cursor)
cursor.seek(&Dim::from(start), Bias::Right, &());
Self { cursor }
}
fn visible(snapshot: &'a Snapshot, start: usize) -> Self {
let mut cursor = snapshot.entries_by_path.cursor();
cursor.seek(&VisibleCount(start), Bias::Right, &());
Self::Visible(cursor)
pub fn ix(&self) -> usize {
*self.cursor.seek_start().deref()
}
fn visible_files(snapshot: &'a Snapshot, start: usize) -> Self {
let mut cursor = snapshot.entries_by_path.cursor();
cursor.seek(&VisibleFileCount(start), Bias::Right, &());
Self::VisibleFiles(cursor)
pub fn advance_to_ix(&mut self, ix: usize) {
self.cursor.seek_forward(&Dim::from(ix), Bias::Right, &());
}
fn next_internal(&mut self) {
match self {
Self::Files(cursor) => {
let ix = *cursor.seek_start();
cursor.seek_forward(&FileCount(ix.0 + 1), Bias::Right, &());
}
Self::Visible(cursor) => {
let ix = *cursor.seek_start();
cursor.seek_forward(&VisibleCount(ix.0 + 1), Bias::Right, &());
}
Self::VisibleFiles(cursor) => {
let ix = *cursor.seek_start();
cursor.seek_forward(&VisibleFileCount(ix.0 + 1), Bias::Right, &());
}
}
pub fn advance(&mut self) {
self.advance_to_ix(self.ix() + 1);
}
fn item(&self) -> Option<&'a Entry> {
match self {
Self::Files(cursor) => cursor.item(),
Self::Visible(cursor) => cursor.item(),
Self::VisibleFiles(cursor) => cursor.item(),
}
pub fn item(&self) -> Option<&'a Entry> {
self.cursor.item()
}
}
impl<'a> Iterator for EntryIter<'a> {
impl<'a> EntryIter<'a, VisibleCountAndPath<'a>> {
pub fn advance_sibling(&mut self) -> bool {
let start_count = self.cursor.seek_start().count.unwrap();
while let Some(item) = self.cursor.item() {
self.cursor.seek_forward(
&VisibleCountAndPath {
count: None,
path: PathSearch::Successor(item.path.as_ref()),
},
Bias::Right,
&(),
);
if self.cursor.seek_start().count.unwrap() > start_count {
return true;
}
}
false
}
}
impl<'a, Dim> Iterator for EntryIter<'a, Dim>
where
Dim: sum_tree::SeekDimension<'a, EntrySummary> + From<usize> + Deref<Target = usize>,
{
type Item = &'a Entry;
fn next(&mut self) -> Option<Self::Item> {
if let Some(entry) = self.item() {
self.next_internal();
self.advance();
Some(entry)
} else {
None