Fix rendering of markdown tables (#18315)

Andrey Arutiunian created

- Closes: https://github.com/zed-industries/zed/issues/11024

## Release Notes:

- Improved Markdown Preview rendering of tables

## Before:


![image](https://github.com/user-attachments/assets/25f05604-38a9-4bde-901c-6d53a5d9d94d)

<img width="2035" alt="Screenshot 2024-09-25 at 05 47 19"
src="https://github.com/user-attachments/assets/a30c56f5-4793-44c2-8527-294189f9e724">

## Now:


![image](https://github.com/user-attachments/assets/ce06f045-d0db-4b8c-a1fc-2811d35f2683)


<img width="2040" alt="Screenshot 2024-09-25 at 05 47 48"
src="https://github.com/user-attachments/assets/76e5d217-9110-4c5d-9fad-dc63ae0b75f4">

## Note:

I'm not a Rust programmer and this is my first PR in Zed (because i just
want to fix this, so i can view my notes in Markdown in Zed, not slow
Visual Studio Code) - so there may be errors. I'm open for critic a

Change summary

crates/markdown_preview/src/markdown_renderer.rs | 56 +++++++++++++++--
1 file changed, 48 insertions(+), 8 deletions(-)

Detailed changes

crates/markdown_preview/src/markdown_renderer.rs 🔗

@@ -6,8 +6,8 @@ use crate::markdown_elements::{
 };
 use gpui::{
     div, px, rems, AbsoluteLength, AnyElement, DefiniteLength, Div, Element, ElementId,
-    HighlightStyle, Hsla, InteractiveText, IntoElement, Keystroke, Modifiers, ParentElement,
-    SharedString, Styled, StyledText, TextStyle, WeakView, WindowContext,
+    HighlightStyle, Hsla, InteractiveText, IntoElement, Keystroke, Length, Modifiers,
+    ParentElement, SharedString, Styled, StyledText, TextStyle, WeakView, WindowContext,
 };
 use settings::Settings;
 use std::{
@@ -16,7 +16,7 @@ use std::{
 };
 use theme::{ActiveTheme, SyntaxTheme, ThemeSettings};
 use ui::{
-    h_flex, v_flex, Checkbox, FluentBuilder, InteractiveElement, LinkPreview, Selection,
+    h_flex, relative, v_flex, Checkbox, FluentBuilder, InteractiveElement, LinkPreview, Selection,
     StatefulInteractiveElement, Tooltip,
 };
 use workspace::Workspace;
@@ -231,12 +231,48 @@ fn render_markdown_list_item(
 }
 
 fn render_markdown_table(parsed: &ParsedMarkdownTable, cx: &mut RenderContext) -> AnyElement {
-    let header = render_markdown_table_row(&parsed.header, &parsed.column_alignments, true, cx);
+    let mut max_lengths: Vec<usize> = vec![0; parsed.header.children.len()];
+
+    for (index, cell) in parsed.header.children.iter().enumerate() {
+        let length = cell.contents.len();
+        max_lengths[index] = length;
+    }
+
+    for row in &parsed.body {
+        for (index, cell) in row.children.iter().enumerate() {
+            let length = cell.contents.len();
+            if length > max_lengths[index] {
+                max_lengths[index] = length;
+            }
+        }
+    }
+
+    let total_max_length: usize = max_lengths.iter().sum();
+    let max_column_widths: Vec<f32> = max_lengths
+        .iter()
+        .map(|&length| length as f32 / total_max_length as f32)
+        .collect();
+
+    let header = render_markdown_table_row(
+        &parsed.header,
+        &parsed.column_alignments,
+        &max_column_widths,
+        true,
+        cx,
+    );
 
     let body: Vec<AnyElement> = parsed
         .body
         .iter()
-        .map(|row| render_markdown_table_row(row, &parsed.column_alignments, false, cx))
+        .map(|row| {
+            render_markdown_table_row(
+                row,
+                &parsed.column_alignments,
+                &max_column_widths,
+                false,
+                cx,
+            )
+        })
         .collect();
 
     cx.with_common_p(v_flex())
@@ -249,14 +285,15 @@ fn render_markdown_table(parsed: &ParsedMarkdownTable, cx: &mut RenderContext) -
 fn render_markdown_table_row(
     parsed: &ParsedMarkdownTableRow,
     alignments: &Vec<ParsedMarkdownTableAlignment>,
+    max_column_widths: &Vec<f32>,
     is_header: bool,
     cx: &mut RenderContext,
 ) -> AnyElement {
     let mut items = vec![];
 
-    for cell in &parsed.children {
+    for (index, cell) in parsed.children.iter().enumerate() {
         let alignment = alignments
-            .get(items.len())
+            .get(index)
             .copied()
             .unwrap_or(ParsedMarkdownTableAlignment::None);
 
@@ -268,8 +305,11 @@ fn render_markdown_table_row(
             ParsedMarkdownTableAlignment::Right => v_flex().items_end(),
         };
 
+        let max_width = max_column_widths.get(index).unwrap_or(&0.0);
+
         let mut cell = container
-            .w_full()
+            .w(Length::Definite(relative(*max_width)))
+            .h_full()
             .child(contents)
             .px_2()
             .py_1()