charmbracelet / charmbracelet/bubbletea

Bubbletea apps hang if invoked within shell process substitution

Open
#792 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
44.9k
Forks
1.3k
PR merge metrics
No merged PRs in 30d

Description

**Describe the bug**
Example from this repo:

``` sh
# 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 git@github.com: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:
1. Bubbletea detects that the invocation is part of process substitution and falls back to interacting with outputs in a way that doesn't hang
2. 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!

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.