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
119
120
//! Compute lines on simple text.
//!
//! The input is a single `&str`.
//!
//! Computed rows will include start/end byte offsets in the input string.

mod lines_iterator;
mod row;

pub use self::lines_iterator::LinesIterator;
pub use self::row::Row;
use unicode_segmentation::UnicodeSegmentation;
use unicode_width::UnicodeWidthStr;

/// The length and width of a part of a string.
pub struct Span {
    /// The length (in bytes) of the string.
    pub length: usize,
    /// The unicode-width of the string.
    pub width: usize,
}

/// Compute lines for the given content and width.
///
/// Equivalent to constructing a new `LinesIterator` and collecting it.
pub fn make_lines(content: &str, width: usize) -> Vec<Row> {
    LinesIterator::new(content, width).collect()
}

/// Computes a prefix that fits in the given `width`.
///
/// Takes non-breakable elements from `iter`, while keeping the string width
/// under `width` (and adding `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:
///
/// ```
/// use unicode_segmentation::UnicodeSegmentation;
///
/// # use cursive::utils::lines::simple::prefix;
/// # fn main() {
/// let my_text = "blah...";
/// // This returns the number of bytes for a prefix of `my_text` that
/// // fits within 5 cells.
/// prefix(my_text.graphemes(true), 5, "");
/// # }
/// ```
pub fn prefix<'a, I>(iter: I, available_width: usize, delimiter: &str) -> Span
where
    I: Iterator<Item = &'a str>,
{
    let delimiter_width = delimiter.width();
    let delimiter_len = delimiter.len();

    // `current_width` is the width of everything
    // before the next token, including any space.
    let mut current_width = 0;
    let sum: usize = iter
        .take_while(|token| {
            let width = token.width();
            if current_width + width > available_width {
                false
            } else {
                // Include the delimiter after this token.
                current_width += width;
                current_width += delimiter_width;
                true
            }
        })
        .map(|token| token.len() + delimiter_len)
        .sum();

    // We counted delimiter once too many times,
    // but only if the iterator was non empty.
    let length = sum.saturating_sub(delimiter_len);

    // `current_width` includes a delimiter after the last token
    debug_assert!(current_width <= available_width + delimiter_width);

    Span {
        length,
        width: current_width,
    }
}

/// Computes the longest suffix that fits in the given `width`.
///
/// Doesn't break inside elements returned by `iter`.
///
/// Returns the number of bytes of the longest
/// suffix from `text` that fits in `width`.
///
/// This is a shortcut for `prefix_length(iter.rev(), width, delimiter)`
pub fn suffix<'a, I>(iter: I, width: usize, delimiter: &str) -> Span
where
    I: DoubleEndedIterator<Item = &'a str>,
{
    prefix(iter.rev(), width, delimiter)
}

/// Computes the longest suffix that fits in the given `width`.
///
/// Breaks between any two graphemes.
pub fn simple_suffix(text: &str, width: usize) -> Span {
    suffix(text.graphemes(true), width, "")
}

/// Computes the longest prefix that fits in the given width.
///
/// Breaks between any two graphemes.
pub fn simple_prefix(text: &str, width: usize) -> Span {
    prefix(text.graphemes(true), width, "")
}

#[cfg(test)]
mod tests;