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 { private readonly Action? configureTableBuilder; private readonly bool omitPreformat; public TableRenderer( bool omitPreformat, Action? configureTableBuilder) { this.omitPreformat = omitPreformat; 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 header = new(); List> data = new(); Dictionary align = new(); foreach (TableRow row in table.OfType()) { // 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 cells = GetCellValues(row); data.Add(cells); } // Set up the table. ConsoleTableBuilder builder = ConsoleTableBuilder .From(data) .WithColumn(header.OfType().ToArray()) .WithHeaderTextAlignment(align) .WithTextAlignment(align); this.configureTableBuilder?.Invoke(builder); // Format the final table. string formatted = builder.Export().ToString().TrimEnd(); // Write out the table including making sure two lines are above it. renderer.EnsureTwoLines(); if (!this.omitPreformat) { renderer.WriteLine("```"); } renderer.WriteLine(formatted); if (!this.omitPreformat) { renderer.WriteLine("```"); renderer.WriteLine(); } } private static List GetCellValues(TableRow row) { List cells = new(); foreach (TableCell cell in row.OfType()) { // 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 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, }; } } } } }