mirror of
https://github.com/Textualize/rich.git
synced 2025-12-23 07:08:35 +00:00
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:
parent
4d6d631a3d
commit
4ad22afa63
16 changed files with 2673 additions and 0 deletions
117
RichPS7/Classes/Color.ps1
Normal file
117
RichPS7/Classes/Color.ps1
Normal 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
188
RichPS7/Classes/Console.ps1
Normal 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
238
RichPS7/Classes/Panel.ps1
Normal 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
|
||||
}
|
||||
213
RichPS7/Classes/Progress.ps1
Normal file
213
RichPS7/Classes/Progress.ps1
Normal 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
110
RichPS7/Classes/Style.ps1
Normal 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
285
RichPS7/Classes/Table.ps1
Normal 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
|
||||
}
|
||||
65
RichPS7/Examples/01-Colors.ps1
Normal file
65
RichPS7/Examples/01-Colors.ps1
Normal 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 ""
|
||||
83
RichPS7/Examples/02-Tables.ps1
Normal file
83
RichPS7/Examples/02-Tables.ps1
Normal 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 ""
|
||||
93
RichPS7/Examples/03-Panels.ps1
Normal file
93
RichPS7/Examples/03-Panels.ps1
Normal 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 ""
|
||||
136
RichPS7/Examples/04-Progress.ps1
Normal file
136
RichPS7/Examples/04-Progress.ps1
Normal 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 ""
|
||||
197
RichPS7/Examples/05-Complete-Demo.ps1
Normal file
197
RichPS7/Examples/05-Complete-Demo.ps1
Normal 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
286
RichPS7/QUICKSTART.md
Normal 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
384
RichPS7/README.md
Normal 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.
|
||||
|
||||

|
||||

|
||||
|
||||
## 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
84
RichPS7/RichPS7.psd1
Normal 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
33
RichPS7/RichPS7.psm1
Normal 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
|
||||
161
RichPS7/Tests/Basic-Test.ps1
Normal file
161
RichPS7/Tests/Basic-Test.ps1
Normal 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
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue