diff --git a/crates/markdown/src/html/html_parser.rs b/crates/markdown/src/html/html_parser.rs index 8aa5da0cea7ea160721875fa889a720fe4c8bed1..5ab9a48b720255641db245f99e5da08765c4a32a 100644 --- a/crates/markdown/src/html/html_parser.rs +++ b/crates/markdown/src/html/html_parser.rs @@ -867,6 +867,51 @@ mod tests { assert_eq!(table.body[1].columns.len(), 2); } + #[test] + fn parses_html_table_th_defaults_to_center() { + let html = "
H1H2
ab
"; + let parsed = parse_html_block(html, 0..html.len()).unwrap(); + + let ParsedHtmlElement::Table(table) = &parsed.children[0] else { + panic!("expected table"); + }; + + assert_eq!(table.header.len(), 1); + for column in &table.header[0].columns { + assert!(column.is_header); + assert_eq!(column.alignment, Alignment::Center); + } + + for column in &table.body[0].columns { + assert!(!column.is_header); + assert_eq!(column.alignment, Alignment::None); + } + } + + #[test] + fn parses_html_table_explicit_align_attribute_preserved() { + let html = "\ + \ + \ + \ + \ + \ + \ + \ + \ +
H1H2
ab
"; + let parsed = parse_html_block(html, 0..html.len()).unwrap(); + + let ParsedHtmlElement::Table(table) = &parsed.children[0] else { + panic!("expected table"); + }; + + assert_eq!(table.header[0].columns[0].alignment, Alignment::Right); + assert_eq!(table.header[0].columns[1].alignment, Alignment::Left); + assert_eq!(table.body[0].columns[0].alignment, Alignment::Center); + assert_eq!(table.body[0].columns[1].alignment, Alignment::Right); + } + #[test] fn parses_html_list_as_explicit_list_node() { let parsed = parse_html_block( diff --git a/crates/markdown/src/markdown.rs b/crates/markdown/src/markdown.rs index 937e38c39509cc580f2f5a571339ce0dced83efb..a900837b98e4f2d2f72a8880034b0c5a0b6a2a26 100644 --- a/crates/markdown/src/markdown.rs +++ b/crates/markdown/src/markdown.rs @@ -1730,15 +1730,28 @@ impl Element for MarkdownElement { } } MarkdownTag::Paragraph => { - self.push_markdown_paragraph(&mut builder, range, markdown_end, None); + let text_align_override = builder + .table + .current_cell_alignment() + .and_then(alignment_to_text_align); + self.push_markdown_paragraph( + &mut builder, + range, + markdown_end, + text_align_override, + ); } MarkdownTag::Heading { level, .. } => { + let text_align_override = builder + .table + .current_cell_alignment() + .and_then(alignment_to_text_align); self.push_markdown_heading( &mut builder, *level, range, markdown_end, - None, + text_align_override, ); } MarkdownTag::BlockQuote(kind) => { @@ -2000,13 +2013,10 @@ impl Element for MarkdownElement { let is_header = builder.table.in_head; let row_index = builder.table.row_index; let col_index = builder.table.col_index; - let alignment = builder.table.alignments.get(col_index).copied(); - let text_align = match alignment { - Some(Alignment::Left) => TextAlign::Left, - Some(Alignment::Center) => TextAlign::Center, - Some(Alignment::Right) => TextAlign::Right, - _ => self.style.base_text_style.text_align, - }; + let alignment = builder.table.current_cell_alignment(); + let text_align = alignment + .and_then(alignment_to_text_align) + .unwrap_or(self.style.base_text_style.text_align); let mut cell_div = div() .flex() @@ -2445,6 +2455,25 @@ impl TableState { fn end_cell(&mut self) { self.col_index += 1; } + + fn current_cell_alignment(&self) -> Option { + if self.alignments.is_empty() { + return None; + } + if self.in_head { + return Some(Alignment::Center); + } + self.alignments.get(self.col_index).copied() + } +} + +fn alignment_to_text_align(alignment: Alignment) -> Option { + match alignment { + Alignment::Left => Some(TextAlign::Left), + Alignment::Center => Some(TextAlign::Center), + Alignment::Right => Some(TextAlign::Right), + Alignment::None => None, + } } struct MarkdownElementBuilder { @@ -3474,6 +3503,37 @@ mod tests { assert_eq!(second_word, "b"); } + #[test] + fn test_table_state_current_cell_alignment_centers_headers() { + let mut table = TableState::default(); + table.start(vec![Alignment::Left, Alignment::Right, Alignment::None]); + + table.start_head(); + for _ in 0..3 { + assert_eq!(table.current_cell_alignment(), Some(Alignment::Center)); + table.end_cell(); + } + + table.end_head(); + table.start_row(); + assert_eq!(table.current_cell_alignment(), Some(Alignment::Left)); + table.end_cell(); + assert_eq!(table.current_cell_alignment(), Some(Alignment::Right)); + table.end_cell(); + assert_eq!(table.current_cell_alignment(), Some(Alignment::None)); + table.end_cell(); + table.end_row(); + + table.end(); + assert_eq!(table.current_cell_alignment(), None); + } + + #[test] + fn test_table_state_current_cell_alignment_outside_table() { + let table = TableState::default(); + assert_eq!(table.current_cell_alignment(), None); + } + #[test] fn test_table_checkbox_detection() { let md = "| Done |\n|------|\n| [x] |\n| [ ] |";