Bubbletea apps hang if invoked within shell process substitution
Describe the bug Example from this repo:
# works
go run tutorials/commands/main.go
# hangs forever
cat <(go run tutorials/commands/main.go)
Setup Please complete the following information along with version numbers, if applicable.
- OS [e.g. Ubuntu, macOS] - macOS Ventura 13.5
- Shell [e.g. zsh, fish] - tested in zsh (
zsh 5.9 (x86_64-apple-darwin22.0) and bash (GNU bash, version 3.2.57(1)-release (arm64-apple-darwin22)) - Terminal Emulator [e.g. kitty, iterm] - tested in iTerm2 3.4.19
- Terminal Multiplexer [e.g. tmux] - none in use
To Reproduce Steps to reproduce the behavior:
git clone [email protected]:charmbracelet/bubbletea.git /tmp/btea-bug
cd /tmp/btea-bug
go build -o repro tutorials/commands/main.go
./repro
echo 'cat <(./repro) is about to hang'
cat <(./repro)
Source Code Please include source code if needed to reproduce the behavior.
No additional source code needed, but I believe there are two places in bubble tea where this hangs, maybe more:
- https://github.com/charmbracelet/bubbletea/blob/91dd1200733714c4fb7bc7ffb24af2c35cc2f111/tty.go#L23
- https://github.com/charmbracelet/bubbletea/blob/91dd1200733714c4fb7bc7ffb24af2c35cc2f111/tty.go#L29
I'm especially interested in the case where WithOutput(os.Stderr) is added here: https://github.com/charmbracelet/bubbletea/blob/91dd1200733714c4fb7bc7ffb24af2c35cc2f111/tutorials/commands/main.go#L74
Expected behavior
Either:
- Bubbletea detects that the invocation is part of process substitution and falls back to interacting with outputs in a way that doesn't hang
- Bubbletea documents how to detect and avoid this hang (we could just check whether stdout is a pipe or a device, but we'd like to have a bubbletea UI on stderr while stdout is redirected. We have this working today, but can't detect the process substitution, so we have a place where the UI hangs unexpectedly.)
Apologies if you already have this documented somewhere; I haven't been able to find it.
Additional context
I found this while investigating this: https://github.com/anchore/syft/issues/1439#issuecomment-1659113437
Note: We are using WithOutput(os.Stderr) when calling NewProgram. Invocations like syft whatever | grep foo work fine with bubbletea going to stderr, but invocations like diff <(syft whatever) <(syft the-other) hang.
I'd be happy to help with the investigation and the fix - just let me know how I can help!