diff --git a/crates/markdown_preview/src/markdown_renderer.rs b/crates/markdown_preview/src/markdown_renderer.rs index ce63cf96099a3f5eb0973a6ee97263e2734d3225..38b38466394cf8073b26b1ca5728eecc8230d9c1 100644 --- a/crates/markdown_preview/src/markdown_renderer.rs +++ b/crates/markdown_preview/src/markdown_renderer.rs @@ -233,10 +233,11 @@ fn render_markdown_list_item( cx: &mut RenderContext, ) -> AnyElement { use ParsedMarkdownListItemType::*; + let depth = parsed.depth.saturating_sub(1) as usize; let bullet = match &parsed.item_type { - Ordered(order) => format!("{}.", order).into_any_element(), - Unordered => "•".into_any_element(), + Ordered(order) => list_item_prefix(*order as usize, true, depth).into_any_element(), + Unordered => list_item_prefix(1, false, depth).into_any_element(), Task(checked, range) => div() .id(cx.next_id(range)) .mt(cx.scaled_rems(3.0 / 16.0)) @@ -292,10 +293,8 @@ fn render_markdown_list_item( .collect(); let item = h_flex() - .when(!parsed.nested, |this| { - this.pl(cx.scaled_rems(parsed.depth.saturating_sub(1) as f32)) - }) - .when(parsed.nested && parsed.depth > 1, |this| this.ml_neg_1p5()) + .when(!parsed.nested, |this| this.pl(cx.scaled_rems(depth as f32))) + .when(parsed.nested && depth > 0, |this| this.ml_neg_1p5()) .items_start() .children(vec![ bullet, @@ -880,6 +879,38 @@ impl Render for InteractiveMarkdownElementTooltip { } } +/// Returns the prefix for a list item. +fn list_item_prefix(order: usize, ordered: bool, depth: usize) -> String { + let ix = order.saturating_sub(1); + const NUMBERED_PREFIXES_1: &str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + const NUMBERED_PREFIXES_2: &str = "abcdefghijklmnopqrstuvwxyz"; + const BULLETS: [&str; 5] = ["•", "◦", "▪", "‣", "⁃"]; + + if ordered { + match depth { + 0 => format!("{}. ", order), + 1 => format!( + "{}. ", + NUMBERED_PREFIXES_1 + .chars() + .nth(ix % NUMBERED_PREFIXES_1.len()) + .unwrap() + ), + _ => format!( + "{}. ", + NUMBERED_PREFIXES_2 + .chars() + .nth(ix % NUMBERED_PREFIXES_2.len()) + .unwrap() + ), + } + } else { + let depth = depth.min(BULLETS.len() - 1); + let bullet = BULLETS[depth]; + return format!("{} ", bullet); + } +} + #[cfg(test)] mod tests { use super::*; @@ -1020,4 +1051,25 @@ mod tests { ]) ); } + + #[test] + fn test_list_item_prefix() { + assert_eq!(list_item_prefix(1, true, 0), "1. "); + assert_eq!(list_item_prefix(2, true, 0), "2. "); + assert_eq!(list_item_prefix(3, true, 0), "3. "); + assert_eq!(list_item_prefix(11, true, 0), "11. "); + assert_eq!(list_item_prefix(1, true, 1), "A. "); + assert_eq!(list_item_prefix(2, true, 1), "B. "); + assert_eq!(list_item_prefix(3, true, 1), "C. "); + assert_eq!(list_item_prefix(1, true, 2), "a. "); + assert_eq!(list_item_prefix(2, true, 2), "b. "); + assert_eq!(list_item_prefix(7, true, 2), "g. "); + assert_eq!(list_item_prefix(1, true, 1), "A. "); + assert_eq!(list_item_prefix(1, true, 2), "a. "); + assert_eq!(list_item_prefix(1, false, 0), "• "); + assert_eq!(list_item_prefix(1, false, 1), "◦ "); + assert_eq!(list_item_prefix(1, false, 2), "▪ "); + assert_eq!(list_item_prefix(1, false, 3), "‣ "); + assert_eq!(list_item_prefix(1, false, 4), "⁃ "); + } }