From 0ffe4f11b393eab805ec7fd89a01c03a2b689ca3 Mon Sep 17 00:00:00 2001 From: Robin Olsen Date: Tue, 17 Feb 2026 20:03:43 +0100 Subject: [PATCH] add command to specify task add runTask to run spesific task with spesific interface --- cmd/survey/cmd.go | 49 +++++++++++--------- cmd/survey/init.go | 8 +++- cmd/survey/intro.go | 10 ++-- cmd/survey/runner.go | 99 ++++++++++++++++++++++------------------ internal/style/styles.go | 9 ++-- 5 files changed, 98 insertions(+), 77 deletions(-) diff --git a/cmd/survey/cmd.go b/cmd/survey/cmd.go index 65d86b0..ff1ae29 100644 --- a/cmd/survey/cmd.go +++ b/cmd/survey/cmd.go @@ -3,14 +3,12 @@ package main import ( "fmt" - "github.com/LazyBachelor/LazyPM/pkg/cli/repl" "github.com/LazyBachelor/LazyPM/pkg/task" - "github.com/LazyBachelor/LazyPM/pkg/tui" - "github.com/LazyBachelor/LazyPM/pkg/web" "github.com/spf13/cobra" ) var interfaceType string +var stage int var rootCmd = &cobra.Command{ Use: "survey", @@ -42,29 +40,37 @@ var submitCmd = &cobra.Command{ func runStartCmd(cmd *cobra.Command, args []string) error { interfaces := initInterfaces() - if cmd.Flags().Changed("interface") { - switch interfaceType { - case "tui": - interfaces = []task.Interface{tui.NewTui()} - case "repl": - interfaces = []task.Interface{repl.NewRepl()} - case "web": - interfaces = []task.Interface{web.NewWeb()} - default: - return fmt.Errorf("invalid interface type: %s", interfaceType) - } - } - - if err := newIntroModel().Run(); err != nil { - return returnIfUserQuit(err, "failed to run intro") - } - svc, cleanup, err := initializeServices(cmd.Context()) if err != nil { return returnIfUserQuit(err, "failed to initialize services") } defer cleanup() + tasks := initTasks(svc) + + if cmd.Flags().Changed("interface") { + if _, ok := interfaces[interfaceType]; !ok { + return fmt.Errorf("invalid interface, valid are (tui, repl, web)") + } + interfaces = map[string]task.Interface{ + interfaceType: interfaces[interfaceType], + } + } + + if cmd.Flags().Changed("stage") { + if stage < 1 || stage > len(tasks) { + return fmt.Errorf("invalid stage") + } + if err := runTask(cmd.Context(), tasks[stage-1], interfaces[interfaceType]); err != nil { + return err + } + return nil + } + + if err := newIntroModel().Run(); err != nil { + return returnIfUserQuit(err, "failed to run intro") + } + surveyTasks := initTasks(svc) if err := taskLoop(cmd.Context(), surveyTasks, interfaces); err != nil { @@ -75,7 +81,8 @@ func runStartCmd(cmd *cobra.Command, args []string) error { func init() { rootCmd.CompletionOptions.DisableDefaultCmd = true - startCmd.Flags().StringVarP(&interfaceType, "interface", "i", "", "Specify which interface to use for the survey (tui, repl, web).") + startCmd.Flags().StringVarP(&interfaceType, "interface", "i", "tui", "Specify interface.") + startCmd.Flags().IntVarP(&stage, "stage", "s", 1, "Run stage directly") rootCmd.AddCommand(startCmd) rootCmd.AddCommand(submitCmd) } diff --git a/cmd/survey/init.go b/cmd/survey/init.go index d4ca196..fdaacd8 100644 --- a/cmd/survey/init.go +++ b/cmd/survey/init.go @@ -27,6 +27,10 @@ func initTasks(svc *service.Services) []*task.Task { } } -func initInterfaces() []task.Interface { - return []task.Interface{repl.NewRepl(), tui.NewTui(), web.NewWeb()} +func initInterfaces() map[string]task.Interface { + return map[string]task.Interface{ + "repl": repl.NewRepl(), + "tui": tui.NewTui(), + "web": web.NewWeb(), + } } diff --git a/cmd/survey/intro.go b/cmd/survey/intro.go index 32553a9..5624222 100644 --- a/cmd/survey/intro.go +++ b/cmd/survey/intro.go @@ -114,7 +114,8 @@ func (m introModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { func (m introModel) View() string { if m.width < 55 || m.height < 16 { - return lipgloss.Place(m.width, m.height, lipgloss.Center, lipgloss.Center, "Terminal too small.") + return lipgloss.Place(m.width, m.height, lipgloss.Center, lipgloss.Center, + style.TextStyle.Render("Terminal too small.")) } var content string @@ -127,10 +128,9 @@ func (m introModel) View() string { return "" } - boxWidth := min(m.width-10, 90) + boxWidth := min(m.width-10, 80) - boxStyle := lipgloss.NewStyle(). - Border(style.DefaultBorder). + boxStyle := style.BorderStyle. Margin(1, 0).Padding(2, 4).Width(boxWidth) var b strings.Builder @@ -138,7 +138,7 @@ func (m introModel) View() string { b.WriteString(style.TitleStyle.Render(IntroTitle)) b.WriteString("\n") - b.WriteString(boxStyle.Render(content)) + b.WriteString(boxStyle.Render(style.TextStyle.Render(content))) b.WriteString("\n") helpText := "Press " + keys.Continue.Help().Key + " to continue • " + diff --git a/cmd/survey/runner.go b/cmd/survey/runner.go index 68eb6bf..d46ae10 100644 --- a/cmd/survey/runner.go +++ b/cmd/survey/runner.go @@ -10,60 +10,71 @@ import ( "github.com/LazyBachelor/LazyPM/pkg/task" ) -func taskLoop(ctx context.Context, surveyTasks []*task.Task, interfaces []task.Interface) error { - interfaceIndex := rand.Int() % len(interfaces) +func runTask(ctx context.Context, t *task.Task, i task.Interface) error { + t.SetInterface(i) + t.SetInterfaceType(tasks.InterfaceToType(i)) - for _, t := range surveyTasks { + doneChan := make(chan bool, 1) + quitChan := make(chan bool, 1) + feedbackChan := make(chan task.ValidationFeedback, 10) - t.SetInterface(interfaces[interfaceIndex]) - t.SetInterfaceType(tasks.InterfaceToType(interfaces[interfaceIndex])) + if validated, ok := i.(task.ValidatedInterface); ok { + validated.SetChannels(feedbackChan, quitChan) + } - doneChan := make(chan bool, 1) - quitChan := make(chan bool, 1) - feedbackChan := make(chan task.ValidationFeedback, 10) + if err := t.Initialize(ctx); err != nil { + return fmt.Errorf("failed to initialize task: %w", err) + } - if validated, ok := interfaces[interfaceIndex].(task.ValidatedInterface); ok { - validated.SetChannels(feedbackChan, quitChan) + if err := t.IntroduceTask(); err != nil { + return returnIfUserQuit(err, "failed to display task introduction screen") + } + + t.SetChannels(feedbackChan, doneChan, quitChan) + + go t.StartValidationLoop(ctx) + + interfaceDone := make(chan error, 1) + go func() { + interfaceDone <- t.StartInterface(ctx, t.Config) + }() + + select { + case <-doneChan: + close(quitChan) + <-interfaceDone + fmt.Println("Task completed successfully!") + + case err := <-interfaceDone: + close(quitChan) + if err != nil { + return returnIfUserQuit(err, "failed to start task interface") } + fmt.Println("Task incomplete - you exited early") + } - if err := t.Initialize(ctx); err != nil { - return fmt.Errorf("failed to initialize task: %w", err) - } + if err := t.StartQuestionnaire(); err != nil { + return returnIfUserQuit(err, "failed to start questionnaire") + } + return nil +} - if err := t.IntroduceTask(); err != nil { - return returnIfUserQuit(err, "failed to display task introduction screen") - } +func taskLoop(ctx context.Context, surveyTasks []*task.Task, interfaces map[string]task.Interface) error { + var ifaceNames []string + for name := range interfaces { + ifaceNames = append(ifaceNames, name) + } - t.SetChannels(feedbackChan, doneChan, quitChan) + rand.Shuffle(len(ifaceNames), func(i, j int) { + ifaceNames[i], ifaceNames[j] = ifaceNames[j], ifaceNames[i] + }) - go t.StartValidationLoop(ctx) + for i, task := range surveyTasks { + idx := i % len(ifaceNames) + selected := interfaces[ifaceNames[idx]] - interfaceDone := make(chan error, 1) - go func() { - interfaceDone <- t.StartInterface(ctx, t.Config) - }() - - select { - case <-doneChan: - close(quitChan) - <-interfaceDone - fmt.Println("Task completed successfully!") - - case err := <-interfaceDone: - close(quitChan) - if err != nil { - return returnIfUserQuit(err, "failed to start task interface") - } - fmt.Println("Task incomplete - you exited early") - } - - if err := t.StartQuestionnaire(); err != nil { - return returnIfUserQuit(err, "failed to start questionnaire") - } - - interfaceIndex++ - if interfaceIndex >= len(interfaces) { - interfaceIndex = 0 + if err := runTask(ctx, task, selected); err != nil { + return err } } return nil diff --git a/internal/style/styles.go b/internal/style/styles.go index 3899269..5643cd5 100644 --- a/internal/style/styles.go +++ b/internal/style/styles.go @@ -8,7 +8,7 @@ var ( SecondaryColor = lipgloss.AdaptiveColor{Light: "#ff6f61", Dark: "#ff6347"} AccentColor = lipgloss.AdaptiveColor{Light: "#6a5acd", Dark: "#9370db"} Background = lipgloss.AdaptiveColor{Light: "#ffffff", Dark: "#1e1e1e"} - TextColor = lipgloss.AdaptiveColor{Light: "#000000", Dark: "#ffffff"} + TextColor = lipgloss.AdaptiveColor{Light: "#252525b7", Dark: "#ffffff"} ) var ( @@ -21,8 +21,7 @@ var ( ) var ( - TitleStyle = lipgloss.NewStyle().Foreground(PrimaryColor).Bold(true) - DescriptionStyle = lipgloss.NewStyle().Foreground(TextColor).Italic(true) - DetailStyle = lipgloss.NewStyle().Foreground(SecondaryColor) - HelpStyle = lipgloss.NewStyle().Align(lipgloss.Center).Foreground(AccentColor) + TitleStyle = lipgloss.NewStyle().Foreground(PrimaryColor).Bold(true) + TextStyle = lipgloss.NewStyle().Foreground(TextColor) + HelpStyle = lipgloss.NewStyle().Align(lipgloss.Center).Foreground(AccentColor) )