From d2cf5c772723f7c89db91b95fc3fa676d5f7c134 Mon Sep 17 00:00:00 2001 From: Asherah Connor Date: Thu, 11 Jul 2024 13:37:28 +0300 Subject: [PATCH] cm: count ol items from start of each list. Fixes #323; this fixes OL tasklists incidentally. --- src/cm.rs | 43 +++++++++++++++++++++++++++++------------ src/tests/commonmark.rs | 26 ++++++++++++++++++++----- 2 files changed, 52 insertions(+), 17 deletions(-) diff --git a/src/cm.rs b/src/cm.rs index e0a51dfa..d251c320 100644 --- a/src/cm.rs +++ b/src/cm.rs @@ -1,9 +1,9 @@ use crate::ctype::{isalpha, isdigit, ispunct, isspace}; -use crate::nodes::TableAlignment; use crate::nodes::{ AstNode, ListDelimType, ListType, NodeCodeBlock, NodeHeading, NodeHtmlBlock, NodeLink, NodeMath, NodeTable, NodeValue, NodeWikiLink, }; +use crate::nodes::{NodeList, TableAlignment}; #[cfg(feature = "shortcodes")] use crate::parser::shortcodes::NodeShortCode; use crate::parser::Options; @@ -61,6 +61,7 @@ struct CommonMarkFormatter<'a, 'o> { in_tight_list_item: bool, custom_escape: Option, u8) -> bool>, footnote_ix: u32, + ol_stack: Vec, } #[derive(PartialEq, Clone, Copy)] @@ -98,6 +99,7 @@ impl<'a, 'o> CommonMarkFormatter<'a, 'o> { in_tight_list_item: false, custom_escape: None, footnote_ix: 0, + ol_stack: vec![], } } @@ -420,18 +422,35 @@ impl<'a, 'o> CommonMarkFormatter<'a, 'o> { } fn format_list(&mut self, node: &'a AstNode<'a>, entering: bool) { - if !entering - && match node.next_sibling() { + let ol_start = match node.data.borrow().value { + NodeValue::List(NodeList { + list_type: ListType::Ordered, + start, + .. + }) => Some(start), + _ => None, + }; + + if entering { + if let Some(start) = ol_start { + self.ol_stack.push(start); + } + } else { + if ol_start.is_some() { + self.ol_stack.pop(); + } + + if match node.next_sibling() { Some(next_sibling) => matches!( next_sibling.data.borrow().value, NodeValue::CodeBlock(..) | NodeValue::List(..) ), _ => false, + } { + self.cr(); + write!(self, "").unwrap(); + self.blankline(); } - { - self.cr(); - write!(self, "").unwrap(); - self.blankline(); } } @@ -446,11 +465,11 @@ impl<'a, 'o> CommonMarkFormatter<'a, 'o> { let marker_width = if parent.list_type == ListType::Bullet { 2 } else { - let list_number = match node.data.borrow().value { - NodeValue::Item(ref ni) => ni.start, - NodeValue::TaskItem(_) => parent.start, - _ => unreachable!(), - }; + let last_stack = self.ol_stack.last_mut().unwrap(); + let list_number = *last_stack; + if entering { + *last_stack += 1; + } let list_delim = parent.delimiter; write!( listmarker, diff --git a/src/tests/commonmark.rs b/src/tests/commonmark.rs index d2bda4d8..5fb0a268 100644 --- a/src/tests/commonmark.rs +++ b/src/tests/commonmark.rs @@ -7,12 +7,9 @@ use ntest::test_case; #[test] fn commonmark_removes_redundant_strong() { - let options = Options::default(); - let input = "This is **something **even** better**"; let output = "This is **something even better**\n"; - - commonmark(input, output, Some(&options)); + commonmark(input, output, None); } #[test] @@ -52,7 +49,7 @@ fn math(markdown: &str, cm: &str) { options.extension.math_dollars = true; options.extension.math_code = true; - commonmark(markdown, cm, Some(&options)); + commonmark(markdown, cm, None); } #[test_case("This [[url]] that", "This [[url|url]] that\n")] @@ -63,3 +60,22 @@ fn wikilinks(markdown: &str, cm: &str) { commonmark(markdown, cm, Some(&options)); } +#[test] +fn commonmark_relist() { + commonmark( + concat!("3. one\n", "5. two\n",), + // Note that right now we always include enough room for up to two + // digits. TODO: Ideally we determine the maximum digit length before + // getting this far. + concat!("3. one\n", "4. two\n",), + None, + ); + + let mut options = Options::default(); + options.extension.tasklist = true; + commonmark( + concat!("3. [ ] one\n", "5. [ ] two\n",), + concat!("3. [ ] one\n", "4. [ ] two\n",), + Some(&options), + ); +}