summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSam Tay <sam.chong.tay@gmail.com>2020-06-12 01:29:50 -0700
committerSam Tay <sam.chong.tay@gmail.com>2020-06-12 01:29:50 -0700
commitdaa97e7dcf382a991fda5991a4cdac6299e32f63 (patch)
treeffabfeaa8cf0e76beb057b12f36163612e231681
parentb4fec5208ada5cc9c0ddcd4a395f164f8b346fe1 (diff)
Update markdown tests
-rw-r--r--src/tui/app.rs2
-rw-r--r--src/tui/markdown.rs303
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);
+ }
}
}