diff --git a/MfGames.Markdown.Gemtext.sln.DotSettings b/MfGames.Markdown.Gemtext.sln.DotSettings
index 06b6404..3fc229d 100644
--- a/MfGames.Markdown.Gemtext.sln.DotSettings
+++ b/MfGames.Markdown.Gemtext.sln.DotSettings
@@ -1366,5 +1366,6 @@ using(DataAccessAdapter dataAccessAdapter = new DataAccessAdapter(ConnectionStri
True2.0InCSharpStatement
+ TrueTrue
diff --git a/src/MfGames.Markdown.Gemtext.Tests/TableTests.cs b/src/MfGames.Markdown.Gemtext.Tests/TableTests.cs
index b470aac..0c82a21 100644
--- a/src/MfGames.Markdown.Gemtext.Tests/TableTests.cs
+++ b/src/MfGames.Markdown.Gemtext.Tests/TableTests.cs
@@ -1,13 +1,60 @@
+using ConsoleTableExt;
+
+using Markdig;
+
using MfGames.Markdown.Gemtext;
+using MfGames.Markdown.Gemtext.Extensions;
+
using Xunit;
namespace MfGames.Markdown.Gemini.Tests
{
public class TableTests
{
- [Fact(Skip = "Tables are out of scope at this point")]
- public void SimpleImageLink()
+ [Fact]
+ public void AlignedTable()
{
+ MarkdownPipeline pipeline = new MarkdownPipelineBuilder()
+ .Use(
+ new GemtextPipeTableExtension(
+ new GemtextPipeTableOptions()
+ {
+ ConfigureTableBuilder = (x) =>
+ x.WithFormat(
+ ConsoleTableBuilderFormat.MarkDown),
+ }))
+ .Build();
+ string input = string.Join(
+ "\n",
+ "aaa|bbb|ccc",
+ "--:|---|:-:",
+ "1|2|3",
+ "4|5|6");
+ string expected = string.Join(
+ "\n",
+ "| aaa | bbb | ccc |",
+ "|-----|-----|-----|",
+ "| 1 | 2 | 3 |",
+ "| 4 | 5 | 6 |",
+ "");
+ string actual = MarkdownGemtext.ToGemtext(input, pipeline);
+
+ Assert.Equal(expected, actual);
+ }
+
+ [Fact]
+ public void SimpleTable()
+ {
+ MarkdownPipeline pipeline = new MarkdownPipelineBuilder()
+ .Use(
+ new GemtextPipeTableExtension(
+ new GemtextPipeTableOptions()
+ {
+ ConfigureTableBuilder = (x) =>
+ x.WithFormat(
+ ConsoleTableBuilderFormat.MarkDown),
+ }))
+ .Build();
string input = string.Join(
"\n",
"a|b|c",
@@ -16,14 +63,12 @@ namespace MfGames.Markdown.Gemini.Tests
"4|5|6");
string expected = string.Join(
"\n",
- "┌───┬───┬───┐",
- "│ a │ b │ c │",
- "╞═══╪═══╪═══╡",
- "│ 1 │ 2 │ 3 │",
- "├───┼───┼───┤",
- "│ 4 │ 5 │ 6 │",
- "└───┴───┴───┘");
- string actual = MarkdownGemtext.ToGemtext(input);
+ "| a | b | c |",
+ "|---|---|---|",
+ "| 1 | 2 | 3 |",
+ "| 4 | 5 | 6 |",
+ "");
+ string actual = MarkdownGemtext.ToGemtext(input, pipeline);
Assert.Equal(expected, actual);
}
diff --git a/src/MfGames.Markdown.Gemtext/Extensions/GemtextPipeTableExtension.cs b/src/MfGames.Markdown.Gemtext/Extensions/GemtextPipeTableExtension.cs
new file mode 100644
index 0000000..7b34954
--- /dev/null
+++ b/src/MfGames.Markdown.Gemtext/Extensions/GemtextPipeTableExtension.cs
@@ -0,0 +1,65 @@
+using Markdig;
+using Markdig.Extensions.Tables;
+using Markdig.Parsers.Inlines;
+using Markdig.Renderers;
+
+using MfGames.Markdown.Gemtext.Renderers;
+using MfGames.Markdown.Gemtext.Renderers.Gemtext.Blocks;
+
+namespace MfGames.Markdown.Gemtext.Extensions
+{
+ ///
+ /// Extension method to control how links are processed inside blocks.
+ ///
+ ///
+ public class GemtextPipeTableExtension : IMarkdownExtension
+ {
+ ///
+ /// Initializes a new instance of the
+ /// class.
+ ///
+ /// The options.
+ public GemtextPipeTableExtension(
+ GemtextPipeTableOptions? options = null)
+ {
+ this.Options = options ?? new GemtextPipeTableOptions();
+ }
+
+ ///
+ /// Gets the options.
+ ///
+ public GemtextPipeTableOptions Options { get; }
+
+ ///
+ public void Setup(MarkdownPipelineBuilder pipeline)
+ {
+ pipeline.PreciseSourceLocation = true;
+
+ if (!pipeline.BlockParsers.Contains())
+ {
+ pipeline.BlockParsers.Insert(0, new PipeTableBlockParser());
+ }
+
+ LineBreakInlineParser? lineBreakParser =
+ pipeline.InlineParsers.FindExact();
+
+ if (!pipeline.InlineParsers.Contains())
+ {
+ pipeline.InlineParsers.InsertBefore(
+ new PipeTableParser(lineBreakParser!, this.Options));
+ }
+ }
+
+ ///
+ public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
+ {
+ if (renderer is not GemtextRenderer gemtext)
+ {
+ return;
+ }
+
+ gemtext.ObjectRenderers.Add(
+ new TableRenderer(this.Options.ConfigureTableBuilder));
+ }
+ }
+}
diff --git a/src/MfGames.Markdown.Gemtext/Extensions/GemtextPipeTableOptions.cs b/src/MfGames.Markdown.Gemtext/Extensions/GemtextPipeTableOptions.cs
new file mode 100644
index 0000000..3de1d18
--- /dev/null
+++ b/src/MfGames.Markdown.Gemtext/Extensions/GemtextPipeTableOptions.cs
@@ -0,0 +1,16 @@
+using System;
+
+using ConsoleTableExt;
+
+using Markdig.Extensions.Tables;
+
+namespace MfGames.Markdown.Gemtext.Extensions
+{
+ public class GemtextPipeTableOptions : PipeTableOptions
+ {
+ ///
+ /// Gets or sets the table builder to control formatting.
+ ///
+ public Action? ConfigureTableBuilder { get; set; }
+ }
+}
diff --git a/src/MfGames.Markdown.Gemtext/MfGames.Markdown.Gemtext.csproj b/src/MfGames.Markdown.Gemtext/MfGames.Markdown.Gemtext.csproj
index 1073790..479b8a7 100644
--- a/src/MfGames.Markdown.Gemtext/MfGames.Markdown.Gemtext.csproj
+++ b/src/MfGames.Markdown.Gemtext/MfGames.Markdown.Gemtext.csproj
@@ -18,7 +18,8 @@
-
+
+
diff --git a/src/MfGames.Markdown.Gemtext/Renderers/Gemtext/Blocks/TableRenderer.cs b/src/MfGames.Markdown.Gemtext/Renderers/Gemtext/Blocks/TableRenderer.cs
new file mode 100644
index 0000000..8e63c6a
--- /dev/null
+++ b/src/MfGames.Markdown.Gemtext/Renderers/Gemtext/Blocks/TableRenderer.cs
@@ -0,0 +1,120 @@
+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;
+
+ public TableRenderer(Action? configureTableBuilder)
+ {
+ this.configureTableBuilder = configureTableBuilder;
+ }
+
+ protected override void Write(GemtextRenderer renderer, Table table)
+ {
+ // Make sure we have plenty of space above us.
+ renderer.EnsureTwoLines();
+
+ // 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