Rewrite partition_source to return slices

This changes partition_source so that instead of allocating new strings,
it just returns slices into the original string. It probably doesn't
make a big difference perf-wise, but I felt more comfortable with this,
and also felt it was a little easier to understand exactly what it was
doing.

This is generally equivalent except for the possibility of not having a
newline at the end. In practice that doesn't matter because markdown
code blocks always have a newline. However, to be defensive, the caller
will check for this.
This commit is contained in:
Eric Huss 2025-09-15 18:40:54 -07:00
parent 09f05e8a86
commit c606a010c7

View file

@ -871,9 +871,16 @@ fn add_playground_pre(
code.into() code.into()
} else { } else {
// we need to inject our own main // we need to inject our own main
let (attrs, code) = partition_source(code); let (attrs, code) = partition_rust_source(code);
let newline = if code.is_empty() || code.ends_with('\n') {
format!("# #![allow(unused)]\n{attrs}# fn main() {{\n{code}# }}").into() ""
} else {
"\n"
};
format!(
"# #![allow(unused)]\n{attrs}# fn main() {{\n{code}{newline}# }}"
)
.into()
}; };
content content
} }
@ -980,25 +987,26 @@ fn hide_lines_with_prefix(content: &str, prefix: &str) -> String {
result result
} }
fn partition_source(s: &str) -> (String, String) { /// Splits Rust inner attributes from the given source string.
let mut after_header = false; ///
let mut before = String::new(); /// Returns `(inner_attrs, rest_of_code)`.
let mut after = String::new(); fn partition_rust_source(s: &str) -> (&str, &str) {
static_regex!(
for line in s.lines() { HEADER_RE,
let trimline = line.trim(); r"^(?mx)
let header = trimline.chars().all(char::is_whitespace) || trimline.starts_with("#!["); (
if !header || after_header { (?:
after_header = true; ^[ \t]*\#!\[.* (?:\r?\n)?
after.push_str(line); |
after.push('\n'); ^\s* (?:\r?\n)?
} else { )*
before.push_str(line); )"
before.push('\n'); );
} let split_idx = match HEADER_RE.captures(s) {
} Some(caps) => caps[1].len(),
None => 0,
(before, after) };
s.split_at(split_idx)
} }
struct RenderChapterContext<'a> { struct RenderChapterContext<'a> {
@ -1314,30 +1322,27 @@ mod tests {
} }
#[test] #[test]
fn partition_rust_source() { fn it_partitions_rust_source() {
assert_eq!(partition_source(""), ("".to_string(), "".to_string())); assert_eq!(partition_rust_source(""), ("", ""));
assert_eq!(partition_rust_source("let x = 1;"), ("", "let x = 1;"));
assert_eq!( assert_eq!(
partition_source("let x = 1;"), partition_rust_source("fn main()\n{ let x = 1; }\n"),
("".to_string(), "let x = 1;\n".to_string()) ("", "fn main()\n{ let x = 1; }\n")
); );
assert_eq!( assert_eq!(
partition_source("fn main()\n{ let x = 1; }\n"), partition_rust_source("#![allow(foo)]"),
("".to_string(), "fn main()\n{ let x = 1; }\n".to_string()) ("#![allow(foo)]", "")
); );
assert_eq!( assert_eq!(
partition_source("#![allow(foo)]"), partition_rust_source("#![allow(foo)]\n"),
("#![allow(foo)]\n".to_string(), "".to_string()) ("#![allow(foo)]\n", "")
); );
assert_eq!( assert_eq!(
partition_source("#![allow(foo)]\n"), partition_rust_source("#![allow(foo)]\nlet x = 1;"),
("#![allow(foo)]\n".to_string(), "".to_string()) ("#![allow(foo)]\n", "let x = 1;")
); );
assert_eq!( assert_eq!(
partition_source("#![allow(foo)]\nlet x = 1;"), partition_rust_source(
("#![allow(foo)]\n".to_string(), "let x = 1;\n".to_string())
);
assert_eq!(
partition_source(
"\n\ "\n\
#![allow(foo)]\n\ #![allow(foo)]\n\
\n\ \n\
@ -1345,10 +1350,7 @@ mod tests {
\n\ \n\
let x = 1;" let x = 1;"
), ),
( ("\n#![allow(foo)]\n\n#![allow(bar)]\n\n", "let x = 1;")
"\n#![allow(foo)]\n\n#![allow(bar)]\n\n".to_string(),
"let x = 1;\n".to_string()
)
); );
} }
} }