use crate::utils::*;
use crate::Alignment;
use unicode_width::UnicodeWidthStr as UniW;
pub fn align<'a, TextwrapAlgo, TextwrapWordSep, TextwrapWordSplit, TextwrapOptions>(
text: &str,
alignment: Alignment,
width_or_options: TextwrapOptions,
) -> String
where
TextwrapAlgo: textwrap::wrap_algorithms::WrapAlgorithm,
TextwrapWordSep: textwrap::word_separators::WordSeparator,
TextwrapWordSplit: textwrap::word_splitters::WordSplitter,
TextwrapOptions: Into<textwrap::Options<'a, TextwrapAlgo, TextwrapWordSep, TextwrapWordSplit>>,
{
let options = width_or_options.into();
let width = options.width;
let wrapped = textwrap::wrap(text, options);
let mut wrapped_and_aligned = String::new();
for (i, line) in wrapped.iter().enumerate() {
let last_line = i == wrapped.len() - 1;
wrapped_and_aligned.push_str(&align_line(line, width, alignment, last_line));
if !last_line {
wrapped_and_aligned.push('\n');
}
}
return wrapped_and_aligned;
}
pub fn align_line(line: &str, width: usize, alignment: Alignment, last: bool) -> String {
let remaining = width - UniW::width(line);
match alignment {
Alignment::LEFT => String::from(line) + &" ".repeat(remaining),
Alignment::RIGHT => " ".repeat(remaining) + line,
Alignment::CENTER => {
let before = remaining / 2;
" ".repeat(before) + line + &" ".repeat(remaining - before)
}
Alignment::JUSTIFY => {
if last {
String::from(line) + &" ".repeat(remaining)
} else {
let mut words: Vec<&str> = line.split(" ").collect();
let spaces = split_evenly(words.len() + remaining - 1, words.len() - 1);
let mut aligned = if words.len() != 0 {
String::from(words.remove(0))
} else {
String::new()
};
if words.len() == 0 {
aligned.push_str(&" ".repeat(remaining));
} else {
for (word, spacing) in words.iter().zip(spaces) {
aligned.push_str(&" ".repeat(spacing));
aligned.push_str(word);
}
}
aligned
}
}
}
}