diff options
Diffstat (limited to 'src/wrapping.rs')
-rw-r--r-- | src/wrapping.rs | 61 |
1 files changed, 42 insertions, 19 deletions
diff --git a/src/wrapping.rs b/src/wrapping.rs index 771d7f78..d9b0ff89 100644 --- a/src/wrapping.rs +++ b/src/wrapping.rs @@ -1,5 +1,6 @@ use syntect::highlighting::Style as SyntectStyle; use unicode_segmentation::UnicodeSegmentation; +use unicode_width::UnicodeWidthStr; use crate::cli; use crate::config::INLINE_SYMBOL_WIDTH_1; @@ -202,11 +203,21 @@ where let (style, text, graphemes) = stack .pop() - .map(|(style, text)| (style, text, text.grapheme_indices(true).collect::<Vec<_>>())) + .map(|(style, text)| { + ( + style, + text, + text.graphemes(true) + .map(|item| (item.len(), item.width())) + .collect::<Vec<_>>(), + ) + }) .unwrap(); - let new_len = curr_line.len + graphemes.len(); + let graphemes_width: usize = graphemes.iter().map(|(_, w)| w).sum(); + let new_len = curr_line.len + graphemes_width; + #[allow(clippy::comparison_chain)] let must_split = if new_len < line_width { curr_line.push_and_set_len((style, text), new_len); false @@ -228,15 +239,6 @@ where } _ => true, } - } else if new_len == line_width + 1 && stack.is_empty() { - // If the one overhanging char is '\n' then keep it on the current line. - if text.ends_with('\n') { - // Do not count the included '\n': - 1 - curr_line.push_and_set_len((style, text), new_len - 1); - false - } else { - true - } } else { true }; @@ -244,16 +246,29 @@ where // Text must be split, one part (or just `wrap_symbol`) is added to the // current line, the other is pushed onto the stack. if must_split { - let grapheme_split_pos = graphemes.len() - (new_len - line_width) - 1; + let mut width_left = graphemes_width + .saturating_sub(new_len - line_width) + .saturating_sub(wrap_config.left_symbol.width()); // The length does not matter anymore and `curr_line` will be reset // at the end, so move the line segments out. let mut line_segments = curr_line.line_segments; - let next_line = if grapheme_split_pos == 0 { + let next_line = if width_left == 0 { text } else { - let byte_split_pos = graphemes[grapheme_split_pos].0; + let mut byte_split_pos = 0; + // After loop byte_split_pos may still equal to 0. If width_left + // is less than the width of first character, We can't display it. + for &(item_len, item_width) in graphemes.iter() { + if width_left >= item_width { + byte_split_pos += item_len; + width_left -= item_width; + } else { + break; + } + } + let this_line = &text[..byte_split_pos]; line_segments.push((style, this_line)); &text[byte_split_pos..] @@ -273,7 +288,9 @@ where if result.len() == 1 && curr_line.has_text() { let current_permille = (curr_line.text_len() * 1000) / line_width; - let pad_len = line_width.saturating_sub(curr_line.text_len()); + // pad line will add a wrap_config.right_prefix_symbol + let pad_len = line_width + .saturating_sub(curr_line.text_len() + wrap_config.right_prefix_symbol.width()); if wrap_config.use_wrap_right_permille > current_permille && pad_len > 0 { // The inserted spaces, which align a line to the right, point into this string. @@ -785,7 +802,7 @@ mod tests { let lines = wrap_test(&cfg, line, 11); assert_eq!(lines.len(), 2); assert_eq!(lines[0].last().unwrap().1, WR); - assert_eq!(lines[1], [(*SD, " "), (*SD, ">"), (*S1, "ab")]); + assert_eq!(lines[1], [(*SD, " "), (*SD, ">"), (*S1, "ab")]); } #[test] @@ -801,7 +818,7 @@ mod tests { lines, vec![ vec![(*S1, "012"), (*S2, "34"), (*SD, WR)], - vec![(*SD, " "), (*SD, RA), (*S2, "56")] + vec![(*SD, " "), (*SD, RA), (*S2, "56")] ] ); } @@ -940,13 +957,19 @@ mod tests { ); // Not working: Tailored grapheme clusters: क्षि = क् + षि - let line = vec![(*S1, "abc"), (*S2, "deநி"), (*S1, "ghij")]; + // + // Difference compare to previous example (even they may look like the + // same width in text editor.) : + // + // width நி: 2 + // width ö̲: 1 + let line = vec![(*S1, "abc"), (*S2, "dநி"), (*S1, "ghij")]; let lines = wrap_test(&cfg, line, 4); assert_eq!( lines, vec![ vec![(*S1, "abc"), (*SD, W)], - vec![(*S2, "deநி"), (*SD, W)], + vec![(*S2, "dநி"), (*SD, W)], vec![(*S1, "ghij")] ] ); |