Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 38 additions & 1 deletion src/Markdig.Tests/TestPipeTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Table>().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<Table>().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<Table>().FirstOrDefault();
Assert.IsNotNull(table);
foreach (var column in table.ColumnDefinitions)
{
Assert.AreEqual(0, column.Width);
}
}
}
2 changes: 1 addition & 1 deletion src/Markdig/Extensions/Tables/GridTableParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public override BlockState TryOpen(BlockProcessor processor)
}

// Parse a column alignment
if (!TableHelper.ParseColumnHeader(ref line, '-', out TableColumnAlign? columnAlign))
if (!TableHelper.ParseColumnHeader(ref line, '-', out TableColumnAlign? columnAlign, out _))
{
return BlockState.None;
}
Expand Down
7 changes: 7 additions & 0 deletions src/Markdig/Extensions/Tables/PipeTableOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,11 @@ public PipeTableOptions()
/// in all other rows (default behavior).
/// </summary>
public bool UseHeaderForColumnCount { get; set; }


/// <summary>
/// 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.
/// </summary>
public bool InferColumnWidthsFromSeparator { get; set; }
}
45 changes: 34 additions & 11 deletions src/Markdig/Extensions/Tables/PipeTableParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -481,9 +481,10 @@ public bool PostProcess(InlineProcessor state, Inline? root, Inline? lastChild,
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)
{
Expand All @@ -492,7 +493,7 @@ private static bool ParseHeaderString(Inline? inline, out TableColumnAlign? alig

// 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')
{
Expand All @@ -507,7 +508,8 @@ private static bool ParseHeaderString(Inline? inline, out TableColumnAlign? alig
private List<TableColumnDefinition>? FindHeaderRow(List<Inline> delimiters)
{
bool isValidRow = false;
List<TableColumnDefinition>? aligns = null;
int totalDelimiterCount = 0;
List<TableColumnDefinition>? columnDefinitions = null;
for (int i = 0; i < delimiters.Count; i++)
{
if (!IsLine(delimiters[i]))
Expand All @@ -529,18 +531,19 @@ private static bool ParseHeaderString(Inline? inline, out TableColumnAlign? alig

// 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<TableColumnDefinition>();

aligns.Add(new TableColumnDefinition() { Alignment = align });
columnDefinitions ??= new List<TableColumnDefinition>();
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)
Expand All @@ -556,13 +559,13 @@ private static bool ParseHeaderString(Inline? inline, out TableColumnAlign? alig
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;
}

Expand All @@ -576,7 +579,27 @@ private static bool ParseHeaderString(Inline? inline, out TableColumnAlign? alig
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)
Expand Down
14 changes: 8 additions & 6 deletions src/Markdig/Extensions/Tables/TableHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ public static class TableHelper
/// <param name="slice">The text slice.</param>
/// <param name="delimiterChar">The delimiter character (either `-` or `=`).</param>
/// <param name="align">The alignment of the column.</param>
/// <param name="delimiterCount">The number of delimiters.</param>
/// <returns>
/// <c>true</c> if parsing was successful
/// </returns>
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);
}

/// <summary>
Expand All @@ -37,7 +38,7 @@ public static bool ParseColumnHeader(ref StringSlice slice, char delimiterChar,
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 _);
}

/// <summary>
Expand All @@ -49,10 +50,10 @@ public static bool ParseColumnHeaderAuto(ref StringSlice slice, out char delimit
/// <returns>
/// <c>true</c> if parsing was successful
/// </returns>
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;
Expand Down Expand Up @@ -80,7 +81,8 @@ public static bool ParseColumnHeaderDetect(ref StringSlice slice, ref char delim
}

// We expect at least one `-` delimiter char
if (slice.CountAndSkipChar(delimiterChar) == 0)
delimiterCount = slice.CountAndSkipChar(delimiterChar);
if (delimiterCount == 0)
{
return false;
}
Expand Down