use yog_ids::yui_markup::{BIND_CLOSE, BIND_OPEN};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Piece<'a> {
Text(&'a str),
Bind(&'a str),
}
pub fn pieces(attr: &str) -> Vec<Piece<'_>> {
let mut out = Vec::new();
let mut rest = attr;
while let Some(i) = rest.find(BIND_OPEN) {
let after = &rest[i + BIND_OPEN.len()..];
let Some(end) = after.find(BIND_CLOSE) else {
break;
};
if i > 0 {
out.push(Piece::Text(&rest[..i]));
}
out.push(Piece::Bind(after[..end].trim()));
rest = &after[end + BIND_CLOSE.len()..];
}
if !rest.is_empty() {
out.push(Piece::Text(rest));
}
out
}
pub fn names(attr: &str) -> impl Iterator<Item = &str> {
pieces(attr).into_iter().filter_map(|p| match p {
Piece::Bind(name) => Some(name),
Piece::Text(_) => None,
})
}
pub fn whole(attr: &str) -> Option<&str> {
let name = attr
.trim()
.strip_prefix(BIND_OPEN)?
.strip_suffix(BIND_CLOSE)?;
(!name.contains(BIND_CLOSE)).then(|| name.trim())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pieces_and_whole_bindings() {
assert_eq!(
pieces("{u|{x:Bind input}} → {x:Bind output }"),
[
Piece::Text("{u|"),
Piece::Bind("input"),
Piece::Text("} → "),
Piece::Bind("output")
]
);
assert_eq!(pieces("{x:Bind open"), [Piece::Text("{x:Bind open")]);
assert_eq!(whole(" {x:Bind patterns} "), Some("patterns"));
assert_eq!(whole("{x:Bind a}{x:Bind b}"), None);
}
}