1#![allow(dead_code)]
3#![allow(clippy::type_complexity)]
4
5use crate::parser::Link;
6use crate::parser::parse::LABEL_LEN_MAX;
7use nom::branch::alt;
8use nom::bytes::complete::tag;
9use nom::combinator::*;
10use nom::{IResult, Parser};
11use std::borrow::Cow;
12
13const ESCAPABLE: &str = r#" `:<>_\"#;
18
19pub fn rst_text2dest_link(i: &'_ str) -> nom::IResult<&'_ str, Link<'_>> {
22 let (i, (te, de, ti)) = rst_text2dest(i)?;
23 Ok((i, Link::Text2Dest(te, de, ti)))
24}
25
26pub fn rst_text2dest(
50 i: &'_ str,
51) -> nom::IResult<&'_ str, (Cow<'_, str>, Cow<'_, str>, Cow<'_, str>)> {
52 let (i, (ln, ld)) = rst_parse_text2target(true, false)(i)?;
53 let ln = rst_escaped_link_text_transform(ln)?.1;
54 let ld = rst_escaped_link_destination_transform(ld)?.1;
55
56 Ok((i, (ln, ld, Cow::Borrowed(""))))
57}
58
59pub fn rst_text_label2dest_link(i: &'_ str) -> nom::IResult<&'_ str, Link<'_>> {
62 let (i, (te, de, ti)) = rst_text_label2dest(i)?;
63 Ok((i, Link::TextLabel2Dest(te, de, ti)))
64}
65
66pub fn rst_text_label2dest(
90 i: &'_ str,
91) -> nom::IResult<&'_ str, (Cow<'_, str>, Cow<'_, str>, Cow<'_, str>)> {
92 let (i, (ln, ld)) = rst_parse_text2target(false, false)(i)?;
93 let ln = rst_escaped_link_text_transform(ln)?.1;
94 let ld = rst_escaped_link_destination_transform(ld)?.1;
95
96 Ok((i, (ln, ld, Cow::Borrowed(""))))
97}
98
99fn rst_parse_text2target(
115 anonym: bool,
116 label: bool,
117) -> impl Fn(&str) -> IResult<&str, (&str, &str)> {
118 move |i: &str| {
119 let (mut i, inner) = nom::sequence::delimited(
120 tag("`"),
121 nom::bytes::complete::escaped(
122 nom::character::complete::none_of(r#"\`"#),
123 '\\',
124 nom::character::complete::one_of(ESCAPABLE),
125 ),
126 tag("`_"),
127 )
128 .parse(i)?;
129
130 if anonym {
131 let (j, _) = nom::character::complete::char('_')(i)?;
132 i = j;
133 };
134
135 if !i.is_empty() {
137 let _ = nom::combinator::not(nom::character::complete::char('_')).parse(i)?;
138 };
139
140 let (inner_rest, link_text): (&str, &str) = nom::bytes::complete::escaped(
143 nom::character::complete::none_of(r#"\<"#),
144 '\\',
145 nom::character::complete::one_of(ESCAPABLE),
146 )(inner)?;
147 let link_text = link_text.trim_end();
149
150 let (j, mut link_dest_label) = nom::sequence::delimited(
151 tag("<"),
152 nom::bytes::complete::escaped(
153 nom::character::complete::none_of(r#"\<>"#),
154 '\\',
155 nom::character::complete::one_of(ESCAPABLE),
156 ),
157 tag(">"),
158 )
159 .parse(inner_rest)?;
160
161 let (_, _) = nom::combinator::eof(j)?;
163
164 let (_, _) = nom::combinator::not(nom::combinator::eof).parse(link_dest_label)?;
169
170 let last_char_is_ = link_dest_label.is_char_boundary(link_dest_label.len() - 1)
172 && &link_dest_label[link_dest_label.len() - 1..] == "_";
173 if (label && !last_char_is_) || (!label && last_char_is_) {
176 return Err(nom::Err::Error(nom::error::Error::new(
177 i,
178 nom::error::ErrorKind::Tag,
179 )));
180 };
181 if label {
183 link_dest_label = &link_dest_label[..link_dest_label.len() - 1];
184 };
185
186 Ok((i, (link_text, link_dest_label)))
187 }
188}
189
190pub fn rst_text2label_link(i: &'_ str) -> nom::IResult<&'_ str, Link<'_>> {
193 let (i, (te, la)) = rst_text2label(i)?;
194 Ok((i, Link::Text2Label(te, la)))
195}
196
197pub fn rst_text2label(i: &'_ str) -> nom::IResult<&'_ str, (Cow<'_, str>, Cow<'_, str>)> {
227 let (i, (te, la)) = rst_parse_text2label(i)?;
228 let te = rst_escaped_link_text_transform(te)?.1;
229 let la = rst_escaped_link_text_transform(la)?.1;
230
231 Ok((i, (te, la)))
232}
233
234fn rst_parse_text2label(i: &str) -> nom::IResult<&str, (&str, &str)> {
261 let (mut i, (link_text, mut link_label)) = alt((
262 rst_parse_text2target(false, true),
263 nom::combinator::map(rst_parse_simple_label, |s| (s, s)),
264 ))
265 .parse(i)?;
266
267 if let (j, Some(_)) = nom::combinator::opt(nom::character::complete::char('_')).parse(i)? {
269 link_label = "_";
270 i = j;
271 };
272
273 Ok((i, (link_text, link_label)))
274}
275
276pub fn rst_label2dest_link(i: &'_ str) -> nom::IResult<&'_ str, Link<'_>> {
279 let (i, (l, d, t)) = rst_label2dest(i)?;
280 Ok((i, Link::Label2Dest(l, d, t)))
281}
282
283pub fn rst_label2dest(
312 i: &'_ str,
313) -> nom::IResult<&'_ str, (Cow<'_, str>, Cow<'_, str>, Cow<'_, str>)> {
314 let (i, (l, d)) = rst_label2target(false, i)?;
315 Ok((i, (l, d, Cow::from(""))))
316}
317
318pub fn rst_label2label_link(i: &'_ str) -> nom::IResult<&'_ str, Link<'_>> {
321 let (i, (l1, l2)) = rst_label2label(i)?;
322 Ok((i, Link::Label2Label(l1, l2)))
323}
324
325pub fn rst_label2label(i: &'_ str) -> nom::IResult<&'_ str, (Cow<'_, str>, Cow<'_, str>)> {
346 rst_label2target(true, i)
347}
348
349fn rst_label2target(
353 label: bool,
354 i: &'_ str,
355) -> nom::IResult<&'_ str, (Cow<'_, str>, Cow<'_, str>)> {
356 let my_err = |_| {
357 nom::Err::Error(nom::error::Error::new(
358 i,
359 nom::error::ErrorKind::EscapedTransform,
360 ))
361 };
362
363 let (i, c, block_header_is__) =
365 if let (i, Some(c)) = nom::combinator::opt(rst_explicit_markup_block(".. ")).parse(i)? {
366 (i, c, false)
367 } else {
368 let (i, c) = rst_explicit_markup_block("__ ")(i)?;
369 (i, c, true)
370 };
371
372 let (source, target) = match c {
373 Cow::Borrowed(s) => {
374 let (_, (ls, lt)) = if !block_header_is__ {
375 rst_parse_label2target(label)(s)?
376 } else if label {
377 ("", ("_", rst_parse_simple_label(s)?.1))
379 } else {
380 ("", ("_", s))
382 };
383 if !label {
385 let _ = nom::combinator::not(rst_parse_simple_label)
386 .parse(lt)
387 .map_err(my_err)?;
388 };
389 (
390 rst_escaped_link_text_transform(ls)?.1,
391 rst_escaped_link_destination_transform(lt)?.1,
392 )
393 }
394
395 Cow::Owned(strg) => {
396 let (_, (ls, lt)) = if !block_header_is__ {
397 rst_parse_label2target(label)(&strg).map_err(my_err)?
398 } else if label {
399 let s = rst_parse_simple_label(&strg).map_err(my_err)?.1;
401 ("", ("_", s))
402 } else {
403 ("", ("_", strg.as_str()))
405 };
406 if !label {
408 let _ = nom::combinator::not(rst_parse_simple_label)
409 .parse(lt)
410 .map_err(my_err)?;
411 };
412 let ls = Cow::Owned(
413 rst_escaped_link_text_transform(ls)
414 .map_err(my_err)?
415 .1
416 .to_string(),
417 );
418 let lt = Cow::Owned(
419 rst_escaped_link_destination_transform(lt)
420 .map_err(my_err)?
421 .1
422 .to_string(),
423 );
424 (ls, lt)
425 }
426 };
427
428 Ok((i, (source, target)))
433}
434
435fn rst_parse_label2target(label: bool) -> impl Fn(&str) -> IResult<&str, (&str, &str)> {
441 move |i: &str| {
442 let (i, link_text) = alt((
443 nom::sequence::delimited(
444 tag("_`"),
445 nom::bytes::complete::escaped(
446 nom::character::complete::none_of(r#"\`"#),
447 '\\',
448 nom::character::complete::one_of(ESCAPABLE),
449 ),
450 tag("`: "),
451 ),
452 nom::sequence::delimited(
453 tag("_"),
454 nom::bytes::complete::escaped(
455 nom::character::complete::none_of(r#"\:"#),
456 '\\',
457 nom::character::complete::one_of(ESCAPABLE),
458 ),
459 tag(": "),
460 ),
461 nom::combinator::value("_", tag("__: ")),
462 ))
463 .parse(i)?;
464
465 let link_target = if label {
466 rst_parse_simple_label(i)?.1
468 } else {
469 i
471 };
472
473 Ok(("", (link_text, link_target)))
474 }
475}
476
477fn rst_parse_simple_label(i: &str) -> nom::IResult<&str, &str> {
482 fn take_word_consume_first_ending_underscore(i: &str) -> nom::IResult<&str, &str> {
485 let mut i = i;
486 let (k, mut r) = nom::bytes::complete::take_till1(|c: char| {
487 !(c.is_alphanumeric() || c == '-' || c == '_')
488 })(i)?;
489 if r.len() >= 3 && r.is_char_boundary(r.len() - 2) && &r[r.len() - 2..] == "__" {
491 i = &i[r.len() - 1..];
493 r = &r[..r.len() - 2];
495 } else if !r.is_empty() && r.is_char_boundary(r.len() - 1) && &r[r.len() - 1..] == "_" {
497 i = k;
499 r = &r[..r.len() - 1]
501 } else {
502 return Err(nom::Err::Error(nom::error::Error::new(
503 k,
504 nom::error::ErrorKind::Tag,
505 )));
506 };
507
508 Ok((i, r))
509 }
510
511 let (i, r) = nom::combinator::verify(
512 alt((
513 nom::sequence::delimited(
514 tag("`"),
515 nom::bytes::complete::escaped(
516 nom::character::complete::none_of(r#"\`"#),
517 '\\',
518 nom::character::complete::one_of(ESCAPABLE),
519 ),
520 tag("`_"),
521 ),
522 take_word_consume_first_ending_underscore,
523 )),
524 |s: &str| s.len() <= LABEL_LEN_MAX,
525 )
526 .parse(i)?;
527
528 let _ = nom::combinator::not(alt((nom::combinator::eof, tag("``")))).parse(r)?;
530
531 Ok((i, r))
532}
533
534fn rst_explicit_markup_block<'a>(
557 block_header: &'a str,
558) -> impl Fn(&'a str) -> IResult<&'a str, Cow<'a, str>> {
559 move |i: &'a str| {
560 fn indent<'a>(wsp1: &'a str, wsp2: &'a str) -> impl Fn(&'a str) -> IResult<&'a str, ()> {
561 move |i: &str| {
562 let (i, _) = nom::character::complete::line_ending(i)?;
563 let (i, _) = nom::bytes::complete::tag(wsp1)(i)?;
564 let (i, _) = nom::bytes::complete::tag(wsp2)(i)?;
565 Ok((i, ()))
566 }
567 }
568
569 let (i, (wsp1, wsp2)) = nom::sequence::pair(
570 nom::character::complete::space0,
571 nom::combinator::map(nom::bytes::complete::tag(block_header), |_| " "),
572 )
573 .parse(i)?;
574
575 let (j, v) = nom::multi::separated_list1(
576 indent(wsp1, wsp2),
577 nom::character::complete::not_line_ending,
578 )
579 .parse(i)?;
580
581 if v.len() == 1 {
583 return Ok((j, Cow::Borrowed(v[0])));
584 };
585
586 let mut s = String::new();
587 let mut is_first = true;
588
589 for subs in &v {
590 if !is_first {
591 s.push(' ');
592 }
593 s.push_str(subs);
594 is_first = false;
595 }
596
597 Ok((j, Cow::from(s)))
598 }
599}
600
601fn rst_escaped_link_text_transform(i: &'_ str) -> IResult<&'_ str, Cow<'_, str>> {
607 nom::combinator::map(
608 nom::bytes::complete::escaped_transform(
609 nom::bytes::complete::is_not("\\"),
610 '\\',
611 alt((
613 tag("\\"),
614 tag("`"),
615 tag(":"),
616 tag("<"),
617 tag(">"),
618 tag("_"),
619 value("", tag(" ")),
620 )),
621 ),
622 |s| if s == i { Cow::from(i) } else { Cow::from(s) },
623 )
624 .parse(i)
625}
626
627fn remove_whitespace(i: &'_ str) -> IResult<&'_ str, Cow<'_, str>> {
629 let mut res = Cow::Borrowed("");
630 let mut j = i;
631 while !j.is_empty() {
632 let (k, _) = nom::character::complete::multispace0(j)?;
633 let (k, s) = nom::bytes::complete::escaped(
634 nom::character::complete::none_of("\\\r\n \t"),
635 '\\',
636 nom::character::complete::one_of(r#" :`<>\"#),
637 )(k)?;
638 res = match res {
639 Cow::Borrowed("") => Cow::Borrowed(s),
640 Cow::Borrowed(res_str) => {
641 let mut strg = res_str.to_string();
642 strg.push_str(s);
643 Cow::Owned(strg)
644 }
645 Cow::Owned(mut strg) => {
646 strg.push_str(s);
647 Cow::Owned(strg)
648 }
649 };
650 j = k;
651 }
652
653 Ok((j, res))
654}
655
656fn rst_escaped_link_destination_transform(i: &'_ str) -> IResult<&'_ str, Cow<'_, str>> {
661 let my_err = |_| {
662 nom::Err::Error(nom::error::Error::new(
663 i,
664 nom::error::ErrorKind::EscapedTransform,
665 ))
666 };
667
668 let c = &*remove_whitespace(i)?.1;
669
670 let s = nom::bytes::complete::escaped_transform::<_, nom::error::Error<_>, _, _, _, _, _, _>(
671 nom::bytes::complete::is_not("\\"),
672 '\\',
673 nom::character::complete::one_of(ESCAPABLE),
674 )(c)
675 .map_err(my_err)?
676 .1;
677
678 if s == i {
680 Ok(("", Cow::Borrowed(i)))
681 } else {
682 Ok(("", Cow::Owned(s)))
683 }
684}
685
686#[cfg(test)]
687mod tests {
688 use super::*;
689 use nom::error::ErrorKind;
690
691 #[test]
692 fn test_rst_text2dest() {
693 let expected = (
694 "abc",
695 (
696 Cow::from("Python home page"),
697 Cow::from("http://www.python.org"),
698 Cow::from(""),
699 ),
700 );
701 assert_eq!(
702 rst_text2dest("`Python home page <http://www.python.org>`__abc").unwrap(),
703 expected
704 );
705
706 let expected = (
707 "abc",
708 (
709 Cow::from(r#"Python<home> page"#),
710 Cow::from("http://www.python.org"),
711 Cow::from(""),
712 ),
713 );
714 assert_eq!(
715 rst_text2dest(r#"`Python\ \<home\> page <http://www.python.org>`__abc"#).unwrap(),
716 expected
717 );
718
719 let expected = (
720 "abc",
721 (
722 Cow::from(r#"my news at <http://python.org>"#),
723 Cow::from("http://news.python.org"),
724 Cow::from(""),
725 ),
726 );
727 assert_eq!(
728 rst_text2dest(r#"`my news at \<http://python.org\> <http://news.python.org>`__abc"#)
729 .unwrap(),
730 expected
731 );
732
733 let expected = (
734 "abc",
735 (
736 Cow::from(r#"my news at <http://python.org>"#),
737 Cow::from(r#"http://news. <python>.org"#),
738 Cow::from(""),
739 ),
740 );
741 assert_eq!(
742 rst_text2dest(
743 r#"`my news at \<http\://python.org\> <http:// news.\ \<python\>.org>`__abc"#
744 )
745 .unwrap(),
746 expected
747 );
748 }
749
750 #[test]
751 fn test_rst_parse_text2dest_label() {
752 let expected = ("abc", ("Python home page", "http://www.python.org"));
753 assert_eq!(
754 rst_parse_text2target(false, false)("`Python home page <http://www.python.org>`_abc")
755 .unwrap(),
756 expected
757 );
758
759 let expected = nom::Err::Error(nom::error::Error::new("abc", ErrorKind::Tag));
760 assert_eq!(
761 rst_parse_text2target(false, false)("`Python home page <http://www.python.org_>`_abc")
762 .unwrap_err(),
763 expected
764 );
765
766 let expected = nom::Err::Error(nom::error::Error::new("", ErrorKind::Tag));
767 assert_eq!(
768 rst_parse_text2target(false, false)("`_abc").unwrap_err(),
769 expected
770 );
771
772 let expected = ("abc", ("Python home page", "http://www.python.org"));
773 assert_eq!(
774 rst_parse_text2target(true, false)("`Python home page <http://www.python.org>`__abc")
775 .unwrap(),
776 expected
777 );
778
779 let expected = ("abc", (r#"Python\ \<home\> page"#, "http://www.python.org"));
780 assert_eq!(
781 rst_parse_text2target(false, false)(
782 r#"`Python\ \<home\> page <http://www.python.org>`_abc"#
783 )
784 .unwrap(),
785 expected
786 );
787
788 let expected = (
789 "abc",
790 (
791 r#"my news at \<http://python.org\>"#,
792 "http://news.python.org",
793 ),
794 );
795 assert_eq!(
796 rst_parse_text2target(false, false)(
797 r#"`my news at \<http://python.org\> <http://news.python.org>`_abc"#
798 )
799 .unwrap(),
800 expected
801 );
802
803 let expected = (
804 "abc",
805 (
806 r#"my news at \<http\://python.org\>"#,
807 r#"http:// news.\ \<python\>.org"#,
808 ),
809 );
810 assert_eq!(
811 rst_parse_text2target(false, false)(
812 r#"`my news at \<http\://python.org\> <http:// news.\ \<python\>.org>`_abc"#
813 )
814 .unwrap(),
815 expected
816 );
817
818 let expected = (
819 "abc",
820 (
821 r#"my news at \<http\://python.org\>"#,
822 r#"http:// news.\ \<python\>.org"#,
823 ),
824 );
825 assert_eq!(
826 rst_parse_text2target(false, false)(
827 r#"`my news at \<http\://python.org\> <http:// news.\ \<python\>.org>`_abc"#
828 )
829 .unwrap(),
830 expected
831 );
832 let expected = ("abc", (r#"rst link text"#, "rst_link_label"));
833 assert_eq!(
834 rst_parse_text2target(false, true)(r#"`rst link text <rst_link_label_>`_abc"#).unwrap(),
835 expected
836 );
837
838 let expected = nom::Err::Error(nom::error::Error::new("abc", ErrorKind::Tag));
839 assert_eq!(
840 rst_parse_text2target(false, true)(r#"`my news <python webpage>`_abc"#).unwrap_err(),
841 expected
842 );
843 }
844
845 #[test]
846 fn test_rst_text2label() {
847 assert_eq!(
848 rst_text2label(r#"link_text_ abc"#),
849 Ok((" abc", (Cow::from("link_text"), Cow::from("link_text"))))
850 );
851 assert_eq!(
852 rst_text2label(r#"`li\:nk text`_ abc"#),
853 Ok((" abc", (Cow::from("li:nk text"), Cow::from("li:nk text"))))
854 );
855 assert_eq!(
856 rst_text2label("`link text`__ abc"),
857 Ok((" abc", (Cow::from("link text"), Cow::from("_"))))
858 );
859 }
860
861 #[test]
862 fn test_rst_parse_text2label() {
863 assert_eq!(
864 rst_parse_text2label("linktext_ abc"),
865 Ok((" abc", ("linktext", "linktext")))
866 );
867
868 assert_eq!(
869 rst_parse_text2label("linktext__ abc"),
870 Ok((" abc", ("linktext", "_")))
871 );
872
873 assert_eq!(
874 rst_parse_text2label("link_text_ abc"),
875 Ok((" abc", ("link_text", "link_text")))
876 );
877
878 assert_eq!(
879 rst_parse_text2label("`link text`_ abc"),
880 Ok((" abc", ("link text", "link text")))
881 );
882
883 assert_eq!(
884 rst_parse_text2label("`link text`_abc"),
885 Ok(("abc", ("link text", "link text")))
886 );
887
888 assert_eq!(
889 rst_parse_text2label("`link_text`_ abc"),
890 Ok((" abc", ("link_text", "link_text")))
891 );
892
893 assert_eq!(
894 rst_parse_text2label("`link text`__ abc"),
895 Ok((" abc", ("link text", "_")))
896 );
897
898 assert_eq!(
899 rst_parse_text2label("`link text<link label_>`_ abc"),
900 Ok((" abc", ("link text", "link label")))
901 );
902 }
903
904 #[test]
905 fn test_rst_label2dest() {
906 let expected = (
907 "\nabc",
908 (
909 Cow::from("Python: home page"),
910 Cow::from("http://www.python.org"),
911 Cow::from(""),
912 ),
913 );
914 assert_eq!(
915 rst_label2dest(".. _`Python: home page`: http://www.python.org\nabc").unwrap(),
916 expected
917 );
918 assert_eq!(
919 rst_label2dest(" .. _`Python: home page`: http://www.py\n thon.org \nabc")
920 .unwrap(),
921 expected
922 );
923
924 let expected = nom::Err::Error(nom::error::Error::new(
925 "x .. _`Python: home page`: http://www.python.org\nabc",
926 ErrorKind::Tag,
927 ));
928 assert_eq!(
929 rst_label2dest("x .. _`Python: home page`: http://www.python.org\nabc").unwrap_err(),
930 expected
931 );
932
933 let expected = (
934 "",
935 (
936 Cow::from("Python: `home page`"),
937 Cow::from("http://www.python .org"),
938 Cow::from(""),
939 ),
940 );
941 assert_eq!(
942 rst_label2dest(r#".. _Python\: \`home page\`: http://www.python\ .org"#).unwrap(),
943 expected
944 );
945 assert_eq!(
946 rst_label2dest(r#".. _`Python: \`home page\``: http://www.python\ .org"#).unwrap(),
947 expected
948 );
949
950 let expected = (
951 "",
952 (
953 Cow::from("my news at <http://python.org>"),
954 Cow::from("http://news.python.org"),
955 Cow::from(""),
956 ),
957 );
958 assert_eq!(
959 rst_label2dest(r#".. _`my news at <http://python.org>`: http://news.python.org"#)
960 .unwrap(),
961 expected
962 );
963 assert_eq!(
964 rst_label2dest(r#".. _`my news at \<http://python.org\>`: http://news.python.org"#)
965 .unwrap(),
966 expected
967 );
968 assert_eq!(
969 rst_label2dest(r#".. _my news at \<http\://python.org\>: http://news.python.org"#)
970 .unwrap(),
971 expected
972 );
973
974 let expected = (
975 "",
976 (
977 Cow::from("my news"),
978 Cow::from("http://news.<python>.org"),
979 Cow::from(""),
980 ),
981 );
982 assert_eq!(
983 rst_label2dest(r#".. _my news: http://news.<python>.org"#).unwrap(),
984 expected
985 );
986 assert_eq!(
987 rst_label2dest(r#".. _my news: http://news.\<python\>.org"#).unwrap(),
988 expected
989 );
990
991 let expected = (
992 "",
993 (
994 Cow::from("_"),
995 Cow::from("http://news.python.org"),
996 Cow::from(""),
997 ),
998 );
999 assert_eq!(
1000 rst_label2dest(r#".. __: http://news.python.org"#).unwrap(),
1001 expected
1002 );
1003 assert_eq!(
1004 rst_label2dest(r#"__ http://news.python.org"#).unwrap(),
1005 expected
1006 );
1007 assert_eq!(
1008 rst_label2dest(".. _label: `link destination`_").unwrap_err(),
1009 nom::Err::Error(nom::error::Error::new(
1010 ".. _label: `link destination`_",
1011 ErrorKind::EscapedTransform
1012 )),
1013 );
1014 assert_eq!(
1015 rst_label2dest("__ link_destination_").unwrap_err(),
1016 nom::Err::Error(nom::error::Error::new(
1017 "__ link_destination_",
1018 ErrorKind::EscapedTransform
1019 )),
1020 );
1021 }
1022
1023 #[test]
1024 fn test_rst_label2label() {
1025 assert_eq!(
1026 rst_label2label(" .. _`alt label`: `label`_\nabc"),
1027 Ok(("\nabc", (Cow::from("alt label"), Cow::from("label"))))
1028 );
1029 assert_eq!(
1030 rst_label2label(" .. __: label_\nabc"),
1031 Ok(("\nabc", (Cow::from("_"), Cow::from("label"))))
1032 );
1033 assert_eq!(
1034 rst_label2label(" __ label_\nabc"),
1035 Ok(("\nabc", (Cow::from("_"), Cow::from("label"))))
1036 );
1037 assert_eq!(
1038 rst_label2label("_label: label").unwrap_err(),
1039 nom::Err::Error(nom::error::Error::new("_label: label", ErrorKind::Tag)),
1040 );
1041 assert_eq!(
1042 rst_label2label("__ destination").unwrap_err(),
1043 nom::Err::Error(nom::error::Error::new("", ErrorKind::Tag)),
1044 );
1045 }
1046
1047 #[test]
1048 fn test_rst_parse_label2target() {
1049 let expected = ("", ("Python home page", "http://www.python.org"));
1050 assert_eq!(
1051 rst_parse_label2target(false)("_Python home page: http://www.python.org").unwrap(),
1052 expected
1053 );
1054 assert_eq!(
1055 rst_parse_label2target(false)("_`Python home page`: http://www.python.org").unwrap(),
1056 expected
1057 );
1058
1059 let expected = ("", ("Python: home page", "http://www.python.org"));
1060 assert_eq!(
1061 rst_parse_label2target(false)("_`Python: home page`: http://www.python.org").unwrap(),
1062 expected
1063 );
1064
1065 let expected = ("", (r#"Python\: home page"#, "http://www.python.org"));
1066 assert_eq!(
1067 rst_parse_label2target(false)(r#"_Python\: home page: http://www.python.org"#).unwrap(),
1068 expected
1069 );
1070
1071 let expected = (
1072 "",
1073 ("my news at <http://python.org>", "http://news.python.org"),
1074 );
1075 assert_eq!(
1076 rst_parse_label2target(false)(
1077 r#"_`my news at <http://python.org>`: http://news.python.org"#
1078 )
1079 .unwrap(),
1080 expected
1081 );
1082
1083 let expected = (
1084 "",
1085 (
1086 r#"my news at \<http://python.org\>"#,
1087 "http://news.python.org",
1088 ),
1089 );
1090 assert_eq!(
1091 rst_parse_label2target(false)(
1092 r#"_`my news at \<http://python.org\>`: http://news.python.org"#
1093 )
1094 .unwrap(),
1095 expected
1096 );
1097
1098 let expected = (
1099 "",
1100 (
1101 r#"my news at \<http\://python.org\>"#,
1102 "http://news.python.org",
1103 ),
1104 );
1105 assert_eq!(
1106 rst_parse_label2target(false)(
1107 r#"_my news at \<http\://python.org\>: http://news.python.org"#
1108 )
1109 .unwrap(),
1110 expected
1111 );
1112
1113 let expected = ("", ("_", "http://news.python.org"));
1114 assert_eq!(
1115 rst_parse_label2target(false)(r#"__: http://news.python.org"#).unwrap(),
1116 expected
1117 );
1118
1119 let expected = ("", ("alt_label", "one_word_label"));
1120 assert_eq!(
1121 rst_parse_label2target(true)("_alt_label: one_word_label_").unwrap(),
1122 expected
1123 );
1124
1125 let expected = ("", ("alt label", "more words label"));
1126 assert_eq!(
1127 rst_parse_label2target(true)("_`alt label`: `more words label`_").unwrap(),
1128 expected
1129 );
1130 }
1131
1132 #[test]
1133 fn test_parse_simple_label() {
1134 let expected = ("", "one_word_label");
1135 assert_eq!(rst_parse_simple_label("one_word_label_").unwrap(), expected);
1136
1137 let expected = (" abc", "one_word_label");
1138 assert_eq!(
1139 rst_parse_simple_label("one_word_label_ abc").unwrap(),
1140 expected
1141 );
1142 assert_eq!(
1143 rst_parse_simple_label("`one_word_label`_ abc").unwrap(),
1144 expected
1145 );
1146
1147 let expected = ("", "more words label");
1148 assert_eq!(
1149 rst_parse_simple_label("`more words label`_").unwrap(),
1150 expected
1151 );
1152
1153 let expected = (". abc", "more words label");
1154 assert_eq!(
1155 rst_parse_simple_label("`more words label`_. abc").unwrap(),
1156 expected
1157 );
1158
1159 let expected = ("? abc", "more words label");
1160 assert_eq!(
1161 rst_parse_simple_label("`more words label`_? abc").unwrap(),
1162 expected
1163 );
1164
1165 let expected = (" abc", "more words label");
1166 assert_eq!(
1167 rst_parse_simple_label("`more words label`_ abc").unwrap(),
1168 expected
1169 );
1170
1171 assert_eq!(
1172 rst_parse_simple_label("_").unwrap_err(),
1173 nom::Err::Error(nom::error::Error::new("", ErrorKind::Not)),
1174 );
1175
1176 assert_eq!(
1177 rst_parse_simple_label("``_").unwrap_err(),
1178 nom::Err::Error(nom::error::Error::new("``_", ErrorKind::TakeTill1)),
1179 );
1180 }
1181
1182 #[test]
1183 fn test_rst_explicit_markup_block() {
1184 assert_eq!(
1185 rst_explicit_markup_block(".. ")(".. 11111"),
1186 Ok(("", Cow::from("11111")))
1187 );
1188 assert_eq!(
1189 rst_explicit_markup_block(".. ")(" .. 11111\nout"),
1190 Ok(("\nout", Cow::from("11111")))
1191 );
1192 assert_eq!(
1193 rst_explicit_markup_block(".. ")(" .. 11111\n 222222\n 333333\nout"),
1194 Ok(("\nout", Cow::from("11111 222222 333333")))
1195 );
1196 assert_eq!(
1197 rst_explicit_markup_block(".. ")(" .. first\n second\n 1indent\nout"),
1198 Ok(("\nout", Cow::from("first second 1indent")))
1199 );
1200 assert_eq!(
1201 rst_explicit_markup_block(".. ")(" ..first"),
1202 Err(nom::Err::Error(nom::error::Error::new(
1203 "..first",
1204 ErrorKind::Tag
1205 )))
1206 );
1207 assert_eq!(
1208 rst_explicit_markup_block(".. ")("x .. first"),
1209 Err(nom::Err::Error(nom::error::Error::new(
1210 "x .. first",
1211 ErrorKind::Tag
1212 )))
1213 );
1214 }
1215
1216 #[test]
1217 fn test_rst_escaped_link_text_transform() {
1218 assert_eq!(rst_escaped_link_text_transform(""), Ok(("", Cow::from(""))));
1219 assert_eq!(
1221 rst_escaped_link_text_transform(" "),
1222 Ok(("", Cow::from(" ")))
1223 );
1224 assert_eq!(
1226 rst_escaped_link_text_transform(r#"\ \ \ "#),
1227 Ok(("", Cow::from("")))
1228 );
1229 assert_eq!(
1230 rst_escaped_link_text_transform(r#"abc`:<>abc"#),
1231 Ok(("", Cow::from(r#"abc`:<>abc"#)))
1232 );
1233 assert_eq!(
1234 rst_escaped_link_text_transform(r#"\:\`\<\>\\"#),
1235 Ok(("", Cow::from(r#":`<>\"#)))
1236 );
1237 }
1238
1239 #[test]
1240 fn test_rst_escaped_link_destination_transform() {
1241 assert_eq!(
1242 rst_escaped_link_destination_transform(""),
1243 Ok(("", Cow::Borrowed("")))
1244 );
1245 assert_eq!(
1247 rst_escaped_link_destination_transform(" "),
1248 Ok(("", Cow::Borrowed("")))
1249 );
1250 assert_eq!(
1251 rst_escaped_link_destination_transform(" x x"),
1252 Ok(("", Cow::Owned("xx".to_string())))
1253 );
1254 assert_eq!(
1256 rst_escaped_link_destination_transform(r#"\ \ \ "#),
1257 Ok(("", Cow::Owned(" ".to_string())))
1258 );
1259 assert_eq!(
1260 rst_escaped_link_destination_transform(r#"abc`:<>abc"#),
1261 Ok(("", Cow::Borrowed(r#"abc`:<>abc"#)))
1262 );
1263 assert_eq!(
1264 rst_escaped_link_destination_transform(r#"\:\`\<\>\\"#),
1265 Ok(("", Cow::Owned(r#":`<>\"#.to_string())))
1266 );
1267 }
1268 #[test]
1269 fn test_remove_whitespace() {
1270 assert_eq!(remove_whitespace(" abc "), Ok(("", Cow::Borrowed("abc"))));
1271 assert_eq!(
1272 remove_whitespace(" x x"),
1273 Ok(("", Cow::Owned("xx".to_string())))
1274 );
1275 assert_eq!(remove_whitespace(" \t \r \n"), Ok(("", Cow::from(""))));
1276 assert_eq!(
1277 remove_whitespace(r#"\ \ \ "#),
1278 Ok(("", Cow::Borrowed(r#"\ \ \ "#)))
1279 );
1280 assert_eq!(
1281 remove_whitespace(r#"abc`:<>abc"#),
1282 Ok(("", Cow::Borrowed(r#"abc`:<>abc"#)))
1283 );
1284 assert_eq!(
1285 remove_whitespace(r#"\:\`\<\>\\"#),
1286 Ok(("", Cow::Borrowed(r#"\:\`\<\>\\"#)))
1287 );
1288
1289 assert_eq!(
1290 remove_whitespace("http://www.py\n thon.org"),
1291 Ok(("", Cow::Owned("http://www.python.org".to_string())))
1292 );
1293 }
1294}