Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pkg/cli/add_interactive_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func (c *AddInteractiveConfig) checkGitRepository() error {
return nil
}),
),
).WithTheme(styles.HuhTheme()).WithAccessible(console.IsAccessibleMode())
).WithTheme(styles.HuhTheme).WithAccessible(console.IsAccessibleMode())

if err := form.RunWithContext(c.Ctx); err != nil {
return fmt.Errorf("failed to get repository info: %w", err)
Expand Down
2 changes: 1 addition & 1 deletion pkg/cli/add_interactive_engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func (c *AddInteractiveConfig) selectAIEngineAndKey() error {
Options(engineOptions...).
Value(&selectedEngine),
),
).WithTheme(styles.HuhTheme()).WithAccessible(console.IsAccessibleMode())
).WithTheme(styles.HuhTheme).WithAccessible(console.IsAccessibleMode())

if err := form.RunWithContext(c.Ctx); err != nil {
return fmt.Errorf("failed to select coding agent: %w", err)
Expand Down
4 changes: 2 additions & 2 deletions pkg/cli/add_interactive_git.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func (c *AddInteractiveConfig) createWorkflowPRAndConfigureSecret(ctx context.Co
Options(options...).
Value(&chosen),
),
).WithTheme(styles.HuhTheme()).WithAccessible(console.IsAccessibleMode())
).WithTheme(styles.HuhTheme).WithAccessible(console.IsAccessibleMode())

if selectErr := selectForm.Run(); selectErr != nil {
return fmt.Errorf("failed to get user input: %w", selectErr)
Expand Down Expand Up @@ -130,7 +130,7 @@ func (c *AddInteractiveConfig) createWorkflowPRAndConfigureSecret(ctx context.Co
Description("Add a prefix if required, for example: feat: or fix:").
Value(&newTitle),
),
).WithTheme(styles.HuhTheme()).WithAccessible(console.IsAccessibleMode())
).WithTheme(styles.HuhTheme).WithAccessible(console.IsAccessibleMode())
if titleErr := titleForm.Run(); titleErr != nil {
return fmt.Errorf("failed to get user input: %w", titleErr)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/cli/add_interactive_orchestrator.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ func (c *AddInteractiveConfig) confirmChanges(workflowFiles, initFiles []string,
Negative("No, cancel").
Value(&confirmed),
),
).WithTheme(styles.HuhTheme()).WithAccessible(console.IsAccessibleMode())
).WithTheme(styles.HuhTheme).WithAccessible(console.IsAccessibleMode())

if err := form.RunWithContext(c.Ctx); err != nil {
return fmt.Errorf("confirmation failed: %w", err)
Expand Down
2 changes: 1 addition & 1 deletion pkg/cli/add_interactive_schedule.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ func (c *AddInteractiveConfig) selectScheduleFrequency() error {
Options(options...).
Value(&selected),
),
).WithTheme(styles.HuhTheme()).WithAccessible(console.IsAccessibleMode())
).WithTheme(styles.HuhTheme).WithAccessible(console.IsAccessibleMode())

if err := form.RunWithContext(c.Ctx); err != nil {
return fmt.Errorf("failed to select schedule frequency: %w", err)
Expand Down
2 changes: 1 addition & 1 deletion pkg/cli/add_interactive_workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ func (c *AddInteractiveConfig) checkStatusAndOfferRun(ctx context.Context) error
Negative("No, I'll run later").
Value(&runNow),
),
).WithTheme(styles.HuhTheme()).WithAccessible(console.IsAccessibleMode())
).WithTheme(styles.HuhTheme).WithAccessible(console.IsAccessibleMode())

if err := form.RunWithContext(ctx); err != nil {
return nil // Not critical, just skip
Expand Down
6 changes: 3 additions & 3 deletions pkg/cli/engine_secrets.go
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ func promptForCopilotPATUnified(req SecretRequirement, config EngineSecretConfig
return stringutil.ValidateCopilotPAT(s)
}),
),
).WithTheme(styles.HuhTheme()).WithAccessible(console.IsAccessibleMode())
).WithTheme(styles.HuhTheme).WithAccessible(console.IsAccessibleMode())

if err := form.RunWithContext(config.ctx()); err != nil {
return fmt.Errorf("failed to get Copilot token: %w", err)
Expand Down Expand Up @@ -367,7 +367,7 @@ func promptForSystemTokenUnified(req SecretRequirement, config EngineSecretConfi
return nil
}),
),
).WithTheme(styles.HuhTheme()).WithAccessible(console.IsAccessibleMode())
).WithTheme(styles.HuhTheme).WithAccessible(console.IsAccessibleMode())

