private/Invoke-SpectrePromptAsync.ps1
function Invoke-SpectrePromptAsync { <# .SYNOPSIS Shows a Spectre.Console prompt. .DESCRIPTION This function shows a Spectre.Console prompt "asynchronously" in PowerShell by faking the async call. By allowing the prompt to run asynchronously in the background and polling for its completion, it allows ctrl-c interrupts to continue to work within the single-threaded PowerShell world. .PARAMETER Prompt The Spectre.Console prompt to show. .EXAMPLE $result = Invoke-SpectrePromptAsync $prompt #> param ( [Parameter(Mandatory)] $Prompt, [int] $TimeoutSeconds ) $timeout = $null if ($TimeoutSeconds) { $timeout = (Get-Date).AddSeconds($TimeoutSeconds) Write-SpectreHost "[$script:DefaultValueColor]This prompt times out in $TimeoutSeconds seconds...[/]`n" } $cts = [System.Threading.CancellationTokenSource]::new() try { $task = $Prompt.ShowAsync([Spectre.Console.AnsiConsole]::Console, $cts.Token) while (-not $task.AsyncWaitHandle.WaitOne(200)) { # Waiting for the async task this way allows ctrl-c interrupts to continue to work within the single-threaded PowerShell world if ($null -ne $timeout -and (Get-Date) -ge $timeout) { $cts.Cancel() Write-SpectreHost "`n`n[$script:DefaultValueColor]Prompt timed out[/]" } } if (!$task.IsCanceled) { return $task.GetAwaiter().GetResult() } } finally { $cts.Cancel() $task.Dispose() } } |