@@ -146,59 +146,70 @@ impl<'s> ScriptSource<'s> {
146
146
source. content = content;
147
147
}
148
148
149
- const FENCE_CHAR : char = '-' ;
150
-
151
149
let mut rest = source. content ;
152
- while !rest. is_empty ( ) {
153
- let without_spaces = rest. trim_start_matches ( [ ' ' , '\t' ] ) ;
154
- let without_nl = without_spaces. trim_start_matches ( [ '\r' , '\n' ] ) ;
155
- if without_nl == rest {
156
- // nothing trimmed
157
- break ;
158
- } else if without_nl == without_spaces {
159
- // frontmatter must come after a newline
150
+
151
+ // Whitespace may precede a frontmatter but must end with a newline
152
+ const WHITESPACE : [ char ; 4 ] = [ ' ' , '\t' , '\r' , '\n' ] ;
153
+ let trimmed = rest. trim_start_matches ( WHITESPACE ) ;
154
+ if trimmed. len ( ) != rest. len ( ) {
155
+ let trimmed_len = rest. len ( ) - trimmed. len ( ) ;
156
+ let last_trimmed_index = trimmed_len - 1 ;
157
+ if rest. as_bytes ( ) [ last_trimmed_index] != b'\n' {
158
+ // either not a frontmatter or invalid opening
160
159
return Ok ( source) ;
161
160
}
162
- rest = without_nl;
163
161
}
164
- let fence_end = rest
162
+ rest = trimmed;
163
+
164
+ // Opens with a line that starts with 3 or more `-` followed by an optional identifier
165
+ const FENCE_CHAR : char = '-' ;
166
+ let fence_length = rest
165
167
. char_indices ( )
166
168
. find_map ( |( i, c) | ( c != FENCE_CHAR ) . then_some ( i) )
167
- . unwrap_or ( source . content . len ( ) ) ;
168
- let ( fence_pattern , rest ) = match fence_end {
169
+ . unwrap_or ( rest . len ( ) ) ;
170
+ match fence_length {
169
171
0 => {
170
172
return Ok ( source) ;
171
173
}
172
174
1 | 2 => {
175
+ // either not a frontmatter or invalid frontmatter opening
173
176
anyhow:: bail!(
174
- "found {fence_end } `{FENCE_CHAR}` in rust frontmatter, expected at least 3"
177
+ "found {fence_length } `{FENCE_CHAR}` in rust frontmatter, expected at least 3"
175
178
)
176
179
}
177
- _ => rest. split_at ( fence_end) ,
180
+ _ => { }
181
+ }
182
+ let ( fence_pattern, rest) = rest. split_at ( fence_length) ;
183
+ let Some ( info_end_index) = rest. find ( '\n' ) else {
184
+ anyhow:: bail!( "no closing `{fence_pattern}` found for frontmatter" ) ;
178
185
} ;
179
- let nl_fence_pattern = format ! ( "\n {fence_pattern}" ) ;
180
- let ( info, content) = rest. split_once ( "\n " ) . unwrap_or ( ( rest, "" ) ) ;
181
- let info = info. trim ( ) ;
186
+ let ( info, rest) = rest. split_at ( info_end_index) ;
187
+ let info = info. trim_matches ( WHITESPACE ) ;
182
188
if !info. is_empty ( ) {
183
189
source. info = Some ( info) ;
184
190
}
185
- source. content = content;
191
+ let rest = rest
192
+ . strip_prefix ( '\n' )
193
+ . expect ( "earlier `found` + `split_at` left us here" ) ;
186
194
187
- let Some ( frontmatter_nl) = source. content . find ( & nl_fence_pattern) else {
195
+ // Ends with a line that starts with a matching number of `-` only followed by whitespace
196
+ let nl_fence_pattern = format ! ( "\n {fence_pattern}" ) ;
197
+ let Some ( frontmatter_nl) = rest. find ( & nl_fence_pattern) else {
188
198
anyhow:: bail!( "no closing `{fence_pattern}` found for frontmatter" ) ;
189
199
} ;
190
- source. frontmatter = Some ( & source. content [ ..frontmatter_nl + 1 ] ) ;
191
- source. content = & source. content [ frontmatter_nl + nl_fence_pattern. len ( ) ..] ;
192
-
193
- let ( line, content) = source
194
- . content
195
- . split_once ( "\n " )
196
- . unwrap_or ( ( source. content , "" ) ) ;
197
- let line = line. trim ( ) ;
198
- if !line. is_empty ( ) {
199
- anyhow:: bail!( "unexpected trailing content on closing fence: `{line}`" ) ;
200
+ let frontmatter = & rest[ ..frontmatter_nl + 1 ] ;
201
+ let rest = & rest[ frontmatter_nl + nl_fence_pattern. len ( ) ..] ;
202
+ source. frontmatter = Some ( frontmatter) ;
203
+
204
+ let ( after_closing_fence, rest) = rest. split_once ( "\n " ) . unwrap_or ( ( rest, "" ) ) ;
205
+ let after_closing_fence = after_closing_fence. trim_matches ( WHITESPACE ) ;
206
+ if !after_closing_fence. is_empty ( ) {
207
+ // extra characters beyond the original fence pattern, even if they are extra `-`
208
+ anyhow:: bail!( "trailing characters found after frontmatter close" ) ;
200
209
}
201
- source. content = content;
210
+
211
+ let frontmatter_len = input. len ( ) - rest. len ( ) ;
212
+ source. content = & input[ frontmatter_len..] ;
202
213
203
214
Ok ( source)
204
215
}
@@ -534,7 +545,7 @@ content: "\n// infostrings can only be a single identifier.\n\nfn main() {}\n"
534
545
fn main() {}
535
546
"# ,
536
547
) ,
537
- str![ "unexpected trailing content on closing fence: `-` " ] ,
548
+ str![ "trailing characters found after frontmatter close " ] ,
538
549
) ;
539
550
}
540
551
@@ -973,7 +984,7 @@ content: "\nfn main() {}\n"
973
984
fn main() {}
974
985
"# ,
975
986
) ,
976
- str![ "unexpected trailing content on closing fence: `--` " ] ,
987
+ str![ "trailing characters found after frontmatter close " ] ,
977
988
) ;
978
989
}
979
990
@@ -1010,7 +1021,7 @@ time="0.1.25"
1010
1021
fn main() {}
1011
1022
"# ,
1012
1023
) ,
1013
- str![ "unexpected trailing content on closing fence: `-` " ] ,
1024
+ str![ "trailing characters found after frontmatter close " ] ,
1014
1025
) ;
1015
1026
}
1016
1027
0 commit comments