diff options
author | Sam Tay <sam.chong.tay@gmail.com> | 2020-06-12 01:29:50 -0700 |
---|---|---|
committer | Sam Tay <sam.chong.tay@gmail.com> | 2020-06-12 01:29:50 -0700 |
commit | daa97e7dcf382a991fda5991a4cdac6299e32f63 (patch) | |
tree | ffabfeaa8cf0e76beb057b12f36163612e231681 | |
parent | b4fec5208ada5cc9c0ddcd4a395f164f8b346fe1 (diff) |
Update markdown tests
-rw-r--r-- | src/tui/app.rs | 2 | ||||
-rw-r--r-- | src/tui/markdown.rs | 303 |
2 files changed, 251 insertions, 54 deletions
diff --git a/src/tui/app.rs b/src/tui/app.rs index c267a97..0d355e0 100644 --- a/src/tui/app.rs +++ b/src/tui/app.rs @@ -223,7 +223,5 @@ Hit any key to quit this screen: }, ], }]; - - assert_eq!(run(qs).unwrap(), ()); } } diff --git a/src/tui/markdown.rs b/src/tui/markdown.rs index de031ed..644a01c 100644 --- a/src/tui/markdown.rs +++ b/src/tui/markdown.rs @@ -36,6 +36,7 @@ pub struct Parser<'a> { first: bool, item: Option<u64>, in_list: bool, + after_code_block: bool, stack: Vec<Style>, input: &'a str, parser: pulldown_cmark::Parser<'a>, @@ -48,6 +49,7 @@ impl<'a> Parser<'a> { input, item: None, in_list: false, + after_code_block: false, first: true, parser: pulldown_cmark::Parser::new(input), stack: Vec::new(), @@ -108,13 +110,19 @@ impl<'a> Iterator for Parser<'a> { return Some(self.literal("\n\n")); } Tag::Strong => self.stack.push(Style::from(Effect::Bold)), + Tag::Paragraph if self.after_code_block => { + self.after_code_block = false; + return Some(self.literal("\n")); + } Tag::Paragraph if !self.first && !self.in_list => { - return Some(self.literal("\n\n")) + return Some(self.literal("\n\n")); } Tag::List(ix) => { self.item = ix; self.in_list = true; - return Some(self.literal("\n\n")); + if !self.first { + return Some(self.literal("\n\n")); + } } Tag::Item => match self.item { Some(ix) => { @@ -139,6 +147,7 @@ impl<'a> Iterator for Parser<'a> { // TODO underline the link Tag::Link(_, link, _) => return Some(self.literal(format!("]({})", link))), Tag::CodeBlock(_) => { + self.after_code_block = true; self.stack.pop().unwrap(); } Tag::Emphasis | Tag::Strong => { @@ -147,6 +156,7 @@ impl<'a> Iterator for Parser<'a> { Tag::List(_) => { self.item = None; self.in_list = false; + self.first = false; } Tag::Item => { self.item = self.item.map(|ix| ix + 1); @@ -185,9 +195,6 @@ pub fn parse_spans(input: &str) -> Vec<StyledIndexedSpan> { Parser::new(input).collect() } -// TODO update these tests (some expectations will be different now) -// TODO and add more! bang on the code, lists, etc. -// use this as an opportunity to see how pulldown_cmark splits things up // TODO: how to reverse a list in Python answer is broken; test it here! #[cfg(test)] mod tests { @@ -195,59 +202,251 @@ mod tests { use cursive::utils::span::Span; #[test] - fn test_parse() { + fn test_basic_styles() { let input = r" Attention ==== I *really* love __Cursive__!"; let spans = parse_spans(input); let spans: Vec<_> = spans.iter().map(|span| span.resolve(input)).collect(); + let expected_spans = &[ + Span { + content: "Attention", + width: 9, + attr: &Style::from(PaletteColor::TitlePrimary), + }, + Span { + content: "\n\n", + width: 0, + attr: &Style::none(), + }, + Span { + content: "I ", + width: 2, + attr: &Style::none(), + }, + Span { + content: "really", + width: 6, + attr: &Style::from(Effect::Italic), + }, + Span { + content: " love ", + width: 6, + attr: &Style::none(), + }, + Span { + content: "Cursive", + width: 7, + attr: &Style::from(Effect::Bold), + }, + Span { + content: "!", + width: 1, + attr: &Style::none(), + }, + ]; - // println!("{:?}", spans); - assert_eq!( - &spans[..], - &[ - Span { - content: "# ", - width: 2, - attr: &Style::none(), - }, - Span { - content: "Attention", - width: 9, - attr: &Style::none(), - }, - Span { - content: "\n\n", - width: 0, - attr: &Style::none(), - }, - Span { - content: "I ", - width: 2, - attr: &Style::none(), - }, - Span { - content: "really", - width: 6, - attr: &Style::from(Effect::Italic), - }, - Span { - content: " love ", - width: 6, - attr: &Style::none(), - }, - Span { - content: "Cursive", - width: 7, - attr: &Style::from(Effect::Bold), - }, - Span { - content: "!", - width: 1, - attr: &Style::none(), - } - ] - ); + for (span, expected_span) in spans.iter().zip(expected_spans.iter()) { + assert_eq!(span, expected_span); + } + } + + #[test] + fn test_code() { + let input = r" +## project + +Here's some `inline code`. It should escape `*asterisks*`. +It should also respect + + indented code blocks + +and +```python +code fences +``` +Obviously."; + let spans = parse_spans(input); + let spans: Vec<_> = spans.iter().map(|span| span.resolve(input)).collect(); + let expected_spans = &[ + Span { + content: "project", + width: 7, + attr: &Style::from(PaletteColor::TitleSecondary), + }, + Span { + content: "\n\n", + width: 0, + attr: &Style::none(), + }, + Span { + content: "Here's some ", + width: 12, + attr: &Style::none(), + }, + Span { + content: "inline code", + width: 11, + attr: &Style::from(PaletteColor::Secondary), + }, + Span { + content: ". It should escape ", + width: 19, + attr: &Style::none(), + }, + Span { + content: "*asterisks*", + width: 11, + attr: &Style::from(PaletteColor::Secondary), + }, + Span { + content: ".", + width: 1, + attr: &Style::none(), + }, + Span { + content: "\n", + width: 0, + attr: &Style::none(), + }, + Span { + content: "It should also respect", + width: 22, + attr: &Style::none(), + }, + Span { + content: "\n\n", + width: 0, + attr: &Style::from(PaletteColor::Secondary), + }, + Span { + content: "indented code blocks\n", + width: 20, + attr: &Style::from(PaletteColor::Secondary), + }, + Span { + content: "\n", + width: 0, + attr: &Style::none(), + }, + Span { + content: "and", + width: 3, + attr: &Style::none(), + }, + Span { + content: "\n\n", + width: 0, + attr: &Style::from(PaletteColor::Secondary), + }, + Span { + content: "code fences\n", + width: 11, + attr: &Style::from(PaletteColor::Secondary), + }, + Span { + content: "\n", + width: 0, + attr: &Style::none(), + }, + Span { + content: "Obviously.", + width: 10, + attr: &Style::none(), + }, + ]; + + for (span, expected_span) in spans.iter().zip(expected_spans.iter()) { + assert_eq!(span, expected_span); + } + } + + #[test] + fn test_lists() { + let input = r" +1. Do something +0. Then another +or +- do them +- out of order"; + let spans = parse_spans(input); + let spans: Vec<_> = spans.iter().map(|span| span.resolve(input)).collect(); + let expected_spans = &[ + Span { + content: "1. ", + attr: &Style::from(Effect::Bold), + width: 3, + }, + Span { + content: "Do something", + attr: &Style::none(), + width: 12, + }, + Span { + content: "\n", + attr: &Style::none(), + width: 0, + }, + Span { + content: "2. ", + attr: &Style::from(Effect::Bold), + width: 3, + }, + Span { + content: "Then another", + attr: &Style::none(), + width: 12, + }, + Span { + content: "\n", + attr: &Style::none(), + width: 0, + }, + Span { + content: "or", + attr: &Style::none(), + width: 2, + }, + Span { + content: "\n", + attr: &Style::none(), + width: 0, + }, + Span { + content: "\n\n", + attr: &Style::none(), // TODO too many newlines + width: 0, + }, + Span { + content: "• ", + attr: &Style::none(), + width: 2, + }, + Span { + content: "do them", + attr: &Style::none(), + width: 7, + }, + Span { + content: "\n", + attr: &Style::none(), + width: 0, + }, + Span { + content: "• ", + attr: &Style::none(), + width: 2, + }, + Span { + content: "out of order", + attr: &Style::none(), + width: 12, + }, + ]; + + for (span, expected_span) in spans.iter().zip(expected_spans.iter()) { + assert_eq!(span, expected_span); + } } } |