pub const WORD_BOUNDARY: &str = "\u{2581}";
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Prefix {
None,
Always,
WhenAbsent,
}
pub fn escape(text: &str, prefix: Prefix, collapse_runs: bool) -> String {
let mut out = String::with_capacity(text.len() + WORD_BOUNDARY.len());
let mut prev_space = false;
for ch in text.chars() {
if ch == ' ' {
if collapse_runs && prev_space {
continue;
}
prev_space = true;
out.push_str(WORD_BOUNDARY);
} else {
prev_space = false;
out.push(ch);
}
}
let prepend = match prefix {
Prefix::None => false,
Prefix::Always => true,
Prefix::WhenAbsent => !out.starts_with(WORD_BOUNDARY),
};
if prepend {
out.insert_str(0, WORD_BOUNDARY);
}
out
}
pub fn segments(escaped: &str) -> Vec<&str> {
let mut out = Vec::new();
let mut start = 0;
for (at, _) in escaped.match_indices(WORD_BOUNDARY) {
if let Some(segment) = escaped.get(start..at).filter(|s| !s.is_empty()) {
out.push(segment);
}
start = at;
}
if let Some(rest) = escaped.get(start..).filter(|s| !s.is_empty()) {
out.push(rest);
}
out
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn spaces_become_markers_and_are_never_dropped() {
assert_eq!(escape("a b", Prefix::None, false), "a▁b");
assert_eq!(escape(" ", Prefix::None, false), "▁");
assert_eq!(escape("a ", Prefix::None, false), "a▁");
}
#[test]
fn prefix_conventions_differ_on_an_already_marked_start() {
assert_eq!(escape(" a", Prefix::Always, false), "▁▁a");
assert_eq!(escape("a", Prefix::Always, false), "▁a");
assert_eq!(escape(" a", Prefix::WhenAbsent, false), "▁a");
assert_eq!(escape("a", Prefix::WhenAbsent, false), "▁a");
assert_eq!(escape("", Prefix::WhenAbsent, false), "▁");
assert_eq!(escape("", Prefix::None, false), "");
}
#[test]
fn collapsing_runs_merges_only_spaces() {
assert_eq!(escape("a b", Prefix::None, true), "a▁b");
assert_eq!(escape(" ", Prefix::WhenAbsent, true), "▁");
assert_eq!(escape(" ", Prefix::WhenAbsent, false), "▁▁▁");
assert_eq!(escape("a\n\nb", Prefix::None, true), "a\n\nb");
}
#[test]
fn segments_start_at_each_marker() {
assert_eq!(segments("▁a▁b"), vec!["▁a", "▁b"]);
assert_eq!(segments("▁a▁"), vec!["▁a", "▁"]);
assert_eq!(segments("▁"), vec!["▁"]);
assert_eq!(segments("▁▁a"), vec!["▁", "▁a"]);
assert_eq!(segments("a▁b"), vec!["a", "▁b"]);
assert!(segments("").is_empty());
assert_eq!(segments("abc"), vec!["abc"]);
}
}