@@ -10,6 +10,7 @@ pub struct Block<'a> {
1010 pub events : Vec < ( Event < ' a > , Range < usize > ) > ,
1111 pub span : Range < usize > ,
1212 pub inner_span : Range < usize > ,
13+ pub has_nested : bool ,
1314}
1415
1516impl < ' a > Block < ' a > {
@@ -22,6 +23,7 @@ impl<'a> Block<'a> {
2223 events : vec ! [ ( first_event, first_span) ] ,
2324 span,
2425 inner_span,
26+ has_nested : false ,
2527 }
2628 }
2729}
@@ -30,27 +32,42 @@ pub fn parse_blocks<IsStartFn, IsEndFn>(
3032 content : & str ,
3133 is_start : IsStartFn ,
3234 is_end : IsEndFn ,
35+ skip_nested : bool ,
3336) -> Result < Vec < Block > >
3437where
3538 IsStartFn : Fn ( & Event ) -> bool ,
3639 IsEndFn : Fn ( & Event ) -> bool ,
3740{
3841 let mut blocks: Vec < Block > = vec ! [ ] ;
42+ let mut nested_level = 0 ;
3943
4044 for ( event, span) in Parser :: new ( content) . into_offset_iter ( ) {
4145 debug ! ( "{:?} {:?}" , event, span) ;
4246
4347 if is_start ( & event) {
4448 if let Some ( block) = blocks. last_mut ( ) {
4549 if !block. closed {
46- bail ! ( "Block is not closed. Nested blocks are not supported." ) ;
50+ if skip_nested {
51+ nested_level += 1 ;
52+ block. has_nested = true ;
53+ block. events . push ( ( event, span) ) ;
54+ continue ;
55+ } else {
56+ bail ! ( "Block is not closed. Nested blocks are not allowed." ) ;
57+ }
4758 }
4859 }
4960
5061 blocks. push ( Block :: new ( event, span) ) ;
5162 } else if is_end ( & event) {
5263 if let Some ( block) = blocks. last_mut ( ) {
5364 if !block. closed {
65+ if nested_level > 0 {
66+ nested_level -= 1 ;
67+ block. events . push ( ( event, span) ) ;
68+ continue ;
69+ }
70+
5471 block. closed = true ;
5572 block. span = block. span . start ..span. end ;
5673 block. events . push ( ( event, span) ) ;
@@ -114,12 +131,14 @@ mod test {
114131 ] ,
115132 span: 0 ..43 ,
116133 inner_span: 8 ..40 ,
134+ has_nested: false ,
117135 } ] ;
118136
119137 let actual = parse_blocks (
120138 content,
121139 |event| matches ! ( event, Event :: Start ( Tag :: CodeBlock ( CodeBlockKind :: Fenced ( tag) ) ) if tag == & CowStr :: from( "toml" ) ) ,
122140 |event| matches ! ( event, Event :: End ( TagEnd :: CodeBlock ) ) ,
141+ false ,
123142 ) ?;
124143
125144 assert_eq ! ( expected, actual) ;
@@ -153,12 +172,14 @@ mod test {
153172 ] ,
154173 span: 34 ..77 ,
155174 inner_span: 42 ..74 ,
175+ has_nested: false ,
156176 } ] ;
157177
158178 let actual = parse_blocks (
159179 content,
160180 |event| matches ! ( event, Event :: Start ( Tag :: CodeBlock ( CodeBlockKind :: Fenced ( tag) ) ) if tag == & CowStr :: from( "toml" ) ) ,
161181 |event| matches ! ( event, Event :: End ( TagEnd :: CodeBlock ) ) ,
182+ false ,
162183 ) ?;
163184
164185 assert_eq ! ( expected, actual) ;
@@ -199,6 +220,7 @@ mod test {
199220 ] ,
200221 span: 18 ..61 ,
201222 inner_span: 26 ..58 ,
223+ has_nested: false ,
202224 } ,
203225 Block {
204226 closed: true ,
@@ -215,48 +237,22 @@ mod test {
215237 ] ,
216238 span: 126 ..169 ,
217239 inner_span: 134 ..166 ,
240+ has_nested: false ,
218241 } ,
219242 ] ;
220243
221244 let actual = parse_blocks (
222245 content,
223246 |event| matches ! ( event, Event :: Start ( Tag :: CodeBlock ( CodeBlockKind :: Fenced ( tag) ) ) if tag == & CowStr :: from( "toml" ) ) ,
224247 |event| matches ! ( event, Event :: End ( TagEnd :: CodeBlock ) ) ,
248+ false ,
225249 ) ?;
226250
227251 assert_eq ! ( expected, actual) ;
228252
229253 Ok ( ( ) )
230254 }
231255
232- #[ test]
233- fn test_parse_blocks_nested ( ) -> Result < ( ) > {
234- let content = "*a **sentence** with **some** words*" ;
235-
236- let actual = parse_blocks (
237- content,
238- |event| {
239- matches ! (
240- event,
241- Event :: Start ( Tag :: Emphasis ) | Event :: Start ( Tag :: Strong )
242- )
243- } ,
244- |event| {
245- matches ! (
246- event,
247- Event :: End ( TagEnd :: Emphasis ) | Event :: End ( TagEnd :: Strong )
248- )
249- } ,
250- ) ;
251-
252- assert_eq ! (
253- "Block is not closed. Nested blocks are not supported." ,
254- format!( "{}" , actual. unwrap_err( ) . root_cause( ) )
255- ) ;
256-
257- Ok ( ( ) )
258- }
259-
260256 #[ test]
261257 fn test_parse_blocks_text ( ) -> Result < ( ) > {
262258 let content = "\
@@ -283,6 +279,7 @@ mod test {
283279 ] ,
284280 span: 0 ..36 ,
285281 inner_span: 9 ..24 ,
282+ has_nested: false ,
286283 } ,
287284 Block {
288285 closed: true ,
@@ -298,13 +295,96 @@ mod test {
298295 ] ,
299296 span: 37 ..88 ,
300297 inner_span: 48 ..74 ,
298+ has_nested: false ,
301299 } ,
302300 ] ;
303301
304302 let actual = parse_blocks (
305303 content,
306304 |event| matches ! ( event, Event :: Text ( text) if text. starts_with( "{{#tab " ) ) ,
307305 |event| matches ! ( event, Event :: Text ( text) if text. starts_with( "{{#endtab " ) ) ,
306+ false ,
307+ ) ?;
308+
309+ assert_eq ! ( expected, actual) ;
310+
311+ Ok ( ( ) )
312+ }
313+
314+ #[ test]
315+ fn test_parse_blocks_nested_error ( ) -> Result < ( ) > {
316+ let content = "*a **sentence** with **some** words*" ;
317+
318+ let actual = parse_blocks (
319+ content,
320+ |event| {
321+ matches ! (
322+ event,
323+ Event :: Start ( Tag :: Emphasis ) | Event :: Start ( Tag :: Strong )
324+ )
325+ } ,
326+ |event| {
327+ matches ! (
328+ event,
329+ Event :: End ( TagEnd :: Emphasis ) | Event :: End ( TagEnd :: Strong )
330+ )
331+ } ,
332+ false ,
333+ ) ;
334+
335+ assert_eq ! (
336+ "Block is not closed. Nested blocks are not allowed." ,
337+ format!( "{}" , actual. unwrap_err( ) . root_cause( ) )
338+ ) ;
339+
340+ Ok ( ( ) )
341+ }
342+
343+ #[ test]
344+ fn test_parse_blocks_nested ( ) -> Result < ( ) > {
345+ let content = "\
346+ {{#tabs }}\n \
347+ Level 1\n \
348+ {{#tabs }}\n \
349+ Level 2\n \
350+ {{#tabs }}\n \
351+ Level 3\n \
352+ {{#endtabs }}\n \
353+ {{#endtabs }}\n \
354+ {{#endtabs }}\n \
355+ ";
356+
357+ let expected: Vec < Block > = vec ! [ Block {
358+ closed: true ,
359+ events: vec![
360+ ( Event :: Text ( CowStr :: from( "{{#tabs }}" ) ) , 0 ..10 ) ,
361+ ( Event :: SoftBreak , 10 ..11 ) ,
362+ ( Event :: Text ( CowStr :: from( "Level 1" ) ) , 11 ..18 ) ,
363+ ( Event :: SoftBreak , 18 ..19 ) ,
364+ ( Event :: Text ( CowStr :: from( "{{#tabs }}" ) ) , 19 ..29 ) ,
365+ ( Event :: SoftBreak , 29 ..30 ) ,
366+ ( Event :: Text ( CowStr :: from( "Level 2" ) ) , 30 ..37 ) ,
367+ ( Event :: SoftBreak , 37 ..38 ) ,
368+ ( Event :: Text ( CowStr :: from( "{{#tabs }}" ) ) , 38 ..48 ) ,
369+ ( Event :: SoftBreak , 48 ..49 ) ,
370+ ( Event :: Text ( CowStr :: from( "Level 3" ) ) , 49 ..56 ) ,
371+ ( Event :: SoftBreak , 56 ..57 ) ,
372+ ( Event :: Text ( CowStr :: from( "{{#endtabs }}" ) ) , 57 ..70 ) ,
373+ ( Event :: SoftBreak , 70 ..71 ) ,
374+ ( Event :: Text ( CowStr :: from( "{{#endtabs }}" ) ) , 71 ..84 ) ,
375+ ( Event :: SoftBreak , 84 ..85 ) ,
376+ ( Event :: Text ( CowStr :: from( "{{#endtabs }}" ) ) , 85 ..98 ) ,
377+ ] ,
378+ span: 0 ..98 ,
379+ inner_span: 10 ..85 ,
380+ has_nested: true ,
381+ } ] ;
382+
383+ let actual = parse_blocks (
384+ content,
385+ |event| matches ! ( event, Event :: Text ( text) if text. starts_with( "{{#tabs " ) ) ,
386+ |event| matches ! ( event, Event :: Text ( text) if text. starts_with( "{{#endtabs " ) ) ,
387+ true ,
308388 ) ?;
309389
310390 assert_eq ! ( expected, actual) ;
0 commit comments