Add RichPS7: PowerShell 7 port of Python's Rich library

This commit introduces RichPS7, a comprehensive PowerShell 7 module that
ports the core functionality of Python's Rich library for beautiful
terminal formatting.

Core Features Implemented:
- Color Support: RGB, hex codes, and named colors with ANSI escape codes
- Text Styling: Bold, italic, underline, strikethrough, and dim text
- Console: Main output interface with themed messages (info, warning, error, success)
- Tables: Beautiful table rendering with multiple box styles and alignment options
- Panels: Bordered panels with titles, subtitles, and custom styling
- Progress Bars: Live-updating progress bars with ETA estimation

Module Structure:
- Classes/: Core class implementations (Color, Style, Console, Table, Panel, Progress)
- Examples/: 5 comprehensive example scripts demonstrating all features
- Tests/: Basic functionality test suite
- Documentation: README.md and QUICKSTART.md for users

Files Added:
- RichPS7.psm1: Main module file
- RichPS7.psd1: Module manifest
- Classes/Color.ps1: Color handling and ANSI code generation
- Classes/Style.ps1: Text styling and formatting
- Classes/Console.ps1: Console output interface
- Classes/Table.ps1: Table rendering with borders
- Classes/Panel.ps1: Panel components
- Classes/Progress.ps1: Progress tracking and display
- Examples/01-Colors.ps1: Color and styling examples
- Examples/02-Tables.ps1: Table formatting examples
- Examples/03-Panels.ps1: Panel examples
- Examples/04-Progress.ps1: Progress bar examples
- Examples/05-Complete-Demo.ps1: Complete feature demonstration
- Tests/Basic-Test.ps1: Automated test suite
- README.md: Full documentation
- QUICKSTART.md: Quick start guide

Requirements:
- PowerShell 7.0 or higher
- Terminal with ANSI color support

This implementation covers Option 1 (Core Features) from the conversion plan,
providing a solid foundation for PowerShell users who want Rich-style terminal
formatting in their scripts.
This commit is contained in:
Claude 2025-11-13 19:48:35 +00:00
parent 4d6d631a3d
commit 4ad22afa63
No known key found for this signature in database
16 changed files with 2673 additions and 0 deletions

117
RichPS7/Classes/Color.ps1 Normal file
View file

@ -0,0 +1,117 @@
class RichColor {
[int]$Red
[int]$Green
[int]$Blue
[string]$Name
# Constructor for RGB
RichColor([int]$r, [int]$g, [int]$b) {
$this.Red = [Math]::Max(0, [Math]::Min(255, $r))
$this.Green = [Math]::Max(0, [Math]::Min(255, $g))
$this.Blue = [Math]::Max(0, [Math]::Min(255, $b))
$this.Name = ""
}
# Constructor for named color
RichColor([string]$name) {
$this.Name = $name.ToLower()
$rgb = $this.ParseNamedColor($name)
$this.Red = $rgb[0]
$this.Green = $rgb[1]
$this.Blue = $rgb[2]
}
# Parse named colors
hidden [int[]] ParseNamedColor([string]$name) {
$colors = @{
'black' = @(0, 0, 0)
'red' = @(255, 0, 0)
'green' = @(0, 255, 0)
'yellow' = @(255, 255, 0)
'blue' = @(0, 0, 255)
'magenta' = @(255, 0, 255)
'cyan' = @(0, 255, 255)
'white' = @(255, 255, 255)
'bright_black' = @(128, 128, 128)
'bright_red' = @(255, 128, 128)
'bright_green' = @(128, 255, 128)
'bright_yellow' = @(255, 255, 128)
'bright_blue' = @(128, 128, 255)
'bright_magenta' = @(255, 128, 255)
'bright_cyan' = @(128, 255, 255)
'bright_white' = @(255, 255, 255)
'grey' = @(128, 128, 128)
'gray' = @(128, 128, 128)
'orange' = @(255, 165, 0)
'purple' = @(128, 0, 128)
'pink' = @(255, 192, 203)
}
$normalizedName = $name.ToLower().Replace(' ', '_').Replace('-', '_')
if ($colors.ContainsKey($normalizedName)) {
return $colors[$normalizedName]
}
# Try to parse hex color (#RGB or #RRGGBB)
if ($name -match '^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$') {
$hex = $name.Substring(1)
if ($hex.Length -eq 3) {
$r = [Convert]::ToInt32($hex[0].ToString() * 2, 16)
$g = [Convert]::ToInt32($hex[1].ToString() * 2, 16)
$b = [Convert]::ToInt32($hex[2].ToString() * 2, 16)
} else {
$r = [Convert]::ToInt32($hex.Substring(0, 2), 16)
$g = [Convert]::ToInt32($hex.Substring(2, 2), 16)
$b = [Convert]::ToInt32($hex.Substring(4, 2), 16)
}
return @($r, $g, $b)
}
# Default to white if unknown
return @(255, 255, 255)
}
# Get ANSI escape code for foreground color
[string] GetForegroundCode() {
return "`e[38;2;$($this.Red);$($this.Green);$($this.Blue)m"
}
# Get ANSI escape code for background color
[string] GetBackgroundCode() {
return "`e[48;2;$($this.Red);$($this.Green);$($this.Blue)m"
}
# Convert to hex string
[string] ToHex() {
return "#{0:X2}{1:X2}{2:X2}" -f $this.Red, $this.Green, $this.Blue
}
[string] ToString() {
if ($this.Name) {
return $this.Name
}
return $this.ToHex()
}
}
# Helper function to create color from various inputs
function New-RichColor {
param(
[Parameter(ValueFromPipeline)]
$Color
)
if ($Color -is [RichColor]) {
return $Color
}
if ($Color -is [string]) {
return [RichColor]::new($Color)
}
if ($Color -is [array] -and $Color.Count -eq 3) {
return [RichColor]::new($Color[0], $Color[1], $Color[2])
}
return [RichColor]::new("white")
}

188
RichPS7/Classes/Console.ps1 Normal file
View file

@ -0,0 +1,188 @@
class RichConsole {
[int]$Width
[int]$Height
[bool]$ColorSystem
[object]$Theme
RichConsole() {
$this.UpdateSize()
$this.ColorSystem = $this.DetectColorSupport()
$this.Theme = @{
'info' = New-RichColor 'cyan'
'warning' = New-RichColor 'yellow'
'error' = New-RichColor 'red'
'success' = New-RichColor 'green'
}
}
# Detect terminal size
hidden [void] UpdateSize() {
try {
$this.Width = $Host.UI.RawUI.WindowSize.Width
$this.Height = $Host.UI.RawUI.WindowSize.Height
} catch {
$this.Width = 80
$this.Height = 24
}
}
# Detect if terminal supports colors
hidden [bool] DetectColorSupport() {
# PowerShell 7+ has good ANSI support
if ($PSVersionTable.PSVersion.Major -ge 7) {
return $true
}
# Check if running in Windows Terminal or other modern terminals
if ($env:WT_SESSION -or $env:TERM_PROGRAM) {
return $true
}
return $false
}
# Print text with optional style
[void] Print([string]$text) {
Write-Host $text
}
[void] Print([string]$text, [RichStyle]$style) {
if ($style) {
Write-Host $style.Apply($text) -NoNewline
Write-Host ""
} else {
Write-Host $text
}
}
# Print with foreground color
[void] Print([string]$text, [RichColor]$color) {
$style = [RichStyle]::new()
$style.ForegroundColor = $color
$this.Print($text, $style)
}
# Print without newline
[void] PrintNoNewline([string]$text) {
Write-Host $text -NoNewline
}
[void] PrintNoNewline([string]$text, [RichStyle]$style) {
if ($style) {
Write-Host $style.Apply($text) -NoNewline
} else {
Write-Host $text -NoNewline
}
}
# Print a line (rule)
[void] Rule([string]$title) {
$this.Rule($title, $null)
}
[void] Rule([string]$title, [RichColor]$color) {
$this.UpdateSize()
if ($title) {
$titleLen = $title.Length + 2 # Add spaces around title
$leftLen = [Math]::Floor(($this.Width - $titleLen) / 2)
$rightLen = $this.Width - $titleLen - $leftLen
$line = "" * $leftLen + " $title " + "" * $rightLen
} else {
$line = "" * $this.Width
}
if ($color) {
$style = [RichStyle]::new()
$style.ForegroundColor = $color
$this.Print($line, $style)
} else {
$this.Print($line)
}
}
# Print styled text with theme
[void] Info([string]$text) {
$style = [RichStyle]::new()
$style.ForegroundColor = $this.Theme['info']
$this.Print($text, $style)
}
[void] Warning([string]$text) {
$style = [RichStyle]::new()
$style.ForegroundColor = $this.Theme['warning']
$this.Print($text, $style)
}
[void] Error([string]$text) {
$style = [RichStyle]::new()
$style.ForegroundColor = $this.Theme['error']
$this.Print($text, $style)
}
[void] Success([string]$text) {
$style = [RichStyle]::new()
$style.ForegroundColor = $this.Theme['success']
$this.Print($text, $style)
}
# Clear the screen
[void] Clear() {
Clear-Host
}
# Print a blank line
[void] NewLine() {
Write-Host ""
}
[void] NewLine([int]$count) {
for ($i = 0; $i -lt $count; $i++) {
Write-Host ""
}
}
}
# Create a default console instance
$Global:RichConsole = [RichConsole]::new()
# Helper function to get the global console
function Get-RichConsole {
return $Global:RichConsole
}
# Convenience function for printing
function Write-Rich {
param(
[Parameter(Mandatory, Position = 0)]
[string]$Text,
[Parameter(Position = 1)]
[RichStyle]$Style,
[RichColor]$Color,
[switch]$Bold,
[switch]$Italic,
[switch]$Underline,
[switch]$NoNewline
)
$console = Get-RichConsole
# Build style if not provided
if (-not $Style -and ($Color -or $Bold -or $Italic -or $Underline)) {
$Style = [RichStyle]::new()
if ($Color) { $Style.ForegroundColor = $Color }
if ($Bold) { $Style.Bold = $true }
if ($Italic) { $Style.Italic = $true }
if ($Underline) { $Style.Underline = $true }
}
if ($NoNewline) {
$console.PrintNoNewline($Text, $Style)
} else {
$console.Print($Text, $Style)
}
}

