diff --git a/crates/biome_markdown_factory/src/generated/node_factory.rs b/crates/biome_markdown_factory/src/generated/node_factory.rs index 6520598db14f..64e8684eecc6 100644 --- a/crates/biome_markdown_factory/src/generated/node_factory.rs +++ b/crates/biome_markdown_factory/src/generated/node_factory.rs @@ -20,11 +20,11 @@ pub fn md_autolink( ], )) } -pub fn md_bullet(bullet_token: SyntaxToken, content: MdBlockList) -> MdBullet { +pub fn md_bullet(prefix: MdListMarkerPrefix, content: MdBlockList) -> MdBullet { MdBullet::unwrap_cast(SyntaxNode::new_detached( MarkdownSyntaxKind::MD_BULLET, [ - Some(SyntaxElement::Token(bullet_token)), + Some(SyntaxElement::Node(prefix.into_syntax())), Some(SyntaxElement::Node(content.into_syntax())), ], )) @@ -144,6 +144,12 @@ pub fn md_indent_code_block(content: MdInlineItemList) -> MdIndentCodeBlock { [Some(SyntaxElement::Node(content.into_syntax()))], )) } +pub fn md_indent_token(md_indent_char_token: SyntaxToken) -> MdIndentToken { + MdIndentToken::unwrap_cast(SyntaxNode::new_detached( + MarkdownSyntaxKind::MD_INDENT_TOKEN, + [Some(SyntaxElement::Token(md_indent_char_token))], + )) +} pub fn md_inline_code( l_tick_token: SyntaxToken, content: MdInlineItemList, @@ -383,6 +389,42 @@ pub fn md_link_title(content: MdInlineItemList) -> MdLinkTitle { [Some(SyntaxElement::Node(content.into_syntax()))], )) } +pub fn md_list_marker_prefix( + pre_marker_indent: MdIndentTokenList, + marker_token: SyntaxToken, + content_indent: MdIndentTokenList, +) -> MdListMarkerPrefixBuilder { + MdListMarkerPrefixBuilder { + pre_marker_indent, + marker_token, + content_indent, + post_marker_space_token: None, + } +} +pub struct MdListMarkerPrefixBuilder { + pre_marker_indent: MdIndentTokenList, + marker_token: SyntaxToken, + content_indent: MdIndentTokenList, + post_marker_space_token: Option, +} +impl MdListMarkerPrefixBuilder { + pub fn with_post_marker_space_token(mut self, post_marker_space_token: SyntaxToken) -> Self { + self.post_marker_space_token = Some(post_marker_space_token); + self + } + pub fn build(self) -> MdListMarkerPrefix { + MdListMarkerPrefix::unwrap_cast(SyntaxNode::new_detached( + MarkdownSyntaxKind::MD_LIST_MARKER_PREFIX, + [ + Some(SyntaxElement::Node(self.pre_marker_indent.into_syntax())), + Some(SyntaxElement::Token(self.marker_token)), + self.post_marker_space_token + .map(|token| SyntaxElement::Token(token)), + Some(SyntaxElement::Node(self.content_indent.into_syntax())), + ], + )) + } +} pub fn md_newline(value_token: SyntaxToken) -> MdNewline { MdNewline::unwrap_cast(SyntaxNode::new_detached( MarkdownSyntaxKind::MD_NEWLINE, @@ -633,6 +675,18 @@ where .map(|item| Some(item.into_syntax().into())), )) } +pub fn md_indent_token_list(items: I) -> MdIndentTokenList +where + I: IntoIterator, + I::IntoIter: ExactSizeIterator, +{ + MdIndentTokenList::unwrap_cast(SyntaxNode::new_detached( + MarkdownSyntaxKind::MD_INDENT_TOKEN_LIST, + items + .into_iter() + .map(|item| Some(item.into_syntax().into())), + )) +} pub fn md_inline_item_list(items: I) -> MdInlineItemList where I: IntoIterator, diff --git a/crates/biome_markdown_factory/src/generated/syntax_factory.rs b/crates/biome_markdown_factory/src/generated/syntax_factory.rs index 079fcdff278b..5241566fe7ab 100644 --- a/crates/biome_markdown_factory/src/generated/syntax_factory.rs +++ b/crates/biome_markdown_factory/src/generated/syntax_factory.rs @@ -53,10 +53,7 @@ impl SyntaxFactory for MarkdownSyntaxFactory { let mut slots: RawNodeSlots<2usize> = RawNodeSlots::default(); let mut current_element = elements.next(); if let Some(element) = ¤t_element - && matches!( - element.kind(), - T ! [-] | T ! [*] | T ! [+] | MD_ORDERED_LIST_MARKER - ) + && MdListMarkerPrefix::can_cast(element.kind()) { slots.mark_present(); current_element = elements.next(); @@ -313,6 +310,25 @@ impl SyntaxFactory for MarkdownSyntaxFactory { } slots.into_node(MD_INDENT_CODE_BLOCK, children) } + MD_INDENT_TOKEN => { + let mut elements = (&children).into_iter(); + let mut slots: RawNodeSlots<1usize> = RawNodeSlots::default(); + let mut current_element = elements.next(); + if let Some(element) = ¤t_element + && element.kind() == MD_INDENT_CHAR + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if current_element.is_some() { + return RawSyntaxNode::new( + MD_INDENT_TOKEN.to_bogus(), + children.into_iter().map(Some), + ); + } + slots.into_node(MD_INDENT_TOKEN, children) + } MD_INLINE_CODE => { let mut elements = (&children).into_iter(); let mut slots: RawNodeSlots<3usize> = RawNodeSlots::default(); @@ -704,6 +720,49 @@ impl SyntaxFactory for MarkdownSyntaxFactory { } slots.into_node(MD_LINK_TITLE, children) } + MD_LIST_MARKER_PREFIX => { + let mut elements = (&children).into_iter(); + let mut slots: RawNodeSlots<4usize> = RawNodeSlots::default(); + let mut current_element = elements.next(); + if let Some(element) = ¤t_element + && MdIndentTokenList::can_cast(element.kind()) + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if let Some(element) = ¤t_element + && matches!( + element.kind(), + T ! [-] | T ! [*] | T ! [+] | MD_ORDERED_LIST_MARKER + ) + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if let Some(element) = ¤t_element + && element.kind() == MD_LIST_POST_MARKER_SPACE + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if let Some(element) = ¤t_element + && MdIndentTokenList::can_cast(element.kind()) + { + slots.mark_present(); + current_element = elements.next(); + } + slots.next_slot(); + if current_element.is_some() { + return RawSyntaxNode::new( + MD_LIST_MARKER_PREFIX.to_bogus(), + children.into_iter().map(Some), + ); + } + slots.into_node(MD_LIST_MARKER_PREFIX, children) + } MD_NEWLINE => { let mut elements = (&children).into_iter(); let mut slots: RawNodeSlots<1usize> = RawNodeSlots::default(); @@ -1050,6 +1109,9 @@ impl SyntaxFactory for MarkdownSyntaxFactory { MD_BULLET_LIST => Self::make_node_list_syntax(kind, children, MdBullet::can_cast), MD_CODE_NAME_LIST => Self::make_node_list_syntax(kind, children, MdTextual::can_cast), MD_HASH_LIST => Self::make_node_list_syntax(kind, children, MdHash::can_cast), + MD_INDENT_TOKEN_LIST => { + Self::make_node_list_syntax(kind, children, MdIndentToken::can_cast) + } MD_INLINE_ITEM_LIST => { Self::make_node_list_syntax(kind, children, AnyMdInline::can_cast) } diff --git a/crates/biome_markdown_formatter/src/generated.rs b/crates/biome_markdown_formatter/src/generated.rs index c0eddac2ddc4..7bbc5019e64a 100644 --- a/crates/biome_markdown_formatter/src/generated.rs +++ b/crates/biome_markdown_formatter/src/generated.rs @@ -461,6 +461,44 @@ impl IntoFormat for biome_markdown_syntax::MdIndentCodeBl ) } } +impl FormatRule + for crate::markdown::auxiliary::indent_token::FormatMdIndentToken +{ + type Context = MarkdownFormatContext; + #[inline(always)] + fn fmt( + &self, + node: &biome_markdown_syntax::MdIndentToken, + f: &mut MarkdownFormatter, + ) -> FormatResult<()> { + FormatNodeRule::::fmt(self, node, f) + } +} +impl AsFormat for biome_markdown_syntax::MdIndentToken { + type Format<'a> = FormatRefWithRule< + 'a, + biome_markdown_syntax::MdIndentToken, + crate::markdown::auxiliary::indent_token::FormatMdIndentToken, + >; + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new( + self, + crate::markdown::auxiliary::indent_token::FormatMdIndentToken::default(), + ) + } +} +impl IntoFormat for biome_markdown_syntax::MdIndentToken { + type Format = FormatOwnedWithRule< + biome_markdown_syntax::MdIndentToken, + crate::markdown::auxiliary::indent_token::FormatMdIndentToken, + >; + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new( + self, + crate::markdown::auxiliary::indent_token::FormatMdIndentToken::default(), + ) + } +} impl FormatRule for crate::markdown::auxiliary::inline_code::FormatMdInlineCode { @@ -873,6 +911,44 @@ impl IntoFormat for biome_markdown_syntax::MdLinkTitle { ) } } +impl FormatRule + for crate::markdown::auxiliary::list_marker_prefix::FormatMdListMarkerPrefix +{ + type Context = MarkdownFormatContext; + #[inline(always)] + fn fmt( + &self, + node: &biome_markdown_syntax::MdListMarkerPrefix, + f: &mut MarkdownFormatter, + ) -> FormatResult<()> { + FormatNodeRule::::fmt(self, node, f) + } +} +impl AsFormat for biome_markdown_syntax::MdListMarkerPrefix { + type Format<'a> = FormatRefWithRule< + 'a, + biome_markdown_syntax::MdListMarkerPrefix, + crate::markdown::auxiliary::list_marker_prefix::FormatMdListMarkerPrefix, + >; + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new( + self, + crate::markdown::auxiliary::list_marker_prefix::FormatMdListMarkerPrefix::default(), + ) + } +} +impl IntoFormat for biome_markdown_syntax::MdListMarkerPrefix { + type Format = FormatOwnedWithRule< + biome_markdown_syntax::MdListMarkerPrefix, + crate::markdown::auxiliary::list_marker_prefix::FormatMdListMarkerPrefix, + >; + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new( + self, + crate::markdown::auxiliary::list_marker_prefix::FormatMdListMarkerPrefix::default(), + ) + } +} impl FormatRule for crate::markdown::auxiliary::newline::FormatMdNewline { @@ -1467,6 +1543,31 @@ impl IntoFormat for biome_markdown_syntax::MdHashList { ) } } +impl AsFormat for biome_markdown_syntax::MdIndentTokenList { + type Format<'a> = FormatRefWithRule< + 'a, + biome_markdown_syntax::MdIndentTokenList, + crate::markdown::lists::indent_token_list::FormatMdIndentTokenList, + >; + fn format(&self) -> Self::Format<'_> { + FormatRefWithRule::new( + self, + crate::markdown::lists::indent_token_list::FormatMdIndentTokenList::default(), + ) + } +} +impl IntoFormat for biome_markdown_syntax::MdIndentTokenList { + type Format = FormatOwnedWithRule< + biome_markdown_syntax::MdIndentTokenList, + crate::markdown::lists::indent_token_list::FormatMdIndentTokenList, + >; + fn into_format(self) -> Self::Format { + FormatOwnedWithRule::new( + self, + crate::markdown::lists::indent_token_list::FormatMdIndentTokenList::default(), + ) + } +} impl AsFormat for biome_markdown_syntax::MdInlineItemList { type Format<'a> = FormatRefWithRule< 'a, diff --git a/crates/biome_markdown_formatter/src/markdown/auxiliary/indent_token.rs b/crates/biome_markdown_formatter/src/markdown/auxiliary/indent_token.rs new file mode 100644 index 000000000000..ea08f5a0cf0b --- /dev/null +++ b/crates/biome_markdown_formatter/src/markdown/auxiliary/indent_token.rs @@ -0,0 +1,10 @@ +use crate::prelude::*; +use biome_markdown_syntax::MdIndentToken; +use biome_rowan::AstNode; +#[derive(Debug, Clone, Default)] +pub(crate) struct FormatMdIndentToken; +impl FormatNodeRule for FormatMdIndentToken { + fn fmt_fields(&self, node: &MdIndentToken, f: &mut MarkdownFormatter) -> FormatResult<()> { + format_verbatim_node(node.syntax()).fmt(f) + } +} diff --git a/crates/biome_markdown_formatter/src/markdown/auxiliary/list_marker_prefix.rs b/crates/biome_markdown_formatter/src/markdown/auxiliary/list_marker_prefix.rs new file mode 100644 index 000000000000..afde94c1b81b --- /dev/null +++ b/crates/biome_markdown_formatter/src/markdown/auxiliary/list_marker_prefix.rs @@ -0,0 +1,10 @@ +use crate::prelude::*; +use biome_markdown_syntax::MdListMarkerPrefix; +use biome_rowan::AstNode; +#[derive(Debug, Clone, Default)] +pub(crate) struct FormatMdListMarkerPrefix; +impl FormatNodeRule for FormatMdListMarkerPrefix { + fn fmt_fields(&self, node: &MdListMarkerPrefix, f: &mut MarkdownFormatter) -> FormatResult<()> { + format_verbatim_node(node.syntax()).fmt(f) + } +} diff --git a/crates/biome_markdown_formatter/src/markdown/auxiliary/mod.rs b/crates/biome_markdown_formatter/src/markdown/auxiliary/mod.rs index 853b9be651c9..b144e1dfa72e 100644 --- a/crates/biome_markdown_formatter/src/markdown/auxiliary/mod.rs +++ b/crates/biome_markdown_formatter/src/markdown/auxiliary/mod.rs @@ -12,6 +12,7 @@ pub(crate) mod header; pub(crate) mod html_block; pub(crate) mod indent; pub(crate) mod indent_code_block; +pub(crate) mod indent_token; pub(crate) mod inline_code; pub(crate) mod inline_emphasis; pub(crate) mod inline_html; @@ -23,6 +24,7 @@ pub(crate) mod link_destination; pub(crate) mod link_label; pub(crate) mod link_reference_definition; pub(crate) mod link_title; +pub(crate) mod list_marker_prefix; pub(crate) mod newline; pub(crate) mod ordered_list_item; pub(crate) mod paragraph; diff --git a/crates/biome_markdown_formatter/src/markdown/lists/indent_token_list.rs b/crates/biome_markdown_formatter/src/markdown/lists/indent_token_list.rs new file mode 100644 index 000000000000..6bdbaeb3f1e8 --- /dev/null +++ b/crates/biome_markdown_formatter/src/markdown/lists/indent_token_list.rs @@ -0,0 +1,10 @@ +use crate::prelude::*; +use biome_markdown_syntax::MdIndentTokenList; +#[derive(Debug, Clone, Default)] +pub(crate) struct FormatMdIndentTokenList; +impl FormatRule for FormatMdIndentTokenList { + type Context = MarkdownFormatContext; + fn fmt(&self, node: &MdIndentTokenList, f: &mut MarkdownFormatter) -> FormatResult<()> { + f.join().entries(node.iter().formatted()).finish() + } +} diff --git a/crates/biome_markdown_formatter/src/markdown/lists/mod.rs b/crates/biome_markdown_formatter/src/markdown/lists/mod.rs index 5e7f4656a05f..d3e753f35b0d 100644 --- a/crates/biome_markdown_formatter/src/markdown/lists/mod.rs +++ b/crates/biome_markdown_formatter/src/markdown/lists/mod.rs @@ -4,5 +4,6 @@ pub(crate) mod block_list; pub(crate) mod bullet_list; pub(crate) mod code_name_list; pub(crate) mod hash_list; +pub(crate) mod indent_token_list; pub(crate) mod inline_item_list; pub(crate) mod quote_indent_list; diff --git a/crates/biome_markdown_parser/src/parser.rs b/crates/biome_markdown_parser/src/parser.rs index 03c47843427d..812b63b37303 100644 --- a/crates/biome_markdown_parser/src/parser.rs +++ b/crates/biome_markdown_parser/src/parser.rs @@ -166,7 +166,6 @@ impl<'source> MarkdownParser<'source> { /// Record tight/loose information for a parsed list node. pub(crate) fn record_list_tightness(&mut self, range: TextRange, is_tight: bool) { - let range = self.trim_range(range); self.state .list_tightness .push(ListTightness { range, is_tight }); @@ -180,7 +179,6 @@ impl<'source> MarkdownParser<'source> { marker_width: usize, spaces_after_marker: usize, ) { - let range = self.trim_range(range); self.state.list_item_indents.push(ListItemIndent { range, indent, @@ -191,7 +189,6 @@ impl<'source> MarkdownParser<'source> { } pub(crate) fn record_quote_indent(&mut self, range: TextRange, indent: usize) { - let range = self.trim_range(range); self.state.quote_indents.push(QuoteIndent { range, indent }); } @@ -294,33 +291,6 @@ impl<'source> MarkdownParser<'source> { self.state.virtual_line_start = Some(self.cur_range().start()); } - pub(crate) fn trim_range(&self, range: TextRange) -> TextRange { - let start: usize = range.start().into(); - let end: usize = range.end().into(); - if start >= end { - return range; - } - - let source = self.source.source_text(); - let slice = &source[start..end]; - if slice - .trim_matches(|c: char| matches!(c, ' ' | '\t' | '\r')) - .is_empty() - { - return TextRange::new(range.start(), range.start()); - } - let leading = slice - .len() - .saturating_sub(slice.trim_start_matches([' ', '\t', '\r']).len()); - let trailing = slice - .len() - .saturating_sub(slice.trim_end_matches([' ', '\t', '\r']).len()); - let new_start = start + leading; - let new_end = end.saturating_sub(trailing); - - TextRange::new((new_start as u32).into(), (new_end as u32).into()) - } - /// Skip an optional indentation token at line start if it is whitespace-only /// and does not exceed `max_indent` columns. pub fn skip_line_indent(&mut self, max_indent: usize) -> bool { diff --git a/crates/biome_markdown_parser/src/syntax/list.rs b/crates/biome_markdown_parser/src/syntax/list.rs index 7bcdb5056632..a8cd03674d2f 100644 --- a/crates/biome_markdown_parser/src/syntax/list.rs +++ b/crates/biome_markdown_parser/src/syntax/list.rs @@ -155,6 +155,47 @@ fn skip_list_marker_indent(p: &mut MarkdownParser) { } } +/// Emit an MdIndentTokenList containing 0-N MdIndentToken nodes. +/// +/// Consumes whitespace-only MD_TEXTUAL_LITERAL tokens up to `max_columns` +/// columns of indent. Pass 0 for max_columns to consume all remaining whitespace. +/// Returns the number of columns consumed. +fn emit_indent_char_list(p: &mut MarkdownParser, max_columns: usize) -> usize { + let list_m = p.start(); + let mut consumed = 0usize; + while p.at(MD_TEXTUAL_LITERAL) && is_whitespace_only(p.cur_text()) { + let text = p.cur_text(); + let width: usize = text + .chars() + .map(|c| if c == '\t' { TAB_STOP_SPACES } else { 1 }) + .sum(); + if max_columns > 0 && consumed + width > max_columns { + break; + } + consumed += width; + let char_m = p.start(); + p.bump_remap(MD_INDENT_CHAR); + char_m.complete(p, MD_INDENT_TOKEN); + } + list_m.complete(p, MD_INDENT_TOKEN_LIST); + consumed +} + +/// Consume the first whitespace token after the list marker as MD_LIST_POST_MARKER_SPACE. +/// Returns true if a space was consumed. +fn emit_list_post_marker_space(p: &mut MarkdownParser) -> bool { + if !p.at(MD_TEXTUAL_LITERAL) { + return false; + } + let text = p.cur_text(); + if text == " " || text == "\t" { + p.bump_remap(MD_LIST_POST_MARKER_SPACE); + true + } else { + false + } +} + fn is_whitespace_only(text: &str) -> bool { !text.is_empty() && text.chars().all(|c| c == ' ' || c == '\t') } @@ -246,6 +287,11 @@ pub(crate) fn marker_followed_by_whitespace_or_eol(p: &mut MarkdownParser) -> bo return true; } + // MD_HARD_LINE_LITERAL is spaces+newline — counts as whitespace after marker. + if p.at(MD_HARD_LINE_LITERAL) { + return true; + } + if p.at(MD_TEXTUAL_LITERAL) { let text = p.cur_text(); return text.starts_with(' ') || text.starts_with('\t'); @@ -648,22 +694,26 @@ fn parse_bullet(p: &mut MarkdownParser) -> (ParsedSyntax, ListItemBlankInfo) { let m = p.start(); // Compute the marker indent, handling both normal and virtual line start cases. - // For virtual line start (nested list detection), we compute the actual column - // to ensure correct indented code block detection. let marker_indent = compute_marker_indent(p); - skip_list_marker_indent(p); + + // #region MdListMarkerPrefix + let prefix_m = p.start(); + + // Pre-marker indent: consume all whitespace before the marker. + // The 0-3 column rule is enforced by at_bullet_list_item(); no cap needed here. + // In nested contexts, skip_line_indent() may leave more than 3 columns. + emit_indent_char_list(p, 0); // Bullet marker is 1 character (-, *, or +) let marker_width = 1; - // Bump the bullet marker (-, *, or +) - let mut marker_token_text = None; + // Bump the bullet marker + let mut setext_marker = false; if p.at(MD_SETEXT_UNDERLINE_LITERAL) && is_single_dash_setext_marker(p.cur_text()) { - marker_token_text = Some(p.cur_text().to_string()); + setext_marker = true; p.bump_remap(T![-]); } else if p.at(MD_TEXTUAL_LITERAL) && is_textual_bullet_marker(p.cur_text()) { - let text = p.cur_text().to_string(); - marker_token_text = Some(text.clone()); + let text = p.cur_text(); if text == "-" { p.bump_remap(T![-]); } else if text == "*" { @@ -679,50 +729,60 @@ fn parse_bullet(p: &mut MarkdownParser) -> (ParsedSyntax, ListItemBlankInfo) { p.bump(T![+]); } - // Count spaces after marker to determine required indentation. - // Per CommonMark §5.2, content aligns to first non-space after marker. - // - // For the setext-remapped case (marker_token_text is Some), the token includes - // trailing spaces before the newline. This means the first line is empty - // (marker + whitespace + newline), and the trailing spaces shouldn't count - // for indentation purposes. Per CommonMark, the required indent is marker_width + 1. - let (spaces_after_marker, first_line_empty) = if let Some(text) = marker_token_text.as_deref() { - // Setext token case: token is "- " or "- " etc. followed by newline - // The first line is empty, so use minimum indent (marker_width + 1) - let spaces = count_spaces_after_dash_in_token(text, marker_indent + marker_width); - (spaces, true) + // Count spaces BEFORE consuming (peek from source text) + let spaces_after_marker = if setext_marker { + 0 + } else { + count_spaces_after_marker(p.source_after_current(), marker_indent + marker_width) + }; + + let first_line_empty = if setext_marker { + true } else { - let spaces = - count_spaces_after_marker(p.source_after_current(), marker_indent + marker_width); - // Check if first line is empty by looking at what follows - let first_empty = p.lookahead(|p| { - // Skip any whitespace + p.lookahead(|p| { while p.at(MD_TEXTUAL_LITERAL) && is_whitespace_only(p.cur_text()) { p.bump(MD_TEXTUAL_LITERAL); } - // If we hit newline or EOF, first line is empty p.at(NEWLINE) || p.at(T![EOF]) - }); - (spaces, first_empty) + }) }; - // Set required indent for continuation lines - // Required indent = marker width + spaces after marker (minimum 1) - // BUT: if first line is empty (marker + whitespace + newline), use minimum indent + // Post-marker space (first whitespace token after marker) + if !setext_marker { + emit_list_post_marker_space(p); + } + + // Content indent (remaining whitespace tokens on first line) + if !setext_marker && !first_line_empty && spaces_after_marker > 1 { + emit_indent_char_list(p, 0); + } else { + // Empty first line or no content indent -- emit empty MdIndentTokenList + let empty_m = p.start(); + empty_m.complete(p, MD_INDENT_TOKEN_LIST); + } + + prefix_m.complete(p, MD_LIST_MARKER_PREFIX); + // #endregion + let prev_required_indent = p.state().list_item_required_indent; let prev_marker_indent = p.state().list_item_marker_indent; - p.state_mut().list_item_required_indent = if spaces_after_marker > INDENT_CODE_BLOCK_SPACES { - marker_indent + marker_width + 1 - } else if first_line_empty { - // Empty first line: use minimum indent (marker + 1 space) - marker_indent + marker_width + 1 + + let effective_spaces = if setext_marker { + 0 } else { - marker_indent + marker_width + spaces_after_marker.max(1) + spaces_after_marker }; + + p.state_mut().list_item_required_indent = + if effective_spaces > INDENT_CODE_BLOCK_SPACES || first_line_empty { + marker_indent + marker_width + 1 + } else { + marker_indent + marker_width + effective_spaces.max(1) + }; p.state_mut().list_item_marker_indent = marker_indent; // Parse block content (MD_BLOCK_LIST) - let blank_info = parse_list_item_block_content(p, spaces_after_marker); + let blank_info = parse_list_item_block_content(p, effective_spaces); // Restore previous required indent p.state_mut().list_item_required_indent = prev_required_indent; @@ -730,14 +790,8 @@ fn parse_bullet(p: &mut MarkdownParser) -> (ParsedSyntax, ListItemBlankInfo) { let completed = m.complete(p, MD_BULLET); let range = completed.range(p); - let indent = marker_indent + marker_width + spaces_after_marker.max(1); - p.record_list_item_indent( - range, - indent, - marker_indent, - marker_width, - spaces_after_marker, - ); + let indent = marker_indent + marker_width + effective_spaces.max(1); + p.record_list_item_indent(range, indent, marker_indent, marker_width, effective_spaces); (Present(completed), blank_info) } @@ -934,51 +988,60 @@ fn parse_ordered_bullet(p: &mut MarkdownParser) -> (ParsedSyntax, ListItemBlankI } let m = p.start(); - - // Compute the marker indent, handling both normal and virtual line start cases. - // For virtual line start (nested list detection), we compute the actual column - // to ensure correct indented code block detection. let marker_indent = compute_marker_indent(p); - skip_list_marker_indent(p); - // Get marker width from actual token text (e.g., "1." = 2, "10." = 3) - let marker_width = p.cur_text().len(); + // #region MdListMarkerPrefix + let prefix_m = p.start(); + + // Pre-marker indent: consume all whitespace before the marker. + // The 0-3 column rule is enforced by at_order_list_item(); no cap needed here. + // In nested contexts, skip_line_indent() may leave more than 3 columns. + emit_indent_char_list(p, 0); - // Bump the ordered list marker + // Ordered marker (variable width: "1." = 2, "10." = 3, etc.) + let marker_width = p.cur_text().len(); p.bump(MD_ORDERED_LIST_MARKER); - // Count spaces after marker to determine required indentation. - // Per CommonMark §5.2, content aligns to first non-space after marker. + // Count spaces (peek from source text BEFORE consuming) let spaces_after_marker = count_spaces_after_marker(p.source_after_current(), marker_indent + marker_width); - // Check if first line is empty (marker followed by only whitespace + newline) let first_line_empty = p.lookahead(|p| { while p.at(MD_TEXTUAL_LITERAL) && is_whitespace_only(p.cur_text()) { p.bump(MD_TEXTUAL_LITERAL); } - p.at(NEWLINE) || p.at(T![EOF]) + // MD_HARD_LINE_LITERAL is spaces+newline produced by the lexer when + // 2+ trailing spaces precede a newline (hard line break in inline + // context). In list-marker context it means the first line is empty. + p.at(NEWLINE) || p.at(T![EOF]) || p.at(MD_HARD_LINE_LITERAL) }); - // Set required indent for continuation lines - // Required indent = marker width + spaces after marker (minimum 1) - // BUT: if first line is empty (marker + whitespace + newline), use minimum indent + // Post-marker space + emit_list_post_marker_space(p); + + // Content indent + if !first_line_empty && spaces_after_marker > 1 { + emit_indent_char_list(p, 0); + } else { + let empty_m = p.start(); + empty_m.complete(p, MD_INDENT_TOKEN_LIST); + } + + prefix_m.complete(p, MD_LIST_MARKER_PREFIX); + // #endregion + let prev_required_indent = p.state().list_item_required_indent; let prev_marker_indent = p.state().list_item_marker_indent; - p.state_mut().list_item_required_indent = if spaces_after_marker > INDENT_CODE_BLOCK_SPACES { - marker_indent + marker_width + 1 - } else if first_line_empty { - // Empty first line: use minimum indent (marker + 1 space) - marker_indent + marker_width + 1 - } else { - marker_indent + marker_width + spaces_after_marker.max(1) - }; + p.state_mut().list_item_required_indent = + if spaces_after_marker > INDENT_CODE_BLOCK_SPACES || first_line_empty { + marker_indent + marker_width + 1 + } else { + marker_indent + marker_width + spaces_after_marker.max(1) + }; p.state_mut().list_item_marker_indent = marker_indent; - // Parse block content let blank_info = parse_list_item_block_content(p, spaces_after_marker); - // Restore previous required indent p.state_mut().list_item_required_indent = prev_required_indent; p.state_mut().list_item_marker_indent = prev_marker_indent; @@ -1049,28 +1112,6 @@ pub(crate) fn textual_starts_with_ordered_marker(text: &str) -> bool { matches!(chars.peek(), None | Some(' ' | '\t' | '\n' | '\r')) } -fn count_spaces_after_dash_in_token(text: &str, start_column: usize) -> usize { - let mut column = start_column; - let mut seen_dash = false; - - for c in text.chars() { - if !seen_dash { - if c == '-' { - seen_dash = true; - } - continue; - } - - match c { - ' ' => column += 1, - '\t' => column += TAB_STOP_SPACES - (column % TAB_STOP_SPACES), - _ => break, - } - } - - column.saturating_sub(start_column) -} - fn line_indent_from_current(p: &MarkdownParser) -> usize { let mut column = 0usize; for c in p.source_after_current().chars() { @@ -1380,9 +1421,10 @@ fn handle_blank_lines(p: &mut MarkdownParser, state: &mut ListItemLoopState) -> at_blank_line_after_prefix(p) }; - // On the first line, if at a blank line at NEWLINE, fall through to - // handle_first_line_marker_only below. - if state.first_line && blank_line_after_prefix && p.at(NEWLINE) { + // On the first line, if at a blank line at NEWLINE (or MD_HARD_LINE_LITERAL, + // which is spaces+newline), fall through to handle_first_line_marker_only. + if state.first_line && blank_line_after_prefix && (p.at(NEWLINE) || p.at(MD_HARD_LINE_LITERAL)) + { return (LoopAction::FallThrough, line_has_quote_prefix); } @@ -1496,7 +1538,12 @@ fn apply_blank_line_action_with_prefix( } } -/// Handle the first line when at NEWLINE with no inline content (marker-only). +/// Handle the first line when at NEWLINE (or MD_HARD_LINE_LITERAL) with no +/// inline content (marker-only). +/// +/// MD_HARD_LINE_LITERAL is a combined spaces+newline token that the lexer +/// produces when 2+ trailing spaces precede a newline. In list-marker context +/// it semantically represents an empty first line. /// /// Returns `Break` if the item is empty, `Continue` if the next line should be /// processed, or `FallThrough` if this phase doesn't apply. @@ -1504,12 +1551,17 @@ fn handle_first_line_marker_only( p: &mut MarkdownParser, state: &mut ListItemLoopState, ) -> LoopAction { - if !state.first_line || !p.at(NEWLINE) { + let at_hard_line = p.at(MD_HARD_LINE_LITERAL); + if !state.first_line || (!p.at(NEWLINE) && !at_hard_line) { return LoopAction::FallThrough; } let next_is_sibling = p.lookahead(|p| { - p.bump(NEWLINE); + if at_hard_line { + p.bump(MD_HARD_LINE_LITERAL); + } else { + p.bump(NEWLINE); + } if p.at_line_start() { at_bullet_list_item_with_base_indent(p, state.marker_indent) || at_order_list_item_with_base_indent(p, state.marker_indent) @@ -1518,8 +1570,16 @@ fn handle_first_line_marker_only( } }); - // Marker-only line: consume the newline as trivia and continue. - p.parse_as_skipped_trivia_tokens(|p| p.bump(NEWLINE)); + // Marker-only line: emit the newline as an explicit MdNewline node. + // For MD_HARD_LINE_LITERAL, remap to NEWLINE — the trailing spaces are + // insignificant whitespace on an otherwise empty line. + let newline_m = p.start(); + if at_hard_line { + p.bump_remap(NEWLINE); + } else { + p.bump(NEWLINE); + } + newline_m.complete(p, MD_NEWLINE); state.first_line = false; state.last_was_blank = false; @@ -1570,10 +1630,6 @@ fn parse_first_line_blocks( }); if fenced_code_start { - while p.at(MD_TEXTUAL_LITERAL) && is_whitespace_only(p.cur_text()) { - p.parse_as_skipped_trivia_tokens(|p| p.bump(MD_TEXTUAL_LITERAL)); - } - let parsed = with_virtual_line_start(p, p.cur_range().start(), parse_fenced_code_block); if parsed.is_present() { state.record_first_line_block(); @@ -1656,10 +1712,6 @@ fn parse_first_line_blocks( }); if let Some(nested_marker) = nested_marker { - while p.at(MD_TEXTUAL_LITERAL) && is_whitespace_only(p.cur_text()) { - p.parse_as_skipped_trivia_tokens(|p| p.bump(MD_TEXTUAL_LITERAL)); - } - let prev_virtual = p.state().virtual_line_start; let prev_required = p.state().list_item_required_indent; p.state_mut().virtual_line_start = Some(p.cur_range().start()); @@ -1736,11 +1788,6 @@ fn parse_first_line_atx_heading(p: &mut MarkdownParser, state: &mut ListItemLoop return false; } - // Skip leading whitespace as trivia - while p.at(MD_TEXTUAL_LITERAL) && is_whitespace_only(p.cur_text()) { - p.parse_as_skipped_trivia_tokens(|p| p.bump(MD_TEXTUAL_LITERAL)); - } - let header_m = p.start(); // Can't reuse header::parse_hash_list(): in list context `#` may be lexed as @@ -1778,11 +1825,6 @@ fn parse_first_line_blockquote(p: &mut MarkdownParser, state: &mut ListItemLoopS return false; } - // Skip leading whitespace as trivia - while p.at(MD_TEXTUAL_LITERAL) && is_whitespace_only(p.cur_text()) { - p.parse_as_skipped_trivia_tokens(|p| p.bump(MD_TEXTUAL_LITERAL)); - } - let prev_virtual = p.state().virtual_line_start; let prev_required = p.state().list_item_required_indent; p.state_mut().virtual_line_start = Some(p.cur_range().start()); @@ -2308,6 +2350,11 @@ fn at_blank_line_after_prefix(p: &mut MarkdownParser) -> bool { if p.at(T![EOF]) { return true; } + // MD_HARD_LINE_LITERAL (spaces+newline) counts as a blank line + // in list-marker context. + if p.at(MD_HARD_LINE_LITERAL) { + return true; + } while p.at(MD_TEXTUAL_LITERAL) { let text = p.cur_text(); if text == " " || text == "\t" { diff --git a/crates/biome_markdown_parser/src/to_html.rs b/crates/biome_markdown_parser/src/to_html.rs index ade3c9fadcb3..322c81279edf 100644 --- a/crates/biome_markdown_parser/src/to_html.rs +++ b/crates/biome_markdown_parser/src/to_html.rs @@ -566,7 +566,8 @@ impl<'a> HtmlRenderer<'a> { let start = list .md_bullet_list() .first() - .and_then(|bullet| bullet.bullet().ok()) + .and_then(|bullet| bullet.prefix().ok()) + .and_then(|prefix| prefix.marker().ok()) .map_or(1, |marker| { let text = marker.text(); text.trim_start() @@ -596,7 +597,10 @@ impl<'a> HtmlRenderer<'a> { let is_tight = list_is_tight && !item_has_blank_line; let is_empty = is_empty_content(&blocks); - let first_is_paragraph = blocks.first().is_some_and(is_paragraph_block); + let first_is_paragraph = blocks + .iter() + .find(|b| !is_newline_block(b)) + .is_some_and(is_paragraph_block); let last_is_paragraph = blocks .iter() .rev() @@ -969,9 +973,19 @@ impl<'a> HtmlRenderer<'a> { } let mut content = buffer.content; + if state.leading_newline && content.starts_with('\n') { + content.remove(0); + } if state.trim_trailing_newline && content.ends_with('\n') { content.pop(); } + if state.leading_newline + && content.starts_with('<') + && !content.contains('\n') + && !content.ends_with('\n') + { + content.push('\n'); + } self.push_str(&content); self.push_str("\n"); } diff --git a/crates/biome_markdown_parser/tests/md_test_suite/ok/bullet_list.md.snap b/crates/biome_markdown_parser/tests/md_test_suite/ok/bullet_list.md.snap index fb093c848224..d7e4102fd135 100644 --- a/crates/biome_markdown_parser/tests/md_test_suite/ok/bullet_list.md.snap +++ b/crates/biome_markdown_parser/tests/md_test_suite/ok/bullet_list.md.snap @@ -28,7 +28,12 @@ MdDocument { MdBulletListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MINUS@0..1 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@0..1 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -44,7 +49,12 @@ MdDocument { ], }, MdBullet { - bullet: MINUS@11..12 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@11..12 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -60,7 +70,12 @@ MdDocument { ], }, MdBullet { - bullet: MINUS@22..23 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@22..23 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -83,7 +98,12 @@ MdDocument { MdBulletListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: STAR@36..37 "*" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: STAR@36..37 "*" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -99,7 +119,12 @@ MdDocument { ], }, MdBullet { - bullet: STAR@57..58 "*" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: STAR@57..58 "*" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -122,7 +147,12 @@ MdDocument { MdBulletListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: PLUS@73..74 "+" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: PLUS@73..74 "+" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -138,7 +168,12 @@ MdDocument { ], }, MdBullet { - bullet: PLUS@87..88 "+" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: PLUS@87..88 "+" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -169,7 +204,11 @@ MdDocument { 0: MD_BULLET_LIST_ITEM@0..36 0: MD_BULLET_LIST@0..36 0: MD_BULLET@0..11 - 0: MINUS@0..1 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@0..1 + 0: MD_INDENT_TOKEN_LIST@0..0 + 1: MINUS@0..1 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@1..1 1: MD_BLOCK_LIST@1..11 0: MD_PARAGRAPH@1..11 0: MD_INLINE_ITEM_LIST@1..11 @@ -179,7 +218,11 @@ MdDocument { 0: MD_TEXTUAL_LITERAL@10..11 "\n" [] [] 1: (empty) 1: MD_BULLET@11..22 - 0: MINUS@11..12 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@11..12 + 0: MD_INDENT_TOKEN_LIST@11..11 + 1: MINUS@11..12 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@12..12 1: MD_BLOCK_LIST@12..22 0: MD_PARAGRAPH@12..22 0: MD_INLINE_ITEM_LIST@12..22 @@ -189,7 +232,11 @@ MdDocument { 0: MD_TEXTUAL_LITERAL@21..22 "\n" [] [] 1: (empty) 2: MD_BULLET@22..36 - 0: MINUS@22..23 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@22..23 + 0: MD_INDENT_TOKEN_LIST@22..22 + 1: MINUS@22..23 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@23..23 1: MD_BLOCK_LIST@23..36 0: MD_PARAGRAPH@23..35 0: MD_INLINE_ITEM_LIST@23..35 @@ -203,7 +250,11 @@ MdDocument { 1: MD_BULLET_LIST_ITEM@36..73 0: MD_BULLET_LIST@36..73 0: MD_BULLET@36..57 - 0: STAR@36..37 "*" [] [] + 0: MD_LIST_MARKER_PREFIX@36..37 + 0: MD_INDENT_TOKEN_LIST@36..36 + 1: STAR@36..37 "*" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@37..37 1: MD_BLOCK_LIST@37..57 0: MD_PARAGRAPH@37..57 0: MD_INLINE_ITEM_LIST@37..57 @@ -213,7 +264,11 @@ MdDocument { 0: MD_TEXTUAL_LITERAL@56..57 "\n" [] [] 1: (empty) 1: MD_BULLET@57..73 - 0: STAR@57..58 "*" [] [] + 0: MD_LIST_MARKER_PREFIX@57..58 + 0: MD_INDENT_TOKEN_LIST@57..57 + 1: STAR@57..58 "*" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@58..58 1: MD_BLOCK_LIST@58..73 0: MD_PARAGRAPH@58..72 0: MD_INLINE_ITEM_LIST@58..72 @@ -227,7 +282,11 @@ MdDocument { 2: MD_BULLET_LIST_ITEM@73..107 0: MD_BULLET_LIST@73..107 0: MD_BULLET@73..87 - 0: PLUS@73..74 "+" [] [] + 0: MD_LIST_MARKER_PREFIX@73..74 + 0: MD_INDENT_TOKEN_LIST@73..73 + 1: PLUS@73..74 "+" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@74..74 1: MD_BLOCK_LIST@74..87 0: MD_PARAGRAPH@74..87 0: MD_INLINE_ITEM_LIST@74..87 @@ -237,7 +296,11 @@ MdDocument { 0: MD_TEXTUAL_LITERAL@86..87 "\n" [] [] 1: (empty) 1: MD_BULLET@87..107 - 0: PLUS@87..88 "+" [] [] + 0: MD_LIST_MARKER_PREFIX@87..88 + 0: MD_INDENT_TOKEN_LIST@87..87 + 1: PLUS@87..88 "+" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@88..88 1: MD_BLOCK_LIST@88..107 0: MD_PARAGRAPH@88..107 0: MD_INLINE_ITEM_LIST@88..107 diff --git a/crates/biome_markdown_parser/tests/md_test_suite/ok/lazy_continuation.md.snap b/crates/biome_markdown_parser/tests/md_test_suite/ok/lazy_continuation.md.snap index 76dc39d7bbe9..dc50b533627c 100644 --- a/crates/biome_markdown_parser/tests/md_test_suite/ok/lazy_continuation.md.snap +++ b/crates/biome_markdown_parser/tests/md_test_suite/ok/lazy_continuation.md.snap @@ -257,7 +257,12 @@ MdDocument { MdBulletListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MINUS@334..335 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@334..335 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -524,7 +529,11 @@ MdDocument { 15: MD_BULLET_LIST_ITEM@334..374 0: MD_BULLET_LIST@334..374 0: MD_BULLET@334..374 - 0: MINUS@334..335 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@334..335 + 0: MD_INDENT_TOKEN_LIST@334..334 + 1: MINUS@334..335 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@335..335 1: MD_BLOCK_LIST@335..374 0: MD_PARAGRAPH@335..374 0: MD_INLINE_ITEM_LIST@335..374 diff --git a/crates/biome_markdown_parser/tests/md_test_suite/ok/list_continuation_edge_cases.md.snap b/crates/biome_markdown_parser/tests/md_test_suite/ok/list_continuation_edge_cases.md.snap index 965e5117a8df..c863f8c0488a 100644 --- a/crates/biome_markdown_parser/tests/md_test_suite/ok/list_continuation_edge_cases.md.snap +++ b/crates/biome_markdown_parser/tests/md_test_suite/ok/list_continuation_edge_cases.md.snap @@ -81,12 +81,17 @@ MdDocument { MdBulletListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MINUS@45..46 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@45..46 "-" [] [], + post_marker_space_token: MD_LIST_POST_MARKER_SPACE@46..47 " " [] [], + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdQuote { prefix: MdQuotePrefix { pre_marker_indent: MdQuoteIndentList [], - marker_token: R_ANGLE@46..48 ">" [Skipped(" ")] [], + marker_token: R_ANGLE@47..48 ">" [] [], post_marker_space_token: missing (optional), }, content: MdBlockList [ @@ -147,7 +152,12 @@ MdDocument { ], }, MdBullet { - bullet: MINUS@91..92 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@91..92 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -204,13 +214,22 @@ MdDocument { MdBulletListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MINUS@153..155 "- " [] [], - content: MdBlockList [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@153..155 "- " [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, + content: MdBlockList [ + MdNewline { + value_token: NEWLINE@155..156 "\n" [] [], + }, + ], }, ], }, MdNewline { - value_token: NEWLINE@155..157 "\n" [Skipped("\n")] [], + value_token: NEWLINE@156..157 "\n" [] [], }, MdParagraph { list: MdInlineItemList [ @@ -263,7 +282,12 @@ MdDocument { MdBulletListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MINUS@272..273 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@272..273 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -279,7 +303,12 @@ MdDocument { MdBulletListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MINUS@285..288 "-" [Skipped(" "), Skipped(" ")] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@285..288 "-" [Skipped(" "), Skipped(" ")] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -320,7 +349,12 @@ MdDocument { ], }, MdBullet { - bullet: MINUS@367..368 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@367..368 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -371,7 +405,12 @@ MdDocument { MdBulletListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MINUS@451..452 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@451..452 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -393,7 +432,12 @@ MdDocument { ], }, MdBullet { - bullet: MINUS@495..496 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@495..496 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -446,12 +490,16 @@ MdDocument { 3: MD_BULLET_LIST_ITEM@45..106 0: MD_BULLET_LIST@45..106 0: MD_BULLET@45..91 - 0: MINUS@45..46 "-" [] [] - 1: MD_BLOCK_LIST@46..91 - 0: MD_QUOTE@46..90 - 0: MD_QUOTE_PREFIX@46..48 - 0: MD_QUOTE_INDENT_LIST@46..46 - 1: R_ANGLE@46..48 ">" [Skipped(" ")] [] + 0: MD_LIST_MARKER_PREFIX@45..47 + 0: MD_INDENT_TOKEN_LIST@45..45 + 1: MINUS@45..46 "-" [] [] + 2: MD_LIST_POST_MARKER_SPACE@46..47 " " [] [] + 3: MD_INDENT_TOKEN_LIST@47..47 + 1: MD_BLOCK_LIST@47..91 + 0: MD_QUOTE@47..90 + 0: MD_QUOTE_PREFIX@47..48 + 0: MD_QUOTE_INDENT_LIST@47..47 + 1: R_ANGLE@47..48 ">" [] [] 2: (empty) 1: MD_BLOCK_LIST@48..90 0: MD_PARAGRAPH@48..61 @@ -489,7 +537,11 @@ MdDocument { 1: MD_NEWLINE@90..91 0: NEWLINE@90..91 "\n" [] [] 1: MD_BULLET@91..106 - 0: MINUS@91..92 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@91..92 + 0: MD_INDENT_TOKEN_LIST@91..91 + 1: MINUS@91..92 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@92..92 1: MD_BLOCK_LIST@92..106 0: MD_PARAGRAPH@92..106 0: MD_INLINE_ITEM_LIST@92..106 @@ -522,13 +574,19 @@ MdDocument { 0: NEWLINE@151..152 "\n" [] [] 7: MD_NEWLINE@152..153 0: NEWLINE@152..153 "\n" [] [] - 8: MD_BULLET_LIST_ITEM@153..155 - 0: MD_BULLET_LIST@153..155 - 0: MD_BULLET@153..155 - 0: MINUS@153..155 "- " [] [] - 1: MD_BLOCK_LIST@155..155 - 9: MD_NEWLINE@155..157 - 0: NEWLINE@155..157 "\n" [Skipped("\n")] [] + 8: MD_BULLET_LIST_ITEM@153..156 + 0: MD_BULLET_LIST@153..156 + 0: MD_BULLET@153..156 + 0: MD_LIST_MARKER_PREFIX@153..155 + 0: MD_INDENT_TOKEN_LIST@153..153 + 1: MINUS@153..155 "- " [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@155..155 + 1: MD_BLOCK_LIST@155..156 + 0: MD_NEWLINE@155..156 + 0: NEWLINE@155..156 "\n" [] [] + 9: MD_NEWLINE@156..157 + 0: NEWLINE@156..157 "\n" [] [] 10: MD_PARAGRAPH@157..204 0: MD_INLINE_ITEM_LIST@157..204 0: MD_TEXTUAL@157..187 @@ -563,7 +621,11 @@ MdDocument { 15: MD_BULLET_LIST_ITEM@272..385 0: MD_BULLET_LIST@272..385 0: MD_BULLET@272..367 - 0: MINUS@272..273 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@272..273 + 0: MD_INDENT_TOKEN_LIST@272..272 + 1: MINUS@272..273 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@273..273 1: MD_BLOCK_LIST@273..367 0: MD_PARAGRAPH@273..285 0: MD_INLINE_ITEM_LIST@273..285 @@ -575,7 +637,11 @@ MdDocument { 1: MD_BULLET_LIST_ITEM@285..366 0: MD_BULLET_LIST@285..366 0: MD_BULLET@285..366 - 0: MINUS@285..288 "-" [Skipped(" "), Skipped(" ")] [] + 0: MD_LIST_MARKER_PREFIX@285..288 + 0: MD_INDENT_TOKEN_LIST@285..285 + 1: MINUS@285..288 "-" [Skipped(" "), Skipped(" ")] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@288..288 1: MD_BLOCK_LIST@288..366 0: MD_PARAGRAPH@288..366 0: MD_INLINE_ITEM_LIST@288..366 @@ -599,7 +665,11 @@ MdDocument { 2: MD_NEWLINE@366..367 0: NEWLINE@366..367 "\n" [] [] 1: MD_BULLET@367..385 - 0: MINUS@367..368 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@367..368 + 0: MD_INDENT_TOKEN_LIST@367..367 + 1: MINUS@367..368 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@368..368 1: MD_BLOCK_LIST@368..385 0: MD_PARAGRAPH@368..385 0: MD_INLINE_ITEM_LIST@368..385 @@ -631,7 +701,11 @@ MdDocument { 20: MD_BULLET_LIST_ITEM@451..507 0: MD_BULLET_LIST@451..507 0: MD_BULLET@451..495 - 0: MINUS@451..452 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@451..452 + 0: MD_INDENT_TOKEN_LIST@451..451 + 1: MINUS@451..452 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@452..452 1: MD_BLOCK_LIST@452..495 0: MD_PARAGRAPH@452..495 0: MD_INLINE_ITEM_LIST@452..495 @@ -645,7 +719,11 @@ MdDocument { 0: MD_TEXTUAL_LITERAL@494..495 "\n" [] [] 1: (empty) 1: MD_BULLET@495..507 - 0: MINUS@495..496 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@495..496 + 0: MD_INDENT_TOKEN_LIST@495..495 + 1: MINUS@495..496 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@496..496 1: MD_BLOCK_LIST@496..507 0: MD_PARAGRAPH@496..507 0: MD_INLINE_ITEM_LIST@496..507 diff --git a/crates/biome_markdown_parser/tests/md_test_suite/ok/list_indentation.md.snap b/crates/biome_markdown_parser/tests/md_test_suite/ok/list_indentation.md.snap index 1a1ca9a1c53a..005e790ebb66 100644 --- a/crates/biome_markdown_parser/tests/md_test_suite/ok/list_indentation.md.snap +++ b/crates/biome_markdown_parser/tests/md_test_suite/ok/list_indentation.md.snap @@ -111,7 +111,12 @@ MdDocument { MdBulletListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MINUS@52..53 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@52..53 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -172,7 +177,12 @@ MdDocument { MdBulletListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MINUS@135..136 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@135..136 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -236,7 +246,12 @@ MdDocument { MdOrderedListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MD_ORDERED_LIST_MARKER@223..226 "10." [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MD_ORDERED_LIST_MARKER@223..226 "10." [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -297,7 +312,12 @@ MdDocument { MdOrderedListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MD_ORDERED_LIST_MARKER@312..315 "10." [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MD_ORDERED_LIST_MARKER@312..315 "10." [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -361,7 +381,12 @@ MdDocument { MdOrderedListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MD_ORDERED_LIST_MARKER@393..395 "1." [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MD_ORDERED_LIST_MARKER@393..395 "1." [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -422,7 +447,12 @@ MdDocument { MdOrderedListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MD_ORDERED_LIST_MARKER@475..477 "1." [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MD_ORDERED_LIST_MARKER@475..477 "1." [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -489,7 +519,12 @@ MdDocument { MdBulletListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MINUS@558..559 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@558..559 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -532,7 +567,12 @@ MdDocument { MdBulletListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: PLUS@623..624 "+" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: PLUS@623..624 "+" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -575,7 +615,12 @@ MdDocument { MdBulletListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: STAR@657..658 "*" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: STAR@657..658 "*" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -618,7 +663,12 @@ MdDocument { MdBulletListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MINUS@704..705 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@704..705 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -634,7 +684,12 @@ MdDocument { MdBulletListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MINUS@712..715 "-" [Skipped(" "), Skipped(" ")] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@712..715 "-" [Skipped(" "), Skipped(" ")] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -707,7 +762,12 @@ MdDocument { MdBulletListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MINUS@809..810 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@809..810 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -779,7 +839,11 @@ MdDocument { 2: MD_BULLET_LIST_ITEM@52..71 0: MD_BULLET_LIST@52..71 0: MD_BULLET@52..71 - 0: MINUS@52..53 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@52..53 + 0: MD_INDENT_TOKEN_LIST@52..52 + 1: MINUS@52..53 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@53..53 1: MD_BLOCK_LIST@53..71 0: MD_PARAGRAPH@53..71 0: MD_INLINE_ITEM_LIST@53..71 @@ -818,7 +882,11 @@ MdDocument { 6: MD_BULLET_LIST_ITEM@135..157 0: MD_BULLET_LIST@135..157 0: MD_BULLET@135..157 - 0: MINUS@135..136 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@135..136 + 0: MD_INDENT_TOKEN_LIST@135..135 + 1: MINUS@135..136 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@136..136 1: MD_BLOCK_LIST@136..157 0: MD_PARAGRAPH@136..157 0: MD_INLINE_ITEM_LIST@136..157 @@ -859,7 +927,11 @@ MdDocument { 10: MD_ORDERED_LIST_ITEM@223..246 0: MD_BULLET_LIST@223..246 0: MD_BULLET@223..246 - 0: MD_ORDERED_LIST_MARKER@223..226 "10." [] [] + 0: MD_LIST_MARKER_PREFIX@223..226 + 0: MD_INDENT_TOKEN_LIST@223..223 + 1: MD_ORDERED_LIST_MARKER@223..226 "10." [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@226..226 1: MD_BLOCK_LIST@226..246 0: MD_PARAGRAPH@226..246 0: MD_INLINE_ITEM_LIST@226..246 @@ -898,7 +970,11 @@ MdDocument { 14: MD_ORDERED_LIST_ITEM@312..338 0: MD_BULLET_LIST@312..338 0: MD_BULLET@312..338 - 0: MD_ORDERED_LIST_MARKER@312..315 "10." [] [] + 0: MD_LIST_MARKER_PREFIX@312..315 + 0: MD_INDENT_TOKEN_LIST@312..312 + 1: MD_ORDERED_LIST_MARKER@312..315 "10." [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@315..315 1: MD_BLOCK_LIST@315..338 0: MD_PARAGRAPH@315..338 0: MD_INLINE_ITEM_LIST@315..338 @@ -939,7 +1015,11 @@ MdDocument { 18: MD_ORDERED_LIST_ITEM@393..414 0: MD_BULLET_LIST@393..414 0: MD_BULLET@393..414 - 0: MD_ORDERED_LIST_MARKER@393..395 "1." [] [] + 0: MD_LIST_MARKER_PREFIX@393..395 + 0: MD_INDENT_TOKEN_LIST@393..393 + 1: MD_ORDERED_LIST_MARKER@393..395 "1." [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@395..395 1: MD_BLOCK_LIST@395..414 0: MD_PARAGRAPH@395..414 0: MD_INLINE_ITEM_LIST@395..414 @@ -978,7 +1058,11 @@ MdDocument { 22: MD_ORDERED_LIST_ITEM@475..499 0: MD_BULLET_LIST@475..499 0: MD_BULLET@475..499 - 0: MD_ORDERED_LIST_MARKER@475..477 "1." [] [] + 0: MD_LIST_MARKER_PREFIX@475..477 + 0: MD_INDENT_TOKEN_LIST@475..475 + 1: MD_ORDERED_LIST_MARKER@475..477 "1." [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@477..477 1: MD_BLOCK_LIST@477..499 0: MD_PARAGRAPH@477..499 0: MD_INLINE_ITEM_LIST@477..499 @@ -1021,7 +1105,11 @@ MdDocument { 26: MD_BULLET_LIST_ITEM@558..608 0: MD_BULLET_LIST@558..608 0: MD_BULLET@558..608 - 0: MINUS@558..559 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@558..559 + 0: MD_INDENT_TOKEN_LIST@558..558 + 1: MINUS@558..559 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@559..559 1: MD_BLOCK_LIST@559..608 0: MD_PARAGRAPH@559..608 0: MD_INLINE_ITEM_LIST@559..608 @@ -1048,7 +1136,11 @@ MdDocument { 30: MD_BULLET_LIST_ITEM@623..642 0: MD_BULLET_LIST@623..642 0: MD_BULLET@623..642 - 0: PLUS@623..624 "+" [] [] + 0: MD_LIST_MARKER_PREFIX@623..624 + 0: MD_INDENT_TOKEN_LIST@623..623 + 1: PLUS@623..624 "+" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@624..624 1: MD_BLOCK_LIST@624..642 0: MD_PARAGRAPH@624..642 0: MD_INLINE_ITEM_LIST@624..642 @@ -1075,7 +1167,11 @@ MdDocument { 34: MD_BULLET_LIST_ITEM@657..676 0: MD_BULLET_LIST@657..676 0: MD_BULLET@657..676 - 0: STAR@657..658 "*" [] [] + 0: MD_LIST_MARKER_PREFIX@657..658 + 0: MD_INDENT_TOKEN_LIST@657..657 + 1: STAR@657..658 "*" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@658..658 1: MD_BLOCK_LIST@658..676 0: MD_PARAGRAPH@658..676 0: MD_INLINE_ITEM_LIST@658..676 @@ -1102,7 +1198,11 @@ MdDocument { 38: MD_BULLET_LIST_ITEM@704..760 0: MD_BULLET_LIST@704..760 0: MD_BULLET@704..760 - 0: MINUS@704..705 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@704..705 + 0: MD_INDENT_TOKEN_LIST@704..704 + 1: MINUS@704..705 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@705..705 1: MD_BLOCK_LIST@705..760 0: MD_PARAGRAPH@705..712 0: MD_INLINE_ITEM_LIST@705..712 @@ -1114,7 +1214,11 @@ MdDocument { 1: MD_BULLET_LIST_ITEM@712..760 0: MD_BULLET_LIST@712..760 0: MD_BULLET@712..760 - 0: MINUS@712..715 "-" [Skipped(" "), Skipped(" ")] [] + 0: MD_LIST_MARKER_PREFIX@712..715 + 0: MD_INDENT_TOKEN_LIST@712..712 + 1: MINUS@712..715 "-" [Skipped(" "), Skipped(" ")] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@715..715 1: MD_BLOCK_LIST@715..760 0: MD_PARAGRAPH@715..760 0: MD_INLINE_ITEM_LIST@715..760 @@ -1158,7 +1262,11 @@ MdDocument { 44: MD_BULLET_LIST_ITEM@809..841 0: MD_BULLET_LIST@809..841 0: MD_BULLET@809..841 - 0: MINUS@809..810 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@809..810 + 0: MD_INDENT_TOKEN_LIST@809..809 + 1: MINUS@809..810 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@810..810 1: MD_BLOCK_LIST@810..841 0: MD_PARAGRAPH@810..841 0: MD_INLINE_ITEM_LIST@810..841 diff --git a/crates/biome_markdown_parser/tests/md_test_suite/ok/list_interrupt_bullet.md.snap b/crates/biome_markdown_parser/tests/md_test_suite/ok/list_interrupt_bullet.md.snap index 5f80fe9e8f0c..a20849ec50b3 100644 --- a/crates/biome_markdown_parser/tests/md_test_suite/ok/list_interrupt_bullet.md.snap +++ b/crates/biome_markdown_parser/tests/md_test_suite/ok/list_interrupt_bullet.md.snap @@ -32,7 +32,12 @@ MdDocument { MdBulletListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MINUS@35..36 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@35..36 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -70,7 +75,11 @@ MdDocument { 1: MD_BULLET_LIST_ITEM@35..46 0: MD_BULLET_LIST@35..46 0: MD_BULLET@35..46 - 0: MINUS@35..36 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@35..36 + 0: MD_INDENT_TOKEN_LIST@35..35 + 1: MINUS@35..36 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@36..36 1: MD_BLOCK_LIST@36..46 0: MD_PARAGRAPH@36..46 0: MD_INLINE_ITEM_LIST@36..46 diff --git a/crates/biome_markdown_parser/tests/md_test_suite/ok/list_interrupt_ordered.md.snap b/crates/biome_markdown_parser/tests/md_test_suite/ok/list_interrupt_ordered.md.snap index 8d21d616804f..46a283c84140 100644 --- a/crates/biome_markdown_parser/tests/md_test_suite/ok/list_interrupt_ordered.md.snap +++ b/crates/biome_markdown_parser/tests/md_test_suite/ok/list_interrupt_ordered.md.snap @@ -32,7 +32,12 @@ MdDocument { MdOrderedListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MD_ORDERED_LIST_MARKER@36..38 "1." [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MD_ORDERED_LIST_MARKER@36..38 "1." [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -70,7 +75,11 @@ MdDocument { 1: MD_ORDERED_LIST_ITEM@36..50 0: MD_BULLET_LIST@36..50 0: MD_BULLET@36..50 - 0: MD_ORDERED_LIST_MARKER@36..38 "1." [] [] + 0: MD_LIST_MARKER_PREFIX@36..38 + 0: MD_INDENT_TOKEN_LIST@36..36 + 1: MD_ORDERED_LIST_MARKER@36..38 "1." [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@38..38 1: MD_BLOCK_LIST@38..50 0: MD_PARAGRAPH@38..50 0: MD_INLINE_ITEM_LIST@38..50 diff --git a/crates/biome_markdown_parser/tests/md_test_suite/ok/list_marker_trailing_spaces.md b/crates/biome_markdown_parser/tests/md_test_suite/ok/list_marker_trailing_spaces.md new file mode 100644 index 000000000000..5c0dc42fdb00 --- /dev/null +++ b/crates/biome_markdown_parser/tests/md_test_suite/ok/list_marker_trailing_spaces.md @@ -0,0 +1,11 @@ +1. +2. a + +1. +2. b + +- +- c + +- +- d diff --git a/crates/biome_markdown_parser/tests/md_test_suite/ok/list_marker_trailing_spaces.md.snap b/crates/biome_markdown_parser/tests/md_test_suite/ok/list_marker_trailing_spaces.md.snap new file mode 100644 index 000000000000..efe81a3f1f30 --- /dev/null +++ b/crates/biome_markdown_parser/tests/md_test_suite/ok/list_marker_trailing_spaces.md.snap @@ -0,0 +1,298 @@ +--- +source: crates/biome_markdown_parser/tests/spec_test.rs +expression: snapshot +--- + +## Input + +``` +1. +2. a + +1. +2. b + +- +- c + +- +- d + +``` + + +## AST + +``` +MdDocument { + bom_token: missing (optional), + value: MdBlockList [ + MdOrderedListItem { + md_bullet_list: MdBulletList [ + MdBullet { + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MD_ORDERED_LIST_MARKER@0..2 "1." [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, + content: MdBlockList [ + MdNewline { + value_token: NEWLINE@2..5 " \n" [] [], + }, + ], + }, + MdBullet { + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MD_ORDERED_LIST_MARKER@5..7 "2." [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, + content: MdBlockList [ + MdParagraph { + list: MdInlineItemList [ + MdTextual { + value_token: MD_TEXTUAL_LITERAL@7..9 " a" [] [], + }, + MdTextual { + value_token: MD_TEXTUAL_LITERAL@9..10 "\n" [] [], + }, + ], + hard_line: missing (optional), + }, + MdNewline { + value_token: NEWLINE@10..11 "\n" [] [], + }, + ], + }, + MdBullet { + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MD_ORDERED_LIST_MARKER@11..13 "1." [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, + content: MdBlockList [ + MdNewline { + value_token: NEWLINE@13..17 " \n" [] [], + }, + ], + }, + MdBullet { + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MD_ORDERED_LIST_MARKER@17..19 "2." [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, + content: MdBlockList [ + MdParagraph { + list: MdInlineItemList [ + MdTextual { + value_token: MD_TEXTUAL_LITERAL@19..21 " b" [] [], + }, + MdTextual { + value_token: MD_TEXTUAL_LITERAL@21..22 "\n" [] [], + }, + ], + hard_line: missing (optional), + }, + MdNewline { + value_token: NEWLINE@22..23 "\n" [] [], + }, + ], + }, + ], + }, + MdBulletListItem { + md_bullet_list: MdBulletList [ + MdBullet { + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@23..27 "- " [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, + content: MdBlockList [ + MdNewline { + value_token: NEWLINE@27..28 "\n" [] [], + }, + ], + }, + MdBullet { + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@28..29 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, + content: MdBlockList [ + MdParagraph { + list: MdInlineItemList [ + MdTextual { + value_token: MD_TEXTUAL_LITERAL@29..31 " c" [] [], + }, + MdTextual { + value_token: MD_TEXTUAL_LITERAL@31..32 "\n" [] [], + }, + ], + hard_line: missing (optional), + }, + MdNewline { + value_token: NEWLINE@32..33 "\n" [] [], + }, + ], + }, + MdBullet { + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@33..34 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, + content: MdBlockList [ + MdNewline { + value_token: NEWLINE@34..35 "\n" [] [], + }, + ], + }, + MdBullet { + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@35..36 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, + content: MdBlockList [ + MdParagraph { + list: MdInlineItemList [ + MdTextual { + value_token: MD_TEXTUAL_LITERAL@36..38 " d" [] [], + }, + MdTextual { + value_token: MD_TEXTUAL_LITERAL@38..39 "\n" [] [], + }, + ], + hard_line: missing (optional), + }, + ], + }, + ], + }, + ], + eof_token: EOF@39..39 "" [] [], +} +``` + +## CST + +``` +0: MD_DOCUMENT@0..39 + 0: (empty) + 1: MD_BLOCK_LIST@0..39 + 0: MD_ORDERED_LIST_ITEM@0..23 + 0: MD_BULLET_LIST@0..23 + 0: MD_BULLET@0..5 + 0: MD_LIST_MARKER_PREFIX@0..2 + 0: MD_INDENT_TOKEN_LIST@0..0 + 1: MD_ORDERED_LIST_MARKER@0..2 "1." [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@2..2 + 1: MD_BLOCK_LIST@2..5 + 0: MD_NEWLINE@2..5 + 0: NEWLINE@2..5 " \n" [] [] + 1: MD_BULLET@5..11 + 0: MD_LIST_MARKER_PREFIX@5..7 + 0: MD_INDENT_TOKEN_LIST@5..5 + 1: MD_ORDERED_LIST_MARKER@5..7 "2." [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@7..7 + 1: MD_BLOCK_LIST@7..11 + 0: MD_PARAGRAPH@7..10 + 0: MD_INLINE_ITEM_LIST@7..10 + 0: MD_TEXTUAL@7..9 + 0: MD_TEXTUAL_LITERAL@7..9 " a" [] [] + 1: MD_TEXTUAL@9..10 + 0: MD_TEXTUAL_LITERAL@9..10 "\n" [] [] + 1: (empty) + 1: MD_NEWLINE@10..11 + 0: NEWLINE@10..11 "\n" [] [] + 2: MD_BULLET@11..17 + 0: MD_LIST_MARKER_PREFIX@11..13 + 0: MD_INDENT_TOKEN_LIST@11..11 + 1: MD_ORDERED_LIST_MARKER@11..13 "1." [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@13..13 + 1: MD_BLOCK_LIST@13..17 + 0: MD_NEWLINE@13..17 + 0: NEWLINE@13..17 " \n" [] [] + 3: MD_BULLET@17..23 + 0: MD_LIST_MARKER_PREFIX@17..19 + 0: MD_INDENT_TOKEN_LIST@17..17 + 1: MD_ORDERED_LIST_MARKER@17..19 "2." [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@19..19 + 1: MD_BLOCK_LIST@19..23 + 0: MD_PARAGRAPH@19..22 + 0: MD_INLINE_ITEM_LIST@19..22 + 0: MD_TEXTUAL@19..21 + 0: MD_TEXTUAL_LITERAL@19..21 " b" [] [] + 1: MD_TEXTUAL@21..22 + 0: MD_TEXTUAL_LITERAL@21..22 "\n" [] [] + 1: (empty) + 1: MD_NEWLINE@22..23 + 0: NEWLINE@22..23 "\n" [] [] + 1: MD_BULLET_LIST_ITEM@23..39 + 0: MD_BULLET_LIST@23..39 + 0: MD_BULLET@23..28 + 0: MD_LIST_MARKER_PREFIX@23..27 + 0: MD_INDENT_TOKEN_LIST@23..23 + 1: MINUS@23..27 "- " [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@27..27 + 1: MD_BLOCK_LIST@27..28 + 0: MD_NEWLINE@27..28 + 0: NEWLINE@27..28 "\n" [] [] + 1: MD_BULLET@28..33 + 0: MD_LIST_MARKER_PREFIX@28..29 + 0: MD_INDENT_TOKEN_LIST@28..28 + 1: MINUS@28..29 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@29..29 + 1: MD_BLOCK_LIST@29..33 + 0: MD_PARAGRAPH@29..32 + 0: MD_INLINE_ITEM_LIST@29..32 + 0: MD_TEXTUAL@29..31 + 0: MD_TEXTUAL_LITERAL@29..31 " c" [] [] + 1: MD_TEXTUAL@31..32 + 0: MD_TEXTUAL_LITERAL@31..32 "\n" [] [] + 1: (empty) + 1: MD_NEWLINE@32..33 + 0: NEWLINE@32..33 "\n" [] [] + 2: MD_BULLET@33..35 + 0: MD_LIST_MARKER_PREFIX@33..34 + 0: MD_INDENT_TOKEN_LIST@33..33 + 1: MINUS@33..34 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@34..34 + 1: MD_BLOCK_LIST@34..35 + 0: MD_NEWLINE@34..35 + 0: NEWLINE@34..35 "\n" [] [] + 3: MD_BULLET@35..39 + 0: MD_LIST_MARKER_PREFIX@35..36 + 0: MD_INDENT_TOKEN_LIST@35..35 + 1: MINUS@35..36 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@36..36 + 1: MD_BLOCK_LIST@36..39 + 0: MD_PARAGRAPH@36..39 + 0: MD_INLINE_ITEM_LIST@36..39 + 0: MD_TEXTUAL@36..38 + 0: MD_TEXTUAL_LITERAL@36..38 " d" [] [] + 1: MD_TEXTUAL@38..39 + 0: MD_TEXTUAL_LITERAL@38..39 "\n" [] [] + 1: (empty) + 2: EOF@39..39 "" [] [] + +``` diff --git a/crates/biome_markdown_parser/tests/md_test_suite/ok/list_tightness.md.snap b/crates/biome_markdown_parser/tests/md_test_suite/ok/list_tightness.md.snap index 3cb0b701a359..2bef8fd4179c 100644 --- a/crates/biome_markdown_parser/tests/md_test_suite/ok/list_tightness.md.snap +++ b/crates/biome_markdown_parser/tests/md_test_suite/ok/list_tightness.md.snap @@ -113,7 +113,12 @@ MdDocument { MdBulletListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MINUS@63..64 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@63..64 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -129,7 +134,12 @@ MdDocument { ], }, MdBullet { - bullet: MINUS@72..73 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@72..73 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -145,7 +155,12 @@ MdDocument { ], }, MdBullet { - bullet: MINUS@81..82 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@81..82 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -182,7 +197,12 @@ MdDocument { MdOrderedListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MD_ORDERED_LIST_MARKER@112..114 "1." [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MD_ORDERED_LIST_MARKER@112..114 "1." [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -198,7 +218,12 @@ MdDocument { ], }, MdBullet { - bullet: MD_ORDERED_LIST_MARKER@121..123 "2." [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MD_ORDERED_LIST_MARKER@121..123 "2." [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -214,7 +239,12 @@ MdDocument { ], }, MdBullet { - bullet: MD_ORDERED_LIST_MARKER@131..133 "3." [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MD_ORDERED_LIST_MARKER@131..133 "3." [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -273,7 +303,12 @@ MdDocument { MdBulletListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MINUS@201..202 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@201..202 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -292,7 +327,12 @@ MdDocument { ], }, MdBullet { - bullet: MINUS@217..218 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@217..218 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -311,7 +351,12 @@ MdDocument { ], }, MdBullet { - bullet: MINUS@233..234 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@233..234 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -348,7 +393,12 @@ MdDocument { MdOrderedListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MD_ORDERED_LIST_MARKER@270..272 "1." [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MD_ORDERED_LIST_MARKER@270..272 "1." [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -367,7 +417,12 @@ MdDocument { ], }, MdBullet { - bullet: MD_ORDERED_LIST_MARKER@286..288 "2." [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MD_ORDERED_LIST_MARKER@286..288 "2." [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -386,7 +441,12 @@ MdDocument { ], }, MdBullet { - bullet: MD_ORDERED_LIST_MARKER@303..305 "3." [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MD_ORDERED_LIST_MARKER@303..305 "3." [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -469,7 +529,12 @@ MdDocument { MdBulletListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MINUS@419..420 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@419..420 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -491,7 +556,12 @@ MdDocument { ], }, MdBullet { - bullet: MINUS@447..448 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@447..448 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -562,7 +632,12 @@ MdDocument { MdBulletListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MINUS@537..538 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@537..538 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -578,7 +653,12 @@ MdDocument { MdBulletListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MINUS@547..550 "-" [Skipped(" "), Skipped(" ")] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@547..550 "-" [Skipped(" "), Skipped(" ")] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -597,7 +677,19 @@ MdDocument { ], }, MdBullet { - bullet: MINUS@560..563 "-" [Skipped(" "), Skipped(" ")] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [ + MdIndentToken { + md_indent_char_token: MD_INDENT_CHAR@560..561 " " [] [], + }, + MdIndentToken { + md_indent_char_token: MD_INDENT_CHAR@561..562 " " [] [], + }, + ], + marker: MINUS@562..563 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -617,7 +709,12 @@ MdDocument { ], }, MdBullet { - bullet: MINUS@572..573 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@572..573 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -654,7 +751,12 @@ MdDocument { MdBulletListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MINUS@610..611 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@610..611 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -673,7 +775,12 @@ MdDocument { ], }, MdBullet { - bullet: MINUS@621..622 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@621..622 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -689,7 +796,12 @@ MdDocument { MdBulletListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MINUS@631..634 "-" [Skipped(" "), Skipped(" ")] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@631..634 "-" [Skipped(" "), Skipped(" ")] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -705,7 +817,19 @@ MdDocument { ], }, MdBullet { - bullet: MINUS@643..646 "-" [Skipped(" "), Skipped(" ")] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [ + MdIndentToken { + md_indent_char_token: MD_INDENT_CHAR@643..644 " " [] [], + }, + MdIndentToken { + md_indent_char_token: MD_INDENT_CHAR@644..645 " " [] [], + }, + ], + marker: MINUS@645..646 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -763,7 +887,11 @@ MdDocument { 5: MD_BULLET_LIST_ITEM@63..90 0: MD_BULLET_LIST@63..90 0: MD_BULLET@63..72 - 0: MINUS@63..64 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@63..64 + 0: MD_INDENT_TOKEN_LIST@63..63 + 1: MINUS@63..64 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@64..64 1: MD_BLOCK_LIST@64..72 0: MD_PARAGRAPH@64..72 0: MD_INLINE_ITEM_LIST@64..72 @@ -773,7 +901,11 @@ MdDocument { 0: MD_TEXTUAL_LITERAL@71..72 "\n" [] [] 1: (empty) 1: MD_BULLET@72..81 - 0: MINUS@72..73 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@72..73 + 0: MD_INDENT_TOKEN_LIST@72..72 + 1: MINUS@72..73 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@73..73 1: MD_BLOCK_LIST@73..81 0: MD_PARAGRAPH@73..81 0: MD_INLINE_ITEM_LIST@73..81 @@ -783,7 +915,11 @@ MdDocument { 0: MD_TEXTUAL_LITERAL@80..81 "\n" [] [] 1: (empty) 2: MD_BULLET@81..90 - 0: MINUS@81..82 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@81..82 + 0: MD_INDENT_TOKEN_LIST@81..81 + 1: MINUS@81..82 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@82..82 1: MD_BLOCK_LIST@82..90 0: MD_PARAGRAPH@82..90 0: MD_INLINE_ITEM_LIST@82..90 @@ -806,7 +942,11 @@ MdDocument { 9: MD_ORDERED_LIST_ITEM@112..140 0: MD_BULLET_LIST@112..140 0: MD_BULLET@112..121 - 0: MD_ORDERED_LIST_MARKER@112..114 "1." [] [] + 0: MD_LIST_MARKER_PREFIX@112..114 + 0: MD_INDENT_TOKEN_LIST@112..112 + 1: MD_ORDERED_LIST_MARKER@112..114 "1." [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@114..114 1: MD_BLOCK_LIST@114..121 0: MD_PARAGRAPH@114..121 0: MD_INLINE_ITEM_LIST@114..121 @@ -816,7 +956,11 @@ MdDocument { 0: MD_TEXTUAL_LITERAL@120..121 "\n" [] [] 1: (empty) 1: MD_BULLET@121..131 - 0: MD_ORDERED_LIST_MARKER@121..123 "2." [] [] + 0: MD_LIST_MARKER_PREFIX@121..123 + 0: MD_INDENT_TOKEN_LIST@121..121 + 1: MD_ORDERED_LIST_MARKER@121..123 "2." [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@123..123 1: MD_BLOCK_LIST@123..131 0: MD_PARAGRAPH@123..131 0: MD_INLINE_ITEM_LIST@123..131 @@ -826,7 +970,11 @@ MdDocument { 0: MD_TEXTUAL_LITERAL@130..131 "\n" [] [] 1: (empty) 2: MD_BULLET@131..140 - 0: MD_ORDERED_LIST_MARKER@131..133 "3." [] [] + 0: MD_LIST_MARKER_PREFIX@131..133 + 0: MD_INDENT_TOKEN_LIST@131..131 + 1: MD_ORDERED_LIST_MARKER@131..133 "3." [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@133..133 1: MD_BLOCK_LIST@133..140 0: MD_PARAGRAPH@133..140 0: MD_INLINE_ITEM_LIST@133..140 @@ -863,7 +1011,11 @@ MdDocument { 16: MD_BULLET_LIST_ITEM@201..248 0: MD_BULLET_LIST@201..248 0: MD_BULLET@201..217 - 0: MINUS@201..202 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@201..202 + 0: MD_INDENT_TOKEN_LIST@201..201 + 1: MINUS@201..202 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@202..202 1: MD_BLOCK_LIST@202..217 0: MD_PARAGRAPH@202..216 0: MD_INLINE_ITEM_LIST@202..216 @@ -875,7 +1027,11 @@ MdDocument { 1: MD_NEWLINE@216..217 0: NEWLINE@216..217 "\n" [] [] 1: MD_BULLET@217..233 - 0: MINUS@217..218 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@217..218 + 0: MD_INDENT_TOKEN_LIST@217..217 + 1: MINUS@217..218 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@218..218 1: MD_BLOCK_LIST@218..233 0: MD_PARAGRAPH@218..232 0: MD_INLINE_ITEM_LIST@218..232 @@ -887,7 +1043,11 @@ MdDocument { 1: MD_NEWLINE@232..233 0: NEWLINE@232..233 "\n" [] [] 2: MD_BULLET@233..248 - 0: MINUS@233..234 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@233..234 + 0: MD_INDENT_TOKEN_LIST@233..233 + 1: MINUS@233..234 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@234..234 1: MD_BLOCK_LIST@234..248 0: MD_PARAGRAPH@234..248 0: MD_INLINE_ITEM_LIST@234..248 @@ -910,7 +1070,11 @@ MdDocument { 20: MD_ORDERED_LIST_ITEM@270..318 0: MD_BULLET_LIST@270..318 0: MD_BULLET@270..286 - 0: MD_ORDERED_LIST_MARKER@270..272 "1." [] [] + 0: MD_LIST_MARKER_PREFIX@270..272 + 0: MD_INDENT_TOKEN_LIST@270..270 + 1: MD_ORDERED_LIST_MARKER@270..272 "1." [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@272..272 1: MD_BLOCK_LIST@272..286 0: MD_PARAGRAPH@272..285 0: MD_INLINE_ITEM_LIST@272..285 @@ -922,7 +1086,11 @@ MdDocument { 1: MD_NEWLINE@285..286 0: NEWLINE@285..286 "\n" [] [] 1: MD_BULLET@286..303 - 0: MD_ORDERED_LIST_MARKER@286..288 "2." [] [] + 0: MD_LIST_MARKER_PREFIX@286..288 + 0: MD_INDENT_TOKEN_LIST@286..286 + 1: MD_ORDERED_LIST_MARKER@286..288 "2." [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@288..288 1: MD_BLOCK_LIST@288..303 0: MD_PARAGRAPH@288..302 0: MD_INLINE_ITEM_LIST@288..302 @@ -934,7 +1102,11 @@ MdDocument { 1: MD_NEWLINE@302..303 0: NEWLINE@302..303 "\n" [] [] 2: MD_BULLET@303..318 - 0: MD_ORDERED_LIST_MARKER@303..305 "3." [] [] + 0: MD_LIST_MARKER_PREFIX@303..305 + 0: MD_INDENT_TOKEN_LIST@303..303 + 1: MD_ORDERED_LIST_MARKER@303..305 "3." [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@305..305 1: MD_BLOCK_LIST@305..318 0: MD_PARAGRAPH@305..318 0: MD_INLINE_ITEM_LIST@305..318 @@ -987,7 +1159,11 @@ MdDocument { 27: MD_BULLET_LIST_ITEM@419..475 0: MD_BULLET_LIST@419..475 0: MD_BULLET@419..447 - 0: MINUS@419..420 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@419..420 + 0: MD_INDENT_TOKEN_LIST@419..419 + 1: MINUS@419..420 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@420..420 1: MD_BLOCK_LIST@420..447 0: MD_PARAGRAPH@420..447 0: MD_INLINE_ITEM_LIST@420..447 @@ -1001,7 +1177,11 @@ MdDocument { 0: MD_TEXTUAL_LITERAL@446..447 "\n" [] [] 1: (empty) 1: MD_BULLET@447..475 - 0: MINUS@447..448 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@447..448 + 0: MD_INDENT_TOKEN_LIST@447..447 + 1: MINUS@447..448 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@448..448 1: MD_BLOCK_LIST@448..475 0: MD_PARAGRAPH@448..475 0: MD_INLINE_ITEM_LIST@448..475 @@ -1046,7 +1226,11 @@ MdDocument { 34: MD_BULLET_LIST_ITEM@537..582 0: MD_BULLET_LIST@537..582 0: MD_BULLET@537..572 - 0: MINUS@537..538 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@537..538 + 0: MD_INDENT_TOKEN_LIST@537..537 + 1: MINUS@537..538 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@538..538 1: MD_BLOCK_LIST@538..572 0: MD_PARAGRAPH@538..547 0: MD_INLINE_ITEM_LIST@538..547 @@ -1058,7 +1242,11 @@ MdDocument { 1: MD_BULLET_LIST_ITEM@547..572 0: MD_BULLET_LIST@547..572 0: MD_BULLET@547..560 - 0: MINUS@547..550 "-" [Skipped(" "), Skipped(" ")] [] + 0: MD_LIST_MARKER_PREFIX@547..550 + 0: MD_INDENT_TOKEN_LIST@547..547 + 1: MINUS@547..550 "-" [Skipped(" "), Skipped(" ")] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@550..550 1: MD_BLOCK_LIST@550..560 0: MD_PARAGRAPH@550..559 0: MD_INLINE_ITEM_LIST@550..559 @@ -1070,7 +1258,15 @@ MdDocument { 1: MD_NEWLINE@559..560 0: NEWLINE@559..560 "\n" [] [] 1: MD_BULLET@560..572 - 0: MINUS@560..563 "-" [Skipped(" "), Skipped(" ")] [] + 0: MD_LIST_MARKER_PREFIX@560..563 + 0: MD_INDENT_TOKEN_LIST@560..562 + 0: MD_INDENT_TOKEN@560..561 + 0: MD_INDENT_CHAR@560..561 " " [] [] + 1: MD_INDENT_TOKEN@561..562 + 0: MD_INDENT_CHAR@561..562 " " [] [] + 1: MINUS@562..563 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@563..563 1: MD_BLOCK_LIST@563..572 0: MD_PARAGRAPH@563..572 0: MD_INLINE_ITEM_LIST@563..572 @@ -1080,7 +1276,11 @@ MdDocument { 0: MD_TEXTUAL_LITERAL@571..572 "\n" [] [] 1: (empty) 1: MD_BULLET@572..582 - 0: MINUS@572..573 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@572..573 + 0: MD_INDENT_TOKEN_LIST@572..572 + 1: MINUS@572..573 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@573..573 1: MD_BLOCK_LIST@573..582 0: MD_PARAGRAPH@573..582 0: MD_INLINE_ITEM_LIST@573..582 @@ -1103,7 +1303,11 @@ MdDocument { 38: MD_BULLET_LIST_ITEM@610..655 0: MD_BULLET_LIST@610..655 0: MD_BULLET@610..621 - 0: MINUS@610..611 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@610..611 + 0: MD_INDENT_TOKEN_LIST@610..610 + 1: MINUS@610..611 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@611..611 1: MD_BLOCK_LIST@611..621 0: MD_PARAGRAPH@611..620 0: MD_INLINE_ITEM_LIST@611..620 @@ -1115,7 +1319,11 @@ MdDocument { 1: MD_NEWLINE@620..621 0: NEWLINE@620..621 "\n" [] [] 1: MD_BULLET@621..655 - 0: MINUS@621..622 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@621..622 + 0: MD_INDENT_TOKEN_LIST@621..621 + 1: MINUS@621..622 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@622..622 1: MD_BLOCK_LIST@622..655 0: MD_PARAGRAPH@622..631 0: MD_INLINE_ITEM_LIST@622..631 @@ -1127,7 +1335,11 @@ MdDocument { 1: MD_BULLET_LIST_ITEM@631..655 0: MD_BULLET_LIST@631..655 0: MD_BULLET@631..643 - 0: MINUS@631..634 "-" [Skipped(" "), Skipped(" ")] [] + 0: MD_LIST_MARKER_PREFIX@631..634 + 0: MD_INDENT_TOKEN_LIST@631..631 + 1: MINUS@631..634 "-" [Skipped(" "), Skipped(" ")] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@634..634 1: MD_BLOCK_LIST@634..643 0: MD_PARAGRAPH@634..643 0: MD_INLINE_ITEM_LIST@634..643 @@ -1137,7 +1349,15 @@ MdDocument { 0: MD_TEXTUAL_LITERAL@642..643 "\n" [] [] 1: (empty) 1: MD_BULLET@643..655 - 0: MINUS@643..646 "-" [Skipped(" "), Skipped(" ")] [] + 0: MD_LIST_MARKER_PREFIX@643..646 + 0: MD_INDENT_TOKEN_LIST@643..645 + 0: MD_INDENT_TOKEN@643..644 + 0: MD_INDENT_CHAR@643..644 " " [] [] + 1: MD_INDENT_TOKEN@644..645 + 0: MD_INDENT_CHAR@644..645 " " [] [] + 1: MINUS@645..646 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@646..646 1: MD_BLOCK_LIST@646..655 0: MD_PARAGRAPH@646..655 0: MD_INLINE_ITEM_LIST@646..655 diff --git a/crates/biome_markdown_parser/tests/md_test_suite/ok/multiline_list.md.snap b/crates/biome_markdown_parser/tests/md_test_suite/ok/multiline_list.md.snap index 46d25b234478..8e710450d1a1 100644 --- a/crates/biome_markdown_parser/tests/md_test_suite/ok/multiline_list.md.snap +++ b/crates/biome_markdown_parser/tests/md_test_suite/ok/multiline_list.md.snap @@ -31,7 +31,12 @@ MdDocument { MdBulletListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MINUS@0..1 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@0..1 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -53,7 +58,12 @@ MdDocument { ], }, MdBullet { - bullet: MINUS@33..34 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@33..34 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -76,7 +86,12 @@ MdDocument { MdOrderedListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MD_ORDERED_LIST_MARKER@48..50 "1." [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MD_ORDERED_LIST_MARKER@48..50 "1." [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -98,7 +113,12 @@ MdDocument { ], }, MdBullet { - bullet: MD_ORDERED_LIST_MARKER@82..84 "2." [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MD_ORDERED_LIST_MARKER@82..84 "2." [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -121,7 +141,12 @@ MdDocument { MdBulletListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MINUS@99..100 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@99..100 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -137,7 +162,12 @@ MdDocument { MdBulletListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MINUS@115..118 "-" [Skipped(" "), Skipped(" ")] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@115..118 "-" [Skipped(" "), Skipped(" ")] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -153,7 +183,19 @@ MdDocument { ], }, MdBullet { - bullet: MINUS@130..133 "-" [Skipped(" "), Skipped(" ")] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [ + MdIndentToken { + md_indent_char_token: MD_INDENT_CHAR@130..131 " " [] [], + }, + MdIndentToken { + md_indent_char_token: MD_INDENT_CHAR@131..132 " " [] [], + }, + ], + marker: MINUS@132..133 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -173,7 +215,12 @@ MdDocument { ], }, MdBullet { - bullet: MINUS@148..149 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@148..149 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -204,7 +251,11 @@ MdDocument { 0: MD_BULLET_LIST_ITEM@0..48 0: MD_BULLET_LIST@0..48 0: MD_BULLET@0..33 - 0: MINUS@0..1 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@0..1 + 0: MD_INDENT_TOKEN_LIST@0..0 + 1: MINUS@0..1 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@1..1 1: MD_BLOCK_LIST@1..33 0: MD_PARAGRAPH@1..33 0: MD_INLINE_ITEM_LIST@1..33 @@ -218,7 +269,11 @@ MdDocument { 0: MD_TEXTUAL_LITERAL@32..33 "\n" [] [] 1: (empty) 1: MD_BULLET@33..48 - 0: MINUS@33..34 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@33..34 + 0: MD_INDENT_TOKEN_LIST@33..33 + 1: MINUS@33..34 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@34..34 1: MD_BLOCK_LIST@34..48 0: MD_PARAGRAPH@34..47 0: MD_INLINE_ITEM_LIST@34..47 @@ -232,7 +287,11 @@ MdDocument { 1: MD_ORDERED_LIST_ITEM@48..99 0: MD_BULLET_LIST@48..99 0: MD_BULLET@48..82 - 0: MD_ORDERED_LIST_MARKER@48..50 "1." [] [] + 0: MD_LIST_MARKER_PREFIX@48..50 + 0: MD_INDENT_TOKEN_LIST@48..48 + 1: MD_ORDERED_LIST_MARKER@48..50 "1." [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@50..50 1: MD_BLOCK_LIST@50..82 0: MD_PARAGRAPH@50..82 0: MD_INLINE_ITEM_LIST@50..82 @@ -246,7 +305,11 @@ MdDocument { 0: MD_TEXTUAL_LITERAL@81..82 "\n" [] [] 1: (empty) 1: MD_BULLET@82..99 - 0: MD_ORDERED_LIST_MARKER@82..84 "2." [] [] + 0: MD_LIST_MARKER_PREFIX@82..84 + 0: MD_INDENT_TOKEN_LIST@82..82 + 1: MD_ORDERED_LIST_MARKER@82..84 "2." [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@84..84 1: MD_BLOCK_LIST@84..99 0: MD_PARAGRAPH@84..98 0: MD_INLINE_ITEM_LIST@84..98 @@ -260,7 +323,11 @@ MdDocument { 2: MD_BULLET_LIST_ITEM@99..165 0: MD_BULLET_LIST@99..165 0: MD_BULLET@99..148 - 0: MINUS@99..100 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@99..100 + 0: MD_INDENT_TOKEN_LIST@99..99 + 1: MINUS@99..100 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@100..100 1: MD_BLOCK_LIST@100..148 0: MD_PARAGRAPH@100..115 0: MD_INLINE_ITEM_LIST@100..115 @@ -272,7 +339,11 @@ MdDocument { 1: MD_BULLET_LIST_ITEM@115..148 0: MD_BULLET_LIST@115..148 0: MD_BULLET@115..130 - 0: MINUS@115..118 "-" [Skipped(" "), Skipped(" ")] [] + 0: MD_LIST_MARKER_PREFIX@115..118 + 0: MD_INDENT_TOKEN_LIST@115..115 + 1: MINUS@115..118 "-" [Skipped(" "), Skipped(" ")] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@118..118 1: MD_BLOCK_LIST@118..130 0: MD_PARAGRAPH@118..130 0: MD_INLINE_ITEM_LIST@118..130 @@ -282,7 +353,15 @@ MdDocument { 0: MD_TEXTUAL_LITERAL@129..130 "\n" [] [] 1: (empty) 1: MD_BULLET@130..148 - 0: MINUS@130..133 "-" [Skipped(" "), Skipped(" ")] [] + 0: MD_LIST_MARKER_PREFIX@130..133 + 0: MD_INDENT_TOKEN_LIST@130..132 + 0: MD_INDENT_TOKEN@130..131 + 0: MD_INDENT_CHAR@130..131 " " [] [] + 1: MD_INDENT_TOKEN@131..132 + 0: MD_INDENT_CHAR@131..132 " " [] [] + 1: MINUS@132..133 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@133..133 1: MD_BLOCK_LIST@133..148 0: MD_PARAGRAPH@133..148 0: MD_INLINE_ITEM_LIST@133..148 @@ -292,7 +371,11 @@ MdDocument { 0: MD_TEXTUAL_LITERAL@147..148 "\n" [] [] 1: (empty) 1: MD_BULLET@148..165 - 0: MINUS@148..149 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@148..149 + 0: MD_INDENT_TOKEN_LIST@148..148 + 1: MINUS@148..149 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@149..149 1: MD_BLOCK_LIST@149..165 0: MD_PARAGRAPH@149..165 0: MD_INLINE_ITEM_LIST@149..165 diff --git a/crates/biome_markdown_parser/tests/md_test_suite/ok/ordered_list.md.snap b/crates/biome_markdown_parser/tests/md_test_suite/ok/ordered_list.md.snap index f1c98f087c14..34ed681b8244 100644 --- a/crates/biome_markdown_parser/tests/md_test_suite/ok/ordered_list.md.snap +++ b/crates/biome_markdown_parser/tests/md_test_suite/ok/ordered_list.md.snap @@ -25,7 +25,12 @@ MdDocument { MdOrderedListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MD_ORDERED_LIST_MARKER@0..2 "1." [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MD_ORDERED_LIST_MARKER@0..2 "1." [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -41,7 +46,12 @@ MdDocument { ], }, MdBullet { - bullet: MD_ORDERED_LIST_MARKER@14..16 "2." [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MD_ORDERED_LIST_MARKER@14..16 "2." [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -57,7 +67,12 @@ MdDocument { ], }, MdBullet { - bullet: MD_ORDERED_LIST_MARKER@29..31 "3." [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MD_ORDERED_LIST_MARKER@29..31 "3." [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -80,7 +95,12 @@ MdDocument { MdOrderedListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MD_ORDERED_LIST_MARKER@44..46 "1)" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MD_ORDERED_LIST_MARKER@44..46 "1)" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -96,7 +116,12 @@ MdDocument { ], }, MdBullet { - bullet: MD_ORDERED_LIST_MARKER@65..67 "2)" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MD_ORDERED_LIST_MARKER@65..67 "2)" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -127,7 +152,11 @@ MdDocument { 0: MD_ORDERED_LIST_ITEM@0..44 0: MD_BULLET_LIST@0..44 0: MD_BULLET@0..14 - 0: MD_ORDERED_LIST_MARKER@0..2 "1." [] [] + 0: MD_LIST_MARKER_PREFIX@0..2 + 0: MD_INDENT_TOKEN_LIST@0..0 + 1: MD_ORDERED_LIST_MARKER@0..2 "1." [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@2..2 1: MD_BLOCK_LIST@2..14 0: MD_PARAGRAPH@2..14 0: MD_INLINE_ITEM_LIST@2..14 @@ -137,7 +166,11 @@ MdDocument { 0: MD_TEXTUAL_LITERAL@13..14 "\n" [] [] 1: (empty) 1: MD_BULLET@14..29 - 0: MD_ORDERED_LIST_MARKER@14..16 "2." [] [] + 0: MD_LIST_MARKER_PREFIX@14..16 + 0: MD_INDENT_TOKEN_LIST@14..14 + 1: MD_ORDERED_LIST_MARKER@14..16 "2." [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@16..16 1: MD_BLOCK_LIST@16..29 0: MD_PARAGRAPH@16..29 0: MD_INLINE_ITEM_LIST@16..29 @@ -147,7 +180,11 @@ MdDocument { 0: MD_TEXTUAL_LITERAL@28..29 "\n" [] [] 1: (empty) 2: MD_BULLET@29..44 - 0: MD_ORDERED_LIST_MARKER@29..31 "3." [] [] + 0: MD_LIST_MARKER_PREFIX@29..31 + 0: MD_INDENT_TOKEN_LIST@29..29 + 1: MD_ORDERED_LIST_MARKER@29..31 "3." [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@31..31 1: MD_BLOCK_LIST@31..44 0: MD_PARAGRAPH@31..43 0: MD_INLINE_ITEM_LIST@31..43 @@ -161,7 +198,11 @@ MdDocument { 1: MD_ORDERED_LIST_ITEM@44..81 0: MD_BULLET_LIST@44..81 0: MD_BULLET@44..65 - 0: MD_ORDERED_LIST_MARKER@44..46 "1)" [] [] + 0: MD_LIST_MARKER_PREFIX@44..46 + 0: MD_INDENT_TOKEN_LIST@44..44 + 1: MD_ORDERED_LIST_MARKER@44..46 "1)" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@46..46 1: MD_BLOCK_LIST@46..65 0: MD_PARAGRAPH@46..65 0: MD_INLINE_ITEM_LIST@46..65 @@ -171,7 +212,11 @@ MdDocument { 0: MD_TEXTUAL_LITERAL@64..65 "\n" [] [] 1: (empty) 1: MD_BULLET@65..81 - 0: MD_ORDERED_LIST_MARKER@65..67 "2)" [] [] + 0: MD_LIST_MARKER_PREFIX@65..67 + 0: MD_INDENT_TOKEN_LIST@65..65 + 1: MD_ORDERED_LIST_MARKER@65..67 "2)" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@67..67 1: MD_BLOCK_LIST@67..81 0: MD_PARAGRAPH@67..81 0: MD_INLINE_ITEM_LIST@67..81 diff --git a/crates/biome_markdown_parser/tests/md_test_suite/ok/paragraph_interruption.md.snap b/crates/biome_markdown_parser/tests/md_test_suite/ok/paragraph_interruption.md.snap index 001299ce640d..ea465511a670 100644 --- a/crates/biome_markdown_parser/tests/md_test_suite/ok/paragraph_interruption.md.snap +++ b/crates/biome_markdown_parser/tests/md_test_suite/ok/paragraph_interruption.md.snap @@ -79,7 +79,12 @@ MdDocument { MdBulletListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MINUS@52..53 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@52..53 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdParagraph { list: MdInlineItemList [ @@ -225,7 +230,11 @@ MdDocument { 5: MD_BULLET_LIST_ITEM@52..70 0: MD_BULLET_LIST@52..70 0: MD_BULLET@52..70 - 0: MINUS@52..53 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@52..53 + 0: MD_INDENT_TOKEN_LIST@52..52 + 1: MINUS@52..53 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@53..53 1: MD_BLOCK_LIST@53..70 0: MD_PARAGRAPH@53..70 0: MD_INLINE_ITEM_LIST@53..70 diff --git a/crates/biome_markdown_parser/tests/md_test_suite/ok/setext_heading_edge_cases.md.snap b/crates/biome_markdown_parser/tests/md_test_suite/ok/setext_heading_edge_cases.md.snap index 38c56e66ae82..89a9715a994d 100644 --- a/crates/biome_markdown_parser/tests/md_test_suite/ok/setext_heading_edge_cases.md.snap +++ b/crates/biome_markdown_parser/tests/md_test_suite/ok/setext_heading_edge_cases.md.snap @@ -125,7 +125,12 @@ MdDocument { MdBulletListItem { md_bullet_list: MdBulletList [ MdBullet { - bullet: MINUS@48..49 "-" [] [], + prefix: MdListMarkerPrefix { + pre_marker_indent: MdIndentTokenList [], + marker: MINUS@48..49 "-" [] [], + post_marker_space_token: missing (optional), + content_indent: MdIndentTokenList [], + }, content: MdBlockList [ MdSetextHeader { content: MdInlineItemList [ @@ -230,7 +235,11 @@ MdDocument { 11: MD_BULLET_LIST_ITEM@48..66 0: MD_BULLET_LIST@48..66 0: MD_BULLET@48..66 - 0: MINUS@48..49 "-" [] [] + 0: MD_LIST_MARKER_PREFIX@48..49 + 0: MD_INDENT_TOKEN_LIST@48..48 + 1: MINUS@48..49 "-" [] [] + 2: (empty) + 3: MD_INDENT_TOKEN_LIST@49..49 1: MD_BLOCK_LIST@49..66 0: MD_SETEXT_HEADER@49..59 0: MD_INLINE_ITEM_LIST@49..54 diff --git a/crates/biome_markdown_syntax/src/generated/kind.rs b/crates/biome_markdown_syntax/src/generated/kind.rs index 675db8d4392a..ef6f90f8cf50 100644 --- a/crates/biome_markdown_syntax/src/generated/kind.rs +++ b/crates/biome_markdown_syntax/src/generated/kind.rs @@ -48,6 +48,8 @@ pub enum MarkdownSyntaxKind { MD_ENTITY_LITERAL, MD_QUOTE_PRE_MARKER_INDENT, MD_QUOTE_POST_MARKER_SPACE, + MD_INDENT_CHAR, + MD_LIST_POST_MARKER_SPACE, ERROR_TOKEN, NEWLINE, WHITESPACE, @@ -103,6 +105,9 @@ pub enum MarkdownSyntaxKind { MD_INDENT, MD_THEMATIC_BREAK_BLOCK, MD_NEWLINE, + MD_INDENT_TOKEN, + MD_INDENT_TOKEN_LIST, + MD_LIST_MARKER_PREFIX, #[doc(hidden)] __LAST, } @@ -151,6 +156,8 @@ impl MarkdownSyntaxKind { | MD_ENTITY_LITERAL | MD_QUOTE_PRE_MARKER_INDENT | MD_QUOTE_POST_MARKER_SPACE + | MD_INDENT_CHAR + | MD_LIST_POST_MARKER_SPACE ) } pub const fn is_list(self) -> bool { @@ -163,6 +170,7 @@ impl MarkdownSyntaxKind { | MD_BULLET_LIST | MD_INLINE_ITEM_LIST | MD_INDENTED_CODE_LINE_LIST + | MD_INDENT_TOKEN_LIST ) } pub fn from_keyword(ident: &str) -> Option { diff --git a/crates/biome_markdown_syntax/src/generated/macros.rs b/crates/biome_markdown_syntax/src/generated/macros.rs index a9283a42f552..11444cd9b201 100644 --- a/crates/biome_markdown_syntax/src/generated/macros.rs +++ b/crates/biome_markdown_syntax/src/generated/macros.rs @@ -64,6 +64,10 @@ macro_rules! map_syntax_node { let $pattern = unsafe { $crate::MdIndentCodeBlock::new_unchecked(node) }; $body } + $crate::MarkdownSyntaxKind::MD_INDENT_TOKEN => { + let $pattern = unsafe { $crate::MdIndentToken::new_unchecked(node) }; + $body + } $crate::MarkdownSyntaxKind::MD_INLINE_CODE => { let $pattern = unsafe { $crate::MdInlineCode::new_unchecked(node) }; $body @@ -109,6 +113,10 @@ macro_rules! map_syntax_node { let $pattern = unsafe { $crate::MdLinkTitle::new_unchecked(node) }; $body } + $crate::MarkdownSyntaxKind::MD_LIST_MARKER_PREFIX => { + let $pattern = unsafe { $crate::MdListMarkerPrefix::new_unchecked(node) }; + $body + } $crate::MarkdownSyntaxKind::MD_NEWLINE => { let $pattern = unsafe { $crate::MdNewline::new_unchecked(node) }; $body @@ -181,6 +189,10 @@ macro_rules! map_syntax_node { let $pattern = unsafe { $crate::MdHashList::new_unchecked(node) }; $body } + $crate::MarkdownSyntaxKind::MD_INDENT_TOKEN_LIST => { + let $pattern = unsafe { $crate::MdIndentTokenList::new_unchecked(node) }; + $body + } $crate::MarkdownSyntaxKind::MD_INLINE_ITEM_LIST => { let $pattern = unsafe { $crate::MdInlineItemList::new_unchecked(node) }; $body diff --git a/crates/biome_markdown_syntax/src/generated/nodes.rs b/crates/biome_markdown_syntax/src/generated/nodes.rs index fd51a99c381f..98a97be7768a 100644 --- a/crates/biome_markdown_syntax/src/generated/nodes.rs +++ b/crates/biome_markdown_syntax/src/generated/nodes.rs @@ -81,12 +81,12 @@ impl MdBullet { } pub fn as_fields(&self) -> MdBulletFields { MdBulletFields { - bullet: self.bullet(), + prefix: self.prefix(), content: self.content(), } } - pub fn bullet(&self) -> SyntaxResult { - support::required_token(&self.syntax, 0usize) + pub fn prefix(&self) -> SyntaxResult { + support::required_node(&self.syntax, 0usize) } pub fn content(&self) -> MdBlockList { support::list(&self.syntax, 1usize) @@ -102,7 +102,7 @@ impl Serialize for MdBullet { } #[derive(Serialize)] pub struct MdBulletFields { - pub bullet: SyntaxResult, + pub prefix: SyntaxResult, pub content: MdBlockList, } #[derive(Clone, PartialEq, Eq, Hash)] @@ -491,6 +491,41 @@ pub struct MdIndentCodeBlockFields { pub content: MdInlineItemList, } #[derive(Clone, PartialEq, Eq, Hash)] +pub struct MdIndentToken { + pub(crate) syntax: SyntaxNode, +} +impl MdIndentToken { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { syntax } + } + pub fn as_fields(&self) -> MdIndentTokenFields { + MdIndentTokenFields { + md_indent_char_token: self.md_indent_char_token(), + } + } + pub fn md_indent_char_token(&self) -> SyntaxResult { + support::required_token(&self.syntax, 0usize) + } +} +impl Serialize for MdIndentToken { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct MdIndentTokenFields { + pub md_indent_char_token: SyntaxResult, +} +#[derive(Clone, PartialEq, Eq, Hash)] pub struct MdInlineCode { pub(crate) syntax: SyntaxNode, } @@ -1006,6 +1041,56 @@ pub struct MdLinkTitleFields { pub content: MdInlineItemList, } #[derive(Clone, PartialEq, Eq, Hash)] +pub struct MdListMarkerPrefix { + pub(crate) syntax: SyntaxNode, +} +impl MdListMarkerPrefix { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub const unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { syntax } + } + pub fn as_fields(&self) -> MdListMarkerPrefixFields { + MdListMarkerPrefixFields { + pre_marker_indent: self.pre_marker_indent(), + marker: self.marker(), + post_marker_space_token: self.post_marker_space_token(), + content_indent: self.content_indent(), + } + } + pub fn pre_marker_indent(&self) -> MdIndentTokenList { + support::list(&self.syntax, 0usize) + } + pub fn marker(&self) -> SyntaxResult { + support::required_token(&self.syntax, 1usize) + } + pub fn post_marker_space_token(&self) -> Option { + support::token(&self.syntax, 2usize) + } + pub fn content_indent(&self) -> MdIndentTokenList { + support::list(&self.syntax, 3usize) + } +} +impl Serialize for MdListMarkerPrefix { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.as_fields().serialize(serializer) + } +} +#[derive(Serialize)] +pub struct MdListMarkerPrefixFields { + pub pre_marker_indent: MdIndentTokenList, + pub marker: SyntaxResult, + pub post_marker_space_token: Option, + pub content_indent: MdIndentTokenList, +} +#[derive(Clone, PartialEq, Eq, Hash)] pub struct MdNewline { pub(crate) syntax: SyntaxNode, } @@ -1862,7 +1947,7 @@ impl std::fmt::Debug for MdBullet { let result = if current_depth < 16 { DEPTH.set(current_depth + 1); f.debug_struct("MdBullet") - .field("bullet", &support::DebugSyntaxResult(self.bullet())) + .field("prefix", &support::DebugSyntaxResult(self.prefix())) .field("content", &self.content()) .finish() } else { @@ -2371,6 +2456,56 @@ impl From for SyntaxElement { n.syntax.into() } } +impl AstNode for MdIndentToken { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(MD_INDENT_TOKEN as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == MD_INDENT_TOKEN + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } + fn into_syntax(self) -> SyntaxNode { + self.syntax + } +} +impl std::fmt::Debug for MdIndentToken { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + thread_local! { static DEPTH : std :: cell :: Cell < u8 > = const { std :: cell :: Cell :: new (0) } }; + let current_depth = DEPTH.get(); + let result = if current_depth < 16 { + DEPTH.set(current_depth + 1); + f.debug_struct("MdIndentToken") + .field( + "md_indent_char_token", + &support::DebugSyntaxResult(self.md_indent_char_token()), + ) + .finish() + } else { + f.debug_struct("MdIndentToken").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: MdIndentToken) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: MdIndentToken) -> Self { + n.syntax.into() + } +} impl AstNode for MdInlineCode { type Language = Language; const KIND_SET: SyntaxKindSet = @@ -2956,6 +3091,59 @@ impl From for SyntaxElement { n.syntax.into() } } +impl AstNode for MdListMarkerPrefix { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(MD_LIST_MARKER_PREFIX as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == MD_LIST_MARKER_PREFIX + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } + fn into_syntax(self) -> SyntaxNode { + self.syntax + } +} +impl std::fmt::Debug for MdListMarkerPrefix { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + thread_local! { static DEPTH : std :: cell :: Cell < u8 > = const { std :: cell :: Cell :: new (0) } }; + let current_depth = DEPTH.get(); + let result = if current_depth < 16 { + DEPTH.set(current_depth + 1); + f.debug_struct("MdListMarkerPrefix") + .field("pre_marker_indent", &self.pre_marker_indent()) + .field("marker", &support::DebugSyntaxResult(self.marker())) + .field( + "post_marker_space_token", + &support::DebugOptionalElement(self.post_marker_space_token()), + ) + .field("content_indent", &self.content_indent()) + .finish() + } else { + f.debug_struct("MdListMarkerPrefix").finish() + }; + DEPTH.set(current_depth); + result + } +} +impl From for SyntaxNode { + fn from(n: MdListMarkerPrefix) -> Self { + n.syntax + } +} +impl From for SyntaxElement { + fn from(n: MdListMarkerPrefix) -> Self { + n.syntax.into() + } +} impl AstNode for MdNewline { type Language = Language; const KIND_SET: SyntaxKindSet = @@ -4286,6 +4474,11 @@ impl std::fmt::Display for MdIndentCodeBlock { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for MdIndentToken { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for MdInlineCode { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) @@ -4341,6 +4534,11 @@ impl std::fmt::Display for MdLinkTitle { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for MdListMarkerPrefix { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for MdNewline { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) @@ -4792,6 +4990,88 @@ impl IntoIterator for MdHashList { } } #[derive(Clone, Eq, PartialEq, Hash)] +pub struct MdIndentTokenList { + syntax_list: SyntaxList, +} +impl MdIndentTokenList { + #[doc = r" Create an AstNode from a SyntaxNode without checking its kind"] + #[doc = r""] + #[doc = r" # Safety"] + #[doc = r" This function must be guarded with a call to [AstNode::can_cast]"] + #[doc = r" or a match on [SyntaxNode::kind]"] + #[inline] + pub unsafe fn new_unchecked(syntax: SyntaxNode) -> Self { + Self { + syntax_list: syntax.into_list(), + } + } +} +impl AstNode for MdIndentTokenList { + type Language = Language; + const KIND_SET: SyntaxKindSet = + SyntaxKindSet::from_raw(RawSyntaxKind(MD_INDENT_TOKEN_LIST as u16)); + fn can_cast(kind: SyntaxKind) -> bool { + kind == MD_INDENT_TOKEN_LIST + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { + syntax_list: syntax.into_list(), + }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + self.syntax_list.node() + } + fn into_syntax(self) -> SyntaxNode { + self.syntax_list.into_node() + } +} +impl Serialize for MdIndentTokenList { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut seq = serializer.serialize_seq(Some(self.len()))?; + for e in self.iter() { + seq.serialize_element(&e)?; + } + seq.end() + } +} +impl AstNodeList for MdIndentTokenList { + type Language = Language; + type Node = MdIndentToken; + fn syntax_list(&self) -> &SyntaxList { + &self.syntax_list + } + fn into_syntax_list(self) -> SyntaxList { + self.syntax_list + } +} +impl Debug for MdIndentTokenList { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_str("MdIndentTokenList ")?; + f.debug_list().entries(self.iter()).finish() + } +} +impl IntoIterator for &MdIndentTokenList { + type Item = MdIndentToken; + type IntoIter = AstNodeListIterator; + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} +impl IntoIterator for MdIndentTokenList { + type Item = MdIndentToken; + type IntoIter = AstNodeListIterator; + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} +#[derive(Clone, Eq, PartialEq, Hash)] pub struct MdInlineItemList { syntax_list: SyntaxList, } diff --git a/crates/biome_markdown_syntax/src/generated/nodes_mut.rs b/crates/biome_markdown_syntax/src/generated/nodes_mut.rs index 4c6007784345..50ed4ea7701f 100644 --- a/crates/biome_markdown_syntax/src/generated/nodes_mut.rs +++ b/crates/biome_markdown_syntax/src/generated/nodes_mut.rs @@ -24,10 +24,10 @@ impl MdAutolink { } } impl MdBullet { - pub fn with_bullet_token(self, element: SyntaxToken) -> Self { + pub fn with_prefix(self, element: MdListMarkerPrefix) -> Self { Self::unwrap_cast( self.syntax - .splice_slots(0usize..=0usize, once(Some(element.into()))), + .splice_slots(0usize..=0usize, once(Some(element.into_syntax().into()))), ) } pub fn with_content(self, element: MdBlockList) -> Self { @@ -159,6 +159,14 @@ impl MdIndentCodeBlock { ) } } +impl MdIndentToken { + pub fn with_md_indent_char_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into()))), + ) + } +} impl MdInlineCode { pub fn with_l_tick_token(self, element: SyntaxToken) -> Self { Self::unwrap_cast( @@ -403,6 +411,32 @@ impl MdLinkTitle { ) } } +impl MdListMarkerPrefix { + pub fn with_pre_marker_indent(self, element: MdIndentTokenList) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(0usize..=0usize, once(Some(element.into_syntax().into()))), + ) + } + pub fn with_marker_token(self, element: SyntaxToken) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(1usize..=1usize, once(Some(element.into()))), + ) + } + pub fn with_post_marker_space_token(self, element: Option) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(2usize..=2usize, once(element.map(|element| element.into()))), + ) + } + pub fn with_content_indent(self, element: MdIndentTokenList) -> Self { + Self::unwrap_cast( + self.syntax + .splice_slots(3usize..=3usize, once(Some(element.into_syntax().into()))), + ) + } +} impl MdNewline { pub fn with_value_token(self, element: SyntaxToken) -> Self { Self::unwrap_cast( diff --git a/xtask/codegen/markdown.ungram b/xtask/codegen/markdown.ungram index c4470c402370..90c835c70eab 100644 --- a/xtask/codegen/markdown.ungram +++ b/xtask/codegen/markdown.ungram @@ -178,6 +178,11 @@ MdQuotePrefix = MdQuoteIndent = 'md_quote_pre_marker_indent' MdQuoteIndentList = MdQuoteIndent* +// Generic indent character for list pre-marker and content indent. +// Reusable across phases (lists, fenced code, thematic breaks). +MdIndentToken = 'md_indent_char' +MdIndentTokenList = MdIndentToken* + MdBulletListItem = MdBulletList MdOrderedListItem = MdBulletList @@ -188,9 +193,17 @@ MdBulletList = MdBullet* // 1. Hey! // ^^^^^^^ MdBullet = - bullet: ('-' | '*' | '+' | 'md_ordered_list_marker') + prefix: MdListMarkerPrefix content: MdBlockList +// Structural tokens around a list marker: indent, marker, post-space, content indent. +// Mirrors MdQuotePrefix pattern. Marker is required; all other fields optional/empty. +MdListMarkerPrefix = + pre_marker_indent: MdIndentTokenList + marker: ('-' | '*' | '+' | 'md_ordered_list_marker') + post_marker_space: 'md_list_post_marker_space'? + content_indent: MdIndentTokenList + // Any block paragraph // // Another block paragraph diff --git a/xtask/codegen/src/markdown_kinds_src.rs b/xtask/codegen/src/markdown_kinds_src.rs index e69fb971cbc5..d3be4b4fdb0c 100644 --- a/xtask/codegen/src/markdown_kinds_src.rs +++ b/xtask/codegen/src/markdown_kinds_src.rs @@ -40,6 +40,8 @@ pub const MARKDOWN_KINDS_SRC: KindsSrc = KindsSrc { "MD_ENTITY_LITERAL", "MD_QUOTE_PRE_MARKER_INDENT", "MD_QUOTE_POST_MARKER_SPACE", + "MD_INDENT_CHAR", + "MD_LIST_POST_MARKER_SPACE", ], tokens: &["ERROR_TOKEN", "NEWLINE", "WHITESPACE", "TAB"], nodes: &[ @@ -96,5 +98,8 @@ pub const MARKDOWN_KINDS_SRC: KindsSrc = KindsSrc { "MD_INDENT", "MD_THEMATIC_BREAK_BLOCK", "MD_NEWLINE", + "MD_INDENT_TOKEN", + "MD_INDENT_TOKEN_LIST", + "MD_LIST_MARKER_PREFIX", ], };