feat(p1-3): kb-parse-md blocks (Markdown body → ParsedBlock tree) #8

Merged
altair823 merged 10 commits from feat/p1-3-parse-md-blocks into main 2026-04-30 15:03:26 +00:00
Showing only changes of commit 23ff4d68af - Show all commits

View File

@@ -1080,7 +1080,15 @@ impl<'a> WalkState<'a> {
current_cell.push(' ');
return;
}
self.with_current_inlines(|buf| buf.push_text(" "));
// Update both `paragraph.text` (via push_text) and the
// open link's flattened text accumulator (via
// push_link_text). Without push_link_text here, a
// multi-line `[text\nmore](href)` collapses to "textmore"
// — losing the visible space between words.
self.with_current_inlines(|buf| {
buf.push_text(" ");
buf.push_link_text(" ");
});
}
// Everything else (HTML, footnote refs, task list markers, math,
// rules, etc.) is dropped silently per design §3.4.
@@ -1639,6 +1647,53 @@ mod tests {
// ---- inline filter -------------------------------------------------------
#[test]
fn link_with_soft_break_preserves_space_in_text() {
// Without the push_link_text fix, this collapses to "multiline".
let body = "[multi\nline](http://x)\n";
let (blocks, _) = parse(body, 1);
assert_eq!(blocks.len(), 1);
match &blocks[0].payload {
ParsedPayload::Paragraph { inlines, .. } => {
let link = inlines
.iter()
.find(|i| matches!(i, Inline::Link { .. }))
.expect("link present");
match link {
Inline::Link { text, href } => {
assert_eq!(text, "multi line");
assert_eq!(href, "http://x");
}
_ => unreachable!(),
}
}
_ => panic!("expected paragraph, got {:?}", blocks[0].payload),
}
}
#[test]
fn link_with_hard_break_preserves_space_in_text() {
// Two trailing spaces + newline = HardBreak in CommonMark.
let body = "[multi \nline](http://x)\n";
let (blocks, _) = parse(body, 1);
assert_eq!(blocks.len(), 1);
match &blocks[0].payload {
ParsedPayload::Paragraph { inlines, .. } => {
let link = inlines
.iter()
.find(|i| matches!(i, Inline::Link { .. }))
.expect("link present");
match link {
Inline::Link { text, .. } => {
assert_eq!(text, "multi line");
}
_ => unreachable!(),
}
}
_ => panic!("expected paragraph"),
}
}
#[test]
fn only_allowed_inlines_emitted() {
let body = "**bold** *em* `code` [link](u)\n";