Skip to content

Commit ba02956

Browse files
Copilotboxofyellow
andauthored
Render Markdig CustomContainer admonition blocks (#132)
* Initial plan * Add ConsoleCustomContainer renderers for Markdig admonition blocks Co-authored-by: boxofyellow <54955040+boxofyellow@users.noreply.github.com> * Move ConsoleCustomContainerRenderer to its own file and update changelog Co-authored-by: boxofyellow <54955040+boxofyellow@users.noreply.github.com> * Fix image URLs and dimensions in CHANGELOG Updated image URLs in CHANGELOG with specific dimensions. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: boxofyellow <54955040+boxofyellow@users.noreply.github.com>
1 parent 39f966b commit ba02956

11 files changed

Lines changed: 148 additions & 0 deletions

File tree

ConsoleMarkdownRenderer.Example/data/example.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,23 @@ Footnote references are placed inline[^example] and the rendered footnotes appea
109109

110110
[^longer-footnote]: A longer footnote with **bold**, *italic*, and `inline code` content.
111111

112+
## Custom Containers (Admonitions)
113+
114+
Custom containers represent admonitions / callouts commonly used in technical documentation.
115+
116+
:::note
117+
This is a *note* admonition with **bold** content.
118+
:::
119+
120+
:::warning
121+
A multi-line warning that contains:
122+
123+
- a list item
124+
- another item with `inline code`
125+
:::
126+
127+
A paragraph with an inline ::tag inline container:: example.
128+
112129
## Definition Lists
113130

114131
Term
@@ -181,6 +198,7 @@ Some text after the block
181198
- [x] Lists
182199
- ~~Should lists use different numbering options as you nest lists~~ We could alternative, maybe we do that later
183200
- [x] Footnotes
201+
- [x] Custom containers (admonitions)
184202
- [ ] One to always leave unchecked
185203

186204
And here is the end

ConsoleMarkdownRenderer.Tests/RendererTests.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,25 @@ public void RendererTests_DefinitionListTest(bool useCrazy)
435435
AssertMarkdownYieldsFormat("definitionList", "citrus", new Style(), useCrazy);
436436
}
437437

438+
[TestMethod]
439+
[DataRow(false)]
440+
[DataRow(true)]
441+
public void RendererTests_CustomContainerInfoTest(bool useCrazy)
442+
{
443+
// The container's Info label (e.g. "note", "warning") should carry the CustomContainerInfo style (bold by default)
444+
AssertMarkdownYieldsFormat("customContainer", "note", new Style(decoration: Decoration.Bold), useCrazy);
445+
AssertMarkdownYieldsFormat("customContainer", "warning", new Style(decoration: Decoration.Bold), useCrazy);
446+
}
447+
448+
[TestMethod]
449+
[DataRow(false)]
450+
[DataRow(true)]
451+
public void RendererTests_CustomContainerInlineTest(bool useCrazy)
452+
{
453+
// Inline custom container content (::tag inline::) carries the CustomContainerInline style (bold by default)
454+
AssertMarkdownYieldsFormat("customContainer", "tag inline", new Style(decoration: Decoration.Bold), useCrazy);
455+
}
456+
438457
[TestMethod]
439458
public void RendererTests_PlainTextUsesDefaultColors()
440459
{
@@ -655,6 +674,9 @@ private static Dictionary<string, int> Counts(string text)
655674
Bold = c_crazyFormat,
656675
CodeBlock = c_crazyFormat,
657676
CodeInLine = c_crazyFormat,
677+
CustomContainer = c_crazyFormat,
678+
CustomContainerInfo = c_crazyFormat,
679+
CustomContainerInline = c_crazyFormat,
658680
DefinitionItem = c_crazyFormat,
659681
DefinitionList = c_crazyFormat,
660682
DefinitionTerm = c_crazyFormat,

ConsoleMarkdownRenderer.Tests/resources/bracketEscaping.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,9 @@ Paragraph with [test21] reference[^bracketfn] embedded.
3434
: Definition with [test25] bracket content.
3535

3636
[test26] paragraph with :smile: emoji and :-) smiley.
37+
38+
:::note
39+
[test27] note with **[test28] bold** content.
40+
:::
41+
42+
Inline ::tag [test29]:: container.

ConsoleMarkdownRenderer.Tests/resources/bracketEscaping.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@
4343
│ │ └───────────────────────────────────────────┘ │ │
4444
│ └───────────────────────────────────────────────┘ │
4545
│ [test26] paragraph with 😄 emoji and 😃 smiley. │
46+
│ ┌───────────────────────────────────────────┐ │
47+
│ │ note │ │
48+
│ │ [test27] note with [test28] bold content. │ │
49+
│ └───────────────────────────────────────────┘ │
50+
│ Inline tag [test29] container. │
4651
│ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │
4752
│ │ ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── │ │
4853
│ │ ┌───────────────────────────────────────────────────────┐ │ │
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
:::note
2+
This is a sample admonition.
3+
:::
4+
5+
:::warning
6+
A callout with **bold** content.
7+
:::
8+
9+
Text with ::tag inline:: container.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
┌──────────────────────────────────┐
2+
│ ┌──────────────────────────────┐ │
3+
│ │ note │ │
4+
│ │ This is a sample admonition. │ │
5+
│ └──────────────────────────────┘ │
6+
│ ┌──────────────────────────────┐ │
7+
│ │ warning │ │
8+
│ │ A callout with bold content. │ │
9+
│ └──────────────────────────────┘ │
10+
│ Text with tag inline container. │
11+
└──────────────────────────────────┘

