markdown: Fix table header alignment and apply alignment to cell content (#56179)

Follow up: https://github.com/zed-industries/zed/pull/53465

For Markdown tables, headers are now always centered (ignoring column
alignment), matching standard Markdown rendering behavior. For HTML
tables, headers default to center but respect explicit `align`
attributes.

This also propagates alignment to paragraphs and headings inside table
cells, not just the cell container itself.

Release Notes:

- N/A
This commit is contained in:
Smit Barmase 2026-05-08 20:54:45 +05:30 committed by GitHub
parent b8c3167a9d
commit 6151889ddf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 114 additions and 9 deletions

View file

@ -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 = "<table><thead><tr><th>H1</th><th>H2</th></tr></thead><tbody><tr><td>a</td><td>b</td></tr></tbody></table>";
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 = "<table>\
<thead><tr>\
<th align=\"right\">H1</th>\
<th align=\"left\">H2</th>\
</tr></thead>\
<tbody><tr>\
<td align=\"center\">a</td>\
<td align=\"right\">b</td>\
</tr></tbody>\
</table>";
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(

View file

@ -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<Alignment> {
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<TextAlign> {
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| [ ] |";