diff --git a/crates/biome_markdown_parser/src/syntax/fenced_code_block.rs b/crates/biome_markdown_parser/src/syntax/fenced_code_block.rs index 87b96a8f19bc..d44845c5945f 100644 --- a/crates/biome_markdown_parser/src/syntax/fenced_code_block.rs +++ b/crates/biome_markdown_parser/src/syntax/fenced_code_block.rs @@ -23,6 +23,7 @@ //! that can be used for syntax highlighting. use crate::parser::MarkdownParser; +use crate::token_source::find_line_start; use biome_markdown_syntax::{T, kind::MarkdownSyntaxKind::*}; use biome_parser::{ Parser, @@ -108,26 +109,6 @@ fn bump_fence(p: &mut MarkdownParser, is_tilde_fence: bool) { } } -/// Find the start position of the current line in the source text. -/// -/// Given a slice of text before the current position, finds the byte offset -/// where the current line begins (after the last newline, handling CRLF). -fn find_line_start(before: &str) -> usize { - let last_newline_pos = before.rfind(['\n', '\r']); - match last_newline_pos { - Some(pos) => { - let bytes = before.as_bytes(); - // Handle CRLF: if we found \r and next char is \n, skip both - if bytes.get(pos) == Some(&b'\r') && bytes.get(pos + 1) == Some(&b'\n') { - pos + 2 - } else { - pos + 1 - } - } - None => 0, - } -} - /// Detect a code fence at the start of a string. /// /// Per CommonMark §4.5: "A code fence is a sequence of at least three diff --git a/crates/biome_markdown_parser/src/syntax/list.rs b/crates/biome_markdown_parser/src/syntax/list.rs index 9bfbfcf485ee..6e6b3645de7d 100644 --- a/crates/biome_markdown_parser/src/syntax/list.rs +++ b/crates/biome_markdown_parser/src/syntax/list.rs @@ -56,7 +56,7 @@ use crate::syntax::thematic_break_block::parse_thematic_break_block; use crate::syntax::with_virtual_line_start; use crate::syntax::{ INDENT_CODE_BLOCK_SPACES, MAX_BLOCK_PREFIX_INDENT, TAB_STOP_SPACES, at_block_interrupt, - at_indent_code_block, is_paragraph_like, + at_indent_code_block, is_paragraph_like, is_whitespace_only, }; /// Tokens that start a new block (used for recovery) @@ -205,10 +205,6 @@ fn emit_list_post_marker_space(p: &mut MarkdownParser) -> bool { } } -fn is_whitespace_only(text: &str) -> bool { - !text.is_empty() && text.chars().all(|c| c == ' ' || c == '\t') -} - /// Check if the remaining content forms a thematic break pattern. /// /// Per CommonMark §4.1, a thematic break is 3 or more matching characters @@ -838,7 +834,11 @@ impl ParseNodeList for OrderedList { type Kind = MarkdownSyntaxKind; type Parser<'source> = MarkdownParser<'source>; - const LIST_KIND: Self::Kind = MD_BULLET_LIST; // Reuse bullet list node structure + // The Markdown grammar defines a single MdBulletList node kind for both + // bullet and ordered lists — the marker type distinguishes them, not the + // CST node kind. This keeps the grammar simpler and avoids duplicating + // the entire list/item node hierarchy. + const LIST_KIND: Self::Kind = MD_BULLET_LIST; fn parse_element(&mut self, p: &mut Self::Parser<'_>) -> ParsedSyntax { parse_list_element_common( diff --git a/crates/biome_markdown_parser/src/syntax/mod.rs b/crates/biome_markdown_parser/src/syntax/mod.rs index e770ee5dfa26..f66de8181485 100644 --- a/crates/biome_markdown_parser/src/syntax/mod.rs +++ b/crates/biome_markdown_parser/src/syntax/mod.rs @@ -1780,7 +1780,7 @@ fn is_empty_list_item(p: &mut MarkdownParser) -> bool { is_empty } -fn is_whitespace_only(text: &str) -> bool { +pub(crate) fn is_whitespace_only(text: &str) -> bool { !text.is_empty() && text.chars().all(|c| c == ' ' || c == '\t') } diff --git a/crates/biome_markdown_parser/src/syntax/quote.rs b/crates/biome_markdown_parser/src/syntax/quote.rs index 2da170df794f..af909584bb16 100644 --- a/crates/biome_markdown_parser/src/syntax/quote.rs +++ b/crates/biome_markdown_parser/src/syntax/quote.rs @@ -43,6 +43,7 @@ use crate::syntax::parse_any_block_with_indent_code_policy; use crate::syntax::parse_error::quote_nesting_too_deep; use crate::syntax::{ INDENT_CODE_BLOCK_SPACES, MAX_BLOCK_PREFIX_INDENT, TAB_STOP_SPACES, is_paragraph_like, + is_whitespace_only, }; /// Check if we're at the start of a block quote (`>`). @@ -197,11 +198,6 @@ fn emit_quote_pre_marker_indents(p: &mut MarkdownParser) { indent_list_m.complete(p, MD_QUOTE_INDENT_LIST); } -/// Check if text contains only spaces and tabs. -fn is_whitespace_only(text: &str) -> bool { - !text.is_empty() && text.chars().all(|c| c == ' ' || c == '\t') -} - /// Calculate indent width accounting for tab expansion (CommonMark §2.2). fn calculate_indent_width(text: &str) -> usize { text.chars() diff --git a/crates/biome_markdown_parser/src/token_source.rs b/crates/biome_markdown_parser/src/token_source.rs index e2c080af11e9..8227064cbae2 100644 --- a/crates/biome_markdown_parser/src/token_source.rs +++ b/crates/biome_markdown_parser/src/token_source.rs @@ -11,7 +11,7 @@ use biome_rowan::{TextRange, TriviaPieceKind}; /// /// Given a slice of text, finds the byte offset where the current line begins /// (after the last newline, handling CRLF). -fn find_line_start(before: &str) -> usize { +pub(crate) fn find_line_start(before: &str) -> usize { let last_newline_pos = before.rfind(['\n', '\r']); match last_newline_pos { Some(pos) => {