Classes/TerminalSlidesClasses.ps1
|
# Public data contracts are loaded from the packaged schema assembly. These # PowerShell classes are private rendering models and never cross the module API. class FrameBufferCell { [string]$Char [bool]$Continuation [string]$Fg [string]$Bg [bool]$Bold [bool]$Italic [bool]$Underline } class TerminalStyledRun { [string]$Text [string]$Foreground [string]$Background [bool]$Bold [bool]$Italic [bool]$Underline TerminalStyledRun([string]$text, [string]$foreground, [string]$background, [bool]$bold, [bool]$italic, [bool]$underline) { $this.Text = $text $this.Foreground = $foreground $this.Background = $background $this.Bold = $bold $this.Italic = $italic $this.Underline = $underline } } class TerminalStyledLine { [System.Collections.Generic.List[TerminalStyledRun]]$Runs TerminalStyledLine() { $this.Runs = [System.Collections.Generic.List[TerminalStyledRun]]::new() } [string] GetText() { $builder = [System.Text.StringBuilder]::new() foreach ($run in $this.Runs) { [void]$builder.Append($run.Text) } return $builder.ToString() } [string] ToString() { return $this.GetText() } } class TerminalStyledGrapheme { [string]$Text [TerminalStyledRun]$Style TerminalStyledGrapheme([string]$text, [TerminalStyledRun]$style) { $this.Text = $text $this.Style = $style } } class TerminalStyledTextElement { [string]$Text [int]$Width [TerminalStyledRun]$Style TerminalStyledTextElement([string]$text, [int]$width, [TerminalStyledRun]$style) { $this.Text = $text $this.Width = $width $this.Style = $style } } class TerminalPreparedRun { [string]$Text [int]$Width [string]$Foreground [string]$Background [bool]$Bold [bool]$Italic [bool]$Underline TerminalPreparedRun([string]$text, [int]$width, [string]$foreground, [string]$background, [bool]$bold, [bool]$italic, [bool]$underline) { $this.Text = $text $this.Width = $width $this.Foreground = $foreground $this.Background = $background $this.Bold = $bold $this.Italic = $italic $this.Underline = $underline } } class TerminalPreparedLine { [System.Collections.Generic.List[TerminalPreparedRun]]$Runs [int]$Width [int]$RenderedWidth [int]$StartColumn [int]$AvailableWidth TerminalPreparedLine([int]$startColumn, [int]$availableWidth) { $this.Runs = [System.Collections.Generic.List[TerminalPreparedRun]]::new() $this.StartColumn = $startColumn $this.AvailableWidth = $availableWidth } [string] GetText() { $builder = [System.Text.StringBuilder]::new() foreach ($run in $this.Runs) { [void]$builder.Append($run.Text) } return $builder.ToString() } [string] ToString() { return $this.GetText() } } class TerminalSpectreCapabilities : Spectre.Console.IReadOnlyCapabilities { [Spectre.Console.ColorSystem]$ColorSystem [bool]$Ansi [bool]$Links [bool]$Legacy [bool]$IsTerminal [bool]$Interactive [bool]$Unicode } class FrameBuffer { [int]$Width [int]$Height [FrameBufferCell[][]]$Cells FrameBuffer([int]$width, [int]$height) { $this.Width = [Math]::Max(1, $width) $this.Height = [Math]::Max(1, $height) $rows = [FrameBufferCell[][]]::new($this.Height) for ($r = 0; $r -lt $this.Height; $r++) { $rows[$r] = [FrameBufferCell[]]::new($this.Width) for ($c = 0; $c -lt $this.Width; $c++) { $rows[$r][$c] = [FrameBufferCell]::new() } } $this.Cells = $rows $this.Clear() } [void] Clear() { for ($r = 0; $r -lt $this.Height; $r++) { for ($c = 0; $c -lt $this.Width; $c++) { $cell = $this.Cells[$r][$c] $cell.Char = ' ' $cell.Continuation = $false $cell.Fg = $null $cell.Bg = $null $cell.Bold = $false $cell.Italic = $false $cell.Underline = $false } } } [void] ClearCellOccupant([int]$row, [int]$col) { if ($row -lt 0 -or $row -ge $this.Height -or $col -lt 0 -or $col -ge $this.Width) { return } $lead = $col while ($lead -gt 0 -and $this.Cells[$row][$lead].Continuation) { $lead-- } $index = $lead do { $cell = $this.Cells[$row][$index] $cell.Char = ' ' $cell.Continuation = $false $cell.Fg = $null $cell.Bg = $null $cell.Bold = $false $cell.Italic = $false $cell.Underline = $false $index++ } while ($index -lt $this.Width -and $this.Cells[$row][$index].Continuation) } [void] SetCell([int]$row, [int]$col, [string]$ch, [string]$fg, [string]$bg, [bool]$bold, [bool]$italic, [bool]$underline) { if ($row -ge 0 -and $row -lt $this.Height -and $col -ge 0 -and $col -lt $this.Width) { $this.ClearCellOccupant($row, $col) $cell = $this.Cells[$row][$col] $cell.Char = $ch $cell.Fg = $fg $cell.Bg = $bg $cell.Bold = $bold $cell.Italic = $italic $cell.Underline = $underline } } [void] SetContinuationCell([int]$row, [int]$col, [string]$fg, [string]$bg, [bool]$bold, [bool]$italic, [bool]$underline) { if ($row -ge 0 -and $row -lt $this.Height -and $col -ge 0 -and $col -lt $this.Width) { $cell = $this.Cells[$row][$col] $cell.Char = ' ' $cell.Continuation = $true $cell.Fg = $fg $cell.Bg = $bg $cell.Bold = $bold $cell.Italic = $italic $cell.Underline = $underline } } [string] GetRowText([int]$row) { if ($row -lt 0 -or $row -ge $this.Height) { return '' } $builder = [System.Text.StringBuilder]::new() foreach ($cell in $this.Cells[$row]) { if (-not $cell.Continuation) { [void]$builder.Append($cell.Char) } } return $builder.ToString() } hidden [int] GetColor256Index([string]$hex) { $rgb = Convert-HexToRgb -Hex $hex return 16 + (36 * [Math]::Round($rgb[0] / 51.0)) + (6 * [Math]::Round($rgb[1] / 51.0)) + [Math]::Round($rgb[2] / 51.0) } [string] Render([bool]$trueColorSupport, [bool]$color256Support) { $sb = [System.Text.StringBuilder]::new() $currentFg = $null $currentBg = $null $currentBold = $false $currentItalic = $false $currentUnderline = $false for ($r = 0; $r -lt $this.Height; $r++) { [void]$sb.Append("`e[$($r + 1);1H") for ($c = 0; $c -lt $this.Width; $c++) { $cell = $this.Cells[$r][$c] if ($cell.Continuation) { continue } $needReset = $false if ($cell.Bold -ne $currentBold -or $cell.Italic -ne $currentItalic -or $cell.Underline -ne $currentUnderline) { $needReset = $true } if ($needReset -or $cell.Fg -ne $currentFg -or $cell.Bg -ne $currentBg) { [void]$sb.Append("`e[0m") $currentFg = $null; $currentBg = $null; $currentBold = $false; $currentItalic = $false; $currentUnderline = $false if ($cell.Bold) { [void]$sb.Append("`e[1m"); $currentBold = $true } if ($cell.Italic) { [void]$sb.Append("`e[3m"); $currentItalic = $true } if ($cell.Underline) { [void]$sb.Append("`e[4m"); $currentUnderline = $true } if ($cell.Fg) { if ($trueColorSupport) { $rgb = Convert-HexToRgb -Hex $cell.Fg [void]$sb.Append("`e[38;2;$($rgb[0]);$($rgb[1]);$($rgb[2])m") } elseif ($color256Support) { $index = $this.GetColor256Index($cell.Fg) [void]$sb.Append("`e[38;5;$index" + 'm') } $currentFg = $cell.Fg } if ($cell.Bg) { if ($trueColorSupport) { $rgb = Convert-HexToRgb -Hex $cell.Bg [void]$sb.Append("`e[48;2;$($rgb[0]);$($rgb[1]);$($rgb[2])m") } elseif ($color256Support) { $index = $this.GetColor256Index($cell.Bg) [void]$sb.Append("`e[48;5;$index" + 'm') } $currentBg = $cell.Bg } } [void]$sb.Append($cell.Char) } } [void]$sb.Append("`e[0m") return $sb.ToString() } } |