mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-13 20:53:07 +00:00
05e1212a50
Backends now have to send input to the given `chan::Sender<Event>`. They send these events from a separate thread, allowing selection between input and callbacks. This currently breaks the BearLibTerminal backend, which requires all calls to come from the UI thread. This might not be super-safe for the ncurses backend also. We hope that input and output are separate enough that they can run concurrently without problem.
138 lines
4.7 KiB
Rust
138 lines
4.7 KiB
Rust
extern crate cursive;
|
|
extern crate pretty_bytes;
|
|
|
|
use std::io;
|
|
|
|
use cursive::Cursive;
|
|
use cursive::traits::{Boxable, With};
|
|
use cursive::utils;
|
|
use cursive::views::{Canvas, Dialog, LinearLayout, ProgressBar};
|
|
use pretty_bytes::converter::convert;
|
|
use std::thread;
|
|
use std::time;
|
|
|
|
// This example is a visual version of the `pv` tool.
|
|
|
|
fn main() {
|
|
let mut siv = Cursive::default();
|
|
|
|
// We'll use this channel to signal the end of the transfer
|
|
let cb_sink = siv.cb_sink().clone();
|
|
|
|
// Use a counter to track progress
|
|
let counter = utils::Counter::new(0);
|
|
let counter_copy = counter.clone();
|
|
let start = time::Instant::now();
|
|
|
|
// If an argument is given, it is the file we'll read from.
|
|
// Else, read from stdin.
|
|
let (source, len) = match std::env::args().nth(1) {
|
|
Some(source) => {
|
|
let meta = std::fs::metadata(&source).unwrap();
|
|
// If possible, read the file size to have a progress bar.
|
|
let len = meta.len();
|
|
(
|
|
Some(source),
|
|
if len > 0 { Some(len) } else { None },
|
|
)
|
|
}
|
|
None => (None, None),
|
|
};
|
|
|
|
// Start the copy in a separate thread
|
|
thread::spawn(move || {
|
|
// Copy to stdout - lock it for better performance.
|
|
let stdout = io::stdout();
|
|
let mut stdout = stdout.lock();
|
|
|
|
match source {
|
|
None => {
|
|
// Copy from stdin - lock it for better performance.
|
|
let stdin = io::stdin();
|
|
let stdin = stdin.lock();
|
|
let mut reader =
|
|
utils::ProgressReader::new(counter_copy, stdin);
|
|
|
|
// And copy!
|
|
io::copy(&mut reader, &mut stdout).unwrap();
|
|
}
|
|
Some(source) => {
|
|
// Copy from stdin - lock it for better performance.
|
|
let input = std::fs::File::open(source).unwrap();
|
|
let mut reader =
|
|
utils::ProgressReader::new(counter_copy, input);
|
|
|
|
// And copy!
|
|
io::copy(&mut reader, &mut stdout).unwrap();
|
|
}
|
|
}
|
|
|
|
// When we're done, shut down the application
|
|
cb_sink.send(Box::new(|s: &mut Cursive| s.quit()));
|
|
});
|
|
|
|
// Add a single view: progress status
|
|
siv.add_layer(
|
|
Dialog::new().title("Copying...").content(
|
|
LinearLayout::vertical()
|
|
.child(
|
|
Canvas::new(counter.clone())
|
|
.with_draw(move |c, printer| {
|
|
let ticks = c.get() as f64;
|
|
let now = time::Instant::now();
|
|
let duration = now - start;
|
|
|
|
let seconds = duration.as_secs() as f64
|
|
+ duration.subsec_nanos() as f64 * 1e-9;
|
|
|
|
let speed = ticks / seconds;
|
|
|
|
// Print ETA if we have a file size
|
|
// Otherwise prints elapsed time.
|
|
if let Some(len) = len {
|
|
let remaining = (len as f64 - ticks) / speed;
|
|
printer.print(
|
|
(0, 0),
|
|
&format!(
|
|
"ETA: {:.1} seconds",
|
|
remaining
|
|
),
|
|
);
|
|
} else {
|
|
printer.print(
|
|
(0, 0),
|
|
&format!(
|
|
"Elapsed: {:.1} seconds",
|
|
seconds
|
|
),
|
|
);
|
|
}
|
|
printer.print(
|
|
(0, 1),
|
|
&format!("Copied: {}", convert(ticks)),
|
|
);
|
|
printer.print(
|
|
(0, 2),
|
|
&format!("Speed: {}/s", convert(speed)),
|
|
);
|
|
})
|
|
.fixed_size((25, 3)),
|
|
)
|
|
.with(|l| {
|
|
// If we have a file length, add a progress bar
|
|
if let Some(len) = len {
|
|
l.add_child(
|
|
ProgressBar::new()
|
|
.max(len as usize)
|
|
.with_value(counter.clone()),
|
|
);
|
|
}
|
|
}),
|
|
),
|
|
);
|
|
|
|
siv.set_fps(10);
|
|
|
|
siv.run();
|
|
}
|