Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions crates/biome_markdown_factory/src/generated/node_factory.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions crates/biome_markdown_factory/src/generated/syntax_factory.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 38 additions & 0 deletions crates/biome_markdown_formatter/src/generated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,44 @@ impl IntoFormat<MarkdownFormatContext> for biome_markdown_syntax::MdBulletListIt
)
}
}
impl FormatRule<biome_markdown_syntax::MdContinuationIndent>
for crate::markdown::auxiliary::continuation_indent::FormatMdContinuationIndent
{
type Context = MarkdownFormatContext;
#[inline(always)]
fn fmt(
&self,
node: &biome_markdown_syntax::MdContinuationIndent,
f: &mut MarkdownFormatter,
) -> FormatResult<()> {
FormatNodeRule::<biome_markdown_syntax::MdContinuationIndent>::fmt(self, node, f)
}
}
impl AsFormat<MarkdownFormatContext> for biome_markdown_syntax::MdContinuationIndent {
type Format<'a> = FormatRefWithRule<
'a,
biome_markdown_syntax::MdContinuationIndent,
crate::markdown::auxiliary::continuation_indent::FormatMdContinuationIndent,
>;
fn format(&self) -> Self::Format<'_> {
FormatRefWithRule::new(
self,
crate::markdown::auxiliary::continuation_indent::FormatMdContinuationIndent::default(),
)
}
}
impl IntoFormat<MarkdownFormatContext> for biome_markdown_syntax::MdContinuationIndent {
type Format = FormatOwnedWithRule<
biome_markdown_syntax::MdContinuationIndent,
crate::markdown::auxiliary::continuation_indent::FormatMdContinuationIndent,
>;
fn into_format(self) -> Self::Format {
FormatOwnedWithRule::new(
self,
crate::markdown::auxiliary::continuation_indent::FormatMdContinuationIndent::default(),
)
}
}
impl FormatRule<biome_markdown_syntax::MdDocument>
for crate::markdown::auxiliary::document::FormatMdDocument
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ impl FormatRule<AnyMdLeafBlock> for FormatAnyMdLeafBlock {
fn fmt(&self, node: &AnyMdLeafBlock, f: &mut MarkdownFormatter) -> FormatResult<()> {
match node {
AnyMdLeafBlock::AnyMdCodeBlock(node) => node.format().fmt(f),
AnyMdLeafBlock::MdContinuationIndent(node) => node.format().fmt(f),
AnyMdLeafBlock::MdHeader(node) => node.format().fmt(f),
AnyMdLeafBlock::MdHtmlBlock(node) => node.format().fmt(f),
AnyMdLeafBlock::MdLinkReferenceDefinition(node) => node.format().fmt(f),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use crate::prelude::*;
use biome_markdown_syntax::MdContinuationIndent;
use biome_rowan::AstNode;
#[derive(Debug, Clone, Default)]
pub(crate) struct FormatMdContinuationIndent;
impl FormatNodeRule<MdContinuationIndent> for FormatMdContinuationIndent {
fn fmt_fields(
&self,
node: &MdContinuationIndent,
f: &mut MarkdownFormatter,
) -> FormatResult<()> {
format_verbatim_node(node.syntax()).fmt(f)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
pub(crate) mod autolink;
pub(crate) mod bullet;
pub(crate) mod bullet_list_item;
pub(crate) mod continuation_indent;
pub(crate) mod document;
pub(crate) mod entity_reference;
pub(crate) mod fenced_code_block;
Expand Down
11 changes: 7 additions & 4 deletions crates/biome_markdown_parser/src/syntax/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2041,10 +2041,13 @@ fn check_continuation_indent(
};
}

// Consume the structural indent as trivia so that block
// detection (at_bullet_list_item, etc.) works on the
// de-indented content. See §5.2 continuation lines.
p.skip_line_indent(state.required_indent);
// Emit the indentation for a continuation line inside a list item
// as an explicit MdContinuationIndent node so it appears in the
// CST rather than as skipped trivia. See CommonMark §5.2:
// https://spec.commonmark.org/0.31.2/#list-items
let ci_m = p.start();
p.emit_line_indent(state.required_indent);
ci_m.complete(p, MD_CONTINUATION_INDENT);
p.set_virtual_line_start();

return ContinuationResult {
Expand Down
40 changes: 28 additions & 12 deletions crates/biome_markdown_parser/src/to_html.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@

use biome_markdown_syntax::{
AnyMdBlock, AnyMdBulletListMember, AnyMdCodeBlock, AnyMdInline, AnyMdLeafBlock,
MarkdownLanguage, MdAutolink, MdBlockList, MdBullet, MdBulletListItem, MdDocument,
MdEntityReference, MdFencedCodeBlock, MdHardLine, MdHeader, MdHtmlBlock, MdIndentCodeBlock,
MdInlineCode, MdInlineEmphasis, MdInlineHtml, MdInlineImage, MdInlineItalic, MdInlineItemList,
MdInlineLink, MdLinkDestination, MdLinkLabel, MdLinkReferenceDefinition, MdLinkTitle,
MdOrderedListItem, MdParagraph, MdQuote, MdReferenceImage, MdReferenceLink,
MarkdownLanguage, MdAutolink, MdBlockList, MdBullet, MdBulletListItem, MdContinuationIndent,
MdDocument, MdEntityReference, MdFencedCodeBlock, MdHardLine, MdHeader, MdHtmlBlock,
MdIndentCodeBlock, MdInlineCode, MdInlineEmphasis, MdInlineHtml, MdInlineImage, MdInlineItalic,
MdInlineItemList, MdInlineLink, MdLinkDestination, MdLinkLabel, MdLinkReferenceDefinition,
MdLinkTitle, MdOrderedListItem, MdParagraph, MdQuote, MdReferenceImage, MdReferenceLink,
MdReferenceLinkLabel, MdSetextHeader, MdSoftBreak, MdTextual, MdThematicBreakBlock,
};
use biome_rowan::{AstNode, AstNodeList, Direction, SyntaxNode, TextRange, WalkEvent};
Expand Down Expand Up @@ -526,6 +526,11 @@ impl<'a> HtmlRenderer<'a> {
}

fn enter(&mut self, node: SyntaxNode<MarkdownLanguage>) {
if MdContinuationIndent::cast(node.clone()).is_some() {
self.opaque_depth = Some(self.depth);
return;
}

if MdInlineItemList::cast(node.clone()).is_some()
&& self
.suppressed_inline_nodes
Expand Down Expand Up @@ -622,7 +627,16 @@ impl<'a> HtmlRenderer<'a> {

if let Some(bullet) = MdBullet::cast(node.clone()) {
let list_is_tight = self.list_stack.last().is_some_and(|state| state.is_tight);
let blocks: Vec<_> = bullet.content().iter().collect();
let blocks: Vec<_> = bullet
.content()
.iter()
.filter(|b| {
!matches!(
b,
AnyMdBlock::AnyMdLeafBlock(AnyMdLeafBlock::MdContinuationIndent(_),)
)
})
.collect();
let item_has_blank_line = blocks
.windows(2)
.any(|pair| is_newline_block(&pair[0]) && is_newline_block(&pair[1]));
Expand Down Expand Up @@ -1173,12 +1187,12 @@ fn render_fenced_code_block(
) {
out.push_str("<pre><code");

// Determine the fence indentation from the explicit indent slot
// Determine the fence indentation from the explicit indent slot.
// The indent list only contains the fence's own 0-3 spaces;
// list/quote indent is handled separately via container_indent.
let fence_leading_indent = indent_list_width(&code.indent());
let container_indent = list_indent + quote_indent;
let fence_indent = fence_leading_indent
.saturating_sub(container_indent)
.min(MAX_BLOCK_PREFIX_INDENT);
let fence_indent = fence_leading_indent.min(MAX_BLOCK_PREFIX_INDENT);
let content_indent = container_indent + fence_indent;

// Get info string (language) - process escapes
Expand Down Expand Up @@ -1749,11 +1763,13 @@ fn is_paragraph_block(block: &AnyMdBlock) -> bool {
)
}

/// Check if a block is a newline (produces no output).
/// Check if a block is a newline or continuation indent (produces no output).
fn is_newline_block(block: &AnyMdBlock) -> bool {
matches!(
block,
AnyMdBlock::AnyMdLeafBlock(AnyMdLeafBlock::MdNewline(_))
AnyMdBlock::AnyMdLeafBlock(
AnyMdLeafBlock::MdNewline(_) | AnyMdLeafBlock::MdContinuationIndent(_),
)
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,20 @@ MdDocument {
MdNewline {
value_token: NEWLINE@6..7 "\n" [] [],
},
MdContinuationIndent {
indent: MdIndentTokenList [
MdIndentToken {
md_indent_char_token: MD_INDENT_CHAR@7..8 " " [] [],
},
MdIndentToken {
md_indent_char_token: MD_INDENT_CHAR@8..9 " " [] [],
},
],
},
MdFencedCodeBlock {
indent: MdIndentTokenList [
MdIndentToken {
md_indent_char_token: MD_INDENT_CHAR@7..10 " " [Whitespace(" "), Whitespace(" ")] [],
md_indent_char_token: MD_INDENT_CHAR@9..10 " " [] [],
},
MdIndentToken {
md_indent_char_token: MD_INDENT_CHAR@10..11 " " [] [],
Expand Down Expand Up @@ -135,10 +145,16 @@ MdDocument {
1: (empty)
1: MD_NEWLINE@6..7
0: NEWLINE@6..7 "\n" [] []
2: MD_FENCED_CODE_BLOCK@7..41
0: MD_INDENT_TOKEN_LIST@7..11
0: MD_INDENT_TOKEN@7..10
0: MD_INDENT_CHAR@7..10 " " [Whitespace(" "), Whitespace(" ")] []
2: MD_CONTINUATION_INDENT@7..9
0: MD_INDENT_TOKEN_LIST@7..9
0: MD_INDENT_TOKEN@7..8
0: MD_INDENT_CHAR@7..8 " " [] []
1: MD_INDENT_TOKEN@8..9
0: MD_INDENT_CHAR@8..9 " " [] []
3: MD_FENCED_CODE_BLOCK@9..41
0: MD_INDENT_TOKEN_LIST@9..11
0: MD_INDENT_TOKEN@9..10
0: MD_INDENT_CHAR@9..10 " " [] []
1: MD_INDENT_TOKEN@10..11
0: MD_INDENT_CHAR@10..11 " " [] []
1: TRIPLE_BACKTICK@11..14 "```" [] []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,10 +215,20 @@ MdDocument {
MdNewline {
value_token: NEWLINE@355..356 "\n" [] [],
},
MdContinuationIndent {
indent: MdIndentTokenList [
MdIndentToken {
md_indent_char_token: MD_INDENT_CHAR@356..357 " " [] [],
},
MdIndentToken {
md_indent_char_token: MD_INDENT_CHAR@357..358 " " [] [],
},
],
},
MdParagraph {
list: MdInlineItemList [
MdTextual {
value_token: MD_TEXTUAL_LITERAL@356..467 "NOTE: the shape of the JSON is considered experimental, and the shape of the JSON might change in the future." [Whitespace(" "), Whitespace(" ")] [],
value_token: MD_TEXTUAL_LITERAL@358..467 "NOTE: the shape of the JSON is considered experimental, and the shape of the JSON might change in the future." [] [],
},
MdTextual {
value_token: MD_TEXTUAL_LITERAL@467..468 "\n" [] [],
Expand All @@ -229,11 +239,21 @@ MdDocument {
MdNewline {
value_token: NEWLINE@468..469 "\n" [] [],
},
MdContinuationIndent {
indent: MdIndentTokenList [
MdIndentToken {
md_indent_char_token: MD_INDENT_CHAR@469..470 " " [] [],
},
MdIndentToken {
md_indent_char_token: MD_INDENT_CHAR@470..471 " " [] [],
},
],
},
MdHtmlBlock {
indent: MdIndentTokenList [],
content: MdInlineItemList [
MdTextual {
value_token: MD_TEXTUAL_LITERAL@469..472 "<" [Whitespace(" "), Whitespace(" ")] [],
value_token: MD_TEXTUAL_LITERAL@471..472 "<" [] [],
},
MdTextual {
value_token: MD_TEXTUAL_LITERAL@472..479 "details" [] [],
Expand Down Expand Up @@ -2302,20 +2322,32 @@ MdDocument {
1: (empty)
1: MD_NEWLINE@355..356
0: NEWLINE@355..356 "\n" [] []
2: MD_PARAGRAPH@356..468
0: MD_INLINE_ITEM_LIST@356..468
0: MD_TEXTUAL@356..467
0: MD_TEXTUAL_LITERAL@356..467 "NOTE: the shape of the JSON is considered experimental, and the shape of the JSON might change in the future." [Whitespace(" "), Whitespace(" ")] []
2: MD_CONTINUATION_INDENT@356..358
0: MD_INDENT_TOKEN_LIST@356..358
0: MD_INDENT_TOKEN@356..357
0: MD_INDENT_CHAR@356..357 " " [] []
1: MD_INDENT_TOKEN@357..358
0: MD_INDENT_CHAR@357..358 " " [] []
3: MD_PARAGRAPH@358..468
0: MD_INLINE_ITEM_LIST@358..468
0: MD_TEXTUAL@358..467
0: MD_TEXTUAL_LITERAL@358..467 "NOTE: the shape of the JSON is considered experimental, and the shape of the JSON might change in the future." [] []
1: MD_TEXTUAL@467..468
0: MD_TEXTUAL_LITERAL@467..468 "\n" [] []
1: (empty)
3: MD_NEWLINE@468..469
4: MD_NEWLINE@468..469
0: NEWLINE@468..469 "\n" [] []
4: MD_HTML_BLOCK@469..2001
0: MD_INDENT_TOKEN_LIST@469..469
1: MD_INLINE_ITEM_LIST@469..2001
0: MD_TEXTUAL@469..472
0: MD_TEXTUAL_LITERAL@469..472 "<" [Whitespace(" "), Whitespace(" ")] []
5: MD_CONTINUATION_INDENT@469..471
0: MD_INDENT_TOKEN_LIST@469..471
0: MD_INDENT_TOKEN@469..470
0: MD_INDENT_CHAR@469..470 " " [] []
1: MD_INDENT_TOKEN@470..471
0: MD_INDENT_CHAR@470..471 " " [] []
6: MD_HTML_BLOCK@471..2001
0: MD_INDENT_TOKEN_LIST@471..471
1: MD_INLINE_ITEM_LIST@471..2001
0: MD_TEXTUAL@471..472
0: MD_TEXTUAL_LITERAL@471..472 "<" [] []
1: MD_TEXTUAL@472..479
0: MD_TEXTUAL_LITERAL@472..479 "details" [] []
2: MD_TEXTUAL@479..480
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -353,10 +353,20 @@ MdDocument {
},
],
},
MdContinuationIndent {
indent: MdIndentTokenList [
MdIndentToken {
md_indent_char_token: MD_INDENT_CHAR@323..324 " " [] [],
},
MdIndentToken {
md_indent_char_token: MD_INDENT_CHAR@324..325 " " [] [],
},
],
},
MdParagraph {
list: MdInlineItemList [
MdTextual {
value_token: MD_TEXTUAL_LITERAL@323..365 "outer continuation at parent indentation" [Whitespace(" "), Whitespace(" ")] [],
value_token: MD_TEXTUAL_LITERAL@325..365 "outer continuation at parent indentation" [] [],
},
MdTextual {
value_token: MD_TEXTUAL_LITERAL@365..366 "\n" [] [],
Expand Down Expand Up @@ -691,14 +701,20 @@ MdDocument {
7: MD_TEXTUAL@322..323
0: MD_TEXTUAL_LITERAL@322..323 "\n" [] []
1: (empty)
2: MD_PARAGRAPH@323..366
0: MD_INLINE_ITEM_LIST@323..366
0: MD_TEXTUAL@323..365
0: MD_TEXTUAL_LITERAL@323..365 "outer continuation at parent indentation" [Whitespace(" "), Whitespace(" ")] []
2: MD_CONTINUATION_INDENT@323..325
0: MD_INDENT_TOKEN_LIST@323..325
0: MD_INDENT_TOKEN@323..324
0: MD_INDENT_CHAR@323..324 " " [] []
1: MD_INDENT_TOKEN@324..325
0: MD_INDENT_CHAR@324..325 " " [] []
3: MD_PARAGRAPH@325..366
0: MD_INLINE_ITEM_LIST@325..366
0: MD_TEXTUAL@325..365
0: MD_TEXTUAL_LITERAL@325..365 "outer continuation at parent indentation" [] []
1: MD_TEXTUAL@365..366
0: MD_TEXTUAL_LITERAL@365..366 "\n" [] []
1: (empty)
3: MD_NEWLINE@366..367
4: MD_NEWLINE@366..367
0: NEWLINE@366..367 "\n" [] []
1: MD_BULLET@367..385
0: MD_LIST_MARKER_PREFIX@367..368
Expand Down
Loading
Loading