238
RichPS7/Classes/Panel.ps1 Normal file
View file

@ -0,0 +1,238 @@
class RichPanel {
[string]$Content
[string]$Title
[string]$Subtitle
[string]$BoxStyle
[RichStyle]$TitleStyle
[RichStyle]$BorderStyle
[RichStyle]$ContentStyle
[int]$Width
[int]$Padding
[string]$TitleAlign
[hashtable]$BoxChars
RichPanel([string]$content) {
$this.Content = $content
$this.BoxStyle = "rounded"
$this.Padding = 1
$this.TitleAlign = "left"
$this.Width = 0 # Auto-width
$this.InitializeBoxChars()
# Default styles
$this.TitleStyle = [RichStyle]::new()
$this.TitleStyle.Bold = $true
}
hidden [void] InitializeBoxChars() {
# Reuse the same box drawing characters as Table
$this.BoxChars = @{
'rounded' = @{
'top_left' = '╭'
'top_right' = '╮'
'bottom_left' = '╰'
'bottom_right' = '╯'
'horizontal' = '─'
'vertical' = '│'
}
'square' = @{
'top_left' = '┌'
'top_right' = '┐'
'bottom_left' = '└'
'bottom_right' = '┘'
'horizontal' = '─'
'vertical' = '│'
}
'double' = @{
'top_left' = '╔'
'top_right' = '╗'
'bottom_left' = '╚'
'bottom_right' = '╝'
'horizontal' = '═'
'vertical' = '║'
}
'heavy' = @{
'top_left' = '┏'
'top_right' = '┓'
'bottom_left' = '┗'
'bottom_right' = '┛'
'horizontal' = '━'
'vertical' = '┃'
}
'simple' = @{
'top_left' = '+'
'top_right' = '+'
'bottom_left' = '+'
'bottom_right' = '+'
'horizontal' = '-'
'vertical' = '|'
}
}
}
# Calculate the width of the panel
hidden [int] CalculateWidth() {
if ($this.Width -gt 0) {
return $this.Width
}
# Calculate based on content
$lines = $this.Content -split "`n"
$maxWidth = 0
foreach ($line in $lines) {
if ($line.Length -gt $maxWidth) {
$maxWidth = $line.Length
}
}
# Add padding
$maxWidth += ($this.Padding * 2)
# Check title width
if ($this.Title) {
$titleWidth = $this.Title.Length + 4 # Add space for title decoration
if ($titleWidth -gt $maxWidth) {
$maxWidth = $titleWidth
}
}
# Ensure minimum width
if ($maxWidth -lt 10) {
$maxWidth = 10
}
return $maxWidth
}
# Align text within given width
hidden [string] AlignText([string]$text, [int]$width, [string]$align) {
$len = $text.Length
if ($len -ge $width) {
return $text.Substring(0, $width)
}
$padding = $width - $len
switch ($align) {
'center' {
$leftPad = [Math]::Floor($padding / 2)
$rightPad = $padding - $leftPad
return (' ' * $leftPad) + $text + (' ' * $rightPad)
}
'right' {
return (' ' * $padding) + $text
}
default { # left
return $text + (' ' * $padding)
}
}
}
# Render the panel
[string] Render() {
$output = [System.Text.StringBuilder]::new()
$box = $this.BoxChars[$this.BoxStyle]
$width = $this.CalculateWidth()
$innerWidth = $width - 2 # Subtract borders
# Top border with title
if ($this.Title) {
$titleText = " $($this.Title) "
if ($this.TitleStyle) {
$titleText = $this.TitleStyle.Apply($titleText)
}
$titleLen = $this.Title.Length + 2
$leftLen = switch ($this.TitleAlign) {
'center' { [Math]::Max(1, [Math]::Floor(($innerWidth - $titleLen) / 2)) }
'right' { [Math]::Max(1, $innerWidth - $titleLen - 1) }
default { 1 } # left
}
$rightLen = [Math]::Max(1, $innerWidth - $titleLen - $leftLen)
$topLine = $box.top_left + ($box.horizontal * $leftLen) + $titleText + ($box.horizontal * $rightLen) + $box.top_right
} else {
$topLine = $box.top_left + ($box.horizontal * $innerWidth) + $box.top_right
}
if ($this.BorderStyle) {
$topLine = $this.BorderStyle.Apply($topLine)
}
[void]$output.AppendLine($topLine)
# Content lines
$lines = $this.Content -split "`n"
$contentWidth = $innerWidth - ($this.Padding * 2)
foreach ($line in $lines) {
$paddedLine = (' ' * $this.Padding) + $line.PadRight($contentWidth) + (' ' * $this.Padding)
if ($this.ContentStyle) {
$paddedLine = $this.ContentStyle.Apply($paddedLine)
}
$bordered = $box.vertical + $paddedLine + $box.vertical
if ($this.BorderStyle) {
# Apply border style to the border characters only
$bordered = $this.BorderStyle.Apply($box.vertical) + $paddedLine + $this.BorderStyle.Apply($box.vertical)
}
[void]$output.AppendLine($bordered)
}
# Bottom border with subtitle
if ($this.Subtitle) {
$subtitleText = " $($this.Subtitle) "
$subtitleLen = $this.Subtitle.Length + 2
$leftLen = [Math]::Max(1, [Math]::Floor(($innerWidth - $subtitleLen) / 2))
$rightLen = [Math]::Max(1, $innerWidth - $subtitleLen - $leftLen)
$bottomLine = $box.bottom_left + ($box.horizontal * $leftLen) + $subtitleText + ($box.horizontal * $rightLen) + $box.bottom_right
} else {
$bottomLine = $box.bottom_left + ($box.horizontal * $innerWidth) + $box.bottom_right
}
if ($this.BorderStyle) {
$bottomLine = $this.BorderStyle.Apply($bottomLine)
}
[void]$output.Append($bottomLine)
return $output.ToString()
}
}
# Helper function to create and render a panel
function New-RichPanel {
param(
[Parameter(Mandatory, Position = 0)]
[string]$Content,
[string]$Title,
[string]$Subtitle,
[string]$BoxStyle = "rounded",
[int]$Width = 0,
[int]$Padding = 1,
[string]$TitleAlign = "left",
[RichStyle]$TitleStyle,
[RichStyle]$BorderStyle,
[RichStyle]$ContentStyle
)
$panel = [RichPanel]::new($Content)
if ($Title) { $panel.Title = $Title }
if ($Subtitle) { $panel.Subtitle = $Subtitle }
$panel.BoxStyle = $BoxStyle
$panel.Width = $Width
$panel.Padding = $Padding
$panel.TitleAlign = $TitleAlign
if ($TitleStyle) { $panel.TitleStyle = $TitleStyle }
if ($BorderStyle) { $panel.BorderStyle = $BorderStyle }
if ($ContentStyle) { $panel.ContentStyle = $ContentStyle }
return $panel
}

View file

