Private/Runtime/Invoke-ElmEventLoop.ps1
|
function Invoke-ElmEventLoop { [CmdletBinding()] param( [Parameter(Mandatory)] [object]$InitialModel, [Parameter(Mandatory)] [scriptblock]$UpdateFn, [Parameter(Mandatory)] [scriptblock]$ViewFn, [Parameter(Mandatory)] [object]$InputQueue, [Parameter()] [int]$TerminalWidth = 80, [Parameter()] [int]$TerminalHeight = 24 ) $esc = [char]27 $hideCursor = $esc + '[?25l' $showCursor = $esc + '[?25h' $model = $InitialModel $prevTree = $null [Console]::Write($hideCursor) try { # Initial render before any messages arrive $viewTree = Invoke-ElmView -ViewFn $ViewFn -Model $model $measuredTree = Measure-ElmViewTree -Root $viewTree -TermWidth $TerminalWidth -TermHeight $TerminalHeight $patches = @(Compare-ElmViewTree -OldTree $null -NewTree $measuredTree) $prevTree = $measuredTree if ($patches.Count -gt 0) { [Console]::Write((ConvertTo-AnsiOutput -Root $measuredTree)) } while ($true) { $msg = $null if ($InputQueue.TryDequeue([ref]$msg)) { $updateResult = Invoke-ElmUpdate -UpdateFn $UpdateFn -Message $msg -Model $model $model = $updateResult.Model $cmd = $updateResult.Cmd if ($null -ne $cmd -and $cmd.Type -eq 'Quit') { break } $viewTree = Invoke-ElmView -ViewFn $ViewFn -Model $model $measuredTree = Measure-ElmViewTree -Root $viewTree -TermWidth $TerminalWidth -TermHeight $TerminalHeight $patches = @(Compare-ElmViewTree -OldTree $prevTree -NewTree $measuredTree) $prevTree = $measuredTree if ($patches.Count -gt 0) { if ($patches[0].Type -eq 'FullRedraw') { $ansiOutput = ConvertTo-AnsiOutput -Root $measuredTree } else { $ansiOutput = ConvertTo-AnsiPatch -Patches $patches } [Console]::Write($ansiOutput) } } else { [System.Threading.Thread]::Sleep(1) } } } finally { [Console]::Write($showCursor) } return $model } |