2016-07-30 06:48:19 +00:00
|
|
|
//! Toolbox to make text layout easier.
|
|
|
|
|
2016-07-30 19:26:41 +00:00
|
|
|
use unicode_segmentation::UnicodeSegmentation;
|
2016-10-02 22:22:29 +00:00
|
|
|
use unicode_width::UnicodeWidthStr;
|
2016-07-30 06:48:19 +00:00
|
|
|
|
|
|
|
mod lines_iterator;
|
|
|
|
mod reader;
|
|
|
|
|
|
|
|
pub use self::lines_iterator::{LinesIterator, Row};
|
|
|
|
pub use self::reader::ProgressReader;
|
|
|
|
|
2017-02-01 19:22:36 +00:00
|
|
|
/// The length and width of a part of a string.
|
|
|
|
pub struct Prefix {
|
|
|
|
/// The length (in bytes) of the string.
|
|
|
|
pub length: usize,
|
|
|
|
/// The unicode-width of the string.
|
|
|
|
pub width: usize
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Computes the length (number of bytes) and width of a prefix that fits in the given `width`.
|
2016-07-30 06:48:19 +00:00
|
|
|
///
|
|
|
|
/// 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;
|
|
|
|
///
|
2017-02-01 19:22:36 +00:00
|
|
|
/// # use cursive::utils::prefix;
|
2016-07-30 06:48:19 +00:00
|
|
|
/// # fn main() {
|
|
|
|
/// let my_text = "blah...";
|
|
|
|
/// // This returns the number of bytes for a prefix of `my_text` that
|
|
|
|
/// // fits within 5 cells.
|
2017-02-01 19:22:36 +00:00
|
|
|
/// prefix(my_text.graphemes(true), 5, "");
|
2016-07-30 06:48:19 +00:00
|
|
|
/// # }
|
|
|
|
/// ```
|
2017-02-01 19:22:36 +00:00
|
|
|
pub fn prefix<'a, I>(iter: I, available_width: usize, delimiter: &str) -> Prefix
|
2016-07-30 22:58:52 +00:00
|
|
|
where I: Iterator<Item = &'a str>
|
2016-07-30 22:52:25 +00:00
|
|
|
{
|
2016-07-30 06:48:19 +00:00
|
|
|
let delimiter_width = delimiter.width();
|
|
|
|
let delimiter_len = delimiter.len();
|
|
|
|
|
2017-02-01 00:30:53 +00:00
|
|
|
let mut current_width = 0;
|
|
|
|
let sum = iter.take_while(|token| {
|
2017-03-06 14:32:03 +00:00
|
|
|
let needed_width = if current_width == 0 {
|
|
|
|
token.width()
|
|
|
|
} else {
|
|
|
|
// We also need to insert the delimiter, if not at the beginning.
|
|
|
|
token.width() + delimiter_width
|
|
|
|
};
|
|
|
|
if current_width + needed_width > available_width {
|
2017-02-01 00:30:53 +00:00
|
|
|
false
|
2016-07-30 06:48:19 +00:00
|
|
|
} else {
|
2017-03-06 14:32:03 +00:00
|
|
|
current_width += needed_width;
|
2017-02-01 00:30:53 +00:00
|
|
|
true
|
2016-07-30 06:48:19 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
.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.
|
2017-03-06 14:32:03 +00:00
|
|
|
let length = sum.saturating_sub(delimiter_len);
|
|
|
|
|
|
|
|
debug_assert!(current_width <= available_width);
|
2017-02-01 19:22:36 +00:00
|
|
|
|
|
|
|
Prefix {
|
|
|
|
length: length,
|
|
|
|
width: current_width
|
|
|
|
}
|
2016-07-30 06:48:19 +00:00
|
|
|
}
|
2016-07-30 19:26:41 +00:00
|
|
|
|
2017-02-01 19:22:36 +00:00
|
|
|
/// Computes the length (number of bytes) and width of a suffix that fits in the given `width`.
|
2016-07-30 19:26:41 +00:00
|
|
|
///
|
2016-07-30 22:52:25 +00:00
|
|
|
/// Doesn't break inside elements returned by `iter`.
|
|
|
|
///
|
2016-07-30 19:26:41 +00:00
|
|
|
/// Returns the number of bytes of the longest
|
|
|
|
/// suffix from `text` that fits in `width`.
|
2016-07-30 22:52:25 +00:00
|
|
|
///
|
|
|
|
/// This is a shortcut for `prefix_length(iter.rev(), width, delimiter)`
|
2017-02-01 19:22:36 +00:00
|
|
|
pub fn suffix<'a, I>(iter: I, width: usize, delimiter: &str) -> Prefix
|
2016-07-30 22:52:25 +00:00
|
|
|
where I: DoubleEndedIterator<Item = &'a str>
|
|
|
|
{
|
2017-02-01 19:22:36 +00:00
|
|
|
prefix(iter.rev(), width, delimiter)
|
2016-07-30 22:52:25 +00:00
|
|
|
}
|
|
|
|
|
2017-02-01 19:22:36 +00:00
|
|
|
/// Computes the length (number of bytes) and width of a suffix that fits in the given `width`.
|
2016-07-30 22:52:25 +00:00
|
|
|
///
|
|
|
|
/// Breaks between any two graphemes.
|
2017-02-01 19:22:36 +00:00
|
|
|
pub fn simple_suffix(text: &str, width: usize) -> Prefix {
|
|
|
|
suffix(text.graphemes(true), width, "")
|
2016-07-30 19:26:41 +00:00
|
|
|
}
|