Skip to content

Render headings via Spectre.Console FigletText (IHeaderStyle, default H1)#113

Draft
Copilot wants to merge 10 commits into
mainfrom
copilot/add-figlett-text-widget-for-h1-headings
Draft

Render headings via Spectre.Console FigletText (IHeaderStyle, default H1)#113
Copilot wants to merge 10 commits into
mainfrom
copilot/add-figlett-text-widget-for-h1-headings

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 12, 2026

New Feature

Adds support for rendering Markdown headings as large FIGlet ASCII art via Spectre.Console's FigletText widget. Heading styles are plumbed through a new IHeaderStyle interface implemented by both the existing TextStyle (styled markup) and a new peer FigletTextStyle (FIGlet ASCII art), so any heading level can independently choose either rendering path.

What does this feature do?

DisplayOptions.Header and DisplayOptions.Headers are typed as IHeaderStyle. Assigning a FigletTextStyle to a level causes that level to be rendered as a FigletText renderable; assigning a TextStyle keeps the original styled, #-wrapped markup. By default Headers[0] is a centered, blue FigletTextStyle, so # headings render as FIGlet ASCII art out of the box. Deeper levels continue to fall through to the styled Header.

// Default: H1 renders as centered, blue FIGlet ASCII art.
var options = new DisplayOptions();

// Opt H1 back into the original styled "#"-wrapped markup:
options.Headers[0] = new TextStyle(decoration: TextDecoration.Bold);

// Or opt a deeper level in to FIGlet rendering:
options.Headers.Add(new FigletTextStyle(
    justification: TextJustification.Center,
    foreground: TextColor.Blue));   // applies to '##' (H2)

Why is this feature needed?

A prominent ASCII-art title makes the top of a document immediately distinguishable from body text in terminal output. Making it the H1 default surfaces the feature without configuration; existing callers can opt back into the original behavior with a single assignment.

Implementation details

  • IHeaderStyle interface with a single TextJustification? Justification member. Both TextStyle and FigletTextStyle implement it; TextStyle.Justification is an explicit interface implementation hard-coded to null. TextStyle remains sealed and is otherwise unchanged.
  • TextJustification enum (Left/Right/Center) mirrors Spectre.Console.Justify, modeled on the existing TextDecoration pattern (including an enum-coverage test).
  • FigletTextStyle is a sealed peer of TextStyle (not a subclass), exposing only Justification and ForegroundFigletText does not support decoration or background, so those properties are intentionally absent.
  • DisplayOptions typed Header/Headers/EffectiveHeader against IHeaderStyle; default Headers is [new FigletTextStyle(justification: TextJustification.Center, foreground: TextColor.Blue)]. WrapHeader still applies to TextStyle entries and is ignored for FigletTextStyle.
  • TextStyleExtensions gains an internal ToSpectreJustify; ToSpectreColor is exposed internally for reuse by the new renderer path.
  • ConsoleHeadingBlockRenderer switches on the runtime IHeaderStyle type and dispatches to a WriteFiglet or WriteStyled helper. The FIGlet path walks the heading's inline tree to collect plain text (FIGlet takes no markup), handling LiteralInline, CodeInline, and nested ContainerInline (emphasis, etc.), then emits a FigletText via a new ConsoleRendererBase<T>.AddRenderable helper that drops an arbitrary IRenderable onto the current frame. The styled path is unchanged.
  • README documents IHeaderStyle, both implementations, the new default, how to opt back into styled markup, and explicit when-to-use / when-to-avoid guidance.

Tests

  • TextJustificationTests — enum coverage against Justify + conversion round-trip.
  • FigletTextStyleTests — defaults, property preservation, equality, IHeaderStyle interface contract (including the explicit TextStyle.Justification => null guarantee).
  • RendererTests cases:
    • FIGlet output replaces the literal heading text with glyph characters (stricter Assert.DoesNotContain("#", output)).
    • Only the configured level uses FIGlet; H2/H3 are asserted to retain their ## … ## / ### … ### wrapping.
    • Regression guard that replacing Headers[0] with a plain TextStyle restores the styled #-wrapped markup for H1.
  • headingBlock.md/headingBlock.txt resource pair extended to cover every FIGlet branch — literal text, inline code, inline emphasis (container), and an empty # heading — plus the existing H2/H3 styled cases. The regenerated .txt lets the FIGlet output be visually inspected in the PR diff.
  • bracketEscaping.md H1 changed to H2 (FIGlet would obscure the bracket characters under test); bracketEscaping.txt regenerated.
  • DisplayTests_NonInteractiveTerminalWithNoLinksExitsCleanlyAsync updated to use H2 so its expected output reflects the new default.

