diff --git a/src/Markdig.Tests/TestPipeTable.cs b/src/Markdig.Tests/TestPipeTable.cs
index cffd479c..b891c722 100644
--- a/src/Markdig.Tests/TestPipeTable.cs
+++ b/src/Markdig.Tests/TestPipeTable.cs
@@ -12,10 +12,47 @@ public sealed class TestPipeTable
[TestCase("| S | \r\n|---|\r\n| G |\r\n\r\n| D | D |\r\n| ---| ---| \r\n| V | V |", 2)]
public void TestTableBug(string markdown, int tableCount = 1)
{
- MarkdownDocument document = Markdown.Parse(markdown, new MarkdownPipelineBuilder().UseAdvancedExtensions().Build());
+ MarkdownDocument document =
+ Markdown.Parse(markdown, new MarkdownPipelineBuilder().UseAdvancedExtensions().Build());
Table[] tables = document.Descendants().OfType
().ToArray();
Assert.AreEqual(tableCount, tables.Length);
}
+
+ [TestCase("A | B\r\n---|---", new[] {50.0f, 50.0f})]
+ [TestCase("A | B\r\n-|---", new[] {25.0f, 75.0f})]
+ [TestCase("A | B\r\n-|---\r\nA | B\r\n---|---", new[] {25.0f, 75.0f})]
+ [TestCase("A | B\r\n---|---|---", new[] {33.33f, 33.33f, 33.33f})]
+ [TestCase("A | B\r\n---|---|---|", new[] {33.33f, 33.33f, 33.33f})]
+ public void TestColumnWidthByHeaderLines(string markdown, float[] expectedWidth)
+ {
+ var pipeline = new MarkdownPipelineBuilder()
+ .UsePipeTables(new PipeTableOptions() {InferColumnWidthsFromSeparator = true})
+ .Build();
+ var document = Markdown.Parse(markdown, pipeline);
+ var table = document.Descendants().OfType().FirstOrDefault();
+ Assert.IsNotNull(table);
+ var actualWidths = table.ColumnDefinitions.Select(x => x.Width).ToList();
+ Assert.AreEqual(actualWidths.Count, expectedWidth.Length);
+ for (int i = 0; i < expectedWidth.Length; i++)
+ {
+ Assert.AreEqual(actualWidths[i], expectedWidth[i], 0.01);
+ }
+ }
+
+ [Test]
+ public void TestColumnWidthIsNotSetWithoutConfigurationFlag()
+ {
+ var pipeline = new MarkdownPipelineBuilder()
+ .UsePipeTables(new PipeTableOptions() {InferColumnWidthsFromSeparator = false})
+ .Build();
+ var document = Markdown.Parse("| A | B | C |\r\n|---|---|---|", pipeline);
+ var table = document.Descendants().OfType().FirstOrDefault();
+ Assert.IsNotNull(table);
+ foreach (var column in table.ColumnDefinitions)
+ {
+ Assert.AreEqual(0, column.Width);
+ }
+ }
}
diff --git a/src/Markdig/Extensions/Tables/GridTableParser.cs b/src/Markdig/Extensions/Tables/GridTableParser.cs
index 6e6d562a..847bd94c 100644
--- a/src/Markdig/Extensions/Tables/GridTableParser.cs
+++ b/src/Markdig/Extensions/Tables/GridTableParser.cs
@@ -43,7 +43,7 @@ public class GridTableParser : BlockParser
}
// Parse a column alignment
- if (!TableHelper.ParseColumnHeader(ref line, '-', out TableColumnAlign? columnAlign))
+ if (!TableHelper.ParseColumnHeader(ref line, '-', out TableColumnAlign? columnAlign, out _))
{
return BlockState.None;
}
diff --git a/src/Markdig/Extensions/Tables/PipeTableOptions.cs b/src/Markdig/Extensions/Tables/PipeTableOptions.cs
index 05181ec2..bbeafac9 100644
--- a/src/Markdig/Extensions/Tables/PipeTableOptions.cs
+++ b/src/Markdig/Extensions/Tables/PipeTableOptions.cs
@@ -33,4 +33,11 @@ public class PipeTableOptions
/// in all other rows (default behavior).
///
public bool UseHeaderForColumnCount { get; set; }
+
+
+ ///
+ /// Gets or sets a value indicating whether column widths should be inferred based on the number of dashes
+ /// in the header separator row. Each column's width will be proportional to the dash count in its respective column.
+ ///
+ public bool InferColumnWidthsFromSeparator { get; set; }
}
\ No newline at end of file
diff --git a/src/Markdig/Extensions/Tables/PipeTableParser.cs b/src/Markdig/Extensions/Tables/PipeTableParser.cs
index 71c14538..f4d17c41 100644
--- a/src/Markdig/Extensions/Tables/PipeTableParser.cs
+++ b/src/Markdig/Extensions/Tables/PipeTableParser.cs
@@ -481,9 +481,10 @@ public class PipeTableParser : InlineParser, IPostInlineProcessor
return false;
}
- private static bool ParseHeaderString(Inline? inline, out TableColumnAlign? align)
+ private static bool ParseHeaderString(Inline? inline, out TableColumnAlign? align, out int delimiterCount)
{
align = 0;
+ delimiterCount = 0;
var literal = inline as LiteralInline;
if (literal is null)
{
@@ -492,7 +493,7 @@ public class PipeTableParser : InlineParser, IPostInlineProcessor
// Work on a copy of the slice
var line = literal.Content;
- if (TableHelper.ParseColumnHeader(ref line, '-', out align))
+ if (TableHelper.ParseColumnHeader(ref line, '-', out align, out delimiterCount))
{
if (line.CurrentChar != '\0')
{
@@ -507,7 +508,8 @@ public class PipeTableParser : InlineParser, IPostInlineProcessor
private List? FindHeaderRow(List delimiters)
{
bool isValidRow = false;
- List? aligns = null;
+ int totalDelimiterCount = 0;
+ List? columnDefinitions = null;
for (int i = 0; i < delimiters.Count; i++)
{
if (!IsLine(delimiters[i]))
@@ -529,18 +531,19 @@ public class PipeTableParser : InlineParser, IPostInlineProcessor
// Check the left side of a `|` delimiter
TableColumnAlign? align = null;
+ int delimiterCount = 0;
if (delimiter.PreviousSibling != null &&
!(delimiter.PreviousSibling is LiteralInline li && li.Content.IsEmptyOrWhitespace()) && // ignore parsed whitespace
- !ParseHeaderString(delimiter.PreviousSibling, out align))
+ !ParseHeaderString(delimiter.PreviousSibling, out align, out delimiterCount))
{
break;
}
// Create aligns until we may have a header row
- aligns ??= new List();
-
- aligns.Add(new TableColumnDefinition() { Alignment = align });
+ columnDefinitions ??= new List();
+ totalDelimiterCount += delimiterCount;
+ columnDefinitions.Add(new TableColumnDefinition() { Alignment = align, Width = delimiterCount});
// If this is the last delimiter, we need to check the right side of the `|` delimiter
if (nextDelimiter is null)
@@ -556,13 +559,13 @@ public class PipeTableParser : InlineParser, IPostInlineProcessor
break;
}
- if (!ParseHeaderString(nextSibling, out align))
+ if (!ParseHeaderString(nextSibling, out align, out delimiterCount))
{
break;
}
-
+ totalDelimiterCount += delimiterCount;
isValidRow = true;
- aligns.Add(new TableColumnDefinition() { Alignment = align });
+ columnDefinitions.Add(new TableColumnDefinition() { Alignment = align, Width = delimiterCount});
break;
}
@@ -576,7 +579,27 @@ public class PipeTableParser : InlineParser, IPostInlineProcessor
break;
}
- return isValidRow ? aligns : null;
+ // calculate the width of the columns in percent based on the delimiter count
+ if (!isValidRow || columnDefinitions == null)
+ {
+ return null;
+ }
+
+ if (Options.InferColumnWidthsFromSeparator)
+ {
+ foreach (var columnDefinition in columnDefinitions)
+ {
+ columnDefinition.Width = (columnDefinition.Width * 100) / totalDelimiterCount;
+ }
+ }
+ else
+ {
+ foreach (var columnDefinition in columnDefinitions)
+ {
+ columnDefinition.Width = 0;
+ }
+ }
+ return columnDefinitions;
}
private static bool IsLine(Inline inline)
diff --git a/src/Markdig/Extensions/Tables/TableHelper.cs b/src/Markdig/Extensions/Tables/TableHelper.cs
index bbbda511..f75090a5 100644
--- a/src/Markdig/Extensions/Tables/TableHelper.cs
+++ b/src/Markdig/Extensions/Tables/TableHelper.cs
@@ -17,12 +17,13 @@ public static class TableHelper
/// The text slice.
/// The delimiter character (either `-` or `=`).
/// The alignment of the column.
+ /// The number of delimiters.
///
/// true if parsing was successful
///
- public static bool ParseColumnHeader(ref StringSlice slice, char delimiterChar, out TableColumnAlign? align)
+ public static bool ParseColumnHeader(ref StringSlice slice, char delimiterChar, out TableColumnAlign? align, out int delimiterCount)
{
- return ParseColumnHeaderDetect(ref slice, ref delimiterChar, out align);
+ return ParseColumnHeaderDetect(ref slice, ref delimiterChar, out align, out delimiterCount);
}
///
@@ -37,7 +38,7 @@ public static class TableHelper
public static bool ParseColumnHeaderAuto(ref StringSlice slice, out char delimiterChar, out TableColumnAlign? align)
{
delimiterChar = '\0';
- return ParseColumnHeaderDetect(ref slice, ref delimiterChar, out align);
+ return ParseColumnHeaderDetect(ref slice, ref delimiterChar, out align, out _);
}
///
@@ -49,10 +50,10 @@ public static class TableHelper
///
/// true if parsing was successful
///
- public static bool ParseColumnHeaderDetect(ref StringSlice slice, ref char delimiterChar, out TableColumnAlign? align)
+ public static bool ParseColumnHeaderDetect(ref StringSlice slice, ref char delimiterChar, out TableColumnAlign? align, out int delimiterCount)
{
align = null;
-
+ delimiterCount = 0;
slice.TrimStart();
var c = slice.CurrentChar;
bool hasLeft = false;
@@ -80,7 +81,8 @@ public static class TableHelper
}
// We expect at least one `-` delimiter char
- if (slice.CountAndSkipChar(delimiterChar) == 0)
+ delimiterCount = slice.CountAndSkipChar(delimiterChar);
+ if (delimiterCount == 0)
{
return false;
}