@ -0,0 +1,213 @@
class RichProgressBar {
[string]$Description
[int]$Total
[int]$Current
[bool]$IsComplete
[datetime]$StartTime
[RichColor]$CompleteColor
[RichColor]$RemainingColor
[int]$Width
RichProgressBar([string]$description, [int]$total) {
$this.Description = $description
$this.Total = $total
$this.Current = 0
$this.IsComplete = $false
$this.StartTime = Get-Date
$this.Width = 40
$this.CompleteColor = New-RichColor 'green'
$this.RemainingColor = New-RichColor 'bright_black'
}
# Update progress
[void] Update([int]$value) {
$this.Current = [Math]::Min($value, $this.Total)
$this.IsComplete = ($this.Current -ge $this.Total)
}
[void] Advance([int]$delta) {
$this.Update($this.Current + $delta)
}
# Get percentage complete
[double] GetPercentage() {
if ($this.Total -eq 0) { return 100.0 }
return ($this.Current / $this.Total) * 100.0
}
# Get elapsed time
[timespan] GetElapsed() {
return (Get-Date) - $this.StartTime
}
# Estimate remaining time
[timespan] GetEstimatedRemaining() {
if ($this.Current -eq 0) {
return [timespan]::Zero
}
$elapsed = $this.GetElapsed()
$rate = $this.Current / $elapsed.TotalSeconds
if ($rate -eq 0) {
return [timespan]::Zero
}
$remaining = $this.Total - $this.Current
$seconds = $remaining / $rate
return [timespan]::FromSeconds($seconds)
}
# Format time span
hidden [string] FormatTimeSpan([timespan]$ts) {
if ($ts.TotalHours -ge 1) {
return "{0:D2}:{1:D2}:{2:D2}" -f [Math]::Floor($ts.TotalHours), $ts.Minutes, $ts.Seconds
} elseif ($ts.TotalMinutes -ge 1) {
return "{0:D2}:{1:D2}" -f $ts.Minutes, $ts.Seconds
} else {
return "{0:D2}s" -f $ts.Seconds
}
}
# Render the progress bar
[string] Render() {
$percentage = $this.GetPercentage()
$filled = [Math]::Floor($this.Width * ($percentage / 100.0))
$remaining = $this.Width - $filled
# Build the bar
$completeStyle = [RichStyle]::new()
$completeStyle.ForegroundColor = $this.CompleteColor
$remainingStyle = [RichStyle]::new()
$remainingStyle.ForegroundColor = $this.RemainingColor
$bar = $completeStyle.Apply('█' * $filled) + $remainingStyle.Apply('░' * $remaining)
# Build the info text
$elapsed = $this.FormatTimeSpan($this.GetElapsed())
$eta = if ($this.IsComplete) {
"Done"
} else {
$this.FormatTimeSpan($this.GetEstimatedRemaining())
}
$percentText = "{0,5:F1}%" -f $percentage
$countText = "$($this.Current)/$($this.Total)"
# Combine everything
return "$($this.Description.PadRight(30)) [$bar] $percentText $countText ETA: $eta"
}
}
class RichProgress {
[System.Collections.ArrayList]$Tasks
[bool]$IsLive
[int]$LastLineCount
RichProgress() {
$this.Tasks = [System.Collections.ArrayList]::new()
$this.IsLive = $false
$this.LastLineCount = 0
}
# Add a task
[RichProgressBar] AddTask([string]$description, [int]$total) {
$task = [RichProgressBar]::new($description, $total)
[void]$this.Tasks.Add($task)
return $task
}
# Start live display
[void] Start() {
$this.IsLive = $true
[Console]::CursorVisible = $false
}
# Stop live display
[void] Stop() {
$this.IsLive = $false
[Console]::CursorVisible = $true
}
# Render all tasks
[string] Render() {
$output = [System.Text.StringBuilder]::new()
foreach ($task in $this.Tasks) {
[void]$output.AppendLine($task.Render())
}
return $output.ToString().TrimEnd()
}
# Update the display
[void] Refresh() {
if (-not $this.IsLive) { return }
# Move cursor up to overwrite previous output
if ($this.LastLineCount -gt 0) {
for ($i = 0; $i -lt $this.LastLineCount; $i++) {
Write-Host "`e[1A`e[2K" -NoNewline
}
}
# Render and display
$output = $this.Render()
Write-Host $output
# Track how many lines we wrote
$this.LastLineCount = ($output -split "`n").Count
}
# Check if all tasks are complete
[bool] IsComplete() {
foreach ($task in $this.Tasks) {
if (-not $task.IsComplete) {
return $false
}
}
return $true
}
}
# Helper function to create a progress display
function New-RichProgress {
return [RichProgress]::new()
}
# Helper function for simple progress tracking
function Invoke-RichProgress {
param(
[Parameter(Mandatory)]
[string]$Description,
[Parameter(Mandatory)]
[array]$Collection,
[Parameter(Mandatory)]
[scriptblock]$ScriptBlock
)
$progress = [RichProgress]::new()
$task = $progress.AddTask($Description, $Collection.Count)
$progress.Start()
try {
foreach ($item in $Collection) {
$progress.Refresh()
# Execute the script block
& $ScriptBlock $item
$task.Advance(1)
}
$progress.Refresh()
Start-Sleep -Milliseconds 500 # Show final state
} finally {
$progress.Stop()
}
}

110
RichPS7/Classes/Style.ps1 Normal file
View file

@ -0,0 +1,110 @@
class RichStyle {
[RichColor]$ForegroundColor
[RichColor]$BackgroundColor
[bool]$Bold
[bool]$Italic
[bool]$Underline
[bool]$Strike
[bool]$Dim
RichStyle() {
$this.Bold = $false
$this.Italic = $false
$this.Underline = $false
$this.Strike = $false
$this.Dim = $false
}
# Get the complete ANSI code for this style
[string] GetAnsiCode() {
$codes = @()
# Text attributes
if ($this.Bold) { $codes += "1" }
if ($this.Dim) { $codes += "2" }
if ($this.Italic) { $codes += "3" }
if ($this.Underline) { $codes += "4" }
if ($this.Strike) { $codes += "9" }
# Build the complete escape sequence
$result = ""
if ($codes.Count -gt 0) {
$result += "`e[$($codes -join ';')m"
}
if ($this.ForegroundColor) {
$result += $this.ForegroundColor.GetForegroundCode()
}
if ($this.BackgroundColor) {
$result += $this.BackgroundColor.GetBackgroundCode()
}
return $result
}
# Reset code
static [string] GetResetCode() {
return "`e[0m"
}
# Apply style to text
[string] Apply([string]$text) {
$code = $this.GetAnsiCode()
if ($code) {
return "$code$text$([RichStyle]::GetResetCode())"
}
return $text
}
# Combine with another style
[RichStyle] Combine([RichStyle]$other) {
$result = [RichStyle]::new()
# Copy from this style
$result.ForegroundColor = $this.ForegroundColor
$result.BackgroundColor = $this.BackgroundColor
$result.Bold = $this.Bold
$result.Italic = $this.Italic
$result.Underline = $this.Underline
$result.Strike = $this.Strike
$result.Dim = $this.Dim
# Override with other style
if ($other.ForegroundColor) { $result.ForegroundColor = $other.ForegroundColor }
if ($other.BackgroundColor) { $result.BackgroundColor = $other.BackgroundColor }
if ($other.Bold) { $result.Bold = $true }
if ($other.Italic) { $result.Italic = $true }
if ($other.Underline) { $result.Underline = $true }
if ($other.Strike) { $result.Strike = $true }
if ($other.Dim) { $result.Dim = $true }
return $result
}
}
# Helper function to create styles easily
function New-RichStyle {
param(
[RichColor]$ForegroundColor,
[RichColor]$BackgroundColor,
[switch]$Bold,
[switch]$Italic,
[switch]$Underline,
[switch]$Strike,
[switch]$Dim
)
$style = [RichStyle]::new()
if ($ForegroundColor) { $style.ForegroundColor = $ForegroundColor }
if ($BackgroundColor) { $style.BackgroundColor = $BackgroundColor }
if ($Bold) { $style.Bold = $true }
if ($Italic) { $style.Italic = $true }
if ($Underline) { $style.Underline = $true }
if ($Strike) { $style.Strike = $true }
if ($Dim) { $style.Dim = $true }
return $style
}

285
RichPS7/Classes/Table.ps1 Normal file
View file

@ -0,0 +1,285 @@
class RichTable {
[string]$Title
[System.Collections.ArrayList]$Columns
[System.Collections.ArrayList]$Rows
[string]$BoxStyle
[RichStyle]$HeaderStyle
[RichStyle]$RowStyle
[bool]$ShowHeader
[bool]$ShowLines
[hashtable]$BoxChars
RichTable() {
$this.Columns = [System.Collections.ArrayList]::new()
$this.Rows = [System.Collections.ArrayList]::new()
$this.BoxStyle = "rounded"
$this.ShowHeader = $true
$this.ShowLines = $false
$this.InitializeBoxChars()
# Default header style
$this.HeaderStyle = [RichStyle]::new()
$this.HeaderStyle.Bold = $true
$this.HeaderStyle.ForegroundColor = New-RichColor 'cyan'
}
hidden [void] InitializeBoxChars() {
# Box drawing characters for different styles
$this.BoxChars = @{
'rounded' = @{
'top_left' = '╭'
'top_right' = '╮'
'bottom_left' = '╰'
'bottom_right' = '╯'
'horizontal' = '─'
'vertical' = '│'
'cross' = '┼'
'top_join' = '┬'
'bottom_join' = '┴'
'left_join' = '├'
'right_join' = '┤'
}
'square' = @{
'top_left' = '┌'
'top_right' = '┐'
'bottom_left' = '└'
'bottom_right' = '┘'
'horizontal' = '─'
'vertical' = '│'
'cross' = '┼'
'top_join' = '┬'
'bottom_join' = '┴'
'left_join' = '├'
'right_join' = '┤'
}
'double' = @{
'top_left' = '╔'
'top_right' = '╗'
'bottom_left' = '╚'
'bottom_right' = '╝'
'horizontal' = '═'
'vertical' = '║'
'cross' = '╬'
'top_join' = '╦'
'bottom_join' = '╩'
'left_join' = '╠'
'right_join' = '╣'
}
'simple' = @{
'top_left' = '+'
'top_right' = '+'
'bottom_left' = '+'
'bottom_right' = '+'
'horizontal' = '-'
'vertical' = '|'
'cross' = '+'
'top_join' = '+'
'bottom_join' = '+'
'left_join' = '+'
'right_join' = '+'
}
}
}
# Add a column
[void] AddColumn([string]$name) {
$this.AddColumn($name, @{})
}
[void] AddColumn([string]$name, [hashtable]$options) {
$column = @{
'Name' = $name
'Width' = if ($options.Width) { $options.Width } else { $null }
'Align' = if ($options.Align) { $options.Align } else { 'left' }
'Style' = if ($options.Style) { $options.Style } else { $null }
}
[void]$this.Columns.Add($column)
}
# Add a row
[void] AddRow([array]$cells) {
[void]$this.Rows.Add($cells)
}
# Calculate column widths
hidden [array] CalculateWidths() {
$widths = @()
for ($i = 0; $i -lt $this.Columns.Count; $i++) {
$column = $this.Columns[$i]
if ($column.Width) {
$widths += $column.Width
} else {
# Calculate based on content
$maxWidth = $column.Name.Length
foreach ($row in $this.Rows) {
if ($i -lt $row.Count) {
$cellWidth = $row[$i].ToString().Length
if ($cellWidth -gt $maxWidth) {
$maxWidth = $cellWidth
}
}
}
$widths += $maxWidth
}
}
return $widths
}
# Align text within a cell
hidden [string] AlignText([string]$text, [int]$width, [string]$align) {
$text = $text.ToString()
$len = $text.Length
if ($len -ge $width) {
return $text.Substring(0, $width)
}
$padding = $width - $len
switch ($align) {
'center' {
$leftPad = [Math]::Floor($padding / 2)
$rightPad = $padding - $leftPad
return (' ' * $leftPad) + $text + (' ' * $rightPad)
}
'right' {
return (' ' * $padding) + $text
}
default { # left
return $text + (' ' * $padding)
}
}
}
# Render the table
[string] Render() {
$output = [System.Text.StringBuilder]::new()
$widths = $this.CalculateWidths()
$box = $this.BoxChars[$this.BoxStyle]
# Top border
[void]$output.Append($box.top_left)
for ($i = 0; $i -lt $widths.Count; $i++) {
[void]$output.Append($box.horizontal * ($widths[$i] + 2))
if ($i -lt $widths.Count - 1) {
[void]$output.Append($box.top_join)
}
}
[void]$output.AppendLine($box.top_right)
# Title (if present)
if ($this.Title) {
$totalWidth = ($widths | Measure-Object -Sum).Sum + ($widths.Count * 2) + ($widths.Count - 1)
$titleText = $this.AlignText($this.Title, $totalWidth, 'center')
[void]$output.Append($box.vertical)
[void]$output.Append($titleText)
[void]$output.AppendLine($box.vertical)
# Separator after title
[void]$output.Append($box.left_join)
for ($i = 0; $i -lt $widths.Count; $i++) {
[void]$output.Append($box.horizontal * ($widths[$i] + 2))
if ($i -lt $widths.Count - 1) {
[void]$output.Append($box.cross)
}
}
[void]$output.AppendLine($box.right_join)
}
# Header row
if ($this.ShowHeader) {
[void]$output.Append($box.vertical)
for ($i = 0; $i -lt $this.Columns.Count; $i++) {
$column = $this.Columns[$i]
$text = $this.AlignText($column.Name, $widths[$i], $column.Align)
if ($this.HeaderStyle) {
$text = $this.HeaderStyle.Apply($text)
}
[void]$output.Append(" $text ")
[void]$output.Append($box.vertical)
}
[void]$output.AppendLine()
# Separator after header
[void]$output.Append($box.left_join)
for ($i = 0; $i -lt $widths.Count; $i++) {
[void]$output.Append($box.horizontal * ($widths[$i] + 2))
if ($i -lt $widths.Count - 1) {
[void]$output.Append($box.cross)
}
}
[void]$output.AppendLine($box.right_join)
}
# Data rows
for ($rowIdx = 0; $rowIdx -lt $this.Rows.Count; $rowIdx++) {
$row = $this.Rows[$rowIdx]
[void]$output.Append($box.vertical)
for ($i = 0; $i -lt $this.Columns.Count; $i++) {
$column = $this.Columns[$i]
$cellValue = if ($i -lt $row.Count) { $row[$i] } else { "" }
$text = $this.AlignText($cellValue, $widths[$i], $column.Align)
if ($column.Style) {
$text = $column.Style.Apply($text)
} elseif ($this.RowStyle) {
$text = $this.RowStyle.Apply($text)
}
[void]$output.Append(" $text ")
[void]$output.Append($box.vertical)
}
[void]$output.AppendLine()
# Row separator (if ShowLines is true)
if ($this.ShowLines -and $rowIdx -lt $this.Rows.Count - 1) {
[void]$output.Append($box.left_join)
for ($i = 0; $i -lt $widths.Count; $i++) {
[void]$output.Append($box.horizontal * ($widths[$i] + 2))
if ($i -lt $widths.Count - 1) {
[void]$output.Append($box.cross)
}
}
[void]$output.AppendLine($box.right_join)
}
}
# Bottom border
[void]$output.Append($box.bottom_left)
for ($i = 0; $i -lt $widths.Count; $i++) {
[void]$output.Append($box.horizontal * ($widths[$i] + 2))
if ($i -lt $widths.Count - 1) {
[void]$output.Append($box.bottom_join)
}
}
[void]$output.Append($box.bottom_right)
return $output.ToString()
}
}
# Helper function to create and render a table
function New-RichTable {
param(
[string]$Title,
[string]$BoxStyle = "rounded",
[switch]$ShowLines,
[switch]$HideHeader
)
$table = [RichTable]::new()
if ($Title) { $table.Title = $Title }
$table.BoxStyle = $BoxStyle
$table.ShowLines = $ShowLines.IsPresent
$table.ShowHeader = -not $HideHeader.IsPresent
return $table
}