Copilot AI changed the title [WIP] Consider using FigletText widget for top-level headings Render headings via Spectre.Console FigletText (opt-in) May 12, 2026
Copilot AI requested a review from boxofyellow May 12, 2026 01:21
@codecov
Copy link
Copy Markdown

codecov Bot commented May 12, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.64%. Comparing base (24b8215) to head (1777dd3).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #113      +/-   ##
==========================================
+ Coverage   95.37%   95.64%   +0.27%     
==========================================
  Files          27       28       +1     
  Lines        1512     1606      +94     
  Branches      160      171      +11     
==========================================
+ Hits         1442     1536      +94     
  Misses         46       46              
  Partials       24       24              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Owner

@boxofyellow boxofyellow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot please check out these comments.

Please also double check https://github.com/boxofyellow/ConsoleMarkdownRenderer/blob/main/docs/adding_a_new_renderer.md to make sure there are no relevant steps missed.

Comment thread ConsoleMarkdownRenderer.Tests/FigletTextStyleTests.cs Outdated
Comment thread ConsoleMarkdownRenderer.Tests/RendererTests.cs Outdated
Comment thread ConsoleMarkdownRenderer.Tests/RendererTests.cs Outdated
Comment thread ConsoleMarkdownRenderer.Tests/RendererTests.cs
Comment thread ObjectRenderers/ConsoleHeadingBlockRenderer.cs Outdated
Comment thread ObjectRenderers/ConsoleHeadingBlockRenderer.cs Outdated
Comment thread ObjectRenderers/ConsoleHeadingBlockRenderer.cs
Comment thread Styling/FigletTextStyle.cs Outdated
Comment thread Styling/TextStyle.cs Outdated
Comment thread README.md
Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 12, 2026

@copilot please check out these comments.

Please also double check https://github.com/boxofyellow/ConsoleMarkdownRenderer/blob/main/docs/adding_a_new_renderer.md to make sure there are no relevant st...

All comments addressed in ae3efc5.

Re: docs/adding_a_new_renderer.md — went through the checklist; this PR modifies an existing renderer so steps 1/2 don't apply, but I covered the renderer-impacting steps that do:

  • Step 3 (DisplayOptions): Header/Headers typed as IHeaderStyle; new default for H1.
  • Step 4 (Clone()): no new properties; Headers/Header were already cloned.
  • Step 5 (resource pair): headingBlock.md was extended to cover every FIGlet branch (LiteralInline, CodeInline, ContainerInline, empty-heading fallback) plus the existing H2/H3 styled cases; headingBlock.txt regenerated so the FIGlet output is visible in the diff.
  • Step 6 (unit tests): RendererTests_TextValidation picks up the new content automatically; explicit tests added for FIGlet-vs-styled dispatch and the regression path.
  • Step 7 (m_crazyOptions): no new DisplayOptions property; Header = (TextStyle)c_crazyFormat cast already in place.
  • Step 8 (bracketEscaping): H1 changed to H2 so the bracket-escape test continues to assert against styled markup (FIGlet would hide the brackets); bracketEscaping.txt regenerated.
  • Step 9 (example doc): example.md was not modified — its existing # An Example header automatically demonstrates the new default FIGlet H1 when the example app runs.

Copilot AI changed the title Render headings via Spectre.Console FigletText (opt-in) Render headings via Spectre.Console FigletText (IHeaderStyle, default H1) May 12, 2026
Copilot AI requested a review from boxofyellow May 12, 2026 11:43
Copy link
Copy Markdown
Owner

@boxofyellow boxofyellow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Please see address these comment.

Comment thread ConsoleMarkdownRenderer.Tests/resources/headingBlock.md Outdated
Comment thread Styling/IHeaderStyle.cs
Comment thread ObjectRenderers/ConsoleHeadingBlockRenderer.cs Outdated
Comment thread ObjectRenderers/ConsoleHeadingBlockRenderer.cs Outdated
Comment thread DisplayOptions.cs Outdated
Comment thread README.md Outdated
Comment thread README.md Outdated
Comment thread README.md
Comment thread DisplayOptions.cs Outdated
Comment thread Styling/IHeaderStyle.cs
Copilot AI and others added 4 commits May 12, 2026 21:53
Co-authored-by: boxofyellow <54955040+boxofyellow@users.noreply.github.com>
Co-authored-by: boxofyellow <54955040+boxofyellow@users.noreply.github.com>
…s via resource test

Co-authored-by: boxofyellow <54955040+boxofyellow@users.noreply.github.com>
…README tidy

