@@ -243,12 +243,9 @@ func runInteractive() (command, preset string, overrides map[string][]string, er
preset = presets[0]
}
- // Screen references for extracting results after the session.
- // These are populated by the resolve screen's builder function.
- var snapshotScreen *screens.Snapshot
- var filePickerScreen *screens.FilePicker
- var targetScreen *screens.Target
- var overwriteScreen *screens.Overwrite
+ // cmdScreens is populated by the resolve screen's builder function
+ // so the caller can extract results after the session completes.
+ var cmdScreens *commandScreens
// The resolve screen sits between menu/preset and command-specific
// screens. It resolves the config and dynamically builds the
@@ -260,8 +257,11 @@ func runInteractive() (command, preset string, overrides map[string][]string, er
p = presetScreen.Value()
}
- return buildCommandScreens(cmd, p, &styles,
- &snapshotScreen, &filePickerScreen, &targetScreen, &overwriteScreen)
+ cmdScreens = buildCommandScreens(cmd, p, &styles)
+ if cmdScreens == nil {
+ return nil
+ }
+ return cmdScreens.list
})
screenList = append(screenList, resolveScreen)
@@ -287,26 +287,30 @@ func runInteractive() (command, preset string, overrides map[string][]string, er
}
// Extract overrides from the completed command-specific screens.
- overrides = extractCommandOverrides(command, snapshotScreen, filePickerScreen, targetScreen, overwriteScreen)
+ overrides = extractCommandOverrides(command, cmdScreens)
return command, preset, overrides, nil
}
+// commandScreens holds the screens built for a command's interactive
+// flow along with typed references to each screen. This lets
+// runInteractive read results from the completed screens without
+// resorting to double-pointer output parameters.
+type commandScreens struct {
+ list []ui.Screen
+ snapshot *screens.Snapshot
+ filePicker *screens.FilePicker
+ target *screens.Target
+ overwrite *screens.Overwrite
+}
+
// buildCommandScreens resolves the config for the given command and
// preset, then builds the command-specific screens that need user
-// input. Screen pointers are stored in the provided output parameters
-// so the caller can extract results after the session completes.
-func buildCommandScreens(
- command, preset string,
- styles *theme.Styles,
- snapshotOut **screens.Snapshot,
- filePickerOut **screens.FilePicker,
- targetOut **screens.Target,
- overwriteOut **screens.Overwrite,
-) []ui.Screen {
+// input. Returns nil when the command needs no interactive screens.
+func buildCommandScreens(command, preset string, styles *theme.Styles) *commandScreens {
switch command {
case "restore":
- return buildRestoreScreens(preset, styles, snapshotOut, filePickerOut, targetOut, overwriteOut)
+ return buildRestoreScreens(preset, styles)
default:
return nil
}
@@ -314,14 +318,7 @@ func buildCommandScreens(
// buildRestoreScreens creates the restore flow screens, skipping any
// that are already provided by the resolved config.
-func buildRestoreScreens(
- preset string,
- styles *theme.Styles,
- snapshotOut **screens.Snapshot,
- filePickerOut **screens.FilePicker,
- targetOut **screens.Target,
- overwriteOut **screens.Overwrite,
-) []ui.Screen {
+func buildRestoreScreens(preset string, styles *theme.Styles) *commandScreens {
cfg, err := config.Resolve(preset, "restore", nil)
if err != nil {
// Config resolution failed. Return no screens so the session
@@ -330,16 +327,15 @@ func buildRestoreScreens(
return nil
}
- var list []ui.Screen
+ cs := &commandScreens{}
// Step 1: Snapshot ID (skip if already provided as an argument).
if len(cfg.Arguments) == 0 {
loader := screens.SnapshotLoader(func() ([]restic.Snapshot, error) {
return restic.ListSnapshots(cfg)
})
- ss := screens.NewSnapshot(loader, styles)
- *snapshotOut = ss
- list = append(list, ss)
+ cs.snapshot = screens.NewSnapshot(loader, styles)
+ cs.list = append(cs.list, cs.snapshot)
}
// Step 2: File selection (skip if include flags set or snapshot
@@ -349,8 +345,8 @@ func buildRestoreScreens(
// Determine the snapshot ID source: from the snapshot screen
// if it exists, otherwise from the resolved config.
snapshotIDFn := func() string {
- if *snapshotOut != nil {
- return (*snapshotOut).Value()
+ if cs.snapshot != nil {
+ return cs.snapshot.Value()
}
if len(cfg.Arguments) > 0 {
return cfg.Arguments[0]
@@ -370,63 +366,54 @@ func buildRestoreScreens(
return restic.RunLs(cfg, snapshotID)
}
- fps := screens.NewFilePicker(fileLoader, snapshotIDFn, styles)
- *filePickerOut = fps
- list = append(list, fps)
+ cs.filePicker = screens.NewFilePicker(fileLoader, snapshotIDFn, styles)
+ cs.list = append(cs.list, cs.filePicker)
}
// Step 3: Target directory (skip if already set).
if !cfg.HasFlag("target") {
- ts := screens.NewTarget(styles)
- *targetOut = ts
- list = append(list, ts)
+ cs.target = screens.NewTarget(styles)
+ cs.list = append(cs.list, cs.target)
}
// Step 4: Overwrite behaviour (skip if already set).
if !cfg.HasFlag("overwrite") {
- ows := screens.NewOverwrite(styles)
- *overwriteOut = ows
- list = append(list, ows)
+ cs.overwrite = screens.NewOverwrite(styles)
+ cs.list = append(cs.list, cs.overwrite)
}
- return list
+ return cs
}
// extractCommandOverrides reads the completed screen values and
// returns a map suitable for passing to runCommand as overrides.
-func extractCommandOverrides(
- command string,
- snapshotScreen *screens.Snapshot,
- filePickerScreen *screens.FilePicker,
- targetScreen *screens.Target,
- overwriteScreen *screens.Overwrite,
-) map[string][]string {
- if command != "restore" {
+func extractCommandOverrides(command string, cs *commandScreens) map[string][]string {
+ if command != "restore" || cs == nil {
return nil
}
overrides := make(map[string][]string)
- if snapshotScreen != nil {
- if v := snapshotScreen.Value(); v != "" {
+ if cs.snapshot != nil {
+ if v := cs.snapshot.Value(); v != "" {
overrides[overrideArgumentsKey] = []string{v}
}
}
- if filePickerScreen != nil {
- if includes := filePickerScreen.Includes(); len(includes) > 0 {
+ if cs.filePicker != nil {
+ if includes := cs.filePicker.Includes(); len(includes) > 0 {
overrides["include"] = includes
}
}
- if targetScreen != nil {
- if v := targetScreen.Value(); v != "" {
+ if cs.target != nil {
+ if v := cs.target.Value(); v != "" {
overrides["target"] = []string{v}
}
}
- if overwriteScreen != nil {
- if v := overwriteScreen.Value(); v != "" {
+ if cs.overwrite != nil {
+ if v := cs.overwrite.Value(); v != "" {
overrides["overwrite"] = []string{v}
}
}