diff --git a/ConsoleMarkdownRenderer.Example/data/example.md b/ConsoleMarkdownRenderer.Example/data/example.md index f8570dd..47490e8 100644 --- a/ConsoleMarkdownRenderer.Example/data/example.md +++ b/ConsoleMarkdownRenderer.Example/data/example.md @@ -109,6 +109,23 @@ Footnote references are placed inline[^example] and the rendered footnotes appea [^longer-footnote]: A longer footnote with **bold**, *italic*, and `inline code` content. +## Custom Containers (Admonitions) + +Custom containers represent admonitions / callouts commonly used in technical documentation. + +:::note +This is a *note* admonition with **bold** content. +::: + +:::warning +A multi-line warning that contains: + +- a list item +- another item with `inline code` +::: + +A paragraph with an inline ::tag inline container:: example. + ## Definition Lists Term @@ -181,6 +198,7 @@ Some text after the block - [x] Lists - ~~Should lists use different numbering options as you nest lists~~ We could alternative, maybe we do that later - [x] Footnotes +- [x] Custom containers (admonitions) - [ ] One to always leave unchecked And here is the end \ No newline at end of file diff --git a/ConsoleMarkdownRenderer.Tests/RendererTests.cs b/ConsoleMarkdownRenderer.Tests/RendererTests.cs index d90516b..544a9e3 100644 --- a/ConsoleMarkdownRenderer.Tests/RendererTests.cs +++ b/ConsoleMarkdownRenderer.Tests/RendererTests.cs @@ -435,6 +435,25 @@ public void RendererTests_DefinitionListTest(bool useCrazy) AssertMarkdownYieldsFormat("definitionList", "citrus", new Style(), useCrazy); } + [TestMethod] + [DataRow(false)] + [DataRow(true)] + public void RendererTests_CustomContainerInfoTest(bool useCrazy) + { + // The container's Info label (e.g. "note", "warning") should carry the CustomContainerInfo style (bold by default) + AssertMarkdownYieldsFormat("customContainer", "note", new Style(decoration: Decoration.Bold), useCrazy); + AssertMarkdownYieldsFormat("customContainer", "warning", new Style(decoration: Decoration.Bold), useCrazy); + } + + [TestMethod] + [DataRow(false)] + [DataRow(true)] + public void RendererTests_CustomContainerInlineTest(bool useCrazy) + { + // Inline custom container content (::tag inline::) carries the CustomContainerInline style (bold by default) + AssertMarkdownYieldsFormat("customContainer", "tag inline", new Style(decoration: Decoration.Bold), useCrazy); + } + [TestMethod] public void RendererTests_PlainTextUsesDefaultColors() { @@ -655,6 +674,9 @@ private static Dictionary Counts(string text) Bold = c_crazyFormat, CodeBlock = c_crazyFormat, CodeInLine = c_crazyFormat, + CustomContainer = c_crazyFormat, + CustomContainerInfo = c_crazyFormat, + CustomContainerInline = c_crazyFormat, DefinitionItem = c_crazyFormat, DefinitionList = c_crazyFormat, DefinitionTerm = c_crazyFormat, diff --git a/ConsoleMarkdownRenderer.Tests/resources/bracketEscaping.md b/ConsoleMarkdownRenderer.Tests/resources/bracketEscaping.md index a194b02..06c45ee 100644 --- a/ConsoleMarkdownRenderer.Tests/resources/bracketEscaping.md +++ b/ConsoleMarkdownRenderer.Tests/resources/bracketEscaping.md @@ -34,3 +34,9 @@ Paragraph with [test21] reference[^bracketfn] embedded. : Definition with [test25] bracket content. [test26] paragraph with :smile: emoji and :-) smiley. + +:::note +[test27] note with **[test28] bold** content. +::: + +Inline ::tag [test29]:: container. diff --git a/ConsoleMarkdownRenderer.Tests/resources/bracketEscaping.txt b/ConsoleMarkdownRenderer.Tests/resources/bracketEscaping.txt index ece90f5..061dde6 100644 --- a/ConsoleMarkdownRenderer.Tests/resources/bracketEscaping.txt +++ b/ConsoleMarkdownRenderer.Tests/resources/bracketEscaping.txt @@ -43,6 +43,11 @@ │ │ └───────────────────────────────────────────┘ │ │ │ └───────────────────────────────────────────────┘ │ │ [test26] paragraph with 😄 emoji and 😃 smiley. │ +│ ┌───────────────────────────────────────────┐ │ +│ │ note │ │ +│ │ [test27] note with [test28] bold content. │ │ +│ └───────────────────────────────────────────┘ │ +│ Inline tag [test29] container. │ │ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ │ │ ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── │ │ │ │ ┌───────────────────────────────────────────────────────┐ │ │ diff --git a/ConsoleMarkdownRenderer.Tests/resources/customContainer.md b/ConsoleMarkdownRenderer.Tests/resources/customContainer.md new file mode 100644 index 0000000..4396fd1 --- /dev/null +++ b/ConsoleMarkdownRenderer.Tests/resources/customContainer.md @@ -0,0 +1,9 @@ +:::note +This is a sample admonition. +::: + +:::warning +A callout with **bold** content. +::: + +Text with ::tag inline:: container. diff --git a/ConsoleMarkdownRenderer.Tests/resources/customContainer.txt b/ConsoleMarkdownRenderer.Tests/resources/customContainer.txt new file mode 100644 index 0000000..486d380 --- /dev/null +++ b/ConsoleMarkdownRenderer.Tests/resources/customContainer.txt @@ -0,0 +1,11 @@ +┌──────────────────────────────────┐ +│ ┌──────────────────────────────┐ │ +│ │ note │ │ +│ │ This is a sample admonition. │ │ +│ └──────────────────────────────┘ │ +│ ┌──────────────────────────────┐ │ +│ │ warning │ │ +│ │ A callout with bold content. │ │ +│ └──────────────────────────────┘ │ +│ Text with tag inline container. │ +└──────────────────────────────────┘ diff --git a/DisplayOptions.cs b/DisplayOptions.cs index 19a6150..1f57624 100644 --- a/DisplayOptions.cs +++ b/DisplayOptions.cs @@ -11,6 +11,24 @@ public sealed class DisplayOptions public TextStyle CodeBlock { get; set; } = new(foreground: TextColor.Yellow, background: TextColor.Blue); public TextStyle CodeInLine { get; set; } = new(foreground: TextColor.Yellow, background: TextColor.Blue); + /// + /// Style applied to the body of a + /// (e.g. an admonition / callout block such as :::note, :::warning, or :::tip). + /// + public TextStyle CustomContainer { get; set; } = new(decoration: TextDecoration.None); + + /// + /// Style applied to the label + /// (e.g. note / warning / tip) emitted at the top of a custom container block. + /// + public TextStyle CustomContainerInfo { get; set; } = new(decoration: TextDecoration.Bold); + + /// + /// Style applied to the contents of an inline + /// (e.g. ::tag content::). + /// + public TextStyle CustomContainerInline { get; set; } = new(decoration: TextDecoration.Bold); + /// /// Style applied to the contents of a /// (all children of each item in a definition list, including its terms and definitions). @@ -114,6 +132,9 @@ public sealed class DisplayOptions Bold = this.Bold, CodeBlock = this.CodeBlock, CodeInLine = this.CodeInLine, + CustomContainer = this.CustomContainer, + CustomContainerInfo = this.CustomContainerInfo, + CustomContainerInline = this.CustomContainerInline, DefinitionItem = this.DefinitionItem, DefinitionList = this.DefinitionList, DefinitionTerm = this.DefinitionTerm, diff --git a/ObjectRenderers/ConsoleCustomContainerRenderer.cs b/ObjectRenderers/ConsoleCustomContainerRenderer.cs new file mode 100644 index 0000000..8fb28bc --- /dev/null +++ b/ObjectRenderers/ConsoleCustomContainerRenderer.cs @@ -0,0 +1,28 @@ +using BoxOfYellow.ConsoleMarkdownRenderer.Styling; +using Markdig.Extensions.CustomContainers; +using Spectre.Console; + +namespace BoxOfYellow.ConsoleMarkdownRenderer.ObjectRenderers +{ + internal class ConsoleCustomContainerRenderer : ConsoleObjectRenderer + { + protected override void Write(ConsoleRenderer renderer, CustomContainer obj) + { + renderer.NewFrame(borderStyle: Style.Plain); + if (!string.IsNullOrEmpty(obj.Info)) + { + renderer + .StartInline() + .AddInLine($"[{renderer.Options.CustomContainerInfo.ToSpectreStyle().ToMarkup()}]") + .WriteEscape(obj.Info) + .AddInLine("[/]") + .EndInline(); + } + renderer + .PushStyle(renderer.Options.CustomContainer.ToSpectreStyle()) + .WriteChildrenChain(obj) + .PopStyle() + .CompleteFrame(); + } + } +} diff --git a/ObjectRenderers/ConsoleObjectRenderers.cs b/ObjectRenderers/ConsoleObjectRenderers.cs index b274c19..80435ed 100644 --- a/ObjectRenderers/ConsoleObjectRenderers.cs +++ b/ObjectRenderers/ConsoleObjectRenderers.cs @@ -1,4 +1,5 @@ using BoxOfYellow.ConsoleMarkdownRenderer.Styling; +using Markdig.Extensions.CustomContainers; using Markdig.Extensions.DefinitionLists; using Markdig.Extensions.Footnotes; using Markdig.Extensions.TaskLists; @@ -47,6 +48,15 @@ protected override void Write(ConsoleRenderer renderer, CodeInline obj) .AddInLine("[/]"); } + internal class ConsoleCustomContainerInlineRenderer : ConsoleObjectRenderer + { + protected override void Write(ConsoleRenderer renderer, CustomContainerInline obj) + => renderer + .AddInLine($"[{renderer.Options.CustomContainerInline.ToSpectreStyle().ToMarkup()}]") + .WriteChildrenChain(obj) + .AddInLine("[/]"); + } + internal class ConsoleDocumentRenderer : ConsoleObjectRenderer { protected override void Write(ConsoleRenderer renderer, MarkdownDocument obj) diff --git a/ObjectRenderers/ConsoleRenderer.cs b/ObjectRenderers/ConsoleRenderer.cs index bd9f833..0a3635f 100644 --- a/ObjectRenderers/ConsoleRenderer.cs +++ b/ObjectRenderers/ConsoleRenderer.cs @@ -19,6 +19,8 @@ internal ConsoleRenderer(DisplayOptions options, bool omitAutolinkInlineRenderer ObjectRenderers.AddRange([ new ConsoleCodeBlockRenderer(), new ConsoleCodeInlineRenderer(), + new ConsoleCustomContainerInlineRenderer(), + new ConsoleCustomContainerRenderer(), new ConsoleDefinitionItemRenderer(), new ConsoleDefinitionListRenderer(), new ConsoleDefinitionTermRenderer(), diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index a24bbb5..252d6bc 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -2,6 +2,22 @@ ## Upcoming Changes +### :art: Renderers :art: +- [#132](https://github.com/boxofyellow/ConsoleMarkdownRenderer/pull/132): Render Markdig CustomContainer admonition blocks + - ```markdown + :::note + This is a *note* admonition with **bold** content. + ::: + ``` + - Rendered + :::note + This is a *note* admonition with **bold** content. + ::: + - Before + Image + - After + Image + ### :wrench: Internal Improvements :wrench: - [#129](https://github.com/boxofyellow/ConsoleMarkdownRenderer/pull/129): Use ConfigureAwait(false) on awaits in published library code - [#131](https://github.com/boxofyellow/ConsoleMarkdownRenderer/pull/131): Use raw string literals for multi-line AssertCrossPlatStringMatch arguments @@ -105,4 +121,4 @@ See the [this project's releases](https://github.com/boxofyellow/ConsoleMarkdown - [v0.10.0](https://github.com/boxofyellow/ConsoleMarkdownRenderer/blob/main/docs/migration_v0.10.0.md) - [v0.9.0](https://github.com/boxofyellow/ConsoleMarkdownRenderer/blob/main/docs/migration_v0.9.0.md) -- [v0.8.0](https://github.com/boxofyellow/ConsoleMarkdownRenderer/blob/main/docs/migration_v0.8.0.md) \ No newline at end of file +- [v0.8.0](https://github.com/boxofyellow/ConsoleMarkdownRenderer/blob/main/docs/migration_v0.8.0.md)