Skip to content

Commit 97326a8

Browse files
committed
Use filetreelist crate
No longer safe Status inside of FileTreeItem. For Status storage, now introduced a new Item, which contains Status alongside FileTreeItem. Note that FileTreeItemKind is no longer publicy available - thus we cannot store this enum anywhere anymore.
1 parent ad45102 commit 97326a8

File tree

9 files changed

+247
-307
lines changed

9 files changed

+247
-307
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111
* changes in commit message inside external editor [[@bc-universe]](https://github.com/bc-universe) ([#1420](https://github.com/extrawurst/gitui/issues/1420))
1212
* add no-verify option on commits to not run hooks [[@dam5h]](https://github.com/dam5h) ([#1374](https://github.com/extrawurst/gitui/issues/1374))
1313
* allow `fetch` on status tab [[@alensiljak]](https://github.com/alensiljak) ([#1471](https://github.com/extrawurst/gitui/issues/1471))
14+
* Use `filetreelist` crate for the status tree. [[@abergmeier]](https://github.com/abergmeier) ([#1504](https://github.com/extrawurst/gitui/issues/1504))
1415

1516
### Fixes
1617
* commit msg history ordered the wrong way ([#1445](https://github.com/extrawurst/gitui/issues/1445))

src/components/changes.rs

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use super::{
2-
status_tree::StatusTreeComponent,
3-
utils::filetree::{FileTreeItem, FileTreeItemKind},
4-
CommandBlocking, DrawableComponent,
2+
status_tree::StatusTreeComponent, CommandBlocking,
3+
DrawableComponent,
54
};
65
use crate::{
76
components::{CommandInfo, Component, EventState},
@@ -17,6 +16,7 @@ use asyncgit::{
1716
StatusItem, StatusItemType,
1817
};
1918
use crossterm::event::Event;
19+
use filetreelist::FileTreeItem;
2020
use std::path::Path;
2121
use tui::{backend::Backend, layout::Rect, Frame};
2222

@@ -72,6 +72,10 @@ impl ChangesComponent {
7272
self.files.selection()
7373
}
7474

75+
pub fn selection_status(&self) -> Option<StatusItem> {
76+
self.files.selection_status()
77+
}
78+
7579
///
7680
pub fn focus_select(&mut self, focus: bool) {
7781
self.files.focus(focus);
@@ -85,16 +89,26 @@ impl ChangesComponent {
8589

8690
///
8791
pub fn is_file_seleted(&self) -> bool {
88-
self.files.is_file_seleted()
92+
self.files.is_file_selected()
8993
}
9094

9195
fn index_add_remove(&mut self) -> Result<bool> {
9296
if let Some(tree_item) = self.selection() {
9397
if self.is_working_dir {
94-
if let FileTreeItemKind::File(i) = tree_item.kind {
95-
let path = Path::new(i.path.as_str());
96-
match i.status {
97-
StatusItemType::Deleted => {
98+
if tree_item.kind().is_path() {
99+
let config =
100+
self.options.borrow().status_show_untracked();
101+
102+
//TODO: check if we can handle the one file case with it aswell
103+
sync::stage_add_all(
104+
&self.repo.borrow(),
105+
tree_item.info().full_path_str(),
106+
config,
107+
)?;
108+
} else {
109+
let path = Path::new(tree_item.info().path_str());
110+
match self.selection_status().map(|s| s.status) {
111+
Some(StatusItemType::Deleted) => {
98112
sync::stage_addremoved(
99113
&self.repo.borrow(),
100114
path,
@@ -105,16 +119,6 @@ impl ChangesComponent {
105119
path,
106120
)?,
107121
};
108-
} else {
109-
let config =
110-
self.options.borrow().status_show_untracked();
111-
112-
//TODO: check if we can handle the one file case with it aswell
113-
sync::stage_add_all(
114-
&self.repo.borrow(),
115-
tree_item.info.full_path.as_str(),
116-
config,
117-
)?;
118122
}
119123

120124
//TODO: this might be slow in big repos,
@@ -130,8 +134,8 @@ impl ChangesComponent {
130134
}
131135
} else {
132136
// this is a staged entry, so lets unstage it
133-
let path = tree_item.info.full_path.as_str();
134-
sync::reset_stage(&self.repo.borrow(), path)?;
137+
let path = tree_item.info().full_path_str();
138+
sync::reset_stage(&self.repo.borrow(), &path)?;
135139
}
136140

137141
return Ok(true);
@@ -160,11 +164,13 @@ impl ChangesComponent {
160164

161165
fn dispatch_reset_workdir(&mut self) -> bool {
162166
if let Some(tree_item) = self.selection() {
163-
let is_folder =
164-
matches!(tree_item.kind, FileTreeItemKind::Path(_));
167+
let is_folder = tree_item.kind().is_path();
165168
self.queue.push(InternalEvent::ConfirmAction(
166169
Action::Reset(ResetItem {
167-
path: tree_item.info.full_path,
170+
path: tree_item
171+
.info()
172+
.full_path_str()
173+
.to_string(),
168174
is_folder,
169175
}),
170176
));
@@ -178,12 +184,13 @@ impl ChangesComponent {
178184
if let Some(tree_item) = self.selection() {
179185
if let Err(e) = sync::add_to_ignore(
180186
&self.repo.borrow(),
181-
&tree_item.info.full_path,
187+
&tree_item.info().full_path_str(),
182188
) {
183189
self.queue.push(InternalEvent::ShowErrorMsg(
184190
format!(
185191
"ignore error:\n{}\nfile:\n{:?}",
186-
e, tree_item.info.full_path
192+
e,
193+
tree_item.info().full_path()
187194
),
188195
));
189196
} else {

src/components/compare_commits.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ impl CompareCommitsComponent {
256256
if let Some(f) = self.details.files().selection_file()
257257
{
258258
let diff_params = DiffParams {
259-
path: f.path.clone(),
259+
path: f.full_path_str().to_string(),
260260
diff_type: DiffType::Commits(ids),
261261
options: DiffOptions::default(),
262262
};
@@ -265,7 +265,11 @@ impl CompareCommitsComponent {
265265
self.git_diff.last()?
266266
{
267267
if params == diff_params {
268-
self.diff.update(f.path, false, last);
268+
self.diff.update(
269+
f.full_path_str().to_string(),
270+
false,
271+
last,
272+
);
269273
return Ok(());
270274
}
271275
}

src/components/inspect_commit.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ impl InspectCommitComponent {
270270
if let Some(f) = self.details.files().selection_file()
271271
{
272272
let diff_params = DiffParams {
273-
path: f.path.clone(),
273+
path: f.full_path_str().to_string(),
274274
diff_type: DiffType::Commit(
275275
request.commit_id,
276276
),
@@ -281,7 +281,11 @@ impl InspectCommitComponent {
281281
self.git_diff.last()?
282282
{
283283
if params == diff_params {
284-
self.diff.update(f.path, false, last);
284+
self.diff.update(
285+
f.full_path_str().to_string(),
286+
false,
287+
last,
288+
);
285289
return Ok(());
286290
}
287291
}

src/components/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ pub use syntax_text::SyntaxTextComponent;
6565
pub use tag_commit::TagCommitComponent;
6666
pub use taglist::TagListComponent;
6767
pub use textinput::{InputType, TextInputComponent};
68-
pub use utils::filetree::FileTreeItemKind;
6968

7069
use crate::ui::style::Theme;
7170
use anyhow::Result;

src/components/status_tree.rs

Lines changed: 47 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
use super::{
2-
utils::{
3-
filetree::{FileTreeItem, FileTreeItemKind},
4-
statustree::{MoveSelection, StatusTree},
5-
},
2+
utils::statustree::{MoveSelection, StatusTree},
63
BlameFileOpen, CommandBlocking, DrawableComponent, FileRevOpen,
74
};
85
use crate::{
@@ -16,11 +13,10 @@ use crate::{
1613
use anyhow::Result;
1714
use asyncgit::{hash, sync::CommitId, StatusItem, StatusItemType};
1815
use crossterm::event::Event;
16+
use filetreelist::{FileTreeItem, TreeItemInfo};
1917
use std::{borrow::Cow, cell::Cell, convert::From, path::Path};
2018
use tui::{backend::Backend, layout::Rect, text::Span, Frame};
2119

22-
//TODO: use new `filetreelist` crate
23-
2420
///
2521
#[allow(clippy::struct_excessive_bools)]
2622
pub struct StatusTreeComponent {
@@ -82,20 +78,23 @@ impl StatusTreeComponent {
8278

8379
///
8480
pub fn selection(&self) -> Option<FileTreeItem> {
85-
self.tree.selected_item()
81+
self.tree.selected_tree_item()
8682
}
8783

88-
///
89-
pub fn selection_file(&self) -> Option<StatusItem> {
84+
pub fn selection_file(&self) -> Option<TreeItemInfo> {
9085
self.tree.selected_item().and_then(|f| {
91-
if let FileTreeItemKind::File(f) = f.kind {
92-
Some(f)
93-
} else {
86+
if f.is_path() {
9487
None
88+
} else {
89+
Some(f.info().clone())
9590
}
9691
})
9792
}
9893

94+
pub fn selection_status(&self) -> Option<StatusItem> {
95+
self.tree.selected_item().and_then(|i| i.status())
96+
}
97+
9998
///
10099
pub fn show_selection(&mut self, show: bool) {
101100
self.show_selection = show;
@@ -124,13 +123,10 @@ impl StatusTreeComponent {
124123
}
125124

126125
///
127-
pub fn is_file_seleted(&self) -> bool {
128-
self.tree.selected_item().map_or(false, |item| {
129-
match item.kind {
130-
FileTreeItemKind::File(_) => true,
131-
FileTreeItemKind::Path(..) => false,
132-
}
133-
})
126+
pub fn is_file_selected(&self) -> bool {
127+
self.tree
128+
.selected_item()
129+
.map_or(false, |item| !item.is_path())
134130
}
135131

136132
fn move_selection(&mut self, dir: MoveSelection) -> bool {
@@ -160,7 +156,8 @@ impl StatusTreeComponent {
160156
string: &str,
161157
indent: usize,
162158
visible: bool,
163-
file_item_kind: &FileTreeItemKind,
159+
status_item: &Option<StatusItem>,
160+
path_collapsed: bool,
164161
width: u16,
165162
selected: bool,
166163
theme: &'b SharedTheme,
@@ -175,8 +172,8 @@ impl StatusTreeComponent {
175172
return None;
176173
}
177174

178-
match file_item_kind {
179-
FileTreeItemKind::File(status_item) => {
175+
match status_item {
176+
Some(status_item) => {
180177
let status_char =
181178
Self::item_status_char(status_item.status);
182179
let file = Path::new(&status_item.path)
@@ -202,9 +199,9 @@ impl StatusTreeComponent {
202199
))
203200
}
204201

205-
FileTreeItemKind::Path(path_collapsed) => {
202+
_ => {
206203
let collapse_char =
207-
if path_collapsed.0 { '▸' } else { '▾' };
204+
if path_collapsed { '▸' } else { '▾' };
208205

209206
let txt = if selected {
210207
format!(
@@ -246,31 +243,30 @@ impl StatusTreeComponent {
246243
let index_above_select =
247244
index < self.tree.selection.unwrap_or(0);
248245

249-
if !item.info.visible && index_above_select {
246+
if !item.is_visible() && index_above_select {
250247
selection_offset_visible += 1;
251248
}
252249

253250
vec_draw_text_info.push(TextDrawInfo {
254-
name: item.info.path.clone(),
255-
indent: item.info.indent,
256-
visible: item.info.visible,
257-
item_kind: &item.kind,
251+
name: item.info().path_str().to_string(),
252+
indent: item.info().indent(),
253+
visible: item.info().is_visible(),
254+
status_item: item.status(),
255+
path_collapsed: item.is_path_collapsed(),
258256
});
259257

260258
let mut idx_temp = index;
261259

262260
while idx_temp < tree_items.len().saturating_sub(2)
263-
&& tree_items[idx_temp].info.indent
264-
< tree_items[idx_temp + 1].info.indent
261+
&& tree_items[idx_temp].info().indent()
262+
< tree_items[idx_temp + 1].info().indent()
265263
{
266264
// fold up the folder/file
267265
idx_temp += 1;
268266
should_skip_over += 1;
269267

270268
// don't fold files up
271-
if let FileTreeItemKind::File(_) =
272-
&tree_items[idx_temp].kind
273-
{
269+
if !tree_items[idx_temp].is_path() {
274270
should_skip_over -= 1;
275271
break;
276272
}
@@ -290,7 +286,7 @@ impl StatusTreeComponent {
290286
let vec_draw_text_info_len = vec_draw_text_info.len();
291287
vec_draw_text_info[vec_draw_text_info_len - 1]
292288
.name += &(String::from("/")
293-
+ &tree_items[idx_temp].info.path);
289+
+ tree_items[idx_temp].info().path_str());
294290
if index_above_select {
295291
selection_offset += 1;
296292
}
@@ -305,11 +301,12 @@ impl StatusTreeComponent {
305301
}
306302

307303
/// Used for drawing the `FileTreeComponent`
308-
struct TextDrawInfo<'a> {
304+
struct TextDrawInfo {
309305
name: String,
310306
indent: u8,
311307
visible: bool,
312-
item_kind: &'a FileTreeItemKind,
308+
status_item: Option<StatusItem>,
309+
path_collapsed: bool,
313310
}
314311

315312
impl DrawableComponent for StatusTreeComponent {
@@ -364,7 +361,8 @@ impl DrawableComponent for StatusTreeComponent {
364361
&draw_text_info.name,
365362
draw_text_info.indent as usize,
366363
draw_text_info.visible,
367-
draw_text_info.item_kind,
364+
&draw_text_info.status_item,
365+
draw_text_info.path_collapsed,
368366
r.width,
369367
self.show_selection && select == index,
370368
&self.theme,
@@ -443,7 +441,9 @@ impl Component for StatusTreeComponent {
443441
queue.push(InternalEvent::OpenPopup(
444442
StackablePopupOpen::BlameFile(
445443
BlameFileOpen {
446-
file_path: status_item.path,
444+
file_path: status_item
445+
.full_path_str()
446+
.to_string(),
447447
commit_id: self.revision,
448448
selection: None,
449449
},
@@ -462,7 +462,9 @@ impl Component for StatusTreeComponent {
462462
queue.push(InternalEvent::OpenPopup(
463463
StackablePopupOpen::FileRevlog(
464464
FileRevOpen::new(
465-
status_item.path,
465+
status_item
466+
.full_path_str()
467+
.to_string(),
466468
),
467469
),
468470
));
@@ -475,7 +477,11 @@ impl Component for StatusTreeComponent {
475477
if let Some(queue) = &self.queue {
476478
queue.push(
477479
InternalEvent::OpenExternalEditor(
478-
Some(status_item.path),
480+
Some(
481+
status_item
482+
.full_path_str()
483+
.to_string(),
484+
),
479485
),
480486
);
481487
}

0 commit comments

Comments
 (0)