Public/Show-InteractiveTranscript.ps1
|
<#
.SYNOPSIS Plays back an interactive transcript recording in the console. .DESCRIPTION Replays an asciicast v2 (.cast) file - as recorded by Start-InteractiveTranscript or asciinema - in the current console, re-emitting the output stream ('o' events) with the original timing. This is the PowerShell-native equivalent of 'asciinema play', covering view scenarios directly inside PowerShell. Input ('i') events are not replayed; resize ('r') events are ignored (the current console keeps its own size). On Windows the console output encoding is temporarily switched to UTF-8 for the playback and restored afterwards: Windows PowerShell 5.1 hosts write [Console] output through the console output codepage, which would otherwise render characters outside CP437 (e.g. heavy box-drawing borders) as literal '?'. .PARAMETER Path The asciicast v2 (.cast) file to play back. .PARAMETER IdleTimeLimit When greater than zero (seconds), pauses longer than this limit are shortened to it, mirroring asciinema's --idle-time-limit behaviour. Zero (default) preserves original timing. .PARAMETER Speed Playback speed multiplier (1 = original speed). Accepts values from 0.1 (ten times slower) to 100 (one hundred times faster). .INPUTS System.String The cast file path from the pipeline. .OUTPUTS None .EXAMPLE Show-InteractiveTranscript -Path .\audit\session01.cast Replays the recording at original speed. .EXAMPLE Show-InteractiveTranscript -Path .\audit\session01.cast -Speed 4 -IdleTimeLimit 2 Replays four times faster, skipping pauses longer than two seconds. #> function Show-InteractiveTranscript { [CmdletBinding()] param( [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [string]$Path, [ValidateRange(0, [double]::MaxValue)] [double]$IdleTimeLimit = 0, [ValidateRange(0.1, 100)] [double]$Speed = 1 ) process { $timeline = Get-BsnCastTimeline -Path $Path # Windows PowerShell 5.1 (.NET Framework) writes [Console] output # through the console OUTPUT CODEPAGE (WriteFile), so playback # characters outside that codepage - e.g. OpenCode's heavy # box-drawing border U+2503 on an OEM-codepage (437) console - are # replaced with literal '?' before rendering, while ASCII and CP437 # blocks survive (the recorded cast itself is lossless UTF-8; pwsh 7 # writes via WriteConsoleW and is unaffected). Switch the console # output encoding to UTF-8 for the duration of the playback and # restore the original afterwards - the same restore discipline the # recording engine uses for the live proxy view (issue #5). $previousOutputEncoding = [Console]::OutputEncoding $changedOutputEncoding = $false if ($previousOutputEncoding.CodePage -ne 65001) { try { [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 $changedOutputEncoding = $true } catch { # No attached console or a host that refuses the switch (some # IDE/redirected setups): playback continues with the current # encoding, which is what previous versions did. Write-Verbose -Message ('Could not switch the console output encoding to UTF-8 for playback: ' + $_.Exception.Message) } } try { $previousTime = 0.0 foreach ($timelineEvent in $timeline.Events) { $eventTime = [double]$timelineEvent[0] $delaySeconds = $eventTime - $previousTime if (($IdleTimeLimit -gt 0) -and ($delaySeconds -gt $IdleTimeLimit)) { $delaySeconds = $IdleTimeLimit } $delaySeconds = $delaySeconds / $Speed if ($delaySeconds -gt 0) { Start-Sleep -Milliseconds ([int]($delaySeconds * 1000)) } $eventType = [string]$timelineEvent[1] if ($eventType -eq 'o') { [Console]::Write([string]$timelineEvent[2]) } $previousTime = $eventTime } } finally { if ($changedOutputEncoding) { try { [Console]::OutputEncoding = $previousOutputEncoding } catch { Write-Verbose -Message ('Could not restore the console output encoding: ' + $_.Exception.Message) } } } } } |