use std::{
fmt::{self, Display, Formatter},
mem::take,
};
use anyhow::{bail, Context, Error};
enum Type
{
Bracket,
Paren,
Square,
Absolute,
Int,
}
enum Piece
{
String(Vec<char>),
ShortBracket(Type, Text),
}
struct Text
{
pieces: Vec<Piece>,
}
impl Display for Text
{
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error>
{
for piece in &self.pieces
{
match piece
{
Piece::String(s) => write!(f, "{}", s.iter().collect::<String>())?,
Piece::ShortBracket(Type::Bracket, text) => write!(f, "{{{text}}}")?,
Piece::ShortBracket(Type::Paren, text) => write!(f, "ł({text}¶)")?,
Piece::ShortBracket(Type::Square, text) => write!(f, "ł[{text}¶]")?,
Piece::ShortBracket(Type::Absolute, text) => write!(f, "ł|{text}¶|")?,
Piece::ShortBracket(Type::Int, text) => write!(f, "ł.{text}¶|")?,
}
}
Ok(())
}
}
fn parse_text(s: &[char]) -> Result<Text, Error>
{
let mut i = 0;
let mut current_string = vec![];
let mut pieces = vec![];
while i < s.len()
{
if "§¹²³¼½".contains(s[i])
{
if !current_string.is_empty()
{
pieces.push(Piece::String(take(&mut current_string)));
}
let length = match s[i]
{
'§' =>
{
i += 1;
s[i].to_digit(36).context("Not a digit for short bracket")? as usize
}
'¹' => 1,
'²' => 2,
'³' => 3,
'¼' => 4,
'½' => 5,
_ => unreachable!(),
};
i += 1;
let typ = match s[i]
{
' ' | '{' | '}' | 'c' => Type::Bracket,
'(' | ')' | 'p' => Type::Paren,
'[' | ']' | 'q' => Type::Square,
'|' | 'a' => Type::Absolute,
'.' | 'i' => Type::Int,
c => bail!("{c:?} isn't supported as a short bracket type"),
};
i += 1;
let inner_text = &s[i..(i + length)];
i += length;
pieces.push(Piece::ShortBracket(typ, parse_text(inner_text)?));
}
else
{
current_string.push(s[i]);
i += 1;
}
}
if !current_string.is_empty()
{
pieces.push(Piece::String(current_string));
}
Ok(Text { pieces })
}
pub fn add_short_brackets(s: &str) -> Result<String, Error>
{
Ok(format!(
"{}",
parse_text(&s.chars().collect::<Vec<_>>()).context("Couldn't resolve short bracketing")?
))
}
#[cfg(test)]
mod tests
{
use crate::shortbrackets::add_short_brackets;
#[test]
fn shortbrackets_integration_test()
{
let tests = vec![
("abcdefg", "abcdefg"),
("¹ abcdefg", "{a}bcdefg"),
("² abcdefg", "{ab}cdefg"),
("³ abcdefg", "{abc}defg"),
("¼ abcdefg", "{abcd}efg"),
("½ abcdefg", "{abcde}fg"),
("¬ abcdefg", "¬ abcdefg"),
("a¹ bcdefg", "a{b}cdefg"),
("a² bcdefg", "a{bc}defg"),
("a³ bcdefg", "a{bcd}efg"),
("a¼ bcdefg", "a{bcde}fg"),
("a½ bcdefg", "a{bcdef}g"),
("a¬ bcdefg", "a¬ bcdefg"),
("³pabcdefg", "ł(abc¶)defg"),
("a§9qbcdefghijklmnop", "ał[bcdefghij¶]klmnop"),
("abcdefgh²ijklmnop", "abcdefghł.jk¶|lmnop"),
];
for (input, output) in tests
{
assert_eq!(add_short_brackets(input).unwrap(), output);
}
}
}