View file

@ -0,0 +1,65 @@
#!/usr/bin/env pwsh
#Requires -Version 7.0
# Example 1: Using Colors with RichPS7
# Import the module
Import-Module "$PSScriptRoot/../RichPS7.psd1" -Force
Write-Host "`n=== RichPS7 Color Examples ===`n" -ForegroundColor Cyan
# Example 1: Named colors
Write-Rich "This is red text" -Color (New-RichColor 'red')
Write-Rich "This is green text" -Color (New-RichColor 'green')
Write-Rich "This is blue text" -Color (New-RichColor 'blue')
Write-Rich "This is yellow text" -Color (New-RichColor 'yellow')
Write-Rich "This is magenta text" -Color (New-RichColor 'magenta')
Write-Rich "This is cyan text" -Color (New-RichColor 'cyan')
Write-Host "`n--- Bright Colors ---`n"
Write-Rich "This is bright red" -Color (New-RichColor 'bright_red')
Write-Rich "This is bright green" -Color (New-RichColor 'bright_green')
Write-Rich "This is bright blue" -Color (New-RichColor 'bright_blue')
Write-Host "`n--- Hex Colors ---`n"
Write-Rich "This is orange (#FFA500)" -Color (New-RichColor '#FFA500')
Write-Rich "This is purple (#9B59B6)" -Color (New-RichColor '#9B59B6')
Write-Rich "This is pink (#FF69B4)" -Color (New-RichColor '#FF69B4')
Write-Host "`n--- RGB Colors ---`n"
$color1 = [RichColor]::new(255, 100, 50) # Orange-red
Write-Rich "Custom RGB: (255, 100, 50)" -Color $color1
$color2 = [RichColor]::new(50, 200, 150) # Teal
Write-Rich "Custom RGB: (50, 200, 150)" -Color $color2
Write-Host "`n--- Text Styles ---`n"
Write-Rich "Bold text" -Bold
Write-Rich "Italic text" -Italic
Write-Rich "Underlined text" -Underline
Write-Rich "Bold + Italic + Underline" -Bold -Italic -Underline
Write-Host "`n--- Combined Styles ---`n"
$style1 = New-RichStyle -ForegroundColor (New-RichColor 'cyan') -Bold
Write-Rich "Bold Cyan Text" -Style $style1
$style2 = New-RichStyle -ForegroundColor (New-RichColor 'yellow') -BackgroundColor (New-RichColor 'blue') -Bold
Write-Rich "Yellow on Blue Background" -Style $style2
$style3 = New-RichStyle -ForegroundColor (New-RichColor '#FF1493') -Italic -Underline
Write-Rich "Hot Pink with Italic and Underline" -Style $style3
Write-Host "`n--- Using the Console Object ---`n"
$console = Get-RichConsole
$console.Info("This is an info message")
$console.Warning("This is a warning message")
$console.Error("This is an error message")
$console.Success("This is a success message")
Write-Host ""

View file

@ -0,0 +1,83 @@
#!/usr/bin/env pwsh
#Requires -Version 7.0
# Example 2: Using Tables with RichPS7
# Import the module
Import-Module "$PSScriptRoot/../RichPS7.psd1" -Force
Write-Host "`n=== RichPS7 Table Examples ===`n" -ForegroundColor Cyan
# Example 1: Simple table
Write-Host "--- Simple Table ---`n"
$table1 = New-RichTable -Title "System Information"
$table1.AddColumn("Property")
$table1.AddColumn("Value")
$table1.AddRow(@("OS", $PSVersionTable.OS))
$table1.AddRow(@("PowerShell Version", $PSVersionTable.PSVersion))
$table1.AddRow(@("Edition", $PSVersionTable.PSEdition))
$table1.AddRow(@("Platform", $PSVersionTable.Platform))
Write-Host $table1.Render()
# Example 2: Table with different box styles
Write-Host "`n--- Different Box Styles ---`n"
foreach ($style in @('rounded', 'square', 'double', 'simple')) {
$table = New-RichTable -BoxStyle $style
$table.AddColumn("Style")
$table.AddColumn("Description")
$table.AddRow(@($style, "This table uses the '$style' box style"))
Write-Host $table.Render()
Write-Host ""
}
# Example 3: Table with alignment
Write-Host "`n--- Table with Alignment ---`n"
$table2 = New-RichTable -Title "Product Pricing"
$table2.AddColumn("Product", @{ Align = 'left' })
$table2.AddColumn("Price", @{ Align = 'right' })
$table2.AddColumn("Quantity", @{ Align = 'center' })
$table2.AddRow(@("Widget", "$19.99", "42"))
$table2.AddRow(@("Gadget", "$29.99", "17"))
$table2.AddRow(@("Doohickey", "$9.99", "103"))
$table2.AddRow(@("Thingamajig", "$49.99", "8"))
Write-Host $table2.Render()
# Example 4: Table with row lines
Write-Host "`n--- Table with Row Lines ---`n"
$table3 = New-RichTable -Title "Server Status" -ShowLines
$table3.AddColumn("Server")
$table3.AddColumn("Status")
$table3.AddColumn("Uptime")
$table3.AddRow(@("web-01", "Running", "45d 12h"))
$table3.AddRow(@("web-02", "Running", "32d 8h"))
$table3.AddRow(@("db-01", "Running", "127d 4h"))
$table3.AddRow(@("cache-01", "Stopped", "0d 0h"))
Write-Host $table3.Render()
# Example 5: Process information table
Write-Host "`n--- Process Information ---`n"
$table4 = New-RichTable -Title "Top Processes by Memory" -BoxStyle "double"
$table4.AddColumn("Process", @{ Align = 'left' })
$table4.AddColumn("PID", @{ Align = 'right' })
$table4.AddColumn("Memory (MB)", @{ Align = 'right' })
$processes = Get-Process | Sort-Object -Property WS -Descending | Select-Object -First 5
foreach ($proc in $processes) {
$memMB = [math]::Round($proc.WS / 1MB, 2)
$table4.AddRow(@($proc.ProcessName, $proc.Id, $memMB))
}
Write-Host $table4.Render()
Write-Host ""

View file

