use std::io::Read;
use std::{env, process};
use sgmlish::transforms::Transform;
use sgmlish::{SgmlEvent, SgmlFragment};
fn main() {
if let Err(err) = run() {
eprintln!("🛑 {}", err);
process::exit(1);
}
}
fn run() -> sgmlish::Result<()> {
let parser = sgmlish::Parser::builder()
.expand_marked_sections()
.expand_entities(|entity| match entity {
"lt" => Some("<"),
"gt" => Some(">"),
"amp" => Some("&"),
"quot" => Some("\""),
"apos" => Some("'"),
_ => None,
})
.build();
let sgml = if let Some(path) = env::args_os().skip(1).next() {
std::fs::read_to_string(path).unwrap()
} else {
let mut buffer = String::new();
std::io::stdin().read_to_string(&mut buffer).unwrap();
buffer
};
let fragment = parser.parse(&sgml)?;
println!("ℹ️ Roundtrip:");
println!("{}", fragment);
println!();
println!("ℹ️ Events:");
for event in &fragment {
println!("{:?}", event);
}
println!();
let normalized = match sgmlish::transforms::normalize_end_tags(fragment.clone()) {
Ok(fragment) => fragment,
Err(err) => {
eprintln!("Error normalizing end tags:");
return Err(err.into());
}
};
if normalized != fragment {
println!("ℹ️ Inserting implied end tags:");
println!("{}", fragment);
println!();
}
println!("ℹ️ Pretty-printed:");
let fragment = reindent(normalized);
println!("{}", fragment);
println!();
Ok(())
}
fn reindent(fragment: SgmlFragment) -> SgmlFragment {
let mut transform = Transform::new();
let mut indent_level = 0;
fn indent(level: usize) -> SgmlEvent<'static> {
let mut s = "\n".to_owned();
for _ in 0..level {
s.push_str(" ");
}
SgmlEvent::Character(s.into())
}
let mut keep_same_line = 0;
for (i, event) in fragment.iter().enumerate().skip(1) {
if keep_same_line > 0 {
keep_same_line -= 1;
continue;
}
match event {
SgmlEvent::OpenStartTag { .. }
| SgmlEvent::Character(_)
| SgmlEvent::ProcessingInstruction(_)
| SgmlEvent::MarkupDeclaration { .. }
| SgmlEvent::MarkedSection { .. } => transform.insert_at(i, indent(indent_level)),
SgmlEvent::CloseStartTag => match &fragment.as_slice()[i + 1..] {
[SgmlEvent::EndTag { .. }, ..] => keep_same_line = 1,
[SgmlEvent::Character(_), SgmlEvent::EndTag { .. }, ..] => keep_same_line = 2,
_ => indent_level += 1,
},
SgmlEvent::EndTag { .. } => {
indent_level -= 1;
transform.insert_at(i, indent(indent_level));
}
SgmlEvent::Attribute { .. } | SgmlEvent::XmlCloseEmptyElement => {}
}
}
transform.apply(fragment)
}