Add scope-based selection and credits

- Selection keys (+/-/*) now work on current scope (parent dataset)
- Add author credits: Florian Schermer, DATAZONE GmbH
- Update help text and README with scope documentation
This commit is contained in:
kidev 2026-01-31 00:15:26 +01:00
parent 1bf3235f9e
commit 194b81bbcf
4 changed files with 76 additions and 21 deletions

View File

@ -91,11 +91,11 @@ zfsdu
| **Tree** | |
| e | Expand all |
| c | Collapse all |
| **Selection** | |
| **Selection (current scope)** | |
| Space | Mark/unmark snapshot |
| + | Select all visible snapshots |
| - | Unselect all visible snapshots |
| * | Invert selection |
| + | Select all in scope |
| - | Unselect all in scope |
| * | Invert selection in scope |
| **Search & Filter** | |
| / | Search (n=next, N=prev) |
| f | Filter visible items |
@ -141,6 +141,11 @@ search_match = "lightred"
- Terminal with UTF-8 support
- Root privileges (for snapshot deletion)
## Author
**Florian Schermer**
[DATAZONE GmbH](https://datazone.de)
## License
CDDL (Common Development and Distribution License) - same as OpenZFS.

View File

@ -561,11 +561,23 @@ impl App {
self.search_matches.contains(&real_index)
}
// Select/Unselect Group (like MC)
// Select/Unselect Group (like MC) - works in current scope
pub fn select_group(&mut self) {
let current_parent = if let Some(real_idx) = self.nth_visible(self.selected) {
self.tree_items.get(real_idx).map(|ti| ti.parent_path.clone())
} else {
None
};
let mut count = 0;
for ti in &self.tree_items {
if ti.visible && ti.item.is_snapshot() {
let in_scope = match &current_parent {
Some(parent) => &ti.parent_path == parent,
None => true,
};
if in_scope {
let name = ti.item.full_name().to_string();
if !self.marked.contains(&name) {
self.marked.push(name);
@ -573,13 +585,28 @@ impl App {
}
}
}
}
self.message = Some(format!("Selected {} snapshot(s)", count));
}
pub fn unselect_group(&mut self) {
let current_parent = if let Some(real_idx) = self.nth_visible(self.selected) {
self.tree_items.get(real_idx).map(|ti| ti.parent_path.clone())
} else {
None
};
let visible_names: Vec<String> = self.tree_items
.iter()
.filter(|ti| ti.visible && ti.item.is_snapshot())
.filter(|ti| {
if !ti.visible || !ti.item.is_snapshot() {
return false;
}
match &current_parent {
Some(parent) => &ti.parent_path == parent,
None => true,
}
})
.map(|ti| ti.item.full_name().to_string())
.collect();
@ -590,17 +617,34 @@ impl App {
}
pub fn invert_selection(&mut self) {
// Get current scope (parent dataset of selected item)
let current_parent = if let Some(real_idx) = self.nth_visible(self.selected) {
self.tree_items.get(real_idx).map(|ti| ti.parent_path.clone())
} else {
None
};
let mut count = 0;
for ti in &self.tree_items {
// Only invert in current scope (same parent)
if ti.visible && ti.item.is_snapshot() {
let in_scope = match &current_parent {
Some(parent) => &ti.parent_path == parent,
None => true, // If no parent, work on all visible
};
if in_scope {
let name = ti.item.full_name().to_string();
if let Some(pos) = self.marked.iter().position(|x| x == &name) {
self.marked.remove(pos);
} else {
self.marked.push(name);
count += 1;
}
}
}
self.message = Some(format!("{} snapshot(s) marked", self.marked.len()));
}
self.message = Some(format!("Inverted {} in scope", count));
}
// Expand all datasets

View File

@ -75,7 +75,7 @@ fn print_help() {
println!(" ↑/k, ↓/j Navigate up/down");
println!(" Enter/l Expand/collapse dataset");
println!(" Space Mark/unmark snapshot");
println!(" +/-/* Select/unselect/invert");
println!(" +/-/* Select/unselect/invert (in scope)");
println!(" s Toggle sort (Size/Date/Name)");
println!(" / Search");
println!(" f Filter");
@ -88,6 +88,9 @@ fn print_help() {
println!();
println!("CONFIG:");
println!(" ~/.config/zfsdu/config.toml");
println!();
println!("(c) Florian Schermer - DATAZONE GmbH");
println!("https://datazone.de");
}
fn run_app<B: ratatui::backend::Backend>(terminal: &mut Terminal<B>, app: &mut App) -> Result<()> {

View File

@ -407,11 +407,11 @@ fn draw_help(f: &mut Frame, app: &App) {
" e Expand all",
" c Collapse all",
"",
" Selection:",
" Selection (current scope):",
" Space Mark/unmark snapshot",
" + Select all visible snapshots",
" - Unselect all visible snapshots",
" * Invert selection",
" + Select all in scope",
" - Unselect all in scope",
" * Invert selection in scope",
"",
" Search & Filter:",
" / Search (n=next, N=prev)",
@ -431,6 +431,9 @@ fn draw_help(f: &mut Frame, app: &App) {
"",
" Config: ~/.config/zfsdu/config.toml",
"",
" (c) Florian Schermer - DATAZONE GmbH",
" https://datazone.de",
"",
" Press any key to close",
];