1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
use super::widgets::{DisplayState, MainWindow};
use crate::{interactive::Traversal, sorted_entries, ByteFormat, WalkOptions, WalkResult};
use failure::Error;
use std::{io, path::PathBuf};
use termion::input::{Keys, TermReadEventsAndRaw};
use tui::widgets::Widget;
use tui::{backend::Backend, Terminal};
/// Options to configure how we display things
#[derive(Clone, Copy)]
pub struct DisplayOptions {
pub byte_format: ByteFormat,
}
impl From<WalkOptions> for DisplayOptions {
fn from(WalkOptions { byte_format, .. }: WalkOptions) -> Self {
DisplayOptions { byte_format }
}
}
/// State and methods representing the interactive disk usage analyser for the terminal
pub struct TerminalApp {
pub traversal: Traversal,
pub display: DisplayOptions,
pub state: DisplayState,
}
impl TerminalApp {
fn draw<B>(&self, terminal: &mut Terminal<B>) -> Result<(), Error>
where
B: Backend,
{
let Self {
traversal,
display,
state,
} = self;
terminal.draw(|mut f| {
let full_screen = f.size();
MainWindow {
traversal,
display: *display,
state: &state,
}
.render(&mut f, full_screen)
})?;
Ok(())
}
pub fn process_events<B, R>(
&mut self,
terminal: &mut Terminal<B>,
keys: Keys<R>,
) -> Result<WalkResult, Error>
where
B: Backend,
R: io::Read + TermReadEventsAndRaw,
{
use termion::event::Key::{Char, Ctrl};
self.draw(terminal)?;
for key in keys.filter_map(Result::ok) {
match key {
Char('s') => self.state.sorting.toggle_size(),
Ctrl('c') | Char('\n') | Char('q') => break,
_ => {}
};
self.draw(terminal)?;
}
Ok(WalkResult {
num_errors: self.traversal.io_errors,
})
}
pub fn initialize<B>(
terminal: &mut Terminal<B>,
options: WalkOptions,
input: Vec<PathBuf>,
) -> Result<TerminalApp, Error>
where
B: Backend,
{
let display_options: DisplayOptions = options.clone().into();
let traversal = Traversal::from_walk(options, input, move |traversal| {
terminal.draw(|mut f| {
let full_screen = f.size();
let state = DisplayState {
root: traversal.root_index,
selected: None,
sorting: Default::default(),
};
MainWindow {
traversal,
display: display_options,
state: &state,
}
.render(&mut f, full_screen)
})?;
Ok(())
})?;
let sorting = Default::default();
let root = traversal.root_index;
let selected = sorted_entries(&traversal.tree, root, sorting)
.next()
.map(|(idx, _)| idx);
Ok(TerminalApp {
state: DisplayState {
root,
selected,
sorting,
},
display: display_options,
traversal: traversal,
})
}
}
|