Created a multiselect prompt
This commit is contained in:
@@ -68,6 +68,7 @@
|
||||
'Invoke-Text'
|
||||
'Invoke-Confirm'
|
||||
'Invoke-Select'
|
||||
'Invoke-MultiSelect'
|
||||
'Invoke-Spinner'
|
||||
)
|
||||
|
||||
|
||||
19
PoshPrompt/functions/Invoke-MultiSelect.ps1
Normal file
19
PoshPrompt/functions/Invoke-MultiSelect.ps1
Normal file
@@ -0,0 +1,19 @@
|
||||
function Invoke-MultiSelect {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory)][string]$Message,
|
||||
[Parameter(Mandatory)][string[]]$Options,
|
||||
[scriptblock]$Validate = $null
|
||||
)
|
||||
|
||||
$initialState = New-PromptState
|
||||
$initialState.HoveredIndex = 0
|
||||
$initialState.SelectedIndices = [System.Collections.Generic.HashSet[int]]::new()
|
||||
|
||||
$renderFn = { param($s) Render-MultiSelectPrompt -State $s -Message $Message -Options $Options }
|
||||
$updateFn = { param($s, $k) Update-MultiSelectStateFromKey -State $s -Key $k -Options $Options -Validate $Validate }
|
||||
|
||||
$finalState = Invoke-RenderLoop -InitialState $initialState -RenderFunction $renderFn -UpdateFunction $updateFn
|
||||
if ($finalState.Status -eq [PromptStatus]::Cancelled) { throw "Operation cancelled by user" }
|
||||
return $finalState.Value
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
function Render-MultiSelectPrompt {
|
||||
param([hashtable]$State, [string]$Message, [string[]]$Options)
|
||||
|
||||
$symbol = Get-Symbol -State $State
|
||||
$symbolBar = Get-SymbolColored -Symbol "│" -State $State
|
||||
$symbolEnd = Get-SymbolColored -Symbol "└" -State $State
|
||||
|
||||
$prompt = "$symbol $Message"
|
||||
|
||||
$renderOptions = {
|
||||
param($state)
|
||||
$out = ""
|
||||
for ($i = 0; $i -lt $Options.Count; $i++) {
|
||||
$out += "`n$symbolBar "
|
||||
|
||||
$params = @{ Style = 'Dim' }
|
||||
$box = '◻'
|
||||
if ($state.SelectedIndices.Contains($i)) {
|
||||
$params = @{ Foreground = 'Green' }
|
||||
$box = '◼'
|
||||
}
|
||||
elseif ($i -eq $state.HoveredIndex) {
|
||||
$params = @{ Foreground = 'Cyan' }
|
||||
}
|
||||
$out += "$(Format-AnsiText $box @params) "
|
||||
|
||||
$params = if ($i -eq $state.HoveredIndex) { @{} } else { @{ Style = 'Dim' } }
|
||||
$out += "$(Format-AnsiText $Options[$i] @params)"
|
||||
}
|
||||
return $out
|
||||
}
|
||||
|
||||
switch ($State.Status) {
|
||||
Submitted {
|
||||
$prompt += "`n$symbolBar $(Format-AnsiText $($State.Value -join ", ") -Style 'Dim')"
|
||||
$prompt += "`n$symbolBar"
|
||||
}
|
||||
Cancelled {
|
||||
$prompt += "`n$symbolBar"
|
||||
$prompt += "`n$symbolEnd"
|
||||
}
|
||||
Error {
|
||||
$prompt += & $renderOptions $State
|
||||
$prompt += "`n$symbolEnd $(Format-AnsiText $State.Feedback -Foreground 'Yellow')"
|
||||
}
|
||||
Default {
|
||||
$prompt += & $renderOptions $State
|
||||
$prompt += "`n$symbolEnd"
|
||||
}
|
||||
}
|
||||
|
||||
return $prompt
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
function Update-MultiSelectStateFromKey {
|
||||
param(
|
||||
[hashtable]$State,
|
||||
[System.ConsoleKeyInfo]$Key,
|
||||
[string[]]$Options,
|
||||
[scriptblock]$Validate = $null
|
||||
)
|
||||
|
||||
$newState = $State.Clone()
|
||||
if (-not $newState.ContainsKey('HoveredIndex')) { $newState.HoveredIndex = 0 }
|
||||
if (-not $newState.ContainsKey('SelectedIndices')) { $newState.SelectedIndices = [System.Collections.Generic.HashSet[int]]::new() }
|
||||
|
||||
switch ($Key.Key) {
|
||||
'UpArrow' { $newState.HoveredIndex = if ($newState.HoveredIndex -gt 0) { $newState.HoveredIndex - 1 } else { $Options.Count - 1 } }
|
||||
'DownArrow' { $newState.HoveredIndex = if ($newState.HoveredIndex -lt ($Options.Count - 1)) { $newState.HoveredIndex + 1 } else { 0 } }
|
||||
'Spacebar' {
|
||||
if ($newState.SelectedIndices.Contains($newState.HoveredIndex)) {
|
||||
[void]$newState.SelectedIndices.Remove($newState.HoveredIndex)
|
||||
}
|
||||
else {
|
||||
[void]$newState.SelectedIndices.Add($newState.HoveredIndex)
|
||||
}
|
||||
}
|
||||
'Enter' {
|
||||
$newState.Value = $Options[$newState.SelectedIndices]
|
||||
if ($Validate) {
|
||||
$err = & $Validate $newState.Value
|
||||
if ($err) {
|
||||
$newState.Status = [PromptStatus]::Error
|
||||
$newState.Feedback = $err
|
||||
}
|
||||
else { $newState.Status = [PromptStatus]::Submitted }
|
||||
}
|
||||
else { $newState.Status = [PromptStatus]::Submitted }
|
||||
}
|
||||
'Escape' { $newState.Status = [PromptStatus]::Cancelled }
|
||||
'C' {
|
||||
if ($Key.Modifiers -band [ConsoleModifiers]::Control) {
|
||||
$newState.Status = [PromptStatus]::Cancelled
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $newState
|
||||
}
|
||||
@@ -14,7 +14,7 @@ PowerShell CLI input prompt library heavily inspired by [github.com/bombshell-de
|
||||
|
||||
**New prompts/macros:**
|
||||
|
||||
- [ ] Multiselect prompt
|
||||
- [x] Multiselect prompt
|
||||
- [ ] Password prompt
|
||||
- [ ] Logs (simple, styled text); Variants = info, success, step, warn, error, default
|
||||
- [ ] Tasks (execute multiple tasks with spinners)
|
||||
|
||||
Reference in New Issue
Block a user