use crate::utils::ColumnDisplayInfo;
#[cfg(feature = "custom_styling")]
mod custom_styling;
#[cfg(not(feature = "custom_styling"))]
mod normal;
#[cfg(feature = "custom_styling")]
pub use custom_styling::*;
#[cfg(not(feature = "custom_styling"))]
pub use normal::*;
pub fn split_line(line: &str, info: &ColumnDisplayInfo, delimiter: char) -> Vec<String> {
let mut lines = Vec::new();
let content_width = usize::from(info.content_width);
let mut elements = split_line_by_delimiter(line, delimiter);
elements.reverse();
let mut current_line = String::new();
while let Some(next) = elements.pop() {
let current_length = measure_text_width(¤t_line);
let next_length = measure_text_width(&next);
let mut added_length = next_length + current_length;
if !current_line.is_empty() {
added_length += 1;
}
let mut remaining_width = content_width - current_length;
if !current_line.is_empty() {
remaining_width = remaining_width.saturating_sub(1);
}
if added_length <= content_width {
if !current_line.is_empty() {
current_line.push(delimiter);
}
current_line += &next;
current_line = check_if_full(&mut lines, content_width, current_line);
continue;
}
if !current_line.is_empty() && remaining_width <= MIN_FREE_CHARS {
elements.push(next);
lines.push(current_line);
current_line = String::new();
continue;
}
if next_length > content_width {
let new_line = current_line.is_empty();
if !new_line {
current_line.push(delimiter);
}
let (mut next, mut remaining) = split_long_word(remaining_width, &next);
if new_line && next.is_empty() {
let mut chars = remaining.chars();
next.push(chars.next().unwrap());
remaining = chars.collect();
}
current_line += &next;
elements.push(remaining);
lines.push(current_line);
current_line = String::new();
continue;
}
lines.push(current_line);
current_line = next.to_string();
current_line = check_if_full(&mut lines, content_width, current_line);
}
if !current_line.is_empty() {
lines.push(current_line);
}
lines
}
const MIN_FREE_CHARS: usize = 2;
fn check_if_full(lines: &mut Vec<String>, content_width: usize, current_line: String) -> String {
if measure_text_width(¤t_line) > content_width.saturating_sub(MIN_FREE_CHARS) {
lines.push(current_line);
return String::new();
}
current_line
}
#[cfg(test)]
mod tests {
use unicode_width::UnicodeWidthStr;
use super::*;
#[test]
fn test_split_long_word() {
let emoji = "🙂↕️"; assert_eq!(emoji.len(), 13);
assert_eq!(emoji.chars().count(), 4);
assert_eq!(emoji.width(), 2);
let (word, remaining) = split_long_word(emoji.width(), emoji);
assert_eq!(word, "\u{1F642}\u{200D}\u{2195}\u{FE0F}");
assert_eq!(word.len(), 13);
assert_eq!(word.chars().count(), 4);
assert_eq!(word.width(), 2);
assert!(remaining.is_empty());
}
}