Files

92 lines
4.0 KiB
PowerShell

# Render parsed Markdown into a WPF TextBlock.
#
# The parse lives in Internal/MarkdownSimple.ps1 and is shared with Avalonia
# (R10); this file only turns blocks into WPF inlines, so the toolkit types stay
# inside UI/WPF (R12). The Avalonia counterpart is
# UI/Avalonia/Extensions/MarkdownRenderAvalonia.ps1 and is deliberately a
# near-mirror of this - same block handling, different inline construction.
#
# Everything goes into a single TextBlock rather than a document/panel per block:
# Run exposes FontSize, FontWeight, FontFamily and Background, so headings, bold
# spans, code and indented bullets all fit in one control, and the existing
# ScrollViewer keeps working unchanged.
function Set-WpfMarkdownText {
[CmdletBinding()]
param(
[Parameter(Mandatory)] $TextBlock,
[string]$Markdown
)
if (-not $TextBlock) { return }
$TextBlock.Inlines.Clear()
if ([string]::IsNullOrEmpty($Markdown)) { return }
$baseSize = if ($TextBlock.FontSize -gt 0) { [double]$TextBlock.FontSize } else { 12.0 }
$style = Get-SimpleMarkdownStyle
$codeBrush = New-Object System.Windows.Media.SolidColorBrush ([System.Windows.Media.ColorConverter]::ConvertFromString($style.CodeBackground))
$codeFont = New-Object System.Windows.Media.FontFamily ($style.CodeFontFamily)
foreach ($block in (ConvertFrom-SimpleMarkdown $Markdown)) {
if ($block.Kind -eq 'Blank') {
$TextBlock.Inlines.Add((New-Object System.Windows.Documents.LineBreak))
continue
}
# Lead-in for list items and quotes. Leading whitespace in a Run is
# preserved, so indentation works without a panel per level.
$lead = switch ($block.Kind) {
'ListItem' { (' ' * ($block.Indent * 4)) + $block.Marker + ' ' }
'Quote' { $style.QuoteMarker }
default { $null }
}
if ($lead) {
$TextBlock.Inlines.Add((New-Object System.Windows.Documents.Run -ArgumentList $lead))
}
foreach ($inline in $block.Inlines) {
if ($inline.LineBreak) {
$TextBlock.Inlines.Add((New-Object System.Windows.Documents.LineBreak))
# Keep continuation lines of a bullet aligned under its text.
if ($block.Kind -eq 'ListItem') {
$pad = ' ' * (($block.Indent * 4) + $block.Marker.Length + 1)
$TextBlock.Inlines.Add((New-Object System.Windows.Documents.Run -ArgumentList $pad))
}
continue
}
# Links become real Hyperlinks; RequestNavigate opens the default
# browser, matching how the About and Welcome dialogs handle theirs.
if ($inline.Url) {
$link = New-Object System.Windows.Documents.Hyperlink
$link.Inlines.Add((New-Object System.Windows.Documents.Run -ArgumentList ([string]$inline.Text)))
try { $link.NavigateUri = New-Object System.Uri ($inline.Url) } catch { }
$link.Add_RequestNavigate({ Open-ExternalUri $_.Uri.AbsoluteUri; $_.Handled = $true })
if ($inline.Bold) { $link.FontWeight = [System.Windows.FontWeights]::Bold }
$TextBlock.Inlines.Add($link)
continue
}
$run = New-Object System.Windows.Documents.Run -ArgumentList ([string]$inline.Text)
if ($inline.Bold -or $block.Kind -eq 'Heading') {
$run.FontWeight = [System.Windows.FontWeights]::Bold
}
if ($block.Kind -eq 'Heading') {
$run.FontSize = Get-SimpleMarkdownHeadingSize -Level $block.Level -BaseSize $baseSize
}
if ($inline.Code -or $block.Kind -eq 'CodeBlock') {
$run.FontFamily = $codeFont
$run.Background = $codeBrush
}
if ($block.Kind -eq 'Quote') {
$run.FontStyle = [System.Windows.FontStyles]::Italic
}
$TextBlock.Inlines.Add($run)
}
$TextBlock.Inlines.Add((New-Object System.Windows.Documents.LineBreak))
}
}