markdown_preview: Improve nested list item prefix style (#39606)

Release Notes:

- Improved nested list item prefix style for Markdown preview.


## Before

<img width="667" height="450" alt="SCR-20251006-rtis"
src="https://github.com/user-attachments/assets/439160c4-7982-463c-9017-268d47c42c0c"
/>

## After

<img width="739" height="440" alt="SCR-20251006-rzlb"
src="https://github.com/user-attachments/assets/f6c237d9-3ff0-4468-ae9c-6853c5c2946a"
/>

---------

Co-authored-by: Bennet Bo Fenner <bennetbo@gmx.de>
This commit is contained in:
Jason Lee
2025-10-28 16:44:05 +01:00
committed by GitHub
co-authored by Bennet Bo Fenner
parent d00ad02b05
commit 55554a8653
@@ -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), "⁃ ");
}
}