if err := form.RunWithContext(config.ctx()); err != nil {
return fmt.Errorf("failed to get %s token: %w", req.Name, err)
Expand Down Expand Up @@ -420,7 +420,7 @@ func promptForGenericAPIKeyUnified(req SecretRequirement, config EngineSecretCon
return nil
}),
),
).WithTheme(styles.HuhTheme()).WithAccessible(console.IsAccessibleMode())
).WithTheme(styles.HuhTheme).WithAccessible(console.IsAccessibleMode())

if err := form.RunWithContext(config.ctx()); err != nil {
return fmt.Errorf("failed to get %s API key: %w", label, err)
Expand Down
6 changes: 3 additions & 3 deletions pkg/cli/interactive.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ func (b *InteractiveWorkflowBuilder) promptForWorkflowName() error {
Value(&b.WorkflowName).
Validate(ValidateWorkflowName),
),
).WithTheme(styles.HuhTheme()).WithAccessible(console.IsAccessibleMode())
).WithTheme(styles.HuhTheme).WithAccessible(console.IsAccessibleMode())

return form.RunWithContext(b.ctx)
}
Expand Down Expand Up @@ -224,7 +224,7 @@ func (b *InteractiveWorkflowBuilder) promptForConfiguration() error {
).
Title("Instructions").
Description("Describe what you want this workflow to accomplish"),
).WithTheme(styles.HuhTheme()).WithAccessible(console.IsAccessibleMode())
).WithTheme(styles.HuhTheme).WithAccessible(console.IsAccessibleMode())

if err := form.RunWithContext(b.ctx); err != nil {
return err
Expand Down Expand Up @@ -269,7 +269,7 @@ func (b *InteractiveWorkflowBuilder) generateWorkflow(force bool) error {
Negative("No, cancel").
Value(&overwrite),
),
).WithTheme(styles.HuhTheme()).WithAccessible(console.IsAccessibleMode())
).WithTheme(styles.HuhTheme).WithAccessible(console.IsAccessibleMode())

if err := confirmForm.Run(); err != nil {
return fmt.Errorf("confirmation failed: %w", err)
Expand Down
6 changes: 3 additions & 3 deletions pkg/cli/run_interactive.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ func selectWorkflow(ctx context.Context, workflows []WorkflowOption) (*WorkflowO
Height(15).
Value(&selected),
),
).WithTheme(styles.HuhTheme()).WithAccessible(console.IsAccessibleMode())
).WithTheme(styles.HuhTheme).WithAccessible(console.IsAccessibleMode())

if err := form.RunWithContext(ctx); err != nil {
return nil, fmt.Errorf("workflow selection cancelled or failed: %w", err)
Expand Down Expand Up @@ -314,7 +314,7 @@ func collectInputsWithMap(ctx context.Context, inputs map[string]*workflow.Input
}

// Show the form
form := huh.NewForm(formGroups...).WithTheme(styles.HuhTheme()).WithAccessible(console.IsAccessibleMode())
form := huh.NewForm(formGroups...).WithTheme(styles.HuhTheme).WithAccessible(console.IsAccessibleMode())
if err := form.RunWithContext(ctx); err != nil {
return nil, fmt.Errorf("input collection cancelled: %w", err)
}
Expand Down Expand Up @@ -351,7 +351,7 @@ func confirmExecution(ctx context.Context, wf *WorkflowOption, inputs []string)
Negative("No, cancel").
Value(&confirm),
),
).WithTheme(styles.HuhTheme()).WithAccessible(console.IsAccessibleMode())
).WithTheme(styles.HuhTheme).WithAccessible(console.IsAccessibleMode())

if err := form.RunWithContext(ctx); err != nil {
runInteractiveLog.Printf("Confirmation failed: %v", err)
Expand Down
2 changes: 1 addition & 1 deletion pkg/console/confirm.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func ConfirmAction(title, affirmative, negative string) (bool, error) {
Negative(negative).
Value(&confirmed),
),
).WithTheme(styles.HuhTheme()).WithAccessible(IsAccessibleMode())
).WithTheme(styles.HuhTheme).WithAccessible(IsAccessibleMode())

if err := confirmForm.Run(); err != nil {
return false, err
Expand Down
2 changes: 1 addition & 1 deletion pkg/console/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func PromptSecretInput(title, description string) (string, error) {
}).
Value(&value),
),
).WithTheme(styles.HuhTheme()).WithAccessible(IsAccessibleMode())
).WithTheme(styles.HuhTheme).WithAccessible(IsAccessibleMode())

