mirror of
https://github.com/taigrr/bubbletea.git
synced 2026-04-02 02:59:09 -07:00
Read input regardless of whether or not it's a TTY
This commit also contains some refactors: * Refactor away inputStatus type * Refactor away program.inputIsTTY member * Simplify how we setup and restore input when it's a TTY
This commit is contained in:
59
tea.go
59
tea.go
@@ -52,8 +52,8 @@ type Model interface {
|
||||
// function.
|
||||
type Cmd func() Msg
|
||||
|
||||
// startupOptions contains configuration options to be run while the program
|
||||
// is initializing.
|
||||
// Options to customize the program during its initialization. These are
|
||||
// generally set with ProgramOptions.
|
||||
//
|
||||
// The options here are treated as bits.
|
||||
type startupOptions byte
|
||||
@@ -62,42 +62,14 @@ func (s startupOptions) has(option startupOptions) bool {
|
||||
return s&option != 0
|
||||
}
|
||||
|
||||
// Available startup options.
|
||||
const (
|
||||
withAltScreen startupOptions = 1 << iota
|
||||
withMouseCellMotion
|
||||
withMouseAllMotion
|
||||
withInputTTY
|
||||
withCustomInput
|
||||
)
|
||||
|
||||
// inputStatus indicates the current state of the input. By default, input is
|
||||
// stdin, however we'll change this if input's not a TTY. The user can also set
|
||||
// the input.
|
||||
type inputStatus int
|
||||
|
||||
const (
|
||||
// Generally this will be stdin.
|
||||
//
|
||||
// Lint ignore note: this is the implicit default value. While it's not
|
||||
// checked explicitly, it's presence nullifies the other possible values
|
||||
// of this type in logical statements.
|
||||
defaultInput inputStatus = iota // nolint:golint,deadcode,unused,varcheck
|
||||
|
||||
// The user explicitly set the input.
|
||||
customInput
|
||||
|
||||
// We've opened a TTY for input.
|
||||
managedInput
|
||||
)
|
||||
|
||||
func (i inputStatus) String() string {
|
||||
return [...]string{
|
||||
"default input",
|
||||
"custom input",
|
||||
"managed input",
|
||||
}[i]
|
||||
}
|
||||
|
||||
// Program is a terminal user interface.
|
||||
type Program struct {
|
||||
initialModel Model
|
||||
@@ -122,8 +94,6 @@ type Program struct {
|
||||
// is on by default.
|
||||
CatchPanics bool
|
||||
|
||||
inputStatus inputStatus
|
||||
inputIsTTY bool
|
||||
outputIsTTY bool
|
||||
console console.Console
|
||||
|
||||
@@ -311,22 +281,19 @@ func (p *Program) Start() error {
|
||||
p.input = f
|
||||
}
|
||||
|
||||
// Is input a terminal?
|
||||
if f, ok := p.input.(*os.File); ok {
|
||||
p.inputIsTTY = isatty.IsTerminal(f.Fd())
|
||||
}
|
||||
|
||||
// If input is not a terminal, and the user hasn't set a custom input, open
|
||||
// a TTY so we can capture input as normal. This will allow things to "just
|
||||
// work" in cases where data was piped or redirected into this application.
|
||||
if !p.inputIsTTY && p.inputStatus != customInput {
|
||||
f, err := openInputTTY()
|
||||
if err != nil {
|
||||
return err
|
||||
if f, ok := p.input.(*os.File); ok {
|
||||
inputIsTTY := isatty.IsTerminal(f.Fd())
|
||||
|
||||
if !inputIsTTY && !p.startupOptions.has(withCustomInput) {
|
||||
f, err := openInputTTY()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.input = f
|
||||
}
|
||||
p.input = f
|
||||
p.inputIsTTY = true
|
||||
p.inputStatus = managedInput
|
||||
}
|
||||
|
||||
// Listen for SIGINT. Note that in most cases ^C will not send an
|
||||
@@ -394,7 +361,7 @@ func (p *Program) Start() error {
|
||||
p.renderer.write(model.View())
|
||||
|
||||
// Subscribe to user input
|
||||
if p.inputIsTTY {
|
||||
if p.input != nil {
|
||||
go func() {
|
||||
for {
|
||||
msg, err := readInput(p.input)
|
||||
|
||||
Reference in New Issue
Block a user