1use mdbook::errors::Result as MdbookResult;
2use pulldown_cmark::{CodeBlockKind::*, Event, Options, Parser, Tag};
3
4use crate::{
5    book_config::OnFailure,
6    parse::parse_admonition,
7    types::{Overrides, RenderTextMode},
8};
9
10pub(crate) fn preprocess(
11    content: &str,
12    on_failure: OnFailure,
13    overrides: &Overrides,
14    render_text_mode: RenderTextMode,
15) -> MdbookResult<String> {
16    let mut id_counter = Default::default();
17    let mut opts = Options::empty();
18    opts.insert(Options::ENABLE_TABLES);
19    opts.insert(Options::ENABLE_FOOTNOTES);
20    opts.insert(Options::ENABLE_STRIKETHROUGH);
21    opts.insert(Options::ENABLE_TASKLISTS);
22
23    let mut admonish_blocks = vec![];
24
25    let events = Parser::new_ext(content, opts);
26
27    for (event, span) in events.into_offset_iter() {
28        if let Event::Start(Tag::CodeBlock(Fenced(info_string))) = event.clone() {
29            let span_content = &content[span.start..span.end];
30            const INDENT_SCAN_MAX: usize = 1024;
31            let indent = indent_of(content, span.start, INDENT_SCAN_MAX);
32
33            let admonition = match parse_admonition(
34                info_string.as_ref(),
35                overrides,
36                span_content,
37                on_failure,
38                indent,
39            ) {
40                Some(admonition) => admonition,
41                None => continue,
42            };
43
44            let admonition = admonition?;
45
46            let new_content = match render_text_mode {
49                RenderTextMode::Html => admonition.html(&mut id_counter),
50                RenderTextMode::Strip => admonition.strip(),
51            };
52
53            admonish_blocks.push((span, new_content));
54        }
55    }
56
57    let mut content = content.to_string();
58    for (span, block) in admonish_blocks.iter().rev() {
59        let pre_content = &content[..span.start];
60        let post_content = &content[span.end..];
61        content = format!("{}{}{}", pre_content, block, post_content);
62    }
63
64    Ok(content)
65}
66
67fn indent_of(content: &str, position: usize, max: usize) -> usize {
80    content[..position]
82        .chars()
83        .rev()
84        .take(max)
86        .position(|c| c == '\n')
87        .unwrap_or_default()
89}
90
91#[cfg(test)]
92mod test {
93    use pretty_assertions::assert_eq;
94
95    use crate::types::AdmonitionDefaults;
96
97    use super::*;
98
99    #[test]
100    fn indent_of_samples() {
101        for (content, position, max, expected) in [
102            ("", 0, 10, 0),
104            ("no newline", 4, 10, 0),
105            ("with\nnewline", 8, 10, 3),
107            ("with\nnewline", 8, 2, 0),
109            (
112                "例えばこれは",
113                "例".len(),
116                1,
118                0,
120            ),
121            (
122                "例え\n  れは",
123                "例え\n  ".len(),
126                4,
128                2,
130            ),
131        ] {
132            let actual = indent_of(content, position, max);
133            assert_eq!(actual, expected);
134        }
135    }
136
137    fn prep(content: &str) -> String {
138        preprocess(
139            content,
140            OnFailure::Continue,
141            &Overrides::default(),
142            RenderTextMode::Html,
143        )
144        .unwrap()
145    }
146
147    #[test]
148    fn adds_admonish() {
149        let content = r#"# Chapter
150```admonish
151A simple admonition.
152```
153Text
154"#;
155
156        let expected = r##"# Chapter
157
158<div id="admonition-note" class="admonition admonish-note" role="note" aria-labelledby="admonition-note-title">
159<div class="admonition-title">
160<div id="admonition-note-title">
161
162Note
163
164</div>
165<a class="admonition-anchor-link" href="#admonition-note"></a>
166</div>
167<div>
168
169A simple admonition.
170
171</div>
172</div>
173Text
174"##;
175
176        assert_eq!(expected, prep(content));
177    }
178
179    #[test]
180    fn adds_admonish_longer_code_fence() {
181        let content = r#"# Chapter
182````admonish
183```json
184{}
185```
186````
187Text
188"#;
189
190        let expected = r##"# Chapter
191
192<div id="admonition-note" class="admonition admonish-note" role="note" aria-labelledby="admonition-note-title">
193<div class="admonition-title">
194<div id="admonition-note-title">
195
196Note
197
198</div>
199<a class="admonition-anchor-link" href="#admonition-note"></a>
200</div>
201<div>
202
203```json
204{}
205```
206
207</div>
208</div>
209Text
210"##;
211
212        assert_eq!(expected, prep(content));
213    }
214
215    #[test]
216    fn adds_admonish_directive() {
217        let content = r#"# Chapter
218```admonish warning
219A simple admonition.
220```
221Text
222"#;
223
224        let expected = r##"# Chapter
225
226<div id="admonition-warning" class="admonition admonish-warning" role="note" aria-labelledby="admonition-warning-title">
227<div class="admonition-title">
228<div id="admonition-warning-title">
229
230Warning
231
232</div>
233<a class="admonition-anchor-link" href="#admonition-warning"></a>
234</div>
235<div>
236
237A simple admonition.
238
239</div>
240</div>
241Text
242"##;
243
244        assert_eq!(expected, prep(content));
245    }
246
247    #[test]
248    fn adds_admonish_directive_alternate() {
249        let content = r#"# Chapter
250```admonish caution
251A warning with alternate title.
252```
253Text
254"#;
255
256        let expected = r##"# Chapter
257
258<div id="admonition-caution" class="admonition admonish-warning" role="note" aria-labelledby="admonition-caution-title">
259<div class="admonition-title">
260<div id="admonition-caution-title">
261
262Caution
263
264</div>
265<a class="admonition-anchor-link" href="#admonition-caution"></a>
266</div>
267<div>
268
269A warning with alternate title.
270
271</div>
272</div>
273Text
274"##;
275
276        assert_eq!(expected, prep(content));
277    }
278
279    #[test]
280    fn adds_admonish_directive_title() {
281        let content = r#"# Chapter
282```admonish warning "Read **this**!"
283A simple admonition.
284```
285Text
286"#;
287
288        let expected = r##"# Chapter
289
290<div id="admonition-read-this" class="admonition admonish-warning" role="note" aria-labelledby="admonition-read-this-title">
291<div class="admonition-title">
292<div id="admonition-read-this-title">
293
294Read **this**!
295
296</div>
297<a class="admonition-anchor-link" href="#admonition-read-this"></a>
298</div>
299<div>
300
301A simple admonition.
302
303</div>
304</div>
305Text
306"##;
307
308        assert_eq!(expected, prep(content));
309    }
310
311    #[test]
312    fn leaves_tables_untouched() {
313        let content = r#"# Heading
317| Head 1 | Head 2 |
318|--------|--------|
319| Row 1  | Row 2  |
320"#;
321
322        let expected = r#"# Heading
323| Head 1 | Head 2 |
324|--------|--------|
325| Row 1  | Row 2  |
326"#;
327
328        assert_eq!(expected, prep(content));
329    }
330
331    #[test]
332    fn leaves_html_untouched() {
333        let content = r#"# Heading
337<del>
338*foo*
339</del>
340"#;
341
342        let expected = r#"# Heading
343<del>
344*foo*
345</del>
346"#;
347
348        assert_eq!(expected, prep(content));
349    }
350
351    #[test]
352    fn html_in_list() {
353        let content = r#"# Heading
3571. paragraph 1
358   ```
359   code 1
360   ```
3612. paragraph 2
362"#;
363
364        let expected = r#"# Heading
3651. paragraph 1
366   ```
367   code 1
368   ```
3692. paragraph 2
370"#;
371
372        assert_eq!(expected, prep(content));
373    }
374
375    #[test]
376    fn info_string_that_changes_length_when_parsed() {
377        let content = r#"
378```admonish note "And \\"<i>in</i>\\" the title"
379With <b>html</b> styling.
380```
381hello
382"#;
383
384        let expected = r##"
385
386<div id="admonition-and-in-the-title" class="admonition admonish-note" role="note" aria-labelledby="admonition-and-in-the-title-title">
387<div class="admonition-title">
388<div id="admonition-and-in-the-title-title">
389
390And "<i>in</i>" the title
391
392</div>
393<a class="admonition-anchor-link" href="#admonition-and-in-the-title"></a>
394</div>
395<div>
396
397With <b>html</b> styling.
398
399</div>
400</div>
401hello
402"##;
403
404        assert_eq!(expected, prep(content));
405    }
406
407    #[test]
408    fn info_string_ending_in_symbol() {
409        let content = r#"
410```admonish warning "Trademark™"
411Should be respected
412```
413hello
414"#;
415
416        let expected = r##"
417
418<div id="admonition-trademark" class="admonition admonish-warning" role="note" aria-labelledby="admonition-trademark-title">
419<div class="admonition-title">
420<div id="admonition-trademark-title">
421
422Trademark™
423
424</div>
425<a class="admonition-anchor-link" href="#admonition-trademark"></a>
426</div>
427<div>
428
429Should be respected
430
431</div>
432</div>
433hello
434"##;
435
436        assert_eq!(expected, prep(content));
437    }
438
439    #[test]
440    fn block_with_additional_classname() {
441        let content = r#"
442```admonish tip.my-style.other-style
443Will have bonus classnames
444```
445"#;
446
447        let expected = r##"
448
449<div id="admonition-tip" class="admonition admonish-tip my-style other-style" role="note" aria-labelledby="admonition-tip-title">
450<div class="admonition-title">
451<div id="admonition-tip-title">
452
453Tip
454
455</div>
456<a class="admonition-anchor-link" href="#admonition-tip"></a>
457</div>
458<div>
459
460Will have bonus classnames
461
462</div>
463</div>
464"##;
465
466        assert_eq!(expected, prep(content));
467    }
468
469    #[test]
470    fn block_with_additional_classname_and_title() {
471        let content = r#"
472```admonish tip.my-style.other-style "Developers don't want you to know this one weird tip!"
473Will have bonus classnames
474```
475"#;
476
477        let expected = r##"
478
479<div id="admonition-developers-dont-want-you-to-know-this-one-weird-tip" class="admonition admonish-tip my-style other-style" role="note" aria-labelledby="admonition-developers-dont-want-you-to-know-this-one-weird-tip-title">
480<div class="admonition-title">
481<div id="admonition-developers-dont-want-you-to-know-this-one-weird-tip-title">
482
483Developers don't want you to know this one weird tip!
484
485</div>
486<a class="admonition-anchor-link" href="#admonition-developers-dont-want-you-to-know-this-one-weird-tip"></a>
487</div>
488<div>
489
490Will have bonus classnames
491
492</div>
493</div>
494"##;
495
496        assert_eq!(expected, prep(content));
497    }
498
499    #[test]
500    fn block_with_empty_additional_classnames_title_content() {
501        let content = r#"
502```admonish .... ""
503```
504"#;
505
506        let expected = r#"
507
508<div id="admonition-default" class="admonition admonish-note" role="note">
509<div>
510
511
512
513</div>
514</div>
515"#;
516
517        assert_eq!(expected, prep(content));
518    }
519
520    #[test]
521    fn unique_ids_same_title() {
522        let content = r#"
523```admonish note "My Note"
524Content zero.
525```
526
527```admonish note "My Note"
528Content one.
529```
530"#;
531
532        let expected = r##"
533
534<div id="admonition-my-note" class="admonition admonish-note" role="note" aria-labelledby="admonition-my-note-title">
535<div class="admonition-title">
536<div id="admonition-my-note-title">
537
538My Note
539
540</div>
541<a class="admonition-anchor-link" href="#admonition-my-note"></a>
542</div>
543<div>
544
545Content zero.
546
547</div>
548</div>
549
550
551<div id="admonition-my-note-1" class="admonition admonish-note" role="note" aria-labelledby="admonition-my-note-1-title">
552<div class="admonition-title">
553<div id="admonition-my-note-1-title">
554
555My Note
556
557</div>
558<a class="admonition-anchor-link" href="#admonition-my-note-1"></a>
559</div>
560<div>
561
562Content one.
563
564</div>
565</div>
566"##;
567
568        assert_eq!(expected, prep(content));
569    }
570
571    #[test]
572    fn v2_config_works() {
573        let content = r#"
574```admonish tip class="my other-style" title="Article Heading"
575Bonus content!
576```
577"#;
578
579        let expected = r##"
580
581<div id="admonition-article-heading" class="admonition admonish-tip my other-style" role="note" aria-labelledby="admonition-article-heading-title">
582<div class="admonition-title">
583<div id="admonition-article-heading-title">
584
585Article Heading
586
587</div>
588<a class="admonition-anchor-link" href="#admonition-article-heading"></a>
589</div>
590<div>
591
592Bonus content!
593
594</div>
595</div>
596"##;
597
598        assert_eq!(expected, prep(content));
599    }
600
601    #[test]
602    fn continue_on_error_output() {
603        let content = r#"
604```admonish title="
605Bonus content!
606```
607"#;
608
609        let expected = r##"
610
611<div id="admonition-error-rendering-admonishment" class="admonition admonish-bug" role="note" aria-labelledby="admonition-error-rendering-admonishment-title">
612<div class="admonition-title">
613<div id="admonition-error-rendering-admonishment-title">
614
615Error rendering admonishment
616
617</div>
618<a class="admonition-anchor-link" href="#admonition-error-rendering-admonishment"></a>
619</div>
620<div>
621
622Failed with:
623
624```log
625'title="' is not a valid directive or TOML key-value pair.
626
627TOML parsing error: TOML parse error at line 1, column 21
628  |
6291 | config = { title=" }
630  |                     ^
631invalid basic string
632
633```
634
635Original markdown input:
636
637````markdown
638```admonish title="
639Bonus content!
640```
641````
642
643
644</div>
645</div>
646"##;
647
648        assert_eq!(expected, prep(content));
649    }
650
651    #[test]
652    fn bail_on_error_output() {
653        let content = r#"
654```admonish title="
655Bonus content!
656```
657"#;
658        assert_eq!(
659            preprocess(
660                content,
661                OnFailure::Bail,
662                &Overrides::default(),
663                RenderTextMode::Html
664            )
665            .unwrap_err()
666            .to_string(),
667            r#"Error processing admonition, bailing:
668```admonish title="
669Bonus content!
670```"#
671                .to_owned()
672        )
673    }
674
675    #[test]
676    fn test_renderer_strip_explicit() {
677        let content = r#"
678````admonish title="Title"
679```rust
680let x = 10;
681x = 20;
682```
683````
684"#;
685        assert_eq!(
686            preprocess(
687                content,
688                OnFailure::Bail,
689                &Overrides::default(),
690                RenderTextMode::Strip
691            )
692            .unwrap(),
693            r#"
694
695```rust
696let x = 10;
697x = 20;
698```
699
700"#
701            .to_owned()
702        )
703    }
704
705    #[test]
706    fn block_collapsible() {
707        let content = r#"
708```admonish collapsible=true
709Hidden
710```
711"#;
712
713        let expected = r##"
714
715<details id="admonition-note" class="admonition admonish-note" role="note" aria-labelledby="admonition-note-title">
716<summary class="admonition-title">
717<div id="admonition-note-title">
718
719Note
720
721</div>
722<a class="admonition-anchor-link" href="#admonition-note"></a>
723</summary>
724<div>
725
726Hidden
727
728</div>
729</details>
730"##;
731
732        assert_eq!(expected, prep(content));
733    }
734
735    #[test]
736    fn default_toml_title() {
737        let content = r#"# Chapter
738```admonish
739A simple admonition.
740```
741Text
742"#;
743
744        let expected = r##"# Chapter
745
746<div id="admonition-admonish" class="admonition admonish-note" role="note" aria-labelledby="admonition-admonish-title">
747<div class="admonition-title">
748<div id="admonition-admonish-title">
749
750Admonish
751
752</div>
753<a class="admonition-anchor-link" href="#admonition-admonish"></a>
754</div>
755<div>
756
757A simple admonition.
758
759</div>
760</div>
761Text
762"##;
763
764        let preprocess_result = preprocess(
765            content,
766            OnFailure::Continue,
767            &Overrides {
768                book: AdmonitionDefaults {
769                    title: Some("Admonish".to_owned()),
770                    css_id_prefix: None,
771                    collapsible: false,
772                },
773                ..Default::default()
774            },
775            RenderTextMode::Html,
776        )
777        .unwrap();
778        assert_eq!(expected, preprocess_result);
779    }
780
781    #[test]
782    fn empty_explicit_title_with_default() {
783        let content = r#"# Chapter
784```admonish title=""
785A simple admonition.
786```
787Text
788"#;
789
790        let expected = r#"# Chapter
791
792<div id="admonition-default" class="admonition admonish-note" role="note">
793<div>
794
795A simple admonition.
796
797</div>
798</div>
799Text
800"#;
801
802        let preprocess_result = preprocess(
803            content,
804            OnFailure::Continue,
805            &Overrides {
806                book: AdmonitionDefaults {
807                    title: Some("Admonish".to_owned()),
808                    css_id_prefix: None,
809                    collapsible: false,
810                },
811                ..Default::default()
812            },
813            RenderTextMode::Html,
814        )
815        .unwrap();
816        assert_eq!(expected, preprocess_result);
817    }
818
819    #[test]
820    fn empty_explicit_title() {
821        let content = r#"# Chapter
822```admonish title=""
823A simple admonition.
824```
825Text
826"#;
827
828        let expected = r#"# Chapter
829
830<div id="admonition-default" class="admonition admonish-note" role="note">
831<div>
832
833A simple admonition.
834
835</div>
836</div>
837Text
838"#;
839
840        assert_eq!(expected, prep(content));
841    }
842
843    #[test]
844    fn standard_custom_id() {
845        let content = r#"# Chapter
846```admonish check id="yay-custom-id"
847A simple admonition.
848```
849Text
850"#;
851
852        let expected = r##"# Chapter
853
854<div id="yay-custom-id" class="admonition admonish-success" role="note" aria-labelledby="yay-custom-id-title">
855<div class="admonition-title">
856<div id="yay-custom-id-title">
857
858Check
859
860</div>
861<a class="admonition-anchor-link" href="#yay-custom-id"></a>
862</div>
863<div>
864
865A simple admonition.
866
867</div>
868</div>
869Text
870"##;
871
872        assert_eq!(expected, prep(content));
873    }
874
875    #[test]
876    fn no_custom_id_default_prefix() {
877        let content = r#"# Chapter
878```admonish check
879A simple admonition.
880```
881Text
882"#;
883
884        let expected = r##"# Chapter
885
886<div id="admonition-check" class="admonition admonish-success" role="note" aria-labelledby="admonition-check-title">
887<div class="admonition-title">
888<div id="admonition-check-title">
889
890Check
891
892</div>
893<a class="admonition-anchor-link" href="#admonition-check"></a>
894</div>
895<div>
896
897A simple admonition.
898
899</div>
900</div>
901Text
902"##;
903
904        assert_eq!(expected, prep(content));
905    }
906
907    #[test]
908    fn no_custom_id_default_prefix_custom_title() {
909        let content = r#"# Chapter
910```admonish check title="Check Mark"
911A simple admonition.
912```
913Text
914"#;
915
916        let expected = r##"# Chapter
917
918<div id="admonition-check-mark" class="admonition admonish-success" role="note" aria-labelledby="admonition-check-mark-title">
919<div class="admonition-title">
920<div id="admonition-check-mark-title">
921
922Check Mark
923
924</div>
925<a class="admonition-anchor-link" href="#admonition-check-mark"></a>
926</div>
927<div>
928
929A simple admonition.
930
931</div>
932</div>
933Text
934"##;
935
936        assert_eq!(expected, prep(content));
937    }
938
939    #[test]
940    fn title_and_content_with_html() {
941        let content = r#"# Chapter
945```admonish success title='Check <span class="emphasis">Mark</span>'
946A <span class="emphasis">simple</span> admonition.
947```
948Text
949"#;
950
951        let expected = r##"# Chapter
952
953<div id="admonition-check-mark" class="admonition admonish-success" role="note" aria-labelledby="admonition-check-mark-title">
954<div class="admonition-title">
955<div id="admonition-check-mark-title">
956
957Check <span class="emphasis">Mark</span>
958
959</div>
960<a class="admonition-anchor-link" href="#admonition-check-mark"></a>
961</div>
962<div>
963
964A <span class="emphasis">simple</span> admonition.
965
966</div>
967</div>
968Text
969"##;
970
971        assert_eq!(expected, prep(content));
972    }
973
974    #[test]
975    fn empty_default_id_prefix() {
976        let content = r#"# Chapter
977```admonish info
978A simple admonition.
979```
980Text
981"#;
982
983        let expected = r##"# Chapter
984
985<div id="info" class="admonition admonish-info" role="note" aria-labelledby="info-title">
986<div class="admonition-title">
987<div id="info-title">
988
989Info
990
991</div>
992<a class="admonition-anchor-link" href="#info"></a>
993</div>
994<div>
995
996A simple admonition.
997
998</div>
999</div>
1000Text
1001"##;
1002
1003        let preprocess_result = preprocess(
1004            content,
1005            OnFailure::Continue,
1006            &Overrides {
1007                book: AdmonitionDefaults {
1008                    title: Some("Info".to_owned()),
1009                    css_id_prefix: Some("".to_owned()),
1010                    collapsible: false,
1011                },
1012                ..Default::default()
1013            },
1014            RenderTextMode::Html,
1015        )
1016        .unwrap();
1017        assert_eq!(expected, preprocess_result);
1018    }
1019
1020    #[test]
1021    fn custom_id_prefix_custom_title() {
1022        let content = r#"# Chapter
1023```admonish info title="My Title"
1024A simple admonition.
1025```
1026Text
1027"#;
1028
1029        let expected = r##"# Chapter
1030
1031<div id="prefix-my-title" class="admonition admonish-info" role="note" aria-labelledby="prefix-my-title-title">
1032<div class="admonition-title">
1033<div id="prefix-my-title-title">
1034
1035My Title
1036
1037</div>
1038<a class="admonition-anchor-link" href="#prefix-my-title"></a>
1039</div>
1040<div>
1041
1042A simple admonition.
1043
1044</div>
1045</div>
1046Text
1047"##;
1048
1049        let preprocess_result = preprocess(
1050            content,
1051            OnFailure::Continue,
1052            &Overrides {
1053                book: AdmonitionDefaults {
1054                    title: Some("Info".to_owned()),
1055                    css_id_prefix: Some("prefix-".to_owned()),
1056                    collapsible: false,
1057                },
1058                ..Default::default()
1059            },
1060            RenderTextMode::Html,
1061        )
1062        .unwrap();
1063        assert_eq!(expected, preprocess_result);
1064    }
1065
1066    #[test]
1067    fn custom_id_custom_title() {
1068        let content = r#"# Chapter
1069```admonish info title="My Title" id="my-section-id"
1070A simple admonition.
1071```
1072Text
1073"#;
1074
1075        let expected = r##"# Chapter
1076
1077<div id="my-section-id" class="admonition admonish-info" role="note" aria-labelledby="my-section-id-title">
1078<div class="admonition-title">
1079<div id="my-section-id-title">
1080
1081My Title
1082
1083</div>
1084<a class="admonition-anchor-link" href="#my-section-id"></a>
1085</div>
1086<div>
1087
1088A simple admonition.
1089
1090</div>
1091</div>
1092Text
1093"##;
1094
1095        let preprocess_result = preprocess(
1096            content,
1097            OnFailure::Continue,
1098            &Overrides {
1099                book: AdmonitionDefaults {
1100                    title: Some("Info".to_owned()),
1101                    css_id_prefix: Some("ignored-prefix-".to_owned()),
1102                    collapsible: false,
1103                },
1104                ..Default::default()
1105            },
1106            RenderTextMode::Html,
1107        )
1108        .unwrap();
1109        assert_eq!(expected, preprocess_result);
1110    }
1111
1112    #[test]
1113    fn list_embed() {
1114        let content = r#"# Chapter
1115
11161. Thing one
1117
1118   ```sh
1119   Thing one
1120   ```
1121
11221. Thing two
1123
1124   ```admonish
1125   Thing two
1126   ```
1127
11281. Thing three
1129
1130   ```sh
1131   Thing three
1132   ```
1133"#;
1134
1135        let expected = r##"# Chapter
1136
11371. Thing one
1138
1139   ```sh
1140   Thing one
1141   ```
1142
11431. Thing two
1144
1145   
1146   <div id="admonition-note" class="admonition admonish-note" role="note" aria-labelledby="admonition-note-title">
1147   <div class="admonition-title">
1148   <div id="admonition-note-title">
1149   
1150   Note
1151   
1152   </div>
1153   <a class="admonition-anchor-link" href="#admonition-note"></a>
1154   </div>
1155   <div>
1156
1157   Thing two
1158
1159   </div>
1160   </div>
1161
11621. Thing three
1163
1164   ```sh
1165   Thing three
1166   ```
1167"##;
1168
1169        assert_eq!(expected, prep(content));
1170    }
1171
1172    #[test]
1174    fn nested_list_should_not_render_indented_code_block() {
1175        let content = r#"# Chapter
1176
1177- Level one
1178
1179  ```admonish
1180  Thing one
1181  line two
1182  ```
1183
1184  - Level two
1185
1186    ```admonish
1187    Thing two
1188    line two
1189    ```
1190
1191    - Level three
1192
1193      ```admonish
1194      Thing three
1195      line two
1196      ```
1197"#;
1198
1199        let expected = r##"# Chapter
1200
1201- Level one
1202
1203  
1204  <div id="admonition-note" class="admonition admonish-note" role="note" aria-labelledby="admonition-note-title">
1205  <div class="admonition-title">
1206  <div id="admonition-note-title">
1207  
1208  Note
1209  
1210  </div>
1211  <a class="admonition-anchor-link" href="#admonition-note"></a>
1212  </div>
1213  <div>
1214
1215  Thing one
1216  line two
1217
1218  </div>
1219  </div>
1220
1221  - Level two
1222
1223    
1224    <div id="admonition-note-1" class="admonition admonish-note" role="note" aria-labelledby="admonition-note-1-title">
1225    <div class="admonition-title">
1226    <div id="admonition-note-1-title">
1227    
1228    Note
1229    
1230    </div>
1231    <a class="admonition-anchor-link" href="#admonition-note-1"></a>
1232    </div>
1233    <div>
1234
1235    Thing two
1236    line two
1237
1238    </div>
1239    </div>
1240
1241    - Level three
1242
1243      
1244      <div id="admonition-note-2" class="admonition admonish-note" role="note" aria-labelledby="admonition-note-2-title">
1245      <div class="admonition-title">
1246      <div id="admonition-note-2-title">
1247      
1248      Note
1249      
1250      </div>
1251      <a class="admonition-anchor-link" href="#admonition-note-2"></a>
1252      </div>
1253      <div>
1254
1255      Thing three
1256      line two
1257
1258      </div>
1259      </div>
1260"##;
1261
1262        assert_eq!(expected, prep(content));
1263    }
1264}