if err := form.Run(); err != nil {
return "", err
Expand Down
2 changes: 1 addition & 1 deletion pkg/console/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func ShowInteractiveList(title string, items []ListItem) (string, error) {
Options(opts...).
Value(&selected),
),
).WithTheme(styles.HuhTheme()).WithAccessible(IsAccessibleMode())
).WithTheme(styles.HuhTheme).WithAccessible(IsAccessibleMode())

if err := form.Run(); err != nil {
listLog.Printf("Error running list form: %v", err)
Expand Down
108 changes: 53 additions & 55 deletions pkg/styles/huh_theme.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,70 +7,68 @@ import (
"charm.land/lipgloss/v2"
)

// HuhTheme returns a huh.ThemeFunc that maps the pkg/styles Dracula-inspired
// HuhTheme is a huh.ThemeFunc that maps the pkg/styles Dracula-inspired
// color palette to huh form fields, giving interactive forms the same visual
// identity as the rest of the CLI output.
func HuhTheme() huh.ThemeFunc {
return func(isDark bool) *huh.Styles {
t := huh.ThemeBase(isDark)
lightDark := lipgloss.LightDark(isDark)
var HuhTheme huh.ThemeFunc = func(isDark bool) *huh.Styles {
t := huh.ThemeBase(isDark)
lightDark := lipgloss.LightDark(isDark)

// Map the pkg/styles palette using lipgloss v2's LightDark helper.
var (
primary = lightDark(lipgloss.Color(hexColorPurpleLight), lipgloss.Color(hexColorPurpleDark))
success = lightDark(lipgloss.Color(hexColorSuccessLight), lipgloss.Color(hexColorSuccessDark))
errorColor = lightDark(lipgloss.Color(hexColorErrorLight), lipgloss.Color(hexColorErrorDark))
warning = lightDark(lipgloss.Color(hexColorWarningLight), lipgloss.Color(hexColorWarningDark))
comment = lightDark(lipgloss.Color(hexColorCommentLight), lipgloss.Color(hexColorCommentDark))
fg = lightDark(lipgloss.Color(hexColorForegroundLight), lipgloss.Color(hexColorForegroundDark))
bg = lightDark(lipgloss.Color(hexColorBackgroundLight), lipgloss.Color(hexColorBackgroundDark))
border = lightDark(lipgloss.Color(hexColorBorderLight), lipgloss.Color(hexColorBorderDark))
)
// Map the pkg/styles palette using lipgloss v2's LightDark helper.
var (
primary = lightDark(lipgloss.Color(hexColorPurpleLight), lipgloss.Color(hexColorPurpleDark))
success = lightDark(lipgloss.Color(hexColorSuccessLight), lipgloss.Color(hexColorSuccessDark))
errorColor = lightDark(lipgloss.Color(hexColorErrorLight), lipgloss.Color(hexColorErrorDark))
warning = lightDark(lipgloss.Color(hexColorWarningLight), lipgloss.Color(hexColorWarningDark))
comment = lightDark(lipgloss.Color(hexColorCommentLight), lipgloss.Color(hexColorCommentDark))
fg = lightDark(lipgloss.Color(hexColorForegroundLight), lipgloss.Color(hexColorForegroundDark))
bg = lightDark(lipgloss.Color(hexColorBackgroundLight), lipgloss.Color(hexColorBackgroundDark))
border = lightDark(lipgloss.Color(hexColorBorderLight), lipgloss.Color(hexColorBorderDark))
)

// Focused field styles
t.Focused.Base = t.Focused.Base.BorderForeground(border)
t.Focused.Card = t.Focused.Base
t.Focused.Title = t.Focused.Title.Foreground(primary).Bold(true)
t.Focused.NoteTitle = t.Focused.NoteTitle.Foreground(primary).Bold(true).MarginBottom(1)
t.Focused.Directory = t.Focused.Directory.Foreground(primary)
t.Focused.Description = t.Focused.Description.Foreground(comment)
t.Focused.ErrorIndicator = t.Focused.ErrorIndicator.Foreground(errorColor)
t.Focused.ErrorMessage = t.Focused.ErrorMessage.Foreground(errorColor)
// Focused field styles
t.Focused.Base = t.Focused.Base.BorderForeground(border)
t.Focused.Card = t.Focused.Base
t.Focused.Title = t.Focused.Title.Foreground(primary).Bold(true)
t.Focused.NoteTitle = t.Focused.NoteTitle.Foreground(primary).Bold(true).MarginBottom(1)
t.Focused.Directory = t.Focused.Directory.Foreground(primary)
t.Focused.Description = t.Focused.Description.Foreground(comment)
t.Focused.ErrorIndicator = t.Focused.ErrorIndicator.Foreground(errorColor)
t.Focused.ErrorMessage = t.Focused.ErrorMessage.Foreground(errorColor)

// Select / navigation indicators
t.Focused.SelectSelector = t.Focused.SelectSelector.Foreground(warning)
t.Focused.NextIndicator = t.Focused.NextIndicator.Foreground(warning)
t.Focused.PrevIndicator = t.Focused.PrevIndicator.Foreground(warning)
// Select / navigation indicators
t.Focused.SelectSelector = t.Focused.SelectSelector.Foreground(warning)
t.Focused.NextIndicator = t.Focused.NextIndicator.Foreground(warning)
t.Focused.PrevIndicator = t.Focused.PrevIndicator.Foreground(warning)

// List option styles
t.Focused.Option = t.Focused.Option.Foreground(fg)
t.Focused.MultiSelectSelector = t.Focused.MultiSelectSelector.Foreground(warning)
t.Focused.SelectedOption = t.Focused.SelectedOption.Foreground(success)
t.Focused.SelectedPrefix = t.Focused.SelectedPrefix.Foreground(success)
t.Focused.UnselectedOption = t.Focused.UnselectedOption.Foreground(fg)
t.Focused.UnselectedPrefix = t.Focused.UnselectedPrefix.Foreground(comment)
// List option styles
t.Focused.Option = t.Focused.Option.Foreground(fg)
t.Focused.MultiSelectSelector = t.Focused.MultiSelectSelector.Foreground(warning)
t.Focused.SelectedOption = t.Focused.SelectedOption.Foreground(success)
t.Focused.SelectedPrefix = t.Focused.SelectedPrefix.Foreground(success)
t.Focused.UnselectedOption = t.Focused.UnselectedOption.Foreground(fg)
t.Focused.UnselectedPrefix = t.Focused.UnselectedPrefix.Foreground(comment)

// Button styles
t.Focused.FocusedButton = t.Focused.FocusedButton.Foreground(bg).Background(primary).Bold(true)
t.Focused.BlurredButton = t.Focused.BlurredButton.Foreground(fg).Background(bg)
t.Focused.Next = t.Focused.FocusedButton
// Button styles
t.Focused.FocusedButton = t.Focused.FocusedButton.Foreground(bg).Background(primary).Bold(true)
t.Focused.BlurredButton = t.Focused.BlurredButton.Foreground(fg).Background(bg)
t.Focused.Next = t.Focused.FocusedButton

// Text input styles
t.Focused.TextInput.Cursor = t.Focused.TextInput.Cursor.Foreground(warning)
t.Focused.TextInput.Placeholder = t.Focused.TextInput.Placeholder.Foreground(comment)
t.Focused.TextInput.Prompt = t.Focused.TextInput.Prompt.Foreground(primary)
// Text input styles
t.Focused.TextInput.Cursor = t.Focused.TextInput.Cursor.Foreground(warning)
t.Focused.TextInput.Placeholder = t.Focused.TextInput.Placeholder.Foreground(comment)
t.Focused.TextInput.Prompt = t.Focused.TextInput.Prompt.Foreground(primary)

// Blurred styles mirror focused but hide the border
t.Blurred = t.Focused
t.Blurred.Base = t.Focused.Base.BorderStyle(lipgloss.HiddenBorder())
t.Blurred.Card = t.Blurred.Base
t.Blurred.NextIndicator = lipgloss.NewStyle()
t.Blurred.PrevIndicator = lipgloss.NewStyle()
// Blurred styles mirror focused but hide the border
t.Blurred = t.Focused
t.Blurred.Base = t.Focused.Base.BorderStyle(lipgloss.HiddenBorder())
t.Blurred.Card = t.Blurred.Base
t.Blurred.NextIndicator = lipgloss.NewStyle()
t.Blurred.PrevIndicator = lipgloss.NewStyle()

// Group header styles
t.Group.Title = t.Focused.Title
t.Group.Description = t.Focused.Description
// Group header styles
t.Group.Title = t.Focused.Title
t.Group.Description = t.Focused.Description

return t
}
return t
}
Loading