@ -0,0 +1,93 @@
#!/usr/bin/env pwsh
#Requires -Version 7.0
# Example 3: Using Panels with RichPS7
# Import the module
Import-Module "$PSScriptRoot/../RichPS7.psd1" -Force
Write-Host "`n=== RichPS7 Panel Examples ===`n" -ForegroundColor Cyan
# Example 1: Simple panel
Write-Host "--- Simple Panel ---`n"
$panel1 = New-RichPanel -Content "This is a simple panel with default styling."
Write-Host $panel1.Render()
# Example 2: Panel with title
Write-Host "`n--- Panel with Title ---`n"
$panel2 = New-RichPanel -Content "This panel has a title!" -Title "Welcome"
Write-Host $panel2.Render()
# Example 3: Different box styles
Write-Host "`n--- Different Box Styles ---`n"
foreach ($style in @('rounded', 'square', 'double', 'heavy')) {
$content = "This panel uses the '$style' box style."
$panel = New-RichPanel -Content $content -Title $style.ToUpper() -BoxStyle $style
Write-Host $panel.Render()
Write-Host ""
}
# Example 4: Panel with title alignment
Write-Host "`n--- Title Alignment ---`n"
$panel3 = New-RichPanel -Content "Left-aligned title" -Title "LEFT" -TitleAlign "left"
Write-Host $panel3.Render()
Write-Host ""
$panel4 = New-RichPanel -Content "Center-aligned title" -Title "CENTER" -TitleAlign "center"
Write-Host $panel4.Render()
Write-Host ""
$panel5 = New-RichPanel -Content "Right-aligned title" -Title "RIGHT" -TitleAlign "right"
Write-Host $panel5.Render()
# Example 5: Panel with subtitle
Write-Host "`n--- Panel with Subtitle ---`n"
$panel6 = New-RichPanel -Content "This panel has both a title and a subtitle." -Title "Main Title" -Subtitle "Subtitle here"
Write-Host $panel6.Render()
# Example 6: Multi-line content
Write-Host "`n--- Multi-line Content ---`n"
$content = @"
This panel contains multiple lines of text.
Each line is displayed within the panel.
You can include as many lines as you want!
This is useful for displaying:
- Instructions
- Status messages
- Help text
- And much more!
"@
$panel7 = New-RichPanel -Content $content -Title "Multi-line Panel" -BoxStyle "double"
Write-Host $panel7.Render()
# Example 7: Styled panels
Write-Host "`n--- Styled Panels ---`n"
$titleStyle = New-RichStyle -ForegroundColor (New-RichColor 'yellow') -Bold
$borderStyle = New-RichStyle -ForegroundColor (New-RichColor 'cyan')
$contentStyle = New-RichStyle -ForegroundColor (New-RichColor 'green')
$panel8 = New-RichPanel -Content "This panel has custom styles!" -Title "Styled Panel" -TitleStyle $titleStyle -BorderStyle $borderStyle -ContentStyle $contentStyle
Write-Host $panel8.Render()
# Example 8: Information panel
Write-Host "`n--- Information Panel ---`n"
$info = @"
PowerShell Version: $($PSVersionTable.PSVersion)
OS: $($PSVersionTable.OS)
Edition: $($PSVersionTable.PSEdition)
"@
$panel9 = New-RichPanel -Content $info -Title "System Information" -BoxStyle "rounded" -Padding 2
Write-Host $panel9.Render()
Write-Host ""

View file

@ -0,0 +1,136 @@
#!/usr/bin/env pwsh
#Requires -Version 7.0
# Example 4: Using Progress Bars with RichPS7
# Import the module
Import-Module "$PSScriptRoot/../RichPS7.psd1" -Force
Write-Host "`n=== RichPS7 Progress Examples ===`n" -ForegroundColor Cyan
# Example 1: Simple progress with Invoke-RichProgress
Write-Host "--- Simple Progress Example ---`n"
$items = 1..20
Invoke-RichProgress -Description "Processing items" -Collection $items -ScriptBlock {
param($item)
# Simulate some work
Start-Sleep -Milliseconds 100
}
Write-Host "`n--- Multiple Tasks ---`n"
# Example 2: Multiple progress bars
$progress = New-RichProgress
# Add multiple tasks
$task1 = $progress.AddTask("Downloading files", 50)
$task2 = $progress.AddTask("Processing data", 100)
$task3 = $progress.AddTask("Uploading results", 30)
$progress.Start()
try {
# Simulate progress on multiple tasks
$random = [Random]::new()
while (-not $progress.IsComplete()) {
# Randomly advance tasks
if (-not $task1.IsComplete) {
$task1.Advance($random.Next(1, 5))
}
if (-not $task2.IsComplete) {
$task2.Advance($random.Next(1, 3))
}
if (-not $task3.IsComplete) {
$task3.Advance($random.Next(1, 4))
}
# Refresh display
$progress.Refresh()
# Small delay
Start-Sleep -Milliseconds 50
}
# Show final state
$progress.Refresh()
Start-Sleep -Milliseconds 500
} finally {
$progress.Stop()
}
Write-Host "`n--- File Processing Simulation ---`n"
# Example 3: Simulating file processing
$files = @(
"document1.pdf"
"document2.pdf"
"document3.pdf"
"spreadsheet1.xlsx"
"spreadsheet2.xlsx"
"presentation1.pptx"
"presentation2.pptx"
"image1.jpg"
"image2.jpg"
"image3.jpg"
)
Invoke-RichProgress -Description "Converting files" -Collection $files -ScriptBlock {
param($file)
# Simulate file processing time based on extension
$delay = switch -Regex ($file) {
'\.pdf$' { 200 }
'\.xlsx$' { 150 }
'\.pptx$' { 180 }
'\.jpg$' { 50 }
default { 100 }
}
Start-Sleep -Milliseconds $delay
}
Write-Host "`n--- Custom Progress Bar ---`n"
# Example 4: Single task with manual updates
$progress2 = New-RichProgress
$task = $progress2.AddTask("Installing packages", 10)
# Customize colors
$task.CompleteColor = New-RichColor 'cyan'
$task.RemainingColor = New-RichColor 'bright_black'
$progress2.Start()
try {
$packages = @(
"core-utils"
"network-tools"
"security-suite"
"dev-dependencies"
"runtime-libraries"
"documentation"
"examples"
"tests"
"benchmarks"
"tools"
)
foreach ($pkg in $packages) {
$task.Description = "Installing $pkg".PadRight(30)
$progress2.Refresh()
Start-Sleep -Milliseconds ([Random]::new().Next(100, 300))
$task.Advance(1)
}
$task.Description = "Installation complete!".PadRight(30)
$progress2.Refresh()
Start-Sleep -Milliseconds 500
} finally {
$progress2.Stop()
}
Write-Host ""

View file

