"#,
before = before,
classes = classes,
after = after
)
})
.into_owned()
}
fn add_playpen_pre(html: &str, playpen_config: &Playpen) -> String {
let regex = Regex::new(r##"((?s)]?class="([^"]+)".*?>(.*?)
)"##).unwrap();
regex
.replace_all(html, |caps: &Captures| {
let text = &caps[1];
let classes = &caps[2];
let code = &caps[3];
if (classes.contains("language-rust") && !classes.contains("ignore"))
|| classes.contains("mdbook-runnable")
{
// wrap the contents in an external pre block
if playpen_config.editable && classes.contains("editable")
|| text.contains("fn main")
|| text.contains("quick_main!")
{
format!("{}
", text)
} else {
// we need to inject our own main
let (attrs, code) = partition_source(code);
format!(
"\n# \
#![allow(unused_variables)]\n{}#fn main() {{\n{}#}}
",
classes, attrs, code
)
}
} else {
// not language-rust, so no-op
text.to_owned()
}
})
.into_owned()
}
fn partition_source(s: &str) -> (String, String) {
let mut after_header = false;
let mut before = String::new();
let mut after = String::new();
for line in s.lines() {
let trimline = line.trim();
let header = trimline.chars().all(|c| c.is_whitespace()) || trimline.starts_with("#![");
if !header || after_header {
after_header = true;
after.push_str(line);
after.push_str("\n");
} else {
before.push_str(line);
before.push_str("\n");
}
}
(before, after)
}
struct RenderItemContext<'a> {
handlebars: &'a Handlebars,
destination: PathBuf,
data: serde_json::Map,
is_index: bool,
html_config: HtmlConfig,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn original_build_header_links() {
let inputs = vec![
(
"blah blah Foo
",
r##"blah blah "##,
),
(
"Foo
",
r##""##,
),
(
"Foo^bar
",
r##""##,
),
(
"",
r##""##,
),
(
"Hï
",
r##""##,
),
(
"Foo
Foo
",
r##""##,
),
];
for (src, should_be) in inputs {
let got = build_header_links(&src);
assert_eq!(got, should_be);
}
}
}