Co-authored-by: boxofyellow <54955040+boxofyellow@users.noreply.github.com>
@boxofyellow boxofyellow force-pushed the copilot/add-figlett-text-widget-for-h1-headings branch from bab9607 to 76c99a8 Compare May 13, 2026 01:53
Copy link
Copy Markdown
Owner

@boxofyellow boxofyellow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Please look at these comments

Additionally as expected this change breaks binary compatibility. All though it seems unlikely to affect must consumers

Please see
https://github.com/boxofyellow/ConsoleMarkdownRenderer/actions/runs/25773333197/job/75700806493?pr=113#step:7:37

So we release this change as 0.11.0 Please prepare a migration guide you can file multiple examples in docs directory

  • EffectiveHeader being public was a mistake, consumers should not need it
  • Changing type of Header and Headers should be a minimal impact since consumers are not really expected to read those properties only set them.

However this change does have a size able functional change. Swopping out the default used for the top leave header. This should be called out and detail a long with example output of before an after for a simple markdown file that details shows this difference.

Please also provide details for consumers where that to obtain the old behavior they only need to clear the Headers list.

Comment thread ConsoleMarkdownRenderer.Tests/RendererTests.cs Outdated
Comment thread ObjectRenderers/ConsoleHeadingBlockRenderer.cs Outdated
Comment thread Styling/TextStyleExtensions.cs
Comment thread README.md Outdated
Comment thread ConsoleMarkdownRenderer.Tests/RendererTests.cs Outdated
Comment thread ObjectRenderers/ConsoleHeadingBlockRenderer.cs
Comment thread ObjectRenderers/ConsoleHeadingBlockRenderer.cs
…age, consolidate ToSpectreStyle

Co-authored-by: boxofyellow <54955040+boxofyellow@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 13, 2026

@copilot Please look at these comments

Additionally as expected this change breaks binary compatibility. All though it seems unlikely to affect must consumers...

All addressed.

  • Migration guide added at docs/migration_v0.11.0.md: covers (1) Header/Headers retyped to IHeaderStyle (low impact; TextStyle still implements it so assignments keep compiling), (2) EffectiveHeader now internal (was a mistake to expose), and (3) the functional H1 → FIGlet default with before/after example output for a simple document.
  • The migration guide calls out options.Headers.Clear() as the one-line restore-old-behavior path (every level falls through to Header), and the README's "Default behavior" snippet was updated to use Headers.Clear() per the inline review.

Copilot AI requested a review from boxofyellow May 13, 2026 11:38
Copy link
Copy Markdown
Owner

@boxofyellow boxofyellow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Please checkout these comments.

Comment thread ConsoleMarkdownRenderer.Tests/RendererTests.cs Outdated
Comment thread ConsoleMarkdownRenderer.Tests/RendererTests.cs Outdated
Comment thread docs/migration_v0.11.0.md Outdated
Comment thread docs/migration_v0.11.0.md Outdated
Comment thread ObjectRenderers/ConsoleHeadingBlockRenderer.cs Outdated
Copilot AI and others added 2 commits May 14, 2026 00:31
…Async, doc trim

Co-authored-by: boxofyellow <54955040+boxofyellow@users.noreply.github.com>
Co-authored-by: boxofyellow <54955040+boxofyellow@users.noreply.github.com>
Copilot AI requested a review from boxofyellow May 14, 2026 00:34
Copy link
Copy Markdown
Owner

@boxofyellow boxofyellow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Please checkout these comments.

Comment thread ConsoleMarkdownRenderer.Tests/FigletTextStyleTests.cs Outdated
Comment thread Styling/FigletTextStyle.cs Outdated
Comment thread Styling/IHeaderStyle.cs Outdated
…ileManager in tests

Co-authored-by: boxofyellow <54955040+boxofyellow@users.noreply.github.com>
Copilot AI requested a review from boxofyellow May 14, 2026 01:11
Copy link
Copy Markdown
Owner

@boxofyellow boxofyellow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Please address this comment.

Comment thread Styling/FigletTextStyle.cs Outdated
…factories

Co-authored-by: boxofyellow <54955040+boxofyellow@users.noreply.github.com>
Copilot AI requested a review from boxofyellow May 14, 2026 01:25
Copy link
Copy Markdown
Owner

@boxofyellow boxofyellow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot please address this comment.

Comment thread Styling/FigletTextStyle.cs Outdated
…uctor

Co-authored-by: boxofyellow <54955040+boxofyellow@users.noreply.github.com>
Copilot AI requested a review from boxofyellow May 14, 2026 01:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Spectre.Console] Consider using FigletText widget for top-level headings

2 participants