@ -0,0 +1,197 @@
#!/usr/bin/env pwsh
#Requires -Version 7.0
# Example 5: Complete RichPS7 Demo - All Features
# Import the module
Import-Module "$PSScriptRoot/../RichPS7.psd1" -Force
$console = Get-RichConsole
# Clear screen
$console.Clear()
# Title
$console.NewLine()
$titleStyle = New-RichStyle -ForegroundColor (New-RichColor 'cyan') -Bold
Write-Rich "╔══════════════════════════════════════════════════════════╗" -Style $titleStyle
Write-Rich "║ RichPS7 - Complete Feature Demo ║" -Style $titleStyle
Write-Rich "║ Beautiful Terminal Formatting for PowerShell 7 ║" -Style $titleStyle
Write-Rich "╚══════════════════════════════════════════════════════════╝" -Style $titleStyle
$console.NewLine()
# Introduction panel
$intro = @"
Welcome to RichPS7!
This demo showcases all the core features:
Colors and text styling
Tables with various formats
Panels with borders
Progress bars with ETA
"@
$panel = New-RichPanel -Content $intro -Title "Introduction" -BoxStyle "rounded"
Write-Host $panel.Render()
Start-Sleep -Seconds 2
# Rule separator
$console.NewLine()
$console.Rule("FEATURE 1: Colors & Styles", (New-RichColor 'yellow'))
$console.NewLine()
# Color demonstration
Write-Rich "Bold text example" -Bold
Write-Rich "Italic text example" -Italic
Write-Rich "Underlined text example" -Underline
$console.NewLine()
Write-Rich "Rainbow colors:" -Bold
$colors = @('red', 'yellow', 'green', 'cyan', 'blue', 'magenta')
foreach ($color in $colors) {
Write-Rich "" -Color (New-RichColor $color) -NoNewline
}
$console.NewLine(2)
Start-Sleep -Seconds 2
# Table demonstration
$console.Rule("FEATURE 2: Tables", (New-RichColor 'green'))
$console.NewLine()
$table = New-RichTable -Title "System Resources" -BoxStyle "double"
$table.AddColumn("Resource", @{ Align = 'left' })
$table.AddColumn("Usage", @{ Align = 'right' })
$table.AddColumn("Status", @{ Align = 'center' })
# Get actual system info
$cpu = Get-Counter '\Processor(_Total)\% Processor Time' -ErrorAction SilentlyContinue
$cpuUsage = if ($cpu) { [math]::Round($cpu.CounterSamples.CookedValue, 1) } else { "N/A" }
$memory = Get-CimInstance -ClassName Win32_OperatingSystem -ErrorAction SilentlyContinue
if (-not $memory) {
# Try Linux approach
$memInfo = Get-Content /proc/meminfo -ErrorAction SilentlyContinue
if ($memInfo) {
$total = ($memInfo | Select-String "MemTotal" | ForEach-Object { ($_ -split '\s+')[1] }) / 1024
$available = ($memInfo | Select-String "MemAvailable" | ForEach-Object { ($_ -split '\s+')[1] }) / 1024
$memUsage = [math]::Round((($total - $available) / $total) * 100, 1)
} else {
$memUsage = "N/A"
}
} else {
$memUsage = [math]::Round((($memory.TotalVisibleMemorySize - $memory.FreePhysicalMemory) / $memory.TotalVisibleMemorySize) * 100, 1)
}
$diskUsage = "N/A"
try {
$disk = Get-PSDrive -Name C -ErrorAction SilentlyContinue
if ($disk) {
$diskUsage = [math]::Round(($disk.Used / ($disk.Used + $disk.Free)) * 100, 1)
} else {
# Try Linux root
$disk = Get-PSDrive -Name / -ErrorAction SilentlyContinue
if ($disk) {
$diskUsage = [math]::Round(($disk.Used / ($disk.Used + $disk.Free)) * 100, 1)
}
}
} catch {
$diskUsage = "N/A"
}
$table.AddRow(@("CPU", "$cpuUsage%", "OK"))
$table.AddRow(@("Memory", "$memUsage%", "OK"))
$table.AddRow(@("Disk", "$diskUsage%", "OK"))
$table.AddRow(@("Network", "12.5 Mbps", "OK"))
Write-Host $table.Render()
$console.NewLine()
Start-Sleep -Seconds 2
# Panel demonstration
$console.Rule("FEATURE 3: Panels", (New-RichColor 'magenta'))
$console.NewLine()
$infoContent = @"
Current Time: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
User: $env:USER
PowerShell: $($PSVersionTable.PSVersion)
"@
$infoPanel = New-RichPanel -Content $infoContent -Title "Session Info" -BoxStyle "heavy" -TitleAlign "center"
Write-Host $infoPanel.Render()
$console.NewLine()
Start-Sleep -Seconds 2
# Progress demonstration
$console.Rule("FEATURE 4: Progress Bars", (New-RichColor 'cyan'))
$console.NewLine()
Write-Host "Simulating a download process...`n"
$progress = New-RichProgress
$download = $progress.AddTask("Downloading package", 100)
$extract = $progress.AddTask("Extracting files", 50)
$install = $progress.AddTask("Installing", 25)
$download.CompleteColor = New-RichColor 'green'
$extract.CompleteColor = New-RichColor 'cyan'
$install.CompleteColor = New-RichColor 'yellow'
$progress.Start()
try {
# Simulate download
while ($download.Current -lt $download.Total) {
$download.Advance([Random]::new().Next(2, 8))
$progress.Refresh()
Start-Sleep -Milliseconds 30
}
# Simulate extract
while ($extract.Current -lt $extract.Total) {
$extract.Advance([Random]::new().Next(1, 5))
$progress.Refresh()
Start-Sleep -Milliseconds 50
}
# Simulate install
while ($install.Current -lt $install.Total) {
$install.Advance([Random]::new().Next(1, 3))
$progress.Refresh()
Start-Sleep -Milliseconds 80
}
$progress.Refresh()
Start-Sleep -Milliseconds 500
} finally {
$progress.Stop()
}
# Completion message
$console.NewLine()
$console.Rule("Demo Complete!", (New-RichColor 'green'))
$console.NewLine()
$outro = @"
Thank you for trying RichPS7!
To get started:
Import-Module RichPS7
Get-Command -Module RichPS7
Check out the Examples directory for more demos.
"@
$outroPanel = New-RichPanel -Content $outro -Title "Next Steps" -Subtitle "Happy Scripting!" -BoxStyle "rounded"
Write-Host $outroPanel.Render()
$console.NewLine()
$console.Success("Demo completed successfully!")
$console.NewLine()

286
RichPS7/QUICKSTART.md Normal file
View file

@ -0,0 +1,286 @@
# RichPS7 Quick Start Guide
Get up and running with RichPS7 in 5 minutes!
## Installation
```powershell
# Clone or download, then import
Import-Module ./RichPS7/RichPS7.psd1
```
## 5-Minute Tutorial
### 1. Print Colored Text (30 seconds)
```powershell
# Simple colored text
Write-Rich "Success!" -Color (New-RichColor 'green') -Bold
# Use the console for themed messages
$console = Get-RichConsole
$console.Info("Information message")
$console.Warning("Warning message")
$console.Error("Error message")
$console.Success("Success message")
```
### 2. Create a Table (1 minute)
```powershell
# Create a table
$table = New-RichTable -Title "My First Table"
# Add columns
$table.AddColumn("Name")
$table.AddColumn("Status")
$table.AddColumn("Count")
# Add rows
$table.AddRow(@("Item 1", "Active", "42"))
$table.AddRow(@("Item 2", "Inactive", "17"))
$table.AddRow(@("Item 3", "Active", "99"))
# Render it
Write-Host $table.Render()
```
### 3. Create a Panel (1 minute)
```powershell
# Simple panel
$panel = New-RichPanel -Content "Hello from RichPS7!" -Title "Welcome"
Write-Host $panel.Render()
# Multi-line panel
$content = @"
This is a panel with multiple lines.
You can include any text you want.
Perfect for highlighting important information!
"@
$panel = New-RichPanel -Content $content -Title "Info" -BoxStyle "double"
Write-Host $panel.Render()
```
### 4. Show Progress (1 minute)
```powershell
# Simple progress bar
$items = 1..50
Invoke-RichProgress -Description "Processing" -Collection $items -ScriptBlock {
param($item)
Start-Sleep -Milliseconds 50 # Your work here
}
```
### 5. Combine Everything (1.5 minutes)
```powershell
# Clear screen and show a complete example
$console = Get-RichConsole
$console.Clear()
# Title
$console.Rule("System Report", (New-RichColor 'cyan'))
$console.NewLine()
# Info panel
$info = @"
Generated: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
PowerShell: $($PSVersionTable.PSVersion)
"@
$panel = New-RichPanel -Content $info -Title "Report Info"
Write-Host $panel.Render()
$console.NewLine()
# Data table
$table = New-RichTable -Title "System Processes" -BoxStyle "rounded"
$table.AddColumn("Process")
$table.AddColumn("PID", @{ Align = 'right' })
$table.AddColumn("Memory (MB)", @{ Align = 'right' })
Get-Process | Select-Object -First 5 | ForEach-Object {
$memMB = [math]::Round($_.WS / 1MB, 1)
$table.AddRow(@($_.ProcessName, $_.Id, $memMB))
}
Write-Host $table.Render()
$console.NewLine()
# Success message
$console.Success("Report generated successfully!")
```
## Next Steps
### Explore Examples
Run the complete demo:
```powershell
./RichPS7/Examples/05-Complete-Demo.ps1
```
Or explore individual examples:
- `01-Colors.ps1` - Colors and text styling
- `02-Tables.ps1` - Table formatting
- `03-Panels.ps1` - Panel styles
- `04-Progress.ps1` - Progress bars
### Customize Your Output
#### Box Styles
Tables and panels support multiple box styles:
```powershell
# Try different styles
foreach ($style in @('rounded', 'square', 'double', 'heavy', 'simple')) {
$panel = New-RichPanel -Content "Using $style style" -Title $style -BoxStyle $style
Write-Host $panel.Render()
}
```
#### Color Schemes
Create custom color schemes:
```powershell
# Define your colors
$primary = New-RichColor '#3498db' # Blue
$success = New-RichColor '#2ecc71' # Green
$warning = New-RichColor '#f39c12' # Orange
$danger = New-RichColor '#e74c3c' # Red
# Use them
Write-Rich "Primary action" -Color $primary -Bold
Write-Rich "Success!" -Color $success
Write-Rich "Warning!" -Color $warning
Write-Rich "Error!" -Color $danger
```
#### Style Presets
Create reusable styles:
```powershell
# Define styles
$headerStyle = New-RichStyle -ForegroundColor (New-RichColor 'cyan') -Bold
$errorStyle = New-RichStyle -ForegroundColor (New-RichColor 'red') -Bold -Underline
$codeStyle = New-RichStyle -ForegroundColor (New-RichColor 'green') -BackgroundColor (New-RichColor 'black')
# Use them
Write-Rich "=== Header ===" -Style $headerStyle
Write-Rich "Error occurred!" -Style $errorStyle
Write-Rich "code snippet" -Style $codeStyle
```
### Real-World Use Cases
#### Script Progress Tracking
```powershell
function Process-Files {
param([string[]]$Files)
Invoke-RichProgress -Description "Processing files" -Collection $Files -ScriptBlock {
param($file)
# Process each file
# ...
}
}
```
#### Status Reports
```powershell
function Show-SystemStatus {
$console = Get-RichConsole
$console.Rule("System Status Report", (New-RichColor 'cyan'))
$console.NewLine()
# CPU Check
if ($cpuUsage -lt 80) {
$console.Success("CPU: OK ($cpuUsage%)")
} else {
$console.Warning("CPU: High ($cpuUsage%)")
}
# Memory Check
if ($memUsage -lt 90) {
$console.Success("Memory: OK ($memUsage%)")
} else {
$console.Error("Memory: Critical ($memUsage%)")
}
}
```
#### Configuration Display
```powershell
function Show-Config {
param($Config)
$table = New-RichTable -Title "Configuration" -BoxStyle "double"
$table.AddColumn("Setting")
$table.AddColumn("Value")
foreach ($key in $Config.Keys) {
$table.AddRow(@($key, $Config[$key]))
}
Write-Host $table.Render()
}
```
## Tips & Tricks
1. **Auto-width tables**: Don't specify column widths - they'll auto-size to content
2. **Multi-line panels**: Use here-strings (`@"..."@`) for multi-line panel content
3. **Console theme**: Customize the global console's theme colors
4. **Progress ETA**: Progress bars automatically calculate and display ETA
5. **Style combinations**: You can combine multiple style attributes (bold + italic + color)
## Getting Help
```powershell
# List all available functions
Get-Command -Module RichPS7
# Get help for a specific function
Get-Help New-RichTable -Full
Get-Help Write-Rich -Examples
```
## Troubleshooting
### Colors not showing?
Make sure you're using PowerShell 7+ and a modern terminal:
```powershell
# Check PowerShell version
$PSVersionTable.PSVersion
# Should be 7.0 or higher
```
### Module not loading?
```powershell
# Try explicit import
Import-Module ./RichPS7/RichPS7.psd1 -Force -Verbose
# Check for errors
$Error[0] | Format-List -Force
```
## Ready to Learn More?
Check out the full [README.md](README.md) for complete API documentation and advanced features!
---
Happy scripting with RichPS7! 🎨✨

