diff --git a/cmd/root.go b/cmd/root.go index 3f3e82d95d663dbf595edc93afe431c7b5aad6cf..9750d9bf6fc1c3b471408996482347a7c195779d 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -283,6 +283,13 @@ func runInteractive(preselectedCommand string) (command, preset string, override } confirmScreen := screens.NewConfirm(previewFn, flagShowCmd) + // When the command has no dedicated TUI screens, the + // preview may be incomplete — additional prompts can + // follow after confirmation. + if cmdScreens == nil { + confirmScreen.SetPartial(true) + } + var result []ui.Screen if cmdScreens != nil { result = append(result, cmdScreens.list...) diff --git a/internal/ui/screens/confirm.go b/internal/ui/screens/confirm.go index fb7cfb6b1970c775672d5a6ec6c7430bb2299589..eeb0dde7fbdd05616e9613cc2b0f458a8505bb63 100644 --- a/internal/ui/screens/confirm.go +++ b/internal/ui/screens/confirm.go @@ -27,6 +27,7 @@ type previewMsg struct { type Confirm struct { previewFn PreviewFunc showCommand bool + partial bool preview string selection string } @@ -75,11 +76,25 @@ func (c *Confirm) Update(msg tea.Msg) (ui.Screen, tea.Cmd) { return c, nil } -// View renders the command preview. +// View renders the command preview. When partial is set, a note +// is appended explaining the preview may be incomplete. func (c *Confirm) View() string { - return c.preview + if c.preview == "" { + return "" + } + if !c.partial { + return c.preview + } + return c.preview + "\n" + partialNote } +// partialNote is shown below the preview when the command has no +// dedicated TUI screens, meaning the session could not collect all +// inputs interactively. +const partialNote = "Note: this preview may be incomplete. " + + "Additional prompts may follow after confirmation.\n" + + "Use --show-command to see the final command after all inputs are collected." + // Title returns the screen's display title. func (c *Confirm) Title() string { return "Confirm execution" } @@ -90,6 +105,10 @@ func (c *Confirm) KeyBindings() []key.Binding { } } +// SetPartial marks the preview as potentially incomplete because +// the command has no dedicated TUI screens to collect all inputs. +func (c *Confirm) SetPartial(partial bool) { c.partial = partial } + // Selection returns "confirmed" after the user presses Enter, or "" // if the screen has not been confirmed yet. func (c *Confirm) Selection() string { return c.selection } diff --git a/internal/ui/screens/confirm_test.go b/internal/ui/screens/confirm_test.go index 2bd6c56ce32bcc16069fc37d6319b9d8ee4a8056..2c238ec3ad76e5328e83fef18f911e963bae1f82 100644 --- a/internal/ui/screens/confirm_test.go +++ b/internal/ui/screens/confirm_test.go @@ -182,6 +182,44 @@ func TestConfirmViewEmptyBeforeInit(t *testing.T) { } } +func TestConfirmPartialShowsNote(t *testing.T) { + t.Parallel() + + c := NewConfirm(func() string { return "command: restic backup\n" }, false) + c.SetPartial(true) + + cmd := c.Init() + if cmd != nil { + msg := cmd() + c.Update(msg) + } + + view := c.View() + if !strings.Contains(view, "may be incomplete") { + t.Errorf("partial View() missing incomplete note; got:\n%s", view) + } + if !strings.Contains(view, "--show-command") { + t.Errorf("partial View() missing --show-command hint; got:\n%s", view) + } +} + +func TestConfirmNonPartialOmitsNote(t *testing.T) { + t.Parallel() + + c := NewConfirm(func() string { return "command: restic backup\n" }, false) + + cmd := c.Init() + if cmd != nil { + msg := cmd() + c.Update(msg) + } + + view := c.View() + if strings.Contains(view, "may be incomplete") { + t.Errorf("non-partial View() should not contain incomplete note; got:\n%s", view) + } +} + func TestConfirmReinitAfterBack(t *testing.T) { t.Parallel()