This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
ConsoleInk.NET is a zero-dependency .NET library for rendering Markdown to ANSI-formatted console output. The library targets .NET Standard 2.0 with C# 10.0 features and uses a streaming-first architecture with a state machine processor for incremental Markdown rendering.
- Core rendering happens through
MarkdownConsoleWriter, aTextWriterimplementation that processes Markdown incrementally - State machine tracks current context (paragraph, heading, list, code block, etc.) without building a full AST
- Minimal lookahead buffering for resolving ambiguities (e.g., Setext headings, tables)
- Direct output generation to target
TextWriteras content is processed
The MarkdownConsoleWriter maintains:
_currentBlockType: Active Markdown block being processed_lastFinalizedBlockType: Previously completed block (for separation logic)_needsSeparationBeforeNextBlock: Flag controlling newline insertion between blocks_paragraphBuffer: Accumulates paragraph text before rendering_lineBuffer: Buffers input for line-by-line processing_linkDefinitions: Dictionary of reference-style link definitions- Table state:
_tableHeaderCells,_tableAlignments,_tableRows
When transitioning between Markdown blocks:
FinalizeBlock()is called to complete the current block- Returns boolean indicating if the block produced output
- Sets
_needsSeparationBeforeNextBlockflag based on block type ProcessLine()consumes this flag to insert appropriate separation
One-step build for everything:
dotnet build src/ConsoleInk.slnThis builds all projects and automatically copies the ConsoleInk.Net.dll to the PowerShell module location (src/powershell-module/ConsoleInk/lib/) via the ConsoleInk.PowerShell.Build MSBuild project.
For Release build (generates NuGet packages):
dotnet build src/ConsoleInk.sln -c ReleaseNuGet package (.nupkg) and symbols (.snupkg) will be in src/ConsoleInk.Net/bin/Release/
Note: The PowerShell module DLL is NOT committed to git. It's copied during build via MSBuild targets in src/powershell-module/ConsoleInk.PowerShell.Build.csproj.
dotnet test src/ConsoleInk.slnRun a specific test:
dotnet test src/ConsoleInk.Net.Tests/ConsoleInk.Net.Tests.csproj --filter "FullyQualifiedName~Render_BoldEmphasis"dotnet run --project src/ConsoleInk.Demo/ConsoleInk.Demo.csprojDirect DLL usage:
pwsh -File ./samples/PowerShell/Demo.ps1MarkdownConsoleWriter.cs(90KB): Core state machine and rendering logicProcessLine(): Main state machine dispatcherDetermineBlockType(): Identifies Markdown block types from inputFinalizeBlock(): Completes current block and manages separationWriteFormattedParagraph(): Handles inline emphasis, links, images, strikethroughWriteListItem(),WriteHeading(),WriteCodeBlock(),WriteTable(): Block-specific renderers
Ansi.cs: ANSI escape code constants (colors, styles)ConsoleTheme.cs: Theme definitions (Default, Monochrome) with color/style configurationMarkdownRenderOptions.cs: Configuration options (width, colors, themes, hyperlinks)MarkdownConsole.cs: Static helper for batch rendering
- Uses xUnit framework
- Test helper:
AssertRender()normalizes line endings and provides detailed log output on failure - Tests verify ANSI output and state transitions for each Markdown feature
- Build project:
ConsoleInk.PowerShell.Build.csproj - Provides
ConvertTo-Markdowncmdlet with pipeline support
WriteFormattedParagraph() uses a single-pass parser with:
- Stack-based style tracking (
_activeStyles) for nested emphasis - Specific ANSI off-codes (
[22mfor bold,[23mfor italic,[29mfor strikethrough) instead of generic reset - Backslash escaping for literal markers (
\*,\_,\~,\!,\[,\],\(,\),\\) - List items use inline formatting:
WriteListItem()callsWriteFormattedParagraph()to ensure links, bold, italic, and other inline styles render properly within list items (see line 1042)
Due to streaming nature, reference link definitions must appear before usage in the input. If a reference link is encountered before its definition, it renders literally. This is documented as a known streaming limitation.
Tables require buffering header, separator, and all rows before rendering (non-streaming):
DetermineBlockType()detects table start (header + separator pattern)ProcessLine()accumulates table rows in_tableRowsFinalizeBlock()triggersWriteTable()to render complete table with proper alignment and padding
Controlled by _needsSeparationBeforeNextBlock flag:
- Headings, code blocks, lists, tables, blockquotes set this flag on finalization
- Paragraphs only set it if they produced output
- Link definitions never set it (non-rendering)
- Blank lines reset current block but don't force separation
- Special case for lists: Consecutive list items of the same list type clear the separation flag to prevent extra newlines between items (see lines 737-751 in
MarkdownConsoleWriter.cs)
- ANSI escape sequences in expected output use constants from
Ansiclass - Line endings normalized to
\ninAssertRender() - Emphasis tests expect specific off-codes, not generic
Ansi.Reset - Logging framework available via optional
loggerparameter toMarkdownConsoleWriter
All public types use namespace ConsoleInk (not ConsoleInk.Net despite project name). This is intentional for simplicity.
- Optional
loggerparameter inMarkdownConsoleWriterconstructor acceptsAction<string>for detailed state machine logging _log()method throughout state machine transitions- Tests can enable logging via
AssertRender()helper
- DO NOT add "Co-Authored-By: Claude" or similar co-authorship claims to commit messages
- DO NOT add "Generated with Claude Code" footer to commit messages
- Keep commit messages professional and focused on the technical changes