384
RichPS7/README.md Normal file
View file

@ -0,0 +1,384 @@
# RichPS7
**Beautiful terminal formatting for PowerShell 7**
RichPS7 is a PowerShell 7 port of Python's popular [Rich](https://github.com/Textualize/rich) library. It brings beautiful terminal formatting, colors, tables, panels, and progress bars to your PowerShell scripts.
![PowerShell Version](https://img.shields.io/badge/PowerShell-7.0+-blue.svg)
![License](https://img.shields.io/badge/license-MIT-green.svg)
## Features
- 🎨 **Rich Colors**: RGB, hex codes, and named colors with full ANSI support
- ✨ **Text Styling**: Bold, italic, underline, strikethrough, and dim text
- 📊 **Tables**: Beautiful tables with multiple box styles and alignment options
- 📦 **Panels**: Bordered panels with titles, subtitles, and custom styles
- 📈 **Progress Bars**: Live-updating progress bars with ETA estimation
- 🖥️ **Console**: Powerful console abstraction with themed output
- 🌈 **Cross-platform**: Works on Windows, macOS, and Linux
## Requirements
- PowerShell 7.0 or higher
- A terminal with ANSI color support (Windows Terminal, iTerm2, etc.)
## Installation
### Option 1: Direct Import
1. Clone or download this repository
2. Import the module:
```powershell
Import-Module ./RichPS7/RichPS7.psd1
```
### Option 2: Install to PowerShell Modules Directory
1. Copy the `RichPS7` folder to your PowerShell modules directory:
```powershell
# Windows
Copy-Item -Recurse ./RichPS7 "$env:USERPROFILE\Documents\PowerShell\Modules\"
# macOS/Linux
Copy-Item -Recurse ./RichPS7 "~/.local/share/powershell/Modules/"
```
2. Import the module:
```powershell
Import-Module RichPS7
```
### Option 3: Add to Profile
Add the import statement to your PowerShell profile for automatic loading:
```powershell
# Open your profile
notepad $PROFILE
# Add this line:
Import-Module RichPS7
```
## Quick Start
```powershell
# Import the module
Import-Module RichPS7
# Print colored text
Write-Rich "Hello, World!" -Color (New-RichColor 'cyan') -Bold
# Create a table
$table = New-RichTable -Title "System Info"
$table.AddColumn("Property")
$table.AddColumn("Value")
$table.AddRow(@("OS", $PSVersionTable.OS))
$table.AddRow(@("PowerShell", $PSVersionTable.PSVersion))
Write-Host $table.Render()
# Create a panel
$panel = New-RichPanel -Content "Important message!" -Title "Alert" -BoxStyle "double"
Write-Host $panel.Render()
# Show a progress bar
Invoke-RichProgress -Description "Processing" -Collection (1..50) -ScriptBlock {
param($item)
Start-Sleep -Milliseconds 50
}
```
## Usage Guide
### Colors
RichPS7 supports multiple ways to specify colors:
```powershell
# Named colors
$red = New-RichColor 'red'
$blue = New-RichColor 'blue'
$brightGreen = New-RichColor 'bright_green'
# Hex colors
$orange = New-RichColor '#FFA500'
$purple = New-RichColor '#9B59B6'
# RGB colors
$custom = [RichColor]::new(255, 128, 64)
# Use colors
Write-Rich "Colored text!" -Color $red
```
**Available named colors:**
- Basic: `black`, `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, `white`
- Bright: `bright_black`, `bright_red`, `bright_green`, `bright_yellow`, `bright_blue`, `bright_magenta`, `bright_cyan`, `bright_white`
- Others: `gray`, `grey`, `orange`, `purple`, `pink`
### Text Styling
Apply various text styles to your output:
```powershell
# Individual styles
Write-Rich "Bold text" -Bold
Write-Rich "Italic text" -Italic
Write-Rich "Underlined text" -Underline
# Combined styles
Write-Rich "Bold and Italic" -Bold -Italic
# Using style objects
$style = New-RichStyle -ForegroundColor (New-RichColor 'cyan') -Bold -Underline
Write-Rich "Styled text" -Style $style
# Foreground and background colors
$style = New-RichStyle `
-ForegroundColor (New-RichColor 'yellow') `
-BackgroundColor (New-RichColor 'blue') `
-Bold
Write-Rich "Yellow on blue" -Style $style
```
### Console
The console object provides themed output and utilities:
```powershell
$console = Get-RichConsole
# Themed messages
$console.Info("Information message")
$console.Warning("Warning message")
$console.Error("Error message")
$console.Success("Success message")
# Rules (horizontal lines)
$console.Rule()
$console.Rule("Section Title")
$console.Rule("Colored Rule", (New-RichColor 'cyan'))
# Utilities
$console.NewLine()
$console.NewLine(3) # Multiple blank lines
$console.Clear() # Clear screen
```
### Tables
Create beautiful tables with various options:
```powershell
# Basic table
$table = New-RichTable
$table.AddColumn("Name")
$table.AddColumn("Age")
$table.AddRow(@("Alice", "30"))
$table.AddRow(@("Bob", "25"))
Write-Host $table.Render()
# Table with title and custom box style
$table = New-RichTable -Title "Users" -BoxStyle "double"
# Columns with alignment
$table.AddColumn("Product", @{ Align = 'left' })
$table.AddColumn("Price", @{ Align = 'right' })
$table.AddColumn("Qty", @{ Align = 'center' })
# Add rows
$table.AddRow(@("Widget", "$19.99", "42"))
$table.AddRow(@("Gadget", "$29.99", "17"))
Write-Host $table.Render()
# Table with row separators
$table = New-RichTable -ShowLines
# ... add columns and rows ...
Write-Host $table.Render()
# Available box styles: 'rounded', 'square', 'double', 'simple'
```
### Panels
Create bordered panels for highlighting content:
```powershell
# Simple panel
$panel = New-RichPanel -Content "Hello, World!"
Write-Host $panel.Render()
# Panel with title
$panel = New-RichPanel -Content "Important info" -Title "Alert"
Write-Host $panel.Render()
# Panel with subtitle
$panel = New-RichPanel `
-Content "Content here" `
-Title "Main Title" `
-Subtitle "Subtitle"
Write-Host $panel.Render()
# Multi-line content
$content = @"
Line 1
Line 2
Line 3
"@
$panel = New-RichPanel -Content $content -Title "Multi-line"
Write-Host $panel.Render()
# Custom styling
$titleStyle = New-RichStyle -ForegroundColor (New-RichColor 'yellow') -Bold
$borderStyle = New-RichStyle -ForegroundColor (New-RichColor 'cyan')
$panel = New-RichPanel `
-Content "Styled panel" `
-Title "Custom" `
-TitleStyle $titleStyle `
-BorderStyle $borderStyle `
-BoxStyle "double"
Write-Host $panel.Render()
# Box styles: 'rounded', 'square', 'double', 'heavy', 'simple'
# Title alignment: 'left', 'center', 'right'
```
### Progress Bars
Show progress for long-running operations:
```powershell
# Simple progress with Invoke-RichProgress
$items = 1..100
Invoke-RichProgress -Description "Processing items" -Collection $items -ScriptBlock {
param($item)
# Do work here
Start-Sleep -Milliseconds 50
}
# Manual progress control
$progress = New-RichProgress
$task = $progress.AddTask("Downloading", 100)
$progress.Start()
try {
for ($i = 0; $i -lt 100; $i++) {
$task.Advance(1)
$progress.Refresh()
Start-Sleep -Milliseconds 50
}
} finally {
$progress.Stop()
}
# Multiple progress bars
$progress = New-RichProgress
$task1 = $progress.AddTask("Task 1", 50)
$task2 = $progress.AddTask("Task 2", 100)
$task3 = $progress.AddTask("Task 3", 75)
$progress.Start()
try {
while (-not $progress.IsComplete()) {
# Update tasks as needed
if (-not $task1.IsComplete) { $task1.Advance(1) }
if (-not $task2.IsComplete) { $task2.Advance(2) }
if (-not $task3.IsComplete) { $task3.Advance(1) }
$progress.Refresh()
Start-Sleep -Milliseconds 50
}
} finally {
$progress.Stop()
}
# Custom colors
$task.CompleteColor = New-RichColor 'cyan'
$task.RemainingColor = New-RichColor 'bright_black'
```
## Examples
Check out the `Examples` directory for complete demonstrations:
- `01-Colors.ps1` - Color and styling examples
- `02-Tables.ps1` - Table formatting examples
- `03-Panels.ps1` - Panel examples with various styles
- `04-Progress.ps1` - Progress bar examples
- `05-Complete-Demo.ps1` - Complete feature demonstration
Run an example:
```powershell
./RichPS7/Examples/05-Complete-Demo.ps1
```
## API Reference
### Functions
- `New-RichColor` - Create a color from name, hex, or RGB
- `New-RichStyle` - Create a text style with colors and attributes
- `Get-RichConsole` - Get the global console instance
- `Write-Rich` - Write styled text to the console
- `New-RichTable` - Create a new table
- `New-RichPanel` - Create a new panel
- `New-RichProgress` - Create a progress tracker
- `Invoke-RichProgress` - Simple progress tracking helper
### Classes
- `RichColor` - Color representation with ANSI code generation
- `RichStyle` - Text style with color and attributes
- `RichConsole` - Console output handler
- `RichTable` - Table renderer
- `RichPanel` - Panel renderer
- `RichProgress` - Progress tracker
- `RichProgressBar` - Individual progress bar
## Comparison with Python Rich
This PowerShell port includes the core features from Python's Rich library:
| Feature | Python Rich | RichPS7 |
|---------|-------------|---------|
| Colors (RGB/Hex/Named) | ✅ | ✅ |
| Text Styling | ✅ | ✅ |
| Tables | ✅ | ✅ |
| Panels | ✅ | ✅ |
| Progress Bars | ✅ | ✅ |
| Console | ✅ | ✅ |
| Syntax Highlighting | ✅ | ⏳ (future) |
| Markdown Rendering | ✅ | ⏳ (future) |
| Tracebacks | ✅ | ⏳ (future) |
| Tree Views | ✅ | ⏳ (future) |
| Live Display | ✅ | 🔶 (partial) |
✅ = Implemented | ⏳ = Planned | 🔶 = Partially implemented
## Contributing
Contributions are welcome! This is a community port of the Rich library.
## License
MIT License - see LICENSE file for details
## Credits
- Original Python Rich library by [Will McGugan](https://github.com/willmcgugan)
- Python Rich: https://github.com/Textualize/rich
## Links
- [Python Rich Documentation](https://rich.readthedocs.io/)
- [PowerShell Documentation](https://docs.microsoft.com/powershell/)
---
Made with ❤️ for the PowerShell community

84
RichPS7/RichPS7.psd1 Normal file
View file

@ -0,0 +1,84 @@
@{
# Script module or binary module file associated with this manifest.
RootModule = 'RichPS7.psm1'
# Version number of this module.
ModuleVersion = '0.1.0'
# ID used to uniquely identify this module
GUID = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'
# Author of this module
Author = 'RichPS7 Contributors'
# Company or vendor of this module
CompanyName = 'Community'
# Copyright statement for this module
Copyright = '(c) 2025 RichPS7 Contributors. MIT License.'
# Description of the functionality provided by this module
Description = 'A PowerShell 7 port of Pythons Rich library - Beautiful terminal formatting with colors, tables, panels, and progress bars. Provides ANSI styling, advanced text formatting, and rich UI components for the terminal.'
# Minimum version of the PowerShell engine required by this module
PowerShellVersion = '7.0'
# Functions to export from this module
FunctionsToExport = @(
'New-RichColor'
'New-RichStyle'
'Get-RichConsole'
'Write-Rich'
'New-RichTable'
'New-RichPanel'
'New-RichProgress'
'Invoke-RichProgress'
)
# Cmdlets to export from this module
CmdletsToExport = @()
# Variables to export from this module
VariablesToExport = @('RichConsole')
# Aliases to export from this module
AliasesToExport = @()
# Private data to pass to the module specified in RootModule/ModuleToProcess
PrivateData = @{
PSData = @{
# Tags applied to this module
Tags = @('Terminal', 'Console', 'Formatting', 'ANSI', 'Colors', 'Rich', 'UI', 'Table', 'Progress', 'Panel')
# A URL to the license for this module.
LicenseUri = 'https://opensource.org/licenses/MIT'
# A URL to the main website for this project.
ProjectUri = 'https://github.com/Textualize/rich'
# ReleaseNotes of this module
ReleaseNotes = @'
## Version 0.1.0 - Initial Release
Core Features:
- ANSI color support with RGB, named colors, and hex codes
- Text styling (bold, italic, underline, strike, dim)
- Console output with styled text
- Table rendering with multiple box styles and alignment
- Panel components with titles and borders
- Progress bars with ETA estimation
- Cross-platform support (PowerShell 7+)
Components:
- RichColor: Color handling and ANSI code generation
- RichStyle: Text styling and formatting
- RichConsole: Main console output interface
- RichTable: Table rendering with borders
- RichPanel: Panel components with decorative borders
- RichProgress: Progress tracking and display
This is a port of the Python Rich library's core functionality to PowerShell 7.
'@
}
}
}

33
RichPS7/RichPS7.psm1 Normal file
View file

@ -0,0 +1,33 @@
#Requires -Version 7.0
# RichPS7 - A PowerShell 7 port of Python's Rich library
# Beautiful terminal formatting for PowerShell
# Import classes in order (dependencies first)
. $PSScriptRoot\Classes\Color.ps1
. $PSScriptRoot\Classes\Style.ps1
. $PSScriptRoot\Classes\Console.ps1
. $PSScriptRoot\Classes\Table.ps1
. $PSScriptRoot\Classes\Panel.ps1
. $PSScriptRoot\Classes\Progress.ps1
# Export functions
Export-ModuleMember -Function @(
'New-RichColor'
'New-RichStyle'
'Get-RichConsole'
'Write-Rich'
'New-RichTable'
'New-RichPanel'
'New-RichProgress'
'Invoke-RichProgress'
)
# Export the global console variable
Export-ModuleMember -Variable 'RichConsole'
# Module initialization message
Write-Host "RichPS7 module loaded. " -NoNewline
Write-Host "Beautiful terminal formatting for PowerShell 7!" -ForegroundColor Cyan
Write-Host "Get started with: " -NoNewline
Write-Host "Get-Command -Module RichPS7" -ForegroundColor Yellow

View file

@ -0,0 +1,161 @@
#!/usr/bin/env pwsh
#Requires -Version 7.0
# Basic functionality test for RichPS7
Write-Host "=== RichPS7 Basic Functionality Test ===`n" -ForegroundColor Cyan
$testsPassed = 0
$testsFailed = 0
function Test-Feature {
param(
[string]$Name,
[scriptblock]$Test
)
Write-Host "Testing: $Name ... " -NoNewline
try {
& $Test
Write-Host "PASS" -ForegroundColor Green
$script:testsPassed++
return $true
} catch {
Write-Host "FAIL" -ForegroundColor Red
Write-Host " Error: $_" -ForegroundColor Red
$script:testsFailed++
return $false
}
}
# Import module
Write-Host "Importing RichPS7 module...`n"
try {
Import-Module "$PSScriptRoot/../RichPS7.psd1" -Force
Write-Host "Module imported successfully!`n" -ForegroundColor Green
} catch {
Write-Host "Failed to import module: $_" -ForegroundColor Red
exit 1
}
# Test 1: Color creation
Test-Feature "Color creation (named)" {
$color = New-RichColor 'red'
if (-not $color) { throw "Color creation failed" }
if ($color.Red -ne 255) { throw "Red value incorrect" }
}
Test-Feature "Color creation (hex)" {
$color = New-RichColor '#FF5733'
if (-not $color) { throw "Hex color creation failed" }
}
Test-Feature "Color creation (RGB)" {
$color = [RichColor]::new(100, 150, 200)
if ($color.Red -ne 100) { throw "RGB color creation failed" }
}
# Test 2: Style creation
Test-Feature "Style creation" {
$style = New-RichStyle -Bold -Italic
if (-not $style.Bold) { throw "Bold not set" }
if (-not $style.Italic) { throw "Italic not set" }
}
Test-Feature "Style with colors" {
$style = New-RichStyle -ForegroundColor (New-RichColor 'cyan')
if (-not $style.ForegroundColor) { throw "Foreground color not set" }
}
# Test 3: Console
Test-Feature "Console instance" {
$console = Get-RichConsole
if (-not $console) { throw "Console not created" }
}
# Test 4: Table creation
Test-Feature "Table creation" {
$table = New-RichTable
if (-not $table) { throw "Table creation failed" }
}
Test-Feature "Table with columns and rows" {
$table = New-RichTable
$table.AddColumn("Col1")
$table.AddColumn("Col2")
$table.AddRow(@("A", "B"))
if ($table.Columns.Count -ne 2) { throw "Column count incorrect" }
if ($table.Rows.Count -ne 1) { throw "Row count incorrect" }
}
Test-Feature "Table rendering" {
$table = New-RichTable
$table.AddColumn("Test")
$table.AddRow(@("Value"))
$output = $table.Render()
if (-not $output) { throw "Table rendering failed" }
if ($output.Length -lt 10) { throw "Table output too short" }
}
# Test 5: Panel creation
Test-Feature "Panel creation" {
$panel = New-RichPanel -Content "Test"
if (-not $panel) { throw "Panel creation failed" }
}
Test-Feature "Panel rendering" {
$panel = New-RichPanel -Content "Test content"
$output = $panel.Render()
if (-not $output) { throw "Panel rendering failed" }
if ($output.Length -lt 10) { throw "Panel output too short" }
}
Test-Feature "Panel with title" {
$panel = New-RichPanel -Content "Test" -Title "Title"
if ($panel.Title -ne "Title") { throw "Panel title not set" }
}
# Test 6: Progress
Test-Feature "Progress creation" {
$progress = New-RichProgress
if (-not $progress) { throw "Progress creation failed" }
}
Test-Feature "Progress task creation" {
$progress = New-RichProgress
$task = $progress.AddTask("Test", 100)
if (-not $task) { throw "Task creation failed" }
if ($task.Total -ne 100) { throw "Task total incorrect" }
}
Test-Feature "Progress advancement" {
$progress = New-RichProgress
$task = $progress.AddTask("Test", 100)
$task.Advance(50)
if ($task.Current -ne 50) { throw "Task advancement failed" }
}
# Test 7: Write-Rich function
Test-Feature "Write-Rich function exists" {
$command = Get-Command Write-Rich -ErrorAction SilentlyContinue
if (-not $command) { throw "Write-Rich function not found" }
}
# Summary
Write-Host "`n=== Test Summary ===" -ForegroundColor Cyan
Write-Host "Tests Passed: $testsPassed" -ForegroundColor Green
Write-Host "Tests Failed: $testsFailed" -ForegroundColor $(if ($testsFailed -gt 0) { 'Red' } else { 'Green' })
if ($testsFailed -eq 0) {
Write-Host "`nAll tests passed! ✓" -ForegroundColor Green
exit 0
} else {
Write-Host "`nSome tests failed! ✗" -ForegroundColor Red
exit 1
}