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;