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}