use crate::console::Console;
use std::io;
fn refill(paragraph: &str, width: usize) -> Vec<String> {
if paragraph.is_empty() {
return vec!["".to_owned()];
}
let mut lines = vec![];
let mut line = String::new();
for word in paragraph.split_whitespace() {
if !line.is_empty() {
let spaces = if line.ends_with('.') {
let first = word.chars().next().expect("Words cannot be empty");
if first == first.to_ascii_uppercase() {
2
} else {
1
}
} else {
1
};
if (line.len() + word.len() + spaces) >= width {
lines.push(line);
line = String::new();
} else {
for _ in 0..spaces {
line.push(' ');
}
}
}
line.push_str(word);
}
if !line.is_empty() {
lines.push(line);
}
lines
}
pub(crate) fn refill_and_print(
console: &mut dyn Console,
paragraph: &str,
indent: &str,
) -> io::Result<()> {
let size = console.size()?;
let lines = refill(paragraph, usize::from(size.x) - 4 - indent.len());
for line in lines {
if line.is_empty() {
console.print("")?;
} else {
console.print(&format!("{}{}", indent, line))?;
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_refill_empty() {
assert_eq!(&[""], refill("", 0).as_slice());
assert_eq!(&[""], refill("", 10).as_slice());
}
#[test]
fn test_refill_nothing_fits() {
assert_eq!(&["this", "is", "some", "text"], refill("this is some text", 0).as_slice());
assert_eq!(&["this", "is", "some", "text"], refill("this is some text", 1).as_slice());
}
#[test]
fn test_refill_some_lines() {
assert_eq!(
&["this is a piece", "of text with", "a-fictitious-very-long-word", "within it"],
refill("this is a piece of text with a-fictitious-very-long-word within it", 16)
.as_slice()
);
}
#[test]
fn test_refill_reformats_periods() {
assert_eq!(&["foo. bar. baz."], refill("foo. bar. baz.", 100).as_slice());
assert_eq!(&["foo. Bar. baz."], refill("foo. Bar. baz.", 100).as_slice());
assert_eq!(&["[some .. range]"], refill("[some .. range]", 100).as_slice());
}
}