From 127649bd7e5c9bb2a3eae60b58bd61f0b050f58d Mon Sep 17 00:00:00 2001 From: digitalMoksha Date: Fri, 27 Sep 2024 21:06:24 -0500 Subject: [PATCH] Allow defintions to follow a term without a blank line --- src/parser/mod.rs | 20 +++-- src/scanners.re | 10 +++ src/scanners.rs | 100 +++++++++++++++++++++++- src/tests/fixtures/description_lists.md | 50 ++++++++---- 4 files changed, 158 insertions(+), 22 deletions(-) diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 3450d48c..6dfdf431 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -288,7 +288,7 @@ pub struct ExtensionOptions { /// let mut options = Options::default(); /// options.extension.description_lists = true; /// assert_eq!(markdown_to_html("Term\n\n: Definition", &options), - /// "
Term
\n
\n

Definition

\n
\n
\n"); + /// "
\n
Term
\n
\n

Definition

\n
\n
\n"); /// ``` pub description_lists: bool, @@ -1503,10 +1503,13 @@ impl<'a, 'o, 'c: 'o> Parser<'a, 'o, 'c> { container.data.borrow_mut().internal_offset = matched; } else if !indented && self.options.extension.description_lists - && line[self.first_nonspace] == b':' + && unwrap_into( + scanners::description_item_start(&line[self.first_nonspace..]), + &mut matched, + ) && self.parse_desc_list_details(container) { - let offset = self.first_nonspace + 1 - self.offset; + let offset = self.first_nonspace + matched - self.offset; self.advance_offset(line, offset, false); if strings::is_space_or_tab(line[self.offset]) { self.advance_offset(line, 1, true); @@ -1748,10 +1751,17 @@ impl<'a, 'o, 'c: 'o> Parser<'a, 'o, 'c> { } } - fn parse_desc_list_details(&mut self, container: &mut &'a AstNode<'a>) -> bool { + fn parse_desc_list_details(&mut self, node: &mut &'a AstNode<'a>) -> bool { + let container = node; + let last_child = match container.last_child() { Some(lc) => lc, - None => return false, + None => { + // Happens when the detail line is directly after the term, + // without a blank line between. + *container = container.parent().unwrap(); + container.last_child().unwrap() + } }; if node_matches!(last_child, NodeValue::Paragraph) { diff --git a/src/scanners.re b/src/scanners.re index 35bbc4f6..ecdcaa8c 100644 --- a/src/scanners.re +++ b/src/scanners.re @@ -431,4 +431,14 @@ pub fn tasklist(s: &[u8]) -> Option<(usize, u8)> { */ } +pub fn description_item_start(s: &[u8]) -> Option { + let mut cursor = 0; + let _marker = 0; + let len = s.len(); +/*!re2c + [:~] ([ \t]+|[\r\n]) { return Some(cursor); } + * { return None; } +*/ +} + // vim: set ft=rust: diff --git a/src/scanners.rs b/src/scanners.rs index 52b2a747..43e72ca6 100644 --- a/src/scanners.rs +++ b/src/scanners.rs @@ -1,4 +1,4 @@ -/* Generated by re2c 3.1 */ +/* Generated by re2c 3.0 */ pub fn atx_heading_start(s: &[u8]) -> Option { let mut cursor = 0; @@ -23848,4 +23848,102 @@ pub fn tasklist(s: &[u8]) -> Option<(usize, u8)> { } } +pub fn description_item_start(s: &[u8]) -> Option { + let mut cursor = 0; + let _marker = 0; + let len = s.len(); + + { + #[allow(unused_assignments)] + let mut yych: u8 = 0; + let mut yystate: usize = 0; + 'yyl: loop { + match yystate { + 0 => { + yych = unsafe { + if cursor < len { + *s.get_unchecked(cursor) + } else { + 0 + } + }; + cursor += 1; + match yych { + 0x3A | 0x7E => { + yystate = 3; + continue 'yyl; + } + _ => { + yystate = 1; + continue 'yyl; + } + } + } + 1 => { + yystate = 2; + continue 'yyl; + } + 2 => { + return None; + } + 3 => { + yych = unsafe { + if cursor < len { + *s.get_unchecked(cursor) + } else { + 0 + } + }; + match yych { + 0x09 | 0x20 => { + cursor += 1; + yystate = 4; + continue 'yyl; + } + 0x0A | 0x0D => { + cursor += 1; + yystate = 6; + continue 'yyl; + } + _ => { + yystate = 2; + continue 'yyl; + } + } + } + 4 => { + yych = unsafe { + if cursor < len { + *s.get_unchecked(cursor) + } else { + 0 + } + }; + match yych { + 0x09 | 0x20 => { + cursor += 1; + yystate = 4; + continue 'yyl; + } + _ => { + yystate = 5; + continue 'yyl; + } + } + } + 5 => { + return Some(cursor); + } + 6 => { + yystate = 5; + continue 'yyl; + } + _ => { + panic!("internal lexer error") + } + } + } + } +} + // vim: set ft=rust: diff --git a/src/tests/fixtures/description_lists.md b/src/tests/fixtures/description_lists.md index 72d4cace..a9ca0fc4 100644 --- a/src/tests/fixtures/description_lists.md +++ b/src/tests/fixtures/description_lists.md @@ -11,8 +11,9 @@ with `:` (after 0-2 spaces); subsequent lines must be indented unless they are lazy paragraph continuations. -The list is tight if there is no blank line between -the term and the first definition, otherwise loose. +There is no distinction between a "tight" list or a +"loose" list. Definitions are always wrapped in `

` +tags. ```````````````````````````````` example apple @@ -23,10 +24,12 @@ orange .

apple
-
red fruit +
+

red fruit

orange
-
orange fruit +
+

orange fruit

```````````````````````````````` @@ -65,10 +68,12 @@ orange .
apple
-
red fruit +
+

red fruit

orange
-
orange fruit +
+

orange fruit

```````````````````````````````` @@ -96,6 +101,8 @@ orange Multiple blocks in a definition: +Note that the column + ```````````````````````````````` example *apple* @@ -144,14 +151,17 @@ term
term
    -
  1. Para one

    -

    Para two

  2. +
  3. +

    Para one

    +

    Para two

    +
```````````````````````````````` Multiple definitions, tight: +(always rendered as loose) ```````````````````````````````` example apple @@ -164,14 +174,18 @@ orange .
apple
-
red fruit +
+

red fruit

-
computer company +
+

computer company

orange
-
orange fruit +
+

orange fruit

-
telecom company +
+

telecom company

```````````````````````````````` @@ -257,10 +271,12 @@ orange .
apple
-
red fruit +
+

red fruit

orange
-
orange fruit +
+

orange fruit

```````````````````````````````` @@ -299,10 +315,12 @@ bim

Foo

bar
-
baz +
+

baz

bim
-
bor +
+

bor

````````````````````````````````