@@ -21,7 +21,7 @@ pub(super) fn expand_manifest(
21
21
path : & std:: path:: Path ,
22
22
gctx : & GlobalContext ,
23
23
) -> CargoResult < String > {
24
- let source = split_source ( content) ?;
24
+ let source = ScriptSource :: parse ( content) ?;
25
25
if let Some ( frontmatter) = source. frontmatter {
26
26
match source. info {
27
27
Some ( "cargo" ) | None => { }
@@ -196,87 +196,89 @@ struct ScriptSource<'s> {
196
196
content : & ' s str ,
197
197
}
198
198
199
- fn split_source ( input : & str ) -> CargoResult < ScriptSource < ' _ > > {
200
- let mut source = ScriptSource {
201
- shebang : None ,
202
- info : None ,
203
- frontmatter : None ,
204
- content : input,
205
- } ;
199
+ impl < ' s > ScriptSource < ' s > {
200
+ fn parse ( input : & ' s str ) -> CargoResult < Self > {
201
+ let mut source = Self {
202
+ shebang : None ,
203
+ info : None ,
204
+ frontmatter : None ,
205
+ content : input,
206
+ } ;
207
+
208
+ // See rust-lang/rust's compiler/rustc_lexer/src/lib.rs's `strip_shebang`
209
+ // Shebang must start with `#!` literally, without any preceding whitespace.
210
+ // For simplicity we consider any line starting with `#!` a shebang,
211
+ // regardless of restrictions put on shebangs by specific platforms.
212
+ if let Some ( rest) = source. content . strip_prefix ( "#!" ) {
213
+ // Ok, this is a shebang but if the next non-whitespace token is `[`,
214
+ // then it may be valid Rust code, so consider it Rust code.
215
+ if rest. trim_start ( ) . starts_with ( '[' ) {
216
+ return Ok ( source) ;
217
+ }
206
218
207
- // See rust-lang/rust's compiler/rustc_lexer/src/lib.rs's `strip_shebang`
208
- // Shebang must start with `#!` literally, without any preceding whitespace.
209
- // For simplicity we consider any line starting with `#!` a shebang,
210
- // regardless of restrictions put on shebangs by specific platforms.
211
- if let Some ( rest ) = source . content . strip_prefix ( "#!" ) {
212
- // Ok, this is a shebang but if the next non-whitespace token is `[`,
213
- // then it may be valid Rust code, so consider it Rust code.
214
- if rest . trim_start ( ) . starts_with ( '[' ) {
215
- return Ok ( source) ;
219
+ // No other choice than to consider this a shebang.
220
+ let newline_end = source
221
+ . content
222
+ . find ( '\n' )
223
+ . map ( |pos| pos + 1 )
224
+ . unwrap_or ( source . content . len ( ) ) ;
225
+ let ( shebang , content ) = source . content . split_at ( newline_end ) ;
226
+ source . shebang = Some ( shebang ) ;
227
+ source. content = content ;
216
228
}
217
229
218
- // No other choice than to consider this a shebang.
219
- let newline_end = source
220
- . content
221
- . find ( '\n' )
222
- . map ( |pos| pos + 1 )
230
+ const FENCE_CHAR : char = '-' ;
231
+
232
+ let mut trimmed_content = source. content ;
233
+ while !trimmed_content. is_empty ( ) {
234
+ let c = trimmed_content;
235
+ let c = c. trim_start_matches ( [ ' ' , '\t' ] ) ;
236
+ let c = c. trim_start_matches ( [ '\r' , '\n' ] ) ;
237
+ if c == trimmed_content {
238
+ break ;
239
+ }
240
+ trimmed_content = c;
241
+ }
242
+ let fence_end = trimmed_content
243
+ . char_indices ( )
244
+ . find_map ( |( i, c) | ( c != FENCE_CHAR ) . then_some ( i) )
223
245
. unwrap_or ( source. content . len ( ) ) ;
224
- let ( shebang, content) = source. content . split_at ( newline_end) ;
225
- source. shebang = Some ( shebang) ;
246
+ let ( fence_pattern, rest) = match fence_end {
247
+ 0 => {
248
+ return Ok ( source) ;
249
+ }
250
+ 1 | 2 => {
251
+ anyhow:: bail!(
252
+ "found {fence_end} `{FENCE_CHAR}` in rust frontmatter, expected at least 3"
253
+ )
254
+ }
255
+ _ => trimmed_content. split_at ( fence_end) ,
256
+ } ;
257
+ let ( info, content) = rest. split_once ( "\n " ) . unwrap_or ( ( rest, "" ) ) ;
258
+ let info = info. trim ( ) ;
259
+ if !info. is_empty ( ) {
260
+ source. info = Some ( info) ;
261
+ }
226
262
source. content = content;
227
- }
228
263
229
- const FENCE_CHAR : char = '-' ;
264
+ let Some ( ( frontmatter, content) ) = source. content . split_once ( fence_pattern) else {
265
+ anyhow:: bail!( "no closing `{fence_pattern}` found for frontmatter" ) ;
266
+ } ;
267
+ source. frontmatter = Some ( frontmatter) ;
268
+ source. content = content;
230
269
231
- let mut trimmed_content = source. content ;
232
- while !trimmed_content. is_empty ( ) {
233
- let c = trimmed_content;
234
- let c = c. trim_start_matches ( [ ' ' , '\t' ] ) ;
235
- let c = c. trim_start_matches ( [ '\r' , '\n' ] ) ;
236
- if c == trimmed_content {
237
- break ;
238
- }
239
- trimmed_content = c;
240
- }
241
- let fence_end = trimmed_content
242
- . char_indices ( )
243
- . find_map ( |( i, c) | ( c != FENCE_CHAR ) . then_some ( i) )
244
- . unwrap_or ( source. content . len ( ) ) ;
245
- let ( fence_pattern, rest) = match fence_end {
246
- 0 => {
247
- return Ok ( source) ;
248
- }
249
- 1 | 2 => {
250
- anyhow:: bail!(
251
- "found {fence_end} `{FENCE_CHAR}` in rust frontmatter, expected at least 3"
252
- )
270
+ let ( line, content) = source
271
+ . content
272
+ . split_once ( "\n " )
273
+ . unwrap_or ( ( source. content , "" ) ) ;
274
+ let line = line. trim ( ) ;
275
+ if !line. is_empty ( ) {
276
+ anyhow:: bail!( "unexpected trailing content on closing fence: `{line}`" ) ;
253
277
}
254
- _ => trimmed_content. split_at ( fence_end) ,
255
- } ;
256
- let ( info, content) = rest. split_once ( "\n " ) . unwrap_or ( ( rest, "" ) ) ;
257
- let info = info. trim ( ) ;
258
- if !info. is_empty ( ) {
259
- source. info = Some ( info) ;
260
- }
261
- source. content = content;
278
+ source. content = content;
262
279
263
- let Some ( ( frontmatter, content) ) = source. content . split_once ( fence_pattern) else {
264
- anyhow:: bail!( "no closing `{fence_pattern}` found for frontmatter" ) ;
265
- } ;
266
- source. frontmatter = Some ( frontmatter) ;
267
- source. content = content;
268
-
269
- let ( line, content) = source
270
- . content
271
- . split_once ( "\n " )
272
- . unwrap_or ( ( source. content , "" ) ) ;
273
- let line = line. trim ( ) ;
274
- if !line. is_empty ( ) {
275
- anyhow:: bail!( "unexpected trailing content on closing fence: `{line}`" ) ;
280
+ Ok ( source)
276
281
}
277
- source. content = content;
278
-
279
- Ok ( source)
280
282
}
281
283
282
284
#[ cfg( test) ]
@@ -291,7 +293,7 @@ mod test_expand {
291
293
fn assert_source ( source : & str , expected : impl IntoData ) {
292
294
use std:: fmt:: Write as _;
293
295
294
- let actual = match split_source ( source) {
296
+ let actual = match ScriptSource :: parse ( source) {
295
297
Ok ( actual) => actual,
296
298
Err ( err) => panic ! ( "unexpected err: {err}" ) ,
297
299
} ;
@@ -497,7 +499,7 @@ content: "\nfn main() {}"
497
499
#[ test]
498
500
fn split_too_few_dashes ( ) {
499
501
assert_err (
500
- split_source (
502
+ ScriptSource :: parse (
501
503
r#"#!/usr/bin/env cargo
502
504
--
503
505
[dependencies]
@@ -513,7 +515,7 @@ fn main() {}
513
515
#[ test]
514
516
fn split_mismatched_dashes ( ) {
515
517
assert_err (
516
- split_source (
518
+ ScriptSource :: parse (
517
519
r#"#!/usr/bin/env cargo
518
520
---
519
521
[dependencies]
@@ -529,7 +531,7 @@ fn main() {}
529
531
#[ test]
530
532
fn split_missing_close ( ) {
531
533
assert_err (
532
- split_source (
534
+ ScriptSource :: parse (
533
535
r#"#!/usr/bin/env cargo
534
536
---
535
537
[dependencies]
0 commit comments