1+ use djls_source:: Span ;
2+
13use crate :: db:: Db as TemplateDb ;
24use crate :: tokens:: Token ;
35use crate :: tokens:: TokenContent ;
6+ use crate :: tokens:: TokenSpans ;
47
58const BLOCK_TAG_START : & str = "{%" ;
69const BLOCK_TAG_END : & str = "%}" ;
@@ -35,14 +38,14 @@ impl<'db> Lexer<'db> {
3538
3639 let token = match self . peek ( ) {
3740 '{' => match self . peek_next ( ) {
38- '%' => self . lex_django_construct ( BLOCK_TAG_END , |content, offset | {
39- Token :: Block { content, offset }
41+ '%' => self . lex_django_construct ( BLOCK_TAG_END , |content, spans | {
42+ Token :: Block { content, spans }
4043 } ) ,
41- '{' => self . lex_django_construct ( VARIABLE_TAG_END , |content, offset | {
42- Token :: Variable { content, offset }
44+ '{' => self . lex_django_construct ( VARIABLE_TAG_END , |content, spans | {
45+ Token :: Variable { content, spans }
4346 } ) ,
44- '#' => self . lex_django_construct ( COMMENT_TAG_END , |content, offset | {
45- Token :: Comment { content, offset }
47+ '#' => self . lex_django_construct ( COMMENT_TAG_END , |content, spans | {
48+ Token :: Comment { content, spans }
4649 } ) ,
4750 _ => self . lex_text ( ) ,
4851 } ,
@@ -61,35 +64,45 @@ impl<'db> Lexer<'db> {
6164 fn lex_django_construct (
6265 & mut self ,
6366 end : & str ,
64- token_fn : impl FnOnce ( TokenContent < ' db > , usize ) -> Token < ' db > ,
67+ token_fn : impl FnOnce ( TokenContent < ' db > , TokenSpans ) -> Token < ' db > ,
6568 ) -> Token < ' db > {
66- let offset = self . start + 3 ;
69+ let opening_len = 2 ;
70+ let content_start = self . start + opening_len;
6771
6872 self . consume_n ( 2 ) ;
6973
7074 match self . consume_until ( end) {
7175 Ok ( text) => {
72- self . consume_n ( 2 ) ;
7376 let content = TokenContent :: new ( self . db , text) ;
74- token_fn ( content, offset)
77+ let content_end = self . current ;
78+ let span = Span :: from_bounds ( content_start, content_end) ;
79+ self . consume_n ( end. len ( ) ) ;
80+ let full_end = self . current ;
81+ let full_span = Span :: from_bounds ( self . start , full_end) ;
82+ token_fn ( content, TokenSpans :: new ( span, full_span) )
7583 }
7684 Err ( err_text) => {
77- self . synchronize ( ) ;
85+ let content_end = self . current ;
86+ let span = Span :: from_bounds ( content_start, content_end) ;
87+ let full_span = Span :: from_bounds ( self . start , content_end) ;
7888 let content = TokenContent :: new ( self . db , err_text) ;
79- Token :: Error { content, offset }
89+ Token :: Error {
90+ content,
91+ spans : TokenSpans :: new ( span, full_span) ,
92+ }
8093 }
8194 }
8295 }
8396
8497 fn lex_whitespace ( & mut self , c : char ) -> Token < ' db > {
85- let offset = self . start ;
86-
8798 if c == '\n' || c == '\r' {
8899 self . consume ( ) ; // \r or \n
89100 if c == '\r' && self . peek ( ) == '\n' {
90101 self . consume ( ) ; // \n of \r\n
91102 }
92- Token :: Newline { offset }
103+ let span = Span :: from_bounds ( self . start , self . current ) ;
104+ let spans = TokenSpans :: new ( span, span) ;
105+ Token :: Newline { spans }
93106 } else {
94107 self . consume ( ) ; // Consume the first whitespace
95108 while !self . is_at_end ( ) && self . peek ( ) . is_whitespace ( ) {
@@ -98,8 +111,9 @@ impl<'db> Lexer<'db> {
98111 }
99112 self . consume ( ) ;
100113 }
101- let count = self . current - self . start ;
102- Token :: Whitespace { count, offset }
114+ let span = Span :: from_bounds ( self . start , self . current ) ;
115+ let spans = TokenSpans :: new ( span, span) ;
116+ Token :: Whitespace { spans }
103117 }
104118 }
105119
@@ -119,10 +133,9 @@ impl<'db> Lexer<'db> {
119133
120134 let text = & self . source [ text_start..self . current ] ;
121135 let content = TokenContent :: new ( self . db , text. to_string ( ) ) ;
122- Token :: Text {
123- content,
124- offset : self . start ,
125- }
136+ let span = Span :: from_bounds ( self . start , self . current ) ;
137+ let spans = TokenSpans :: new ( span, span) ;
138+ Token :: Text { content, spans }
126139 }
127140
128141 #[ inline]
@@ -156,26 +169,33 @@ impl<'db> Lexer<'db> {
156169
157170 fn consume_until ( & mut self , delimiter : & str ) -> Result < String , String > {
158171 let offset = self . current ;
172+ let mut fallback: Option < usize > = None ;
159173
160174 while self . current < self . source . len ( ) {
161175 if self . source [ self . current ..] . starts_with ( delimiter) {
162- return Ok ( self . source [ offset..self . current ] . trim ( ) . to_string ( ) ) ;
176+ return Ok ( self . source [ offset..self . current ] . to_string ( ) ) ;
163177 }
164- self . consume ( ) ;
165- }
166178
167- Err ( self . source [ offset..self . current ] . trim ( ) . to_string ( ) )
168- }
169-
170- fn synchronize ( & mut self ) {
171- const SYNC_POINTS : & [ u8 ] = b"{\n \r " ;
179+ if fallback. is_none ( )
180+ && ( self . source [ self . current ..] . starts_with ( BLOCK_TAG_START )
181+ || self . source [ self . current ..] . starts_with ( VARIABLE_TAG_START )
182+ || self . source [ self . current ..] . starts_with ( COMMENT_TAG_START ) )
183+ {
184+ fallback = Some ( self . current ) ;
185+ }
172186
173- while ! self . is_at_end ( ) {
174- if SYNC_POINTS . contains ( & self . source . as_bytes ( ) [ self . current ] ) {
175- return ;
187+ let ch = self . peek ( ) ;
188+ if fallback . is_none ( ) && matches ! ( ch , '\n' | '\r' ) {
189+ fallback = Some ( self . current ) ;
176190 }
191+
177192 self . consume ( ) ;
178193 }
194+
195+ let end = fallback. unwrap_or ( self . current ) ;
196+ let text = self . source [ offset..end] . to_string ( ) ;
197+ self . current = end;
198+ Err ( text)
179199 }
180200}
181201
0 commit comments