confirm.go

 1package screens
 2
 3import (
 4	"charm.land/bubbles/v2/key"
 5	tea "charm.land/bubbletea/v2"
 6
 7	"git.secluded.site/keld/internal/ui"
 8)
 9
10// PreviewFunc returns the formatted command preview text. It is
11// called asynchronously from Init via a tea.Cmd. The returned string
12// should match the format of [restic.DryRun].
13type PreviewFunc func() string
14
15// previewMsg carries the result of the async preview generation.
16type previewMsg struct {
17	text string
18}
19
20// Confirm is a Screen adapter that shows the resolved restic command
21// and waits for the user to confirm execution. Enter proceeds,
22// Esc goes back.
23//
24// When showCommand is true, Init returns DoneCmd immediately without
25// calling the preview function — the session completes and the caller
26// prints the dry-run output through the normal --show-command path.
27type Confirm struct {
28	previewFn   PreviewFunc
29	showCommand bool
30	preview     string
31	selection   string
32}
33
34// NewConfirm creates a confirmation screen. The previewFn is called
35// to generate the command preview text. When showCommand is true,
36// the screen auto-completes without user interaction.
37func NewConfirm(previewFn PreviewFunc, showCommand bool) *Confirm {
38	return &Confirm{
39		previewFn:   previewFn,
40		showCommand: showCommand,
41	}
42}
43
44// Init starts the preview generation. In --show-command mode, it
45// skips the preview and returns DoneCmd immediately.
46func (c *Confirm) Init() tea.Cmd {
47	c.selection = ""
48
49	if c.showCommand {
50		return ui.DoneCmd
51	}
52
53	return func() tea.Msg {
54		return previewMsg{text: c.previewFn()}
55	}
56}
57
58// Update handles messages. Esc navigates back, Enter confirms.
59func (c *Confirm) Update(msg tea.Msg) (ui.Screen, tea.Cmd) {
60	switch msg := msg.(type) {
61	case previewMsg:
62		c.preview = msg.text
63		return c, nil
64
65	case tea.KeyPressMsg:
66		if msg.Code == tea.KeyEscape {
67			return c, ui.BackCmd
68		}
69		if msg.Code == tea.KeyEnter && c.preview != "" {
70			c.selection = "confirmed"
71			return c, ui.DoneCmd
72		}
73	}
74
75	return c, nil
76}
77
78// View renders the command preview.
79func (c *Confirm) View() string {
80	return c.preview
81}
82
83// Title returns the screen's display title.
84func (c *Confirm) Title() string { return "Confirm execution" }
85
86// KeyBindings returns bindings for the help bar.
87func (c *Confirm) KeyBindings() []key.Binding {
88	return []key.Binding{
89		key.NewBinding(key.WithKeys("enter"), key.WithHelp("enter", "execute")),
90	}
91}
92
93// Selection returns "confirmed" after the user presses Enter, or ""
94// if the screen has not been confirmed yet.
95func (c *Confirm) Selection() string { return c.selection }