mirror of
https://github.com/psviderski/uncloud.git
synced 2026-08-26 11:03:34 +00:00
88 lines
2.5 KiB
Go
88 lines
2.5 KiB
Go
package tui
|
|
|
|
import (
|
|
"os"
|
|
|
|
"charm.land/huh/v2"
|
|
"charm.land/lipgloss/v2"
|
|
"golang.org/x/term"
|
|
)
|
|
|
|
// Confirm shows a confirmation prompt with a yellow-styled title.
|
|
// If title is empty, it defaults to "Do you want to continue?".
|
|
func Confirm(title string) (bool, error) {
|
|
if title == "" {
|
|
title = "Do you want to continue?"
|
|
}
|
|
|
|
var confirmed bool
|
|
form := huh.NewForm(
|
|
huh.NewGroup(
|
|
huh.NewConfirm().
|
|
Title(title).
|
|
Affirmative("Yes!").
|
|
Negative("No").
|
|
Value(&confirmed),
|
|
),
|
|
).WithTheme(ThemeConfirm()).
|
|
WithAccessible(true).
|
|
// Render to stderr so stdout stays clean for command output.
|
|
WithOutput(os.Stderr)
|
|
if err := form.Run(); err != nil {
|
|
return false, err
|
|
}
|
|
|
|
return confirmed, nil
|
|
}
|
|
|
|
// ThemeConfirm returns a huh theme with a bold yellow title style for the confirmation prompt.
|
|
func ThemeConfirm() huh.Theme {
|
|
return huh.ThemeFunc(func(isDark bool) *huh.Styles {
|
|
t := huh.ThemeBase(isDark)
|
|
t.Focused.Title = t.Focused.Title.Foreground(lipgloss.Yellow).Bold(true)
|
|
return t
|
|
})
|
|
}
|
|
|
|
// ThemeConfirmDanger returns a huh theme with a bold red title style for dangerous confirmation prompts.
|
|
func ThemeConfirmDanger() huh.Theme {
|
|
return huh.ThemeFunc(func(isDark bool) *huh.Styles {
|
|
t := huh.ThemeBase(isDark)
|
|
t.Focused.Title = t.Focused.Title.Foreground(lipgloss.Red).Bold(true)
|
|
return t
|
|
})
|
|
}
|
|
|
|
// IsTerminalAvailable reports whether the control terminal (TTY) is available so an interactive TUI can run.
|
|
func IsTerminalAvailable() bool {
|
|
// Bubbletea interactive programs read keyboard input from stdin and render to stdout (default) or stderr (uncloud),
|
|
// so both must be terminals. In particular, bubbletea falls back to opening /dev/tty when stdin is not a terminal,
|
|
// which fails when there is no controlling terminal. See https://github.com/psviderski/uncloud/issues/386
|
|
return IsStdinTerminal() && IsStderrTerminal()
|
|
}
|
|
|
|
// IsStdinTerminal checks if the standard input is a terminal (TTY).
|
|
func IsStdinTerminal() bool {
|
|
return term.IsTerminal(int(os.Stdin.Fd()))
|
|
}
|
|
|
|
// IsStdoutTerminal checks if the standard output is a terminal (TTY).
|
|
func IsStdoutTerminal() bool {
|
|
return term.IsTerminal(int(os.Stdout.Fd()))
|
|
}
|
|
|
|
// IsStderrTerminal checks if the standard error is a terminal (TTY).
|
|
func IsStderrTerminal() bool {
|
|
return term.IsTerminal(int(os.Stderr.Fd()))
|
|
}
|
|
|
|
// TerminalWidth returns the width of the terminal.
|
|
// Returns 0 if stdout is not a terminal or the width cannot be determined.
|
|
func TerminalWidth() int {
|
|
width, _, err := term.GetSize(int(os.Stdout.Fd()))
|
|
if err != nil || width <= 0 {
|
|
return 0
|
|
}
|
|
return width
|
|
}
|