Public/Out-rwMenuCLI.ps1
|
<# .SYNOPSIS Interactive menu helper that returns selected values. .DESCRIPTION Unified interface for single selection, multi-selection, and yes/no prompts. Automatically detects and uses Spectre.Console if available, falls back to CLI. .PARAMETER Title Question or heading. Default: "Options" .PARAMETER Options Menu choices (required for Single/Multiple modes). .PARAMETER OutputMode Prompt type: Single, Multiple, or YesNo. Default: Single. .PARAMETER DefaultSelection Zero-based index of default option (Single mode only). Default: -1. .PARAMETER CancelLabel Cancel button text. Default: "Cancel". .PARAMETER PreferredUI UI preference: Auto (detect), Spectre (force), or CLI (force). Default: Auto. .EXAMPLE $action = Out-rwMenuCLI -Title 'Choose' -Options @('Start','Stop') -OutputMode Single # Returns: "Start" or "Stop" .EXAMPLE $items = Out-rwMenuCLI -Title 'Pick' -Options @('A','B','C') -OutputMode Multiple # Returns: @('B','A') preserving user order .EXAMPLE if (Out-rwMenuCLI -Title 'Continue?' -OutputMode YesNo) { 'OK' } # Returns: $true or $false #> function Out-rwMenuCLI { [CmdletBinding()] [OutputType([string])] [OutputType([string[]])] [OutputType([bool])] param( [ValidateNotNullOrEmpty()] [ValidateLength(1, 200)] [string]$Title = 'Options', [string[]]$Options, [ValidateSet('Single','Multiple','YesNo')] [string]$OutputMode = 'Single', [int]$DefaultSelection = -1, [ValidateNotNullOrEmpty()] [ValidateLength(1, 100)] [string]$CancelLabel = 'Cancel', [ValidateSet('Auto','Spectre','CLI')] [string]$PreferredUI = 'Auto' ) Write-Verbose "Out-rwMenuCLI: Title='$Title' OutputMode='$OutputMode' Options.Count=$($Options.Count)" if ($OutputMode -in @('Single','Multiple') -and (-not $Options -or $Options.Count -eq 0)) { throw "Options are required for mode '$OutputMode'." } $options = if ($Options) { $Options | ForEach-Object { $_.ToString() } } else { @() } if ($OutputMode -eq 'Single' -and $options.Count -gt 0) { if ($DefaultSelection -lt -1 -or $DefaultSelection -ge $options.Count) { throw "DefaultSelection $DefaultSelection is outside the available options." } } if (Get-rwDirToolsAutomation) { return Get-rwAutomatedMenuSelection -OutputMode $OutputMode -Options $options -DefaultSelection $DefaultSelection } $useUI = if (Test-rwSpectreAvailable) { 'Spectre' } else { 'CLI' } if ($PreferredUI -eq 'CLI') { $useUI = 'CLI' } if ($PreferredUI -eq 'Spectre' -and $useUI -ne 'Spectre') { Write-Warning 'Spectre unavailable, using CLI' } if ($useUI -eq 'Spectre') { $result = Show-rwSpectreMenu -Title $Title -Options $options -OutputMode $OutputMode -DefaultSelection $DefaultSelection if ($null -eq $result -and $OutputMode -ne 'YesNo') { Write-Warning 'Spectre rendering failed, using CLI fallback' $result = Show-rwCLIMenu -Title $Title -Options $options -OutputMode $OutputMode -DefaultSelection $DefaultSelection -CancelLabel $CancelLabel } return $result } else { return Show-rwCLIMenu -Title $Title -Options $options -OutputMode $OutputMode -DefaultSelection $DefaultSelection -CancelLabel $CancelLabel } } function Get-rwAutomatedMenuSelection { param( [ValidateSet('Single','Multiple','YesNo')] [string]$OutputMode, [string[]]$Options, [int]$DefaultSelection = -1 ) if ($OutputMode -eq 'YesNo') { $raw = [Environment]::GetEnvironmentVariable('RW_DIRTOOLS_MENU_YESNO') $choice = if (-not [string]::IsNullOrWhiteSpace($raw)) { $raw -match '^(1|true|y|yes)$' } else { $true } return $choice } $rawSelection = [Environment]::GetEnvironmentVariable('RW_DIRTOOLS_MENU_SELECTION') $requested = @() if ($rawSelection) { $requested = @($rawSelection -split ',' | ForEach-Object { $trimmed = $_.Trim() if (-not [string]::IsNullOrWhiteSpace($trimmed)) { $parsed = 0 if ([int]::TryParse($trimmed, [ref]$parsed)) { $parsed } } }) } $validIndexes = @($requested | Where-Object { $_ -ge 0 -and $_ -lt $Options.Count }) if ($validIndexes.Count -eq 0) { if ($DefaultSelection -ge 0 -and $DefaultSelection -lt $Options.Count) { $validIndexes = @($DefaultSelection) } elseif ($Options.Count -gt 0) { $validIndexes = @(0) } } $selectedValues = @($validIndexes | ForEach-Object { $Options[$_] }) if ($OutputMode -eq 'Single') { return $selectedValues[0] } else { return $selectedValues } } |