On-demand frame capture
Is your feature request related to a problem? Please describe.
The recording strategy (for text files) works on a per-command basis, i.e. record a frame when a command is executed. This can generate inconsistencies when dealing with external programs that can have variant response times, thus affecting golden file stability. Right now, the only way to avoid this is by doing a Hide/Run the program and wait a while for it to return/Show dance that can make the tape file a bit annoying to navigate.
Describe the solution you'd like
It would be great to have a command Set CaptureMode which could either be OnCommand (the default one) or OnDemand. Setting the capture mode to OnDemand would disable the tool from recording an output at every command and only record the output when executing a specific command (e.g. Capture).
Describe alternatives you've considered
This could also be achieved by adding a configuration flag to the binary, such as -capturemode=. It's up to you guys to decide which one would be the best approach.
Additional context Here's a simple use case with a variant response time executable:
// Quits after finding a multiple of 10 or after 1 second.
func main() {
found := make(chan struct{})
go func() {
for {
if rand.Int()%10 != 0 {
time.Sleep(200 * time.Millisecond)
continue
}
close(found)
break
}
}()
select {
case <-found:
fmt.Println("Found :)")
case <-time.After(time.Second):
fmt.Println("Timed out :(")
}
}
Running the above with a simple tape file:
Output simple.txt
Type "./stopWhenFound"
Enter
Sleep 1s
We can have this (when the number is found immediately):
> ./stopWhenFound
────────────────────────────────────────────────────────────────────────────────
> ./stopWhenFound
Found :)
>
────────────────────────────────────────────────────────────────────────────────
> ./stopWhenFound
Found :)
>
────────────────────────────────────────────────────────────────────────────────
Or this (when the number is found after a while):
> ./stopWhenFound
────────────────────────────────────────────────────────────────────────────────
> ./stopWhenFound
────────────────────────────────────────────────────────────────────────────────
> ./stopWhenFound
Found :)
>
────────────────────────────────────────────────────────────────────────────────
When using Hide/Sleep:
Output hiding.txt
Hide
Type "./stopWhenFound"
Enter
Sleep 1s
Show
# The final sleep necessary when using hide/sleep, as vhs must have a .gif output and
# will fail with a "no frames" error if it can't generate it, even though the above should be
# enough for the text output.
# This can be avoided if https://github.com/charmbracelet/vhs/issues/363 gets addressed.
Sleep 100ms
We can have a single frame with the output (the last frame is due to the "required" sleep in the end):
> ./stopWhenFound
Found :)
>
────────────────────────────────────────────────────────────────────────────────
> ./stopWhenFound
Found :)
>
────────────────────────────────────────────────────────────────────────────────
On simple files, the hide/sleep isn't that bad, but when dealing with more complex interactions it can escalate fast. This could be avoided by the suggestion listed in this issue, since (instead of hiding/showing) we could use a Capture line that would record the current terminal frame.