11use crate :: CargoResult ;
22
3+ type Span = std:: ops:: Range < usize > ;
4+
35#[ derive( Debug ) ]
46pub struct ScriptSource < ' s > {
5- shebang : Option < & ' s str > ,
6- info : Option < & ' s str > ,
7- frontmatter : Option < & ' s str > ,
8- content : & ' s str ,
7+ raw : & ' s str ,
8+ shebang : Option < Span > ,
9+ info : Option < Span > ,
10+ frontmatter : Option < Span > ,
11+ content : Span ,
912}
1013
1114impl < ' s > ScriptSource < ' s > {
12- pub fn parse ( input : & ' s str ) -> CargoResult < Self > {
15+ pub fn parse ( raw : & ' s str ) -> CargoResult < Self > {
1316 use winnow:: stream:: FindSlice as _;
17+ use winnow:: stream:: Location as _;
18+ use winnow:: stream:: Offset as _;
1419 use winnow:: stream:: Stream as _;
1520
21+ let content_end = raw. len ( ) ;
1622 let mut source = Self {
23+ raw,
1724 shebang : None ,
1825 info : None ,
1926 frontmatter : None ,
20- content : input ,
27+ content : 0 ..content_end ,
2128 } ;
2229
23- let mut input = winnow:: stream:: LocatingSlice :: new ( input ) ;
30+ let mut input = winnow:: stream:: LocatingSlice :: new ( raw ) ;
2431
2532 if let Some ( shebang_end) = strip_shebang ( input. as_ref ( ) ) {
26- source. shebang = Some ( input. next_slice ( shebang_end) ) ;
27- source. content = input. as_ref ( ) ;
33+ let shebang_start = input. current_token_start ( ) ;
34+ let _ = input. next_slice ( shebang_end) ;
35+ let shebang_end = input. current_token_start ( ) ;
36+ source. shebang = Some ( shebang_start..shebang_end) ;
37+ source. content = shebang_end..content_end;
2838 }
2939
3040 // Whitespace may precede a frontmatter but must end with a newline
@@ -58,35 +68,37 @@ impl<'s> ScriptSource<'s> {
5868 let info = input. next_slice ( info_nl. start ) ;
5969 let info = info. trim_matches ( is_whitespace) ;
6070 if !info. is_empty ( ) {
61- source. info = Some ( info) ;
71+ let info_start = info. offset_from ( & raw ) ;
72+ let info_end = info_start + info. len ( ) ;
73+ source. info = Some ( info_start..info_end) ;
6274 }
6375
6476 // Ends with a line that starts with a matching number of `-` only followed by whitespace
6577 let nl_fence_pattern = format ! ( "\n {fence_pattern}" ) ;
6678 let Some ( frontmatter_nl) = input. find_slice ( nl_fence_pattern. as_str ( ) ) else {
6779 anyhow:: bail!( "no closing `{fence_pattern}` found for frontmatter" ) ;
6880 } ;
69- let frontmatter = input. next_slice ( frontmatter_nl. start + 1 ) ;
70- let frontmatter = frontmatter
71- . strip_prefix ( '\n' )
72- . expect ( "earlier `found` + `split_at` left us here" ) ;
73- source. frontmatter = Some ( frontmatter) ;
81+ let frontmatter_start = input. current_token_start ( ) + 1 ; // skip nl from infostring
82+ let _ = input. next_slice ( frontmatter_nl. start + 1 ) ;
83+ let frontmatter_end = input. current_token_start ( ) ;
84+ source. frontmatter = Some ( frontmatter_start..frontmatter_end) ;
7485 let _ = input. next_slice ( fence_length) ;
7586
7687 let nl = input. find_slice ( "\n " ) ;
7788 let after_closing_fence = input. next_slice (
7889 nl. map ( |span| span. end )
7990 . unwrap_or_else ( || input. eof_offset ( ) ) ,
8091 ) ;
92+ let content_start = input. current_token_start ( ) ;
8193 let after_closing_fence = after_closing_fence. trim_matches ( is_whitespace) ;
8294 if !after_closing_fence. is_empty ( ) {
8395 // extra characters beyond the original fence pattern, even if they are extra `-`
8496 anyhow:: bail!( "trailing characters found after frontmatter close" ) ;
8597 }
8698
87- source. content = input . finish ( ) ;
99+ source. content = content_start..content_end ;
88100
89- let repeat = Self :: parse ( source. content ) ?;
101+ let repeat = Self :: parse ( source. content ( ) ) ?;
90102 if repeat. frontmatter . is_some ( ) {
91103 anyhow:: bail!( "only one frontmatter is supported" ) ;
92104 }
@@ -95,19 +107,19 @@ impl<'s> ScriptSource<'s> {
95107 }
96108
97109 pub fn shebang ( & self ) -> Option < & ' s str > {
98- self . shebang
110+ self . shebang . clone ( ) . map ( |span| & self . raw [ span ] )
99111 }
100112
101113 pub fn info ( & self ) -> Option < & ' s str > {
102- self . info
114+ self . info . clone ( ) . map ( |span| & self . raw [ span ] )
103115 }
104116
105117 pub fn frontmatter ( & self ) -> Option < & ' s str > {
106- self . frontmatter
118+ self . frontmatter . clone ( ) . map ( |span| & self . raw [ span ] )
107119 }
108120
109121 pub fn content ( & self ) -> & ' s str {
110- self . content
122+ & self . raw [ self . content . clone ( ) ]
111123 }
112124}
113125
0 commit comments