From 3184f03ef3026f6687e06ec32dd9308775d68e3a Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 25 Aug 2025 16:30:26 -0500 Subject: [PATCH] refactor(frontmatter): Switch to winnow --- Cargo.lock | 1 + Cargo.toml | 2 ++ src/cargo/util/frontmatter.rs | 44 ++++++++++++++++++++--------------- 3 files changed, 28 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c401a80c8..9adf1b1f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -399,6 +399,7 @@ dependencies = [ "url", "walkdir", "windows-sys 0.60.2", + "winnow", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 4684ef0ec..c2e4976cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -118,6 +118,7 @@ url = "2.5.4" varisat = "0.2.2" walkdir = "2.5.0" windows-sys = "0.60" +winnow = "0.7.13" [workspace.lints.rust] rust_2018_idioms = "warn" # TODO: could this be removed? @@ -220,6 +221,7 @@ unicode-width.workspace = true unicode-xid.workspace = true url.workspace = true walkdir.workspace = true +winnow.workspace = true [target.'cfg(target_has_atomic = "64")'.dependencies] tracing-chrome.workspace = true diff --git a/src/cargo/util/frontmatter.rs b/src/cargo/util/frontmatter.rs index 022973035..3abb4f6d1 100644 --- a/src/cargo/util/frontmatter.rs +++ b/src/cargo/util/frontmatter.rs @@ -10,6 +10,9 @@ pub struct ScriptSource<'s> { impl<'s> ScriptSource<'s> { pub fn parse(input: &'s str) -> CargoResult { + use winnow::stream::FindSlice as _; + use winnow::stream::Stream as _; + let mut source = Self { shebang: None, info: None, @@ -17,25 +20,25 @@ impl<'s> ScriptSource<'s> { content: input, }; - if let Some(shebang_end) = strip_shebang(source.content) { - let (shebang, content) = source.content.split_at(shebang_end); - source.shebang = Some(shebang); - source.content = content; + let mut input = winnow::stream::LocatingSlice::new(input); + + if let Some(shebang_end) = strip_shebang(input.as_ref()) { + source.shebang = Some(input.next_slice(shebang_end)); + source.content = input.as_ref(); } - let mut rest = source.content; - // Whitespace may precede a frontmatter but must end with a newline - if let Some(nl_end) = strip_ws_lines(rest) { - rest = &rest[nl_end..]; + if let Some(nl_end) = strip_ws_lines(input.as_ref()) { + let _ = input.next_slice(nl_end); } // Opens with a line that starts with 3 or more `-` followed by an optional identifier const FENCE_CHAR: char = '-'; - let fence_length = rest + let fence_length = input + .as_ref() .char_indices() .find_map(|(i, c)| (c != FENCE_CHAR).then_some(i)) - .unwrap_or(rest.len()); + .unwrap_or_else(|| input.eof_offset()); match fence_length { 0 => { return Ok(source); @@ -48,11 +51,11 @@ impl<'s> ScriptSource<'s> { } _ => {} } - let (fence_pattern, rest) = rest.split_at(fence_length); - let Some(info_end_index) = rest.find('\n') else { + let fence_pattern = input.next_slice(fence_length); + let Some(info_nl) = input.find_slice("\n") else { anyhow::bail!("no closing `{fence_pattern}` found for frontmatter"); }; - let (info, rest) = rest.split_at(info_end_index); + let info = input.next_slice(info_nl.start); let info = info.trim_matches(is_whitespace); if !info.is_empty() { source.info = Some(info); @@ -60,25 +63,28 @@ impl<'s> ScriptSource<'s> { // Ends with a line that starts with a matching number of `-` only followed by whitespace let nl_fence_pattern = format!("\n{fence_pattern}"); - let Some(frontmatter_nl) = rest.find(&nl_fence_pattern) else { + let Some(frontmatter_nl) = input.find_slice(nl_fence_pattern.as_str()) else { anyhow::bail!("no closing `{fence_pattern}` found for frontmatter"); }; - let frontmatter = &rest[..frontmatter_nl + 1]; + let frontmatter = input.next_slice(frontmatter_nl.start + 1); let frontmatter = frontmatter .strip_prefix('\n') .expect("earlier `found` + `split_at` left us here"); source.frontmatter = Some(frontmatter); - let rest = &rest[frontmatter_nl + nl_fence_pattern.len()..]; + let _ = input.next_slice(fence_length); - let (after_closing_fence, rest) = rest.split_once("\n").unwrap_or((rest, "")); + let nl = input.find_slice("\n"); + let after_closing_fence = input.next_slice( + nl.map(|span| span.end) + .unwrap_or_else(|| input.eof_offset()), + ); let after_closing_fence = after_closing_fence.trim_matches(is_whitespace); if !after_closing_fence.is_empty() { // extra characters beyond the original fence pattern, even if they are extra `-` anyhow::bail!("trailing characters found after frontmatter close"); } - let frontmatter_len = input.len() - rest.len(); - source.content = &input[frontmatter_len..]; + source.content = input.finish(); let repeat = Self::parse(source.content)?; if repeat.frontmatter.is_some() {