mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-27 11:16:03 +00:00
Add ProgressReader
to the utils
module
Should allow to monitor a file download in a progress bar
This commit is contained in:
parent
24e4e41a85
commit
6e247efc1c
@ -1,8 +1,8 @@
|
|||||||
//! Toolbox to make text layout easier.
|
|
||||||
|
|
||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::UnicodeWidthStr;
|
||||||
use unicode_segmentation::UnicodeSegmentation;
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
|
|
||||||
|
use utils::prefix_length;
|
||||||
|
|
||||||
/// Generates rows of text in constrained width.
|
/// Generates rows of text in constrained width.
|
||||||
///
|
///
|
||||||
/// Given a long text and a width constraint, it iterates over
|
/// Given a long text and a width constraint, it iterates over
|
||||||
@ -91,56 +91,3 @@ impl<'a> Iterator for LinesIterator<'a> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes a sub-string length that fits in the given `width`.
|
|
||||||
///
|
|
||||||
/// Takes non-breakable elements from `iter`, while keeping the
|
|
||||||
/// string width under `width` (and adding the length of `delimiter`
|
|
||||||
/// between each element).
|
|
||||||
///
|
|
||||||
/// Given `total_text = iter.collect().join(delimiter)`, the result
|
|
||||||
/// is the length of the longest prefix of `width` or less cells,
|
|
||||||
/// without breaking inside an element.
|
|
||||||
///
|
|
||||||
/// Example:
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # extern crate cursive;
|
|
||||||
/// extern crate unicode_segmentation;
|
|
||||||
/// use unicode_segmentation::UnicodeSegmentation;
|
|
||||||
///
|
|
||||||
/// # use cursive::utils::prefix_length;
|
|
||||||
/// # fn main() {
|
|
||||||
/// let my_text = "blah...";
|
|
||||||
/// // This returns the number of bytes for a prefix of `my_text` that
|
|
||||||
/// // fits within 5 cells.
|
|
||||||
/// prefix_length(my_text.graphemes(true), 5, "");
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
pub fn prefix_length<'a, I: Iterator<Item = &'a str>>(iter: I, width: usize,
|
|
||||||
delimiter: &str)
|
|
||||||
-> usize {
|
|
||||||
let delimiter_width = delimiter.width();
|
|
||||||
let delimiter_len = delimiter.len();
|
|
||||||
|
|
||||||
let sum = iter.scan(0, |w, token| {
|
|
||||||
*w += token.width();
|
|
||||||
if *w > width {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
// Add a space
|
|
||||||
*w += delimiter_width;
|
|
||||||
Some(token)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.map(|token| token.len() + delimiter_len)
|
|
||||||
.fold(0, |a, b| a + b);
|
|
||||||
|
|
||||||
// We counted delimiter once too many times,
|
|
||||||
// but only if the iterator was non empty.
|
|
||||||
if sum == 0 {
|
|
||||||
sum
|
|
||||||
} else {
|
|
||||||
sum - delimiter_len
|
|
||||||
}
|
|
||||||
}
|
|
62
src/utils/mod.rs
Normal file
62
src/utils/mod.rs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
//! Toolbox to make text layout easier.
|
||||||
|
|
||||||
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
|
||||||
|
mod lines_iterator;
|
||||||
|
mod reader;
|
||||||
|
|
||||||
|
pub use self::lines_iterator::{LinesIterator, Row};
|
||||||
|
pub use self::reader::ProgressReader;
|
||||||
|
|
||||||
|
/// Computes a sub-string length that fits in the given `width`.
|
||||||
|
///
|
||||||
|
/// Takes non-breakable elements from `iter`, while keeping the
|
||||||
|
/// string width under `width` (and adding the length of `delimiter`
|
||||||
|
/// between each element).
|
||||||
|
///
|
||||||
|
/// Given `total_text = iter.collect().join(delimiter)`, the result
|
||||||
|
/// is the length of the longest prefix of `width` or less cells,
|
||||||
|
/// without breaking inside an element.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # extern crate cursive;
|
||||||
|
/// extern crate unicode_segmentation;
|
||||||
|
/// use unicode_segmentation::UnicodeSegmentation;
|
||||||
|
///
|
||||||
|
/// # use cursive::utils::prefix_length;
|
||||||
|
/// # fn main() {
|
||||||
|
/// let my_text = "blah...";
|
||||||
|
/// // This returns the number of bytes for a prefix of `my_text` that
|
||||||
|
/// // fits within 5 cells.
|
||||||
|
/// prefix_length(my_text.graphemes(true), 5, "");
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
pub fn prefix_length<'a, I: Iterator<Item = &'a str>>(iter: I, width: usize,
|
||||||
|
delimiter: &str)
|
||||||
|
-> usize {
|
||||||
|
let delimiter_width = delimiter.width();
|
||||||
|
let delimiter_len = delimiter.len();
|
||||||
|
|
||||||
|
let sum = iter.scan(0, |w, token| {
|
||||||
|
*w += token.width();
|
||||||
|
if *w > width {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
// Add a space
|
||||||
|
*w += delimiter_width;
|
||||||
|
Some(token)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(|token| token.len() + delimiter_len)
|
||||||
|
.fold(0, |a, b| a + b);
|
||||||
|
|
||||||
|
// We counted delimiter once too many times,
|
||||||
|
// but only if the iterator was non empty.
|
||||||
|
if sum == 0 {
|
||||||
|
sum
|
||||||
|
} else {
|
||||||
|
sum - delimiter_len
|
||||||
|
}
|
||||||
|
}
|
36
src/utils/reader.rs
Normal file
36
src/utils/reader.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
use std::io::{self, Read};
|
||||||
|
|
||||||
|
use views::Counter;
|
||||||
|
|
||||||
|
/// Wrapper around a `Read` that reports the progress made.
|
||||||
|
///
|
||||||
|
/// Used to monitor a file downloading or other slow IO task
|
||||||
|
/// in a progress bar.
|
||||||
|
pub struct ProgressReader<R: Read> {
|
||||||
|
reader: R,
|
||||||
|
counter: Counter,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<R: Read> ProgressReader<R> {
|
||||||
|
/// Creates a new `ProgressReader` around `reader`.
|
||||||
|
///
|
||||||
|
/// `counter` will be updated with the number of bytes read.
|
||||||
|
///
|
||||||
|
/// You should make sure the progress bar knows how
|
||||||
|
/// many bytes should be received.
|
||||||
|
pub fn new(counter: Counter, reader: R) -> Self {
|
||||||
|
ProgressReader {
|
||||||
|
reader: reader,
|
||||||
|
counter: counter,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: Read> Read for ProgressReader<R> {
|
||||||
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
|
let result = try!(self.reader.read(buf));
|
||||||
|
self.counter.tick(result);
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user