summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Thiel <sebastian.thiel@icloud.com>2024-01-23 15:49:06 +0100
committerSebastian Thiel <sebastian.thiel@icloud.com>2024-01-23 15:49:06 +0100
commitd837d720e3b1e204043b8d89447db0d65ae000ba (patch)
treec097091966e2af1b00916ff6e70d49ee4362b532
parent600bee234edd4e7922017c26927a6f135a02c335 (diff)
parent78b9a8e22568c902132ed98d32e223ff71eb7b06 (diff)
Merge branch 'no-entry-check'
-rw-r--r--src/interactive/app/common.rs19
-rw-r--r--src/interactive/app/eventloop.rs14
-rw-r--r--src/interactive/app/handlers.rs14
-rw-r--r--src/interactive/app/state.rs3
-rw-r--r--src/interactive/app/terminal.rs5
-rw-r--r--src/interactive/app/tests/utils.rs9
-rw-r--r--src/interactive/app/tree_view.rs6
-rw-r--r--src/main.rs6
-rw-r--r--src/options.rs3
9 files changed, 58 insertions, 21 deletions
diff --git a/src/interactive/app/common.rs b/src/interactive/app/common.rs
index 7c89a2f..433a793 100644
--- a/src/interactive/app/common.rs
+++ b/src/interactive/app/common.rs
@@ -56,6 +56,21 @@ pub struct EntryDataBundle {
pub exists: bool,
}
+pub enum EntryCheck {
+ PossiblyCostlyLstat,
+ Disabled,
+}
+
+impl EntryCheck {
+ pub fn new(is_scanning: bool, allow_entry_check: bool) -> Self {
+ if allow_entry_check && !is_scanning {
+ EntryCheck::PossiblyCostlyLstat
+ } else {
+ EntryCheck::Disabled
+ }
+ }
+}
+
/// Note that with `glob_root` present, we will not obtain metadata anymore as we might be seeing
/// a lot of entries. That way, displaying 250k entries is no problem.
pub fn sorted_entries(
@@ -63,7 +78,7 @@ pub fn sorted_entries(
node_idx: TreeIndex,
sorting: SortMode,
glob_root: Option<TreeIndex>,
- is_scanning: bool,
+ check: EntryCheck,
) -> Vec<EntryDataBundle> {
use SortMode::*;
fn cmp_count(l: &EntryDataBundle, r: &EntryDataBundle) -> Ordering {
@@ -77,7 +92,7 @@ pub fn sorted_entries(
let use_glob_path = glob_root.map_or(false, |glob_root| glob_root == node_idx);
let (path, exists, is_dir) = {
let path = path_of(tree, idx, glob_root);
- if is_scanning || glob_root == Some(node_idx) {
+ if matches!(check, EntryCheck::Disabled) || glob_root == Some(node_idx) {
(path, true, entry.is_dir)
} else {
let meta = path.symlink_metadata();
diff --git a/src/interactive/app/eventloop.rs b/src/interactive/app/eventloop.rs
index 1053539..c2562fc 100644
--- a/src/interactive/app/eventloop.rs
+++ b/src/interactive/app/eventloop.rs
@@ -3,7 +3,7 @@ use crate::interactive::{
app::navigation::Navigation,
state::FocussedPane,
widgets::{glob_search, MainWindow, MainWindowProps},
- CursorDirection, CursorMode, DisplayOptions, MarkEntryMode,
+ CursorDirection, CursorMode, DisplayOptions, EntryCheck, MarkEntryMode,
};
use anyhow::Result;
use crossbeam::channel::Receiver;
@@ -197,7 +197,7 @@ impl AppState {
self.entries = tree_view.sorted_entries(
self.navigation().view_root,
self.sorting,
- self.scan.is_some(),
+ self.entry_check(),
);
if !self.received_events {
@@ -217,6 +217,10 @@ impl AppState {
self.reset_message(); // force "scanning" to appear
}
+ pub(crate) fn entry_check(&self) -> EntryCheck {
+ EntryCheck::new(self.scan.is_some(), self.allow_entry_check)
+ }
+
fn process_terminal_event<B>(
&mut self,
window: &mut MainWindow,
@@ -443,7 +447,7 @@ impl AppState {
self.entries = tree.sorted_entries(
self.navigation().view_root,
self.sorting,
- self.scan.is_some(),
+ self.entry_check(),
);
self.navigation_mut().selected = self.entries.first().map(|e| e.index);
@@ -498,7 +502,7 @@ impl AppState {
glob_tree_root: Some(tree_root),
};
let new_entries =
- glob_tree_view.sorted_entries(tree_root, self.sorting, self.scan.is_some());
+ glob_tree_view.sorted_entries(tree_root, self.sorting, self.entry_check());
let new_entries = self
.navigation_mut()
@@ -553,7 +557,7 @@ impl AppState {
self.entries = tree_view.sorted_entries(
self.navigation().view_root,
self.sorting,
- self.scan.is_some(),
+ self.entry_check(),
);
}
}
diff --git a/src/interactive/app/handlers.rs b/src/interactive/app/handlers.rs
index 9639264..1d700c2 100644
--- a/src/interactive/app/handlers.rs
+++ b/src/interactive/app/handlers.rs
@@ -67,7 +67,7 @@ impl AppState {
.map(|parent_idx| {
(
parent_idx,
- tree_view.sorted_entries(parent_idx, self.sorting, self.scan.is_some()),
+ tree_view.sorted_entries(parent_idx, self.sorting, self.entry_check()),
)
})
}
@@ -89,7 +89,7 @@ impl AppState {
self.navigation().selected.map(|previously_selected| {
(
previously_selected,
- tree_view.sorted_entries(previously_selected, self.sorting, self.scan.is_some()),
+ tree_view.sorted_entries(previously_selected, self.sorting, self.entry_check()),
)
})
}
@@ -125,7 +125,7 @@ impl AppState {
self.entries = tree_view.sorted_entries(
self.navigation().view_root,
self.sorting,
- self.scan.is_some(),
+ self.entry_check(),
);
}
@@ -134,7 +134,7 @@ impl AppState {
self.entries = tree_view.sorted_entries(
self.navigation().view_root,
self.sorting,
- self.scan.is_some(),
+ self.entry_check(),
);
}
@@ -143,7 +143,7 @@ impl AppState {
self.entries = tree_view.sorted_entries(
self.navigation().view_root,
self.sorting,
- self.scan.is_some(),
+ self.entry_check(),
);
}
@@ -333,7 +333,7 @@ impl AppState {
self.entries = tree_view.sorted_entries(
self.navigation().view_root,
self.sorting,
- self.scan.is_some(),
+ self.entry_check(),
);
}
@@ -353,7 +353,7 @@ impl AppState {
pub fn go_to_root(&mut self, tree_view: &TreeView<'_>) {
let root = self.navigation().tree_root;
- let entries = tree_view.sorted_entries(root, self.sorting, self.scan.is_some());
+ let entries = tree_view.sorted_entries(root, self.sorting, self.entry_check());
self.navigation_mut().exit_node(root, &entries);
self.entries = entries;
}
diff --git a/src/interactive/app/state.rs b/src/interactive/app/state.rs
index 159e63e..3a0da28 100644
--- a/src/interactive/app/state.rs
+++ b/src/interactive/app/state.rs
@@ -44,6 +44,8 @@ pub struct AppState {
pub walk_options: WalkOptions,
/// The paths used in the initial traversal, at least 1.
pub root_paths: Vec<PathBuf>,
+ /// If true, listed entries will be validated for presence when switching directories.
+ pub allow_entry_check: bool,
}
impl AppState {
@@ -61,6 +63,7 @@ impl AppState {
stats: TraversalStats::default(),
walk_options,
root_paths: input,
+ allow_entry_check: true,
}
}
}
diff --git a/src/interactive/app/terminal.rs b/src/interactive/app/terminal.rs
index a949bbd..16d7031 100644
--- a/src/interactive/app/terminal.rs
+++ b/src/interactive/app/terminal.rs
@@ -1,5 +1,6 @@
use std::path::PathBuf;
+use crate::interactive::EntryCheck;
use anyhow::Result;
use crossbeam::channel::Receiver;
use crosstermion::input::Event;
@@ -28,6 +29,7 @@ impl TerminalApp {
terminal: &mut Terminal<B>,
walk_options: WalkOptions,
byte_format: ByteFormat,
+ entry_check: bool,
input: Vec<PathBuf>,
) -> Result<TerminalApp>
where
@@ -40,6 +42,7 @@ impl TerminalApp {
let window = MainWindow::default();
let mut state = AppState::new(walk_options, input);
+ state.allow_entry_check = entry_check;
let traversal = Traversal::new();
let stats = TraversalStats::default();
@@ -49,7 +52,7 @@ impl TerminalApp {
state.navigation().view_root,
state.sorting,
state.glob_root(),
- state.scan.is_some(),
+ EntryCheck::new(state.scan.is_some(), state.allow_entry_check),
);
state.navigation_mut().selected = state.entries.first().map(|b| b.index);
diff --git a/src/interactive/app/tests/utils.rs b/src/interactive/app/tests/utils.rs
index 0dfd65a..a9907fb 100644
--- a/src/interactive/app/tests/utils.rs
+++ b/src/interactive/app/tests/utils.rs
@@ -198,8 +198,13 @@ pub fn initialized_app_and_terminal_with_closure(
let (_key_send, key_receive) = crossbeam::channel::bounded(0);
let input_paths = fixture_paths.iter().map(|c| convert(c.as_ref())).collect();
- let mut app =
- TerminalApp::initialize(&mut terminal, walk_options, ByteFormat::Metric, input_paths)?;
+ let mut app = TerminalApp::initialize(
+ &mut terminal,
+ walk_options,
+ ByteFormat::Metric,
+ false, /* entry-check */
+ input_paths,
+ )?;
app.traverse()?;
app.run_until_traversed(&mut terminal, key_receive)?;
diff --git a/src/interactive/app/tree_view.rs b/src/interactive/app/tree_view.rs
index 2afc366..5d74371 100644
--- a/src/interactive/app/tree_view.rs
+++ b/src/interactive/app/tree_view.rs
@@ -1,5 +1,5 @@
use super::{sorted_entries, EntryDataBundle, SortMode};
-use crate::interactive::path_of;
+use crate::interactive::{path_of, EntryCheck};
use dua::traverse::{EntryData, Traversal, Tree, TreeIndex};
use petgraph::{visit::Bfs, Direction};
use std::path::{Path, PathBuf};
@@ -50,14 +50,14 @@ impl TreeView<'_> {
&self,
view_root: TreeIndex,
sorting: SortMode,
- is_scanning: bool,
+ check: EntryCheck,
) -> Vec<EntryDataBundle> {
sorted_entries(
&self.traversal.tree,
view_root,
sorting,
self.glob_tree_root,
- is_scanning,
+ check,
)
}
diff --git a/src/main.rs b/src/main.rs
index 787d28e..fe8bd9a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -62,7 +62,10 @@ fn main() -> Result<()> {
let res = match opt.command {
#[cfg(feature = "tui-crossplatform")]
- Some(Interactive { input }) => {
+ Some(Interactive {
+ no_entry_check,
+ input,
+ }) => {
use anyhow::{anyhow, Context};
use crosstermion::terminal::{tui::new_terminal, AlternateRawScreen};
@@ -81,6 +84,7 @@ fn main() -> Result<()> {
&mut terminal,
walk_options,
byte_format,
+ !no_entry_check,
extract_paths_maybe_set_cwd(input, !opt.stay_on_filesystem)?,
)?;
app.traverse()?;
diff --git a/src/options.rs b/src/options.rs
index a59a90b..f2d5635 100644
--- a/src/options.rs
+++ b/src/options.rs
@@ -91,6 +91,9 @@ pub enum Command {
#[cfg(feature = "tui-crossplatform")]
#[clap(name = "interactive", visible_alias = "i")]
Interactive {
+ /// Do not check entries for presence when listing a directory to avoid slugging performance on slow filesystems.
+ #[clap(long, short = 'e')]
+ no_entry_check: bool,
/// One or more input files or directories. If unset, we will use all entries in the current working directory.
#[clap(value_parser)]
input: Vec<PathBuf>,