DisplayOptions.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,24 @@ public sealed class DisplayOptions
1111
public TextStyle CodeBlock { get; set; } = new(foreground: TextColor.Yellow, background: TextColor.Blue);
1212
public TextStyle CodeInLine { get; set; } = new(foreground: TextColor.Yellow, background: TextColor.Blue);
1313

14+
/// <summary>
15+
/// Style applied to the body of a <see cref="Markdig.Extensions.CustomContainers.CustomContainer"/>
16+
/// (e.g. an admonition / callout block such as <c>:::note</c>, <c>:::warning</c>, or <c>:::tip</c>).
17+
/// </summary>
18+
public TextStyle CustomContainer { get; set; } = new(decoration: TextDecoration.None);
19+
20+
/// <summary>
21+
/// Style applied to the <see cref="Markdig.Extensions.CustomContainers.CustomContainer.Info"/> label
22+
/// (e.g. <c>note</c> / <c>warning</c> / <c>tip</c>) emitted at the top of a custom container block.
23+
/// </summary>
24+
public TextStyle CustomContainerInfo { get; set; } = new(decoration: TextDecoration.Bold);
25+
26+
/// <summary>
27+
/// Style applied to the contents of an inline
28+
/// <see cref="Markdig.Extensions.CustomContainers.CustomContainerInline"/> (e.g. <c>::tag content::</c>).
29+
/// </summary>
30+
public TextStyle CustomContainerInline { get; set; } = new(decoration: TextDecoration.Bold);
31+
1432
/// <summary>
1533
/// Style applied to the contents of a <see cref="Markdig.Extensions.DefinitionLists.DefinitionItem"/>
1634
/// (all children of each item in a definition list, including its terms and definitions).
@@ -114,6 +132,9 @@ public sealed class DisplayOptions
114132
Bold = this.Bold,
115133
CodeBlock = this.CodeBlock,
116134
CodeInLine = this.CodeInLine,
135+
CustomContainer = this.CustomContainer,
136+
CustomContainerInfo = this.CustomContainerInfo,
137+
CustomContainerInline = this.CustomContainerInline,
117138
DefinitionItem = this.DefinitionItem,
118139
DefinitionList = this.DefinitionList,
119140
DefinitionTerm = this.DefinitionTerm,
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using BoxOfYellow.ConsoleMarkdownRenderer.Styling;
2+
using Markdig.Extensions.CustomContainers;
3+
using Spectre.Console;
4+
5+
namespace BoxOfYellow.ConsoleMarkdownRenderer.ObjectRenderers
6+
{
7+
internal class ConsoleCustomContainerRenderer : ConsoleObjectRenderer<CustomContainer>
8+
{
9+
protected override void Write(ConsoleRenderer renderer, CustomContainer obj)
10+
{
11+
renderer.NewFrame(borderStyle: Style.Plain);
12+
if (!string.IsNullOrEmpty(obj.Info))
13+
{
14+
renderer
15+
.StartInline()
16+
.AddInLine($"[{renderer.Options.CustomContainerInfo.ToSpectreStyle().ToMarkup()}]")
17+
.WriteEscape(obj.Info)
18+
.AddInLine("[/]")
19+
.EndInline();
20+
}
21+
renderer
22+
.PushStyle(renderer.Options.CustomContainer.ToSpectreStyle())
23+
.WriteChildrenChain(obj)
24+
.PopStyle()
25+
.CompleteFrame();
26+
}
27+
}
28+
}

ObjectRenderers/ConsoleObjectRenderers.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using BoxOfYellow.ConsoleMarkdownRenderer.Styling;
2+
using Markdig.Extensions.CustomContainers;
23
using Markdig.Extensions.DefinitionLists;
34
using Markdig.Extensions.Footnotes;
45
using Markdig.Extensions.TaskLists;
@@ -47,6 +48,15 @@ protected override void Write(ConsoleRenderer renderer, CodeInline obj)
4748
.AddInLine("[/]");
4849
}
4950

51+
internal class ConsoleCustomContainerInlineRenderer : ConsoleObjectRenderer<CustomContainerInline>
52+
{
53+
protected override void Write(ConsoleRenderer renderer, CustomContainerInline obj)
54+
=> renderer
55+
.AddInLine($"[{renderer.Options.CustomContainerInline.ToSpectreStyle().ToMarkup()}]")
56+
.WriteChildrenChain(obj)
57+
.AddInLine("[/]");
58+
}
59+
5060
internal class ConsoleDocumentRenderer : ConsoleObjectRenderer<MarkdownDocument>
5161
{
5262
protected override void Write(ConsoleRenderer renderer, MarkdownDocument obj)

ObjectRenderers/ConsoleRenderer.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ internal ConsoleRenderer(DisplayOptions options, bool omitAutolinkInlineRenderer
1919
ObjectRenderers.AddRange([
2020
new ConsoleCodeBlockRenderer(),
2121
new ConsoleCodeInlineRenderer(),
22+
new ConsoleCustomContainerInlineRenderer(),
23+
new ConsoleCustomContainerRenderer(),
2224
new ConsoleDefinitionItemRenderer(),
2325
new ConsoleDefinitionListRenderer(),
2426
new ConsoleDefinitionTermRenderer(),

0 commit comments

Comments
 (0)