2022-02-16 05:23:44 +00:00
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.IO;
|
|
|
|
using System.Linq;
|
|
|
|
|
|
|
|
using ConsoleTableExt;
|
|
|
|
|
|
|
|
using Markdig.Extensions.Tables;
|
|
|
|
|
|
|
|
namespace MfGames.Markdown.Gemtext.Renderers.Gemtext.Blocks
|
|
|
|
{
|
|
|
|
public class TableRenderer : GemtextObjectRenderer<Table>
|
|
|
|
{
|
|
|
|
private readonly Action<ConsoleTableBuilder>? configureTableBuilder;
|
|
|
|
|
2022-02-16 15:02:11 +00:00
|
|
|
private readonly bool omitPreformat;
|
|
|
|
|
|
|
|
public TableRenderer(
|
|
|
|
bool omitPreformat,
|
|
|
|
Action<ConsoleTableBuilder>? configureTableBuilder)
|
2022-02-16 05:23:44 +00:00
|
|
|
{
|
2022-02-16 15:02:11 +00:00
|
|
|
this.omitPreformat = omitPreformat;
|
2022-02-16 05:23:44 +00:00
|
|
|
this.configureTableBuilder = configureTableBuilder;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected override void Write(GemtextRenderer renderer, Table table)
|
|
|
|
{
|
|
|
|
// Since Gemtext doesn't have a table format per-se, we are going
|
|
|
|
// to use ConsoleTableEx to make a nicely-formatted table and emit
|
|
|
|
// the lines directly. That should produce the desired result.
|
|
|
|
|
|
|
|
// Gather up information about the data since that is where the
|
|
|
|
// builder starts with.
|
|
|
|
bool hasHeader = false;
|
|
|
|
List<object> header = new();
|
|
|
|
List<List<object>> data = new();
|
|
|
|
Dictionary<int, TextAligntment> align = new();
|
|
|
|
|
|
|
|
foreach (TableRow row in table.OfType<TableRow>())
|
|
|
|
{
|
|
|
|
// If we haven't seen a header, then we include that.
|
|
|
|
if (!hasHeader && row.IsHeader)
|
|
|
|
{
|
|
|
|
header = GetCellValues(row);
|
|
|
|
SetAlignments(table, align, row);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, we treat it as a row and go through the columns.
|
|
|
|
List<object> cells = GetCellValues(row);
|
|
|
|
|
|
|
|
data.Add(cells);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set up the table.
|
|
|
|
ConsoleTableBuilder builder = ConsoleTableBuilder
|
|
|
|
.From(data)
|
|
|
|
.WithColumn(header.OfType<string>().ToArray())
|
|
|
|
.WithHeaderTextAlignment(align)
|
|
|
|
.WithTextAlignment(align);
|
|
|
|
|
|
|
|
this.configureTableBuilder?.Invoke(builder);
|
|
|
|
|
|
|
|
// Format the final table.
|
|
|
|
string formatted = builder.Export().ToString().TrimEnd();
|
|
|
|
|
2022-02-16 15:02:11 +00:00
|
|
|
// Write out the table including making sure two lines are above it.
|
|
|
|
renderer.EnsureTwoLines();
|
|
|
|
|
|
|
|
if (!this.omitPreformat)
|
|
|
|
{
|
|
|
|
renderer.WriteLine("```");
|
|
|
|
}
|
|
|
|
|
2022-02-16 05:23:44 +00:00
|
|
|
renderer.WriteLine(formatted);
|
2022-02-16 15:02:11 +00:00
|
|
|
|
|
|
|
if (!this.omitPreformat)
|
|
|
|
{
|
|
|
|
renderer.WriteLine("```");
|
2022-02-16 17:37:41 +00:00
|
|
|
renderer.WriteLine();
|
2022-02-16 15:02:11 +00:00
|
|
|
}
|
2022-02-16 05:23:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private static List<object> GetCellValues(TableRow row)
|
|
|
|
{
|
|
|
|
List<object> cells = new();
|
|
|
|
|
|
|
|
foreach (TableCell cell in row.OfType<TableCell>())
|
|
|
|
{
|
|
|
|
// Write out to a text since we can't have a callback while
|
|
|
|
// rendering the table cells.
|
|
|
|
using var writer = new StringWriter();
|
|
|
|
var innerRenderer = new GemtextRenderer(writer);
|
|
|
|
|
|
|
|
innerRenderer.Render(cell);
|
|
|
|
cells.Add(writer.ToString());
|
|
|
|
}
|
|
|
|
|
|
|
|
return cells;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void SetAlignments(
|
|
|
|
Table table,
|
|
|
|
Dictionary<int, TextAligntment> align,
|
|
|
|
TableRow row)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < row.Count; i++)
|
|
|
|
{
|
|
|
|
// Copied from Markdig's version.
|
|
|
|
var cell = (TableCell)row[i];
|
|
|
|
int columnIndex = cell.ColumnIndex < 0
|
|
|
|
|| cell.ColumnIndex >= table.ColumnDefinitions.Count
|
|
|
|
? i
|
|
|
|
: cell.ColumnIndex;
|
|
|
|
columnIndex =
|
|
|
|
columnIndex >= table.ColumnDefinitions.Count
|
|
|
|
? table.ColumnDefinitions.Count - 1
|
|
|
|
: columnIndex;
|
|
|
|
TableColumnAlign? alignment = table
|
|
|
|
.ColumnDefinitions[columnIndex]
|
|
|
|
.Alignment;
|
|
|
|
|
|
|
|
if (alignment.HasValue)
|
|
|
|
{
|
|
|
|
align[columnIndex] = alignment.Value switch
|
|
|
|
{
|
|
|
|
TableColumnAlign.Center => TextAligntment.Center,
|
|
|
|
TableColumnAlign.Left => TextAligntment.Left,
|
|
|
|
TableColumnAlign.Right => TextAligntment.Right,
|
|
|
|
_ => TextAligntment.Left,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|