HW6BPTDUX4PDA6UI42KLQR4AMOG7FA3OWVABZE72TIUUNO5O4BSAC
fn walk<B: BufRead>(re: &Regex, file: B) -> String {
let mut tokens = String::new();
let t0 = std::io::Cursor::new("<template>");
let t1 = std::io::Cursor::new("</template>");
let config = ParserConfig::new()
.ignore_comments(false);
let parser = EventReader::new_with_config(t0.chain(file).chain(t1), config);
let mut level = 0;
for e in parser {
match e {
Ok(XmlEvent::StartElement { name, attributes, .. }) => {
if level == 0 {
// the "<template>" tag.
level += 1;
continue
}
level += 1;
let mut s = format!("<{}", name.local_name);
for attr in attributes.iter() {
write!(&mut s, " {}=\"{}\"", attr.name.local_name, attr.value).unwrap();
}
if name.local_name == "br" {
write!(&mut s, "/>").unwrap();
} else {
write!(&mut s, ">").unwrap();
#[derive(Clone)]
struct TokenPrinter {
result: String,
current: String,
re: Regex,
post_comment: bool,
}
impl TokenSink for TokenPrinter {
type Handle = ();
fn process_token(&mut self, token: Token, _line_number: u64) -> TokenSinkResult<()> {
match token {
CharacterTokens(contents) => {
if !self.post_comment || !contents.trim().is_empty() {
self.current.push_str(&contents);
self.post_comment = false;
// Replace {bla} with a formatting string.
let arguments = arguments(re, &s);
for args in arguments {
match args {
Arg::Text(t) => writeln!(tokens, "w.write_str({:?})?;", t).unwrap(),
Arg::Arg(a) => writeln!(tokens, "(\n{}\n).render_into(w)?;", a).unwrap(),
},
NullCharacterToken => {},
TagToken(tag) => {
// This is not proper HTML serialization, of course.
self.post_comment = false;
match tag.kind {
StartTag => {
write!(&mut self.current, "<{}", tag.name).unwrap();
}
EndTag => {
write!(&mut self.current, "</{}>", tag.name).unwrap();
tokens.push_str(&contents);
tokens.push_str("\n");
}
Ok(XmlEvent::Characters(contents)) => {
let arguments = arguments(re, &contents);
for args in arguments {
match args {
Arg::Text(t) => {
let re = regex::Regex::new(r"\s+").expect("regex");
let t = re.replace_all(t, " ");
writeln!(tokens, "w.write_str({:?})?;", t).unwrap()
},
Arg::Arg(a) => writeln!(tokens, "({}).render_into(w)?;", a).unwrap(),
}
}
}
Ok(XmlEvent::Whitespace(w)) => {
if !w.chars().any(|x| x == '\n') {
writeln!(tokens, r#"w.write_str(" ")?;"#).unwrap()
}
self.result.push_str("\n");
self.result.push_str(&contents);
self.result.push_str("\n");
self.post_comment = true;
fn walk(re: Regex, input: &str) -> String {
let mut sink = TokenPrinter {
post_comment: true,
re,
current: String::new(),
result: String::new(),
};
let mut chunk = StrTendril::try_from_byte_slice(input.as_bytes()).unwrap();
let mut input = BufferQueue::new();
input.push_back(chunk.try_reinterpret().unwrap());
let mut tok = Tokenizer::new(
sink,
TokenizerOpts::default(),
);
let _ = tok.feed(&mut input);
assert!(input.is_empty());
tok.end();
tok.sink.result
}
fn arguments<'a>(re: &Regex, s: &'a str) -> Vec<Arg<'a>> {
let mut arguments = Vec::new();
let mut start = 0;
for cap in re.captures_iter(s) {
debug!("cap = {:?}", cap);
if let Some(cap2) = cap.get(1) {
arguments.push(Arg::Text("{"));
start = cap2.end()
} else if let Some(cap2) = cap.get(2) {
arguments.push(Arg::Text("}"));
start = cap2.end()
} else if let Some(cap2) = cap.get(3) {
let (a, _) = s.split_at(cap2.end());
let (a, _) = a.split_at(cap2.start());
if cap2.start() > start {
arguments.push(Arg::Text(a.split_at(start).1))
impl TokenPrinter {
fn rollup(&mut self) {
if !self.current.is_empty() {
let args = Args {
start: 0,
caps: self.re.captures_iter(&self.current),
s: &self.current,
reserve: None,
finished: false,
};
for args in args {
match args {
Arg::Text(t) => {
let mut re = regex::Regex::new(r"\s+").expect("regex");
let t = re.replace_all(&t, " ");
writeln!(&mut self.result, "w.write_str({:?})?;", t).unwrap()
},
Arg::Arg(a) => writeln!(&mut self.result, "(\n{}\n).render_into(w)?;", a).unwrap(),
}
if start < s.len() {
arguments.push(Arg::Text(s.split_at(start).1))
}
impl<'a, 'b> Iterator for Args<'a, 'b> {
type Item = Arg<'b>;
fn next(&mut self) -> Option<Self::Item> {
if self.finished {
return None
}
if let Some(r) = self.reserve.take() {
return Some(r)
} else if let Some(cap) = self.caps.next() {
if let Some(cap2) = cap.get(1) {
return if cap2.start() > self.start {
let r = self.s.split_at(cap2.start()).0;
let r = r.split_at(self.start).1;
self.start = cap2.end();
self.reserve = Some(Arg::Text("{"));
Some(Arg::Text(r))
} else {
self.start = cap2.end();
Some(Arg::Text("{"))
}
} else if let Some(cap2) = cap.get(2) {
return if cap2.start() > self.start {
let r = self.s.split_at(cap2.start()).0;
let r = r.split_at(self.start).1;
self.start = cap2.end();
self.reserve = Some(Arg::Text("}"));
Some(Arg::Text(r))
} else {
self.start = cap2.end();
Some(Arg::Text("}"))
}
} else if let Some(cap2) = cap.get(3) {
let r = self.s.split_at(cap2.start()).0;
let r = r.split_at(self.start).1;
return if cap2.start() > self.start {
self.start = cap2.end();
self.reserve = Some(Arg::Arg(cap.get(4).unwrap().as_str()));
Some(Arg::Text(r))
} else {
self.start = cap2.end();
Some(Arg::Arg(cap.get(4).unwrap().as_str()))
}
}
}
if self.start < self.s.len() {
self.finished = true;
Some(Arg::Text(self.s.split_at(self.start).1))
} else {
None
}