Skip to content

Commit

Permalink
preparing for displaying the marked state in entries list
Browse files Browse the repository at this point in the history
  • Loading branch information
Sebastian Thiel committed Jun 6, 2019
1 parent 53add13 commit 2f3f214
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 11 deletions.
7 changes: 7 additions & 0 deletions src/interactive/app/eventloop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ impl Default for FocussedPane {
}
}

pub struct EntryMark {
pub index: TreeIndex,
}

#[derive(Default)]
pub struct AppState {
pub root: TreeIndex,
Expand All @@ -33,6 +37,7 @@ pub struct AppState {
pub sorting: SortMode,
pub message: Option<String>,
pub focussed: FocussedPane,
pub marked: Vec<EntryMark>,
}

/// State and methods representing the interactive disk usage analyser for the terminal
Expand Down Expand Up @@ -109,6 +114,8 @@ impl TerminalApp {
},
FocussedPane::Main => match key {
Char('O') => self.open_that(),
Char(' ') => self.mark_entry(false),
Char('d') => self.mark_entry(true),
Char('u') | Backspace => self.exit_node(),
Char('o') | Char('\n') => self.enter_node(),
Ctrl('u') => self.change_entry_selection(CursorDirection::PageUp),
Expand Down
17 changes: 16 additions & 1 deletion src/interactive/app/handlers.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::interactive::{
app::{FocussedPane, TerminalApp},
app::{EntryMark, FocussedPane, TerminalApp},
sorted_entries,
widgets::HelpPane,
};
Expand Down Expand Up @@ -120,4 +120,19 @@ impl TerminalApp {
self.state.entries =
sorted_entries(&self.traversal.tree, self.state.root, self.state.sorting);
}

pub fn mark_entry(&mut self, advance_cursor: bool) {
if let Some(index) = self.state.selected {
if let Some((existing, _)) =
self.state.marked.iter().find_position(|e| e.index == index)
{
self.state.marked.remove(existing);
} else {
self.state.marked.push(EntryMark { index });
}
if advance_cursor {
self.change_entry_selection(CursorDirection::Down)
}
}
}
}
84 changes: 78 additions & 6 deletions src/interactive/app_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,7 @@ fn index_by_name_and_size(
.node_indices()
.map(|idx| (idx, node_by_index(app, idx)))
.filter_map(|(idx, e)| {
if e.name == name
&& match size {
Some(s) => s == e.size,
None => true,
}
{
if e.name == name && size.map(|s| s == e.size).unwrap_or(true) {
Some(idx)
} else {
None
Expand Down Expand Up @@ -129,13 +124,23 @@ fn simple_user_journey() -> Result<(), Error> {
SortMode::SizeAscending,
"it sets the sort mode to ascending by size"
);
assert_eq!(
node_by_index(&app, app.state.entries[0].index),
node_by_name(&app, fixture_str(long_root)),
"it recomputes the cached entries"
);
// when hitting the S key again
app.process_events(&mut terminal, b"s".keys())?;
assert_eq!(
app.state.sorting,
SortMode::SizeDescending,
"it sets the sort mode to descending by size"
);
assert_eq!(
node_by_index(&app, app.state.entries[0].index),
node_by_name(&app, fixture_str(short_root)),
"it recomputes the cached entries"
);
}

// Entry-Navigation
Expand Down Expand Up @@ -212,6 +217,73 @@ fn simple_user_journey() -> Result<(), Error> {
}
}

// Deletion
{
// when hitting the 'd' key (also move cursor back to start)
app.process_events(&mut terminal, b"k".keys())?;
let previously_selected_index = *app.state.selected.as_ref().unwrap();
app.process_events(&mut terminal, b"d".keys())?;
{
assert_eq!(1, app.state.marked.len(), "it marks only a single node",);
assert_eq!(
node_by_index(&app, previously_selected_index),
node_by_index(&app, app.state.marked[0].index),
"it marks the selected node"
);
assert_eq!(
app.state.selected.as_ref().unwrap().index(),
app.state.entries[1].index.index(),
"moves the cursor down one level to facilitate many markings in a row"
);
}

// when hitting the 'd' key again
{
app.process_events(&mut terminal, b"d".keys())?;

assert_eq!(
2,
app.state.marked.len(),
"it marks the currently selected, second node",
);

assert_eq!(
app.state.selected.as_ref().unwrap().index(),
app.state.entries[1].index.index(),
"it could not advance the cursor, thus the newly marked item is still selected"
);
}

// when hitting the 'd' key once again
{
app.process_events(&mut terminal, b"d".keys())?;

assert_eq!(
1,
app.state.marked.len(),
"it toggled the previous selected entry off",
);

assert_eq!(
node_by_index(&app, previously_selected_index),
node_by_index(&app, app.state.marked[0].index),
"it leaves the first selected entry marked"
);
}
// when hitting the spacebar (after moving up to the first entry)
{
app.process_events(&mut terminal, b"k ".keys())?;

assert_eq!(0, app.state.marked.len(), "it toggles the item off",);

assert_eq!(
node_by_index(&app, previously_selected_index),
node_by_index(&app, *app.state.selected.as_ref().unwrap()),
"it does not advance the selection"
);
}
}

Ok(())
}

Expand Down
5 changes: 4 additions & 1 deletion src/interactive/widgets/entries.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::interactive::{DisplayOptions, EntryDataBundle};
use crate::interactive::{DisplayOptions, EntryDataBundle, EntryMark};
use dua::traverse::{Tree, TreeIndex};
use itertools::Itertools;
use std::{borrow::Borrow, path::Path};
Expand All @@ -16,6 +16,7 @@ pub struct EntriesProps<'a> {
pub display: DisplayOptions,
pub selected: Option<TreeIndex>,
pub entries: &'a [EntryDataBundle],
pub marked: &'a [EntryMark],
pub border_style: Style,
pub is_focussed: bool,
}
Expand All @@ -38,6 +39,7 @@ impl Entries {
display,
entries,
selected,
marked: _,
border_style,
is_focussed,
} = props.borrow();
Expand Down Expand Up @@ -128,6 +130,7 @@ impl Entries {
.into(),
style,
);

let name = Text::Styled(
fill_background_to_right(
format!(
Expand Down
8 changes: 6 additions & 2 deletions src/interactive/widgets/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ use tui::widgets::{Paragraph, Text, Widget};
pub struct Header;

impl Header {
pub fn render(&self, area: Rect, buf: &mut Buffer) {
let bg_color = Color::LightYellow;
pub fn render(&self, has_marked_entries: bool, area: Rect, buf: &mut Buffer) {
let bg_color = if has_marked_entries {
Color::LightYellow
} else {
Color::White
};
let text_color = Color::Black;
let standard = Style {
fg: text_color,
Expand Down
3 changes: 2 additions & 1 deletion src/interactive/widgets/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,13 @@ impl MainWindow {
FocussedPane::Help => (grey, white),
};

Header.render(header_area, buf);
Header.render(!state.marked.is_empty(), header_area, buf);
let props = EntriesProps {
tree: &tree,
root: state.root,
display: *display,
entries: &state.entries,
marked: &state.marked,
selected: state.selected,
border_style: entries_style,
is_focussed: if let FocussedPane::Main = state.focussed {
Expand Down

0 comments on commit 2f3f214

Please sign in to comment.