diff --git a/confirm/command.go b/confirm/command.go index 4ea4547..5d42d9c 100644 --- a/confirm/command.go +++ b/confirm/command.go @@ -4,10 +4,11 @@ import ( "fmt" "os" + "github.com/charmbracelet/gum/internal/exit" + "github.com/alecthomas/kong" tea "github.com/charmbracelet/bubbletea" - "github.com/charmbracelet/gum/internal/exit" "github.com/charmbracelet/gum/style" ) diff --git a/confirm/confirm.go b/confirm/confirm.go index 250fc26..c148da3 100644 --- a/confirm/confirm.go +++ b/confirm/confirm.go @@ -11,9 +11,10 @@ package confirm import ( - "fmt" "time" + "github.com/charmbracelet/gum/timeout" + tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" ) @@ -37,21 +38,8 @@ type model struct { unselectedStyle lipgloss.Style } -const tickInterval = time.Second - -type tickMsg struct{} - -func tick() tea.Cmd { - return tea.Tick(tickInterval, func(time.Time) tea.Msg { - return tickMsg{} - }) -} - func (m model) Init() tea.Cmd { - if m.timeout > 0 { - return tick() - } - return nil + return timeout.Init(m.timeout, m.defaultSelection) } func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { @@ -61,6 +49,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case tea.KeyMsg: switch msg.String() { case "ctrl+c": + m.confirmation = false m.aborted = true fallthrough case "esc": @@ -85,14 +74,16 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.confirmation = true return m, tea.Quit } - case tickMsg: - if m.timeout <= 0 { + case timeout.TickTimeoutMsg: + + if msg.TimeoutValue <= 0 { m.quitting = true m.confirmation = m.defaultSelection return m, tea.Quit } - m.timeout -= tickInterval - return m, tick() + + m.timeout = msg.TimeoutValue + return m, timeout.Tick(msg.TimeoutValue, msg.Data) } return m, nil } @@ -102,27 +93,23 @@ func (m model) View() string { return "" } - var aff, neg, timeout, affirmativeTimeout, negativeTimeout string - + var aff, neg, timeoutStrYes, timeoutStrNo string + timeoutStrNo = "" + timeoutStrYes = "" if m.hasTimeout { - timeout = fmt.Sprintf(" (%d)", max(0, int(m.timeout.Seconds()))) - } - - // set timer based on defaultSelection - if m.defaultSelection { - affirmativeTimeout = m.affirmative + timeout - negativeTimeout = m.negative - } else { - affirmativeTimeout = m.affirmative - negativeTimeout = m.negative + timeout + if m.defaultSelection { + timeoutStrYes = timeout.Str(m.timeout) + } else { + timeoutStrNo = timeout.Str(m.timeout) + } } if m.confirmation { - aff = m.selectedStyle.Render(affirmativeTimeout) - neg = m.unselectedStyle.Render(negativeTimeout) + aff = m.selectedStyle.Render(m.affirmative + timeoutStrYes) + neg = m.unselectedStyle.Render(m.negative + timeoutStrNo) } else { - aff = m.unselectedStyle.Render(affirmativeTimeout) - neg = m.selectedStyle.Render(negativeTimeout) + aff = m.unselectedStyle.Render(m.affirmative + timeoutStrYes) + neg = m.selectedStyle.Render(m.negative + timeoutStrNo) } // If the option is intentionally empty, do not show it. @@ -132,10 +119,3 @@ func (m model) View() string { return lipgloss.JoinVertical(lipgloss.Center, m.promptStyle.Render(m.prompt), lipgloss.JoinHorizontal(lipgloss.Left, aff, neg)) } - -func max(a, b int) int { - if a > b { - return a - } - return b -} diff --git a/confirm/options.go b/confirm/options.go index 3c0881c..672c646 100644 --- a/confirm/options.go +++ b/confirm/options.go @@ -8,14 +8,14 @@ import ( // Options is the customization options for the confirm command. type Options struct { - Affirmative string `help:"The title of the affirmative action" default:"Yes"` - Negative string `help:"The title of the negative action" default:"No"` - Default bool `help:"Default confirmation action" default:"true"` - Timeout time.Duration `help:"Timeout for confirmation" default:"0" env:"GUM_CONFIRM_TIMEOUT"` - Prompt string `arg:"" help:"Prompt to display." default:"Are you sure?"` - PromptStyle style.Styles `embed:"" prefix:"prompt." help:"The style of the prompt" set:"defaultMargin=1 0 0 0" envprefix:"GUM_CONFIRM_PROMPT_"` + Default bool `help:"Default confirmation action" default:"true"` + Affirmative string `help:"The title of the affirmative action" default:"Yes"` + Negative string `help:"The title of the negative action" default:"No"` + Prompt string `arg:"" help:"Prompt to display." default:"Are you sure?"` + PromptStyle style.Styles `embed:"" prefix:"prompt." help:"The style of the prompt" set:"defaultMargin=1 0 0 0" envprefix:"GUM_CONFIRM_PROMPT_"` //nolint:staticcheck SelectedStyle style.Styles `embed:"" prefix:"selected." help:"The style of the selected action" set:"defaultBackground=212" set:"defaultForeground=230" set:"defaultPadding=0 3" set:"defaultMargin=1 1" envprefix:"GUM_CONFIRM_SELECTED_"` //nolint:staticcheck - UnselectedStyle style.Styles `embed:"" prefix:"unselected." help:"The style of the unselected action" set:"defaultBackground=235" set:"defaultForeground=254" set:"defaultPadding=0 3" set:"defaultMargin=1 1" envprefix:"GUM_CONFIRM_UNSELECTED_"` + UnselectedStyle style.Styles `embed:"" prefix:"unselected." help:"The style of the unselected action" set:"defaultBackground=235" set:"defaultForeground=254" set:"defaultPadding=0 3" set:"defaultMargin=1 1" envprefix:"GUM_CONFIRM_UNSELECTED_"` + Timeout time.Duration `help:"Timeout until confirm returns selected value or default if provided" default:"0" env:"GUM_CONFIRM_TIMEOUT"` }