Skip to content

Commit 3c0e4f5

Browse files
Style and language tweaks to workflows init (#372)
* Style and language tweaks to workflows init * Revert change to TS formatting in init GitOrigin-RevId: f9b883dce17e037f1024634f7e0796b6f3213301
1 parent 471c2d5 commit 3c0e4f5

5 files changed

Lines changed: 98 additions & 17 deletions

File tree

cmd/objectdelete.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ Examples:
6161
// Prompt for confirmation unless --yes is specified or non-interactive
6262
if !input.Yes && command.IsInteractive(cmd.Context()) {
6363
if !confirmDelete(input.Keys) {
64-
fmt.Println("Delete cancelled.")
64+
fmt.Println("Delete canceled.")
6565
return nil
6666
}
6767
}

cmd/workflowinit.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ type WorkflowInitInput struct {
2323
InstallAgentSkill bool `cli:"install-agent-skill"`
2424
}
2525

26-
const defaultDir = "workflows-demo"
26+
const defaultDir = "./workflows-demo"
2727

2828
var workflowInitCmd = &cobra.Command{
2929
Use: "init",
@@ -206,7 +206,7 @@ func formatNextSteps(result *scaffold.Result, relDir string) string {
206206
func init() {
207207
workflowInitCmd.Flags().String("language", "", "Language for the workflows project (python, node)")
208208
workflowInitCmd.Flags().String("template", "", "Template to scaffold (defaults to the repo's default template)")
209-
workflowInitCmd.Flags().String("dir", "", "Output directory (default: workflows-demo)")
209+
workflowInitCmd.Flags().String("dir", "", "Output directory (default: ./workflows-demo)")
210210
workflowInitCmd.Flags().Bool("install-deps", false, "Install dependencies after scaffolding")
211211
workflowInitCmd.Flags().Bool("git", false, "Initialize a Git repository")
212212
workflowInitCmd.Flags().Bool("install-agent-skill", false, "Install the Workflows agent skill for detected AI coding tools")

cmd/workflowinitrunner.go

Lines changed: 93 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package cmd
33
import (
44
"bytes"
55
"context"
6+
"errors"
67
"fmt"
78
"os"
89
"os/exec"
@@ -80,6 +81,54 @@ type WorkflowInitRunner struct {
8081
cmd *cobra.Command
8182
}
8283

84+
func truncateDisplayWidth(s string, maxWidth int) string {
85+
if maxWidth <= 0 {
86+
return ""
87+
}
88+
if lipgloss.Width(s) <= maxWidth {
89+
return s
90+
}
91+
92+
const ellipsis = "…"
93+
ellipsisWidth := lipgloss.Width(ellipsis)
94+
if maxWidth <= ellipsisWidth {
95+
return ellipsis
96+
}
97+
98+
available := maxWidth - ellipsisWidth
99+
var b strings.Builder
100+
used := 0
101+
for _, r := range s {
102+
rw := lipgloss.Width(string(r))
103+
if used+rw > available {
104+
break
105+
}
106+
b.WriteRune(r)
107+
used += rw
108+
}
109+
110+
return b.String() + ellipsis
111+
}
112+
113+
func expandHomePath(path string) (string, error) {
114+
if path == "" || path[0] != '~' {
115+
return path, nil
116+
}
117+
if path != "~" && len(path) > 1 && path[1] != '/' && path[1] != '\\' {
118+
// Keep "~user/..." unchanged; we only support current-user home expansion.
119+
return path, nil
120+
}
121+
122+
home, err := os.UserHomeDir()
123+
if err != nil {
124+
return "", fmt.Errorf("failed to resolve home directory: %w", err)
125+
}
126+
if path == "~" {
127+
return home, nil
128+
}
129+
return filepath.Join(home, path[2:]), nil
130+
}
131+
83132
// prePrompt prints a blank line before an interactive prompt for visual spacing.
84133
func (r *WorkflowInitRunner) prePrompt() {
85134
command.Println(r.cmd, "")
@@ -94,6 +143,14 @@ func (r *WorkflowInitRunner) postPrompt() {
94143
}
95144
}
96145

146+
func (r *WorkflowInitRunner) handlePromptError(err error) error {
147+
if errors.Is(err, huh.ErrUserAborted) {
148+
command.Println(r.cmd, "Setup canceled.")
149+
return nil
150+
}
151+
return err
152+
}
153+
97154
// Run executes the full init flow: resolve templates, prompt for options
98155
// (in interactive mode), scaffold, install deps, init git, and print results.
99156
func (r *WorkflowInitRunner) Run(ctx context.Context, input WorkflowInitInput) error {
@@ -126,7 +183,7 @@ func (r *WorkflowInitRunner) Run(ctx context.Context, input WorkflowInitInput) e
126183
),
127184
)
128185
if err := form.Run(); err != nil {
129-
return err
186+
return r.handlePromptError(err)
130187
}
131188
r.postPrompt()
132189
input.Language = language
@@ -198,11 +255,27 @@ func (r *WorkflowInitRunner) Run(ctx context.Context, input WorkflowInitInput) e
198255
input.Template = templates[0].DirName
199256
} else if r.interactive && !skipPrompts {
200257
r.prePrompt()
258+
const maxTemplateNameWidth = 20
259+
const templateDescriptionGap = " "
260+
templateNameStyle := lipgloss.NewStyle().Bold(true)
261+
maxTemplateLabelWidth := 0
262+
for _, t := range templates {
263+
name := truncateDisplayWidth(t.Name, maxTemplateNameWidth)
264+
if w := lipgloss.Width(name); w > maxTemplateLabelWidth {
265+
maxTemplateLabelWidth = w
266+
}
267+
}
268+
201269
var templateOptions []huh.Option[string]
202270
for _, t := range templates {
203-
label := t.Name
271+
name := truncateDisplayWidth(t.Name, maxTemplateNameWidth)
272+
label := templateNameStyle.Render(name)
204273
if t.Description != "" {
205-
label = fmt.Sprintf("%s — %s", t.Name, t.Description)
274+
padding := ""
275+
if pad := maxTemplateLabelWidth - lipgloss.Width(name); pad > 0 {
276+
padding = strings.Repeat(" ", pad)
277+
}
278+
label = fmt.Sprintf("%s%s%s%s", label, padding, templateDescriptionGap, t.Description)
206279
}
207280
templateOptions = append(templateOptions, huh.NewOption(label, t.DirName))
208281
}
@@ -217,7 +290,7 @@ func (r *WorkflowInitRunner) Run(ctx context.Context, input WorkflowInitInput) e
217290
),
218291
)
219292
if err := form.Run(); err != nil {
220-
return err
293+
return r.handlePromptError(err)
221294
}
222295
r.postPrompt()
223296
input.Template = selected
@@ -264,17 +337,21 @@ func (r *WorkflowInitRunner) Run(ctx context.Context, input WorkflowInitInput) e
264337
form := huh.NewForm(
265338
huh.NewGroup(
266339
huh.NewInput().
267-
Title("Where should we create your workflows project?").
340+
Title("Specify a project directory (must be new or empty)").
268341
Value(&dir),
269342
),
270343
)
271344
if err := form.Run(); err != nil {
272-
return err
345+
return r.handlePromptError(err)
273346
}
274347
r.postPrompt()
275348
input.Dir = dir
276349

277-
absDir, err := filepath.Abs(input.Dir)
350+
expandedDir, err := expandHomePath(input.Dir)
351+
if err != nil {
352+
return err
353+
}
354+
absDir, err := filepath.Abs(expandedDir)
278355
if err != nil {
279356
return fmt.Errorf("failed to resolve path: %w", err)
280357
}
@@ -298,7 +375,11 @@ func (r *WorkflowInitRunner) Run(ctx context.Context, input WorkflowInitInput) e
298375

299376
input.Dir = strings.TrimPrefix(input.Dir, "./")
300377

301-
absDir, err := filepath.Abs(input.Dir)
378+
expandedDir, err := expandHomePath(input.Dir)
379+
if err != nil {
380+
return err
381+
}
382+
absDir, err := filepath.Abs(expandedDir)
302383
if err != nil {
303384
return fmt.Errorf("failed to resolve path: %w", err)
304385
}
@@ -319,7 +400,7 @@ func (r *WorkflowInitRunner) Run(ctx context.Context, input WorkflowInitInput) e
319400
form := huh.NewForm(
320401
huh.NewGroup(
321402
huh.NewSelect[string]().
322-
Title("Install dependencies?").
403+
Title("Install project dependencies?").
323404
Description("(recommended)").
324405
Options(
325406
huh.NewOption("Yes", "yes"),
@@ -329,7 +410,7 @@ func (r *WorkflowInitRunner) Run(ctx context.Context, input WorkflowInitInput) e
329410
),
330411
)
331412
if err := form.Run(); err != nil {
332-
return err
413+
return r.handlePromptError(err)
333414
}
334415
r.postPrompt()
335416
wantDeps = installDeps == "yes"
@@ -357,7 +438,7 @@ func (r *WorkflowInitRunner) Run(ctx context.Context, input WorkflowInitInput) e
357438
huh.NewGroup(
358439
huh.NewSelect[string]().
359440
Title("Initialize a new Git repository?").
360-
Description("(optional)").
441+
Description("(recommended)").
361442
Options(
362443
huh.NewOption("Yes", "yes"),
363444
huh.NewOption("No", "no"),
@@ -366,7 +447,7 @@ func (r *WorkflowInitRunner) Run(ctx context.Context, input WorkflowInitInput) e
366447
),
367448
)
368449
if err := form.Run(); err != nil {
369-
return err
450+
return r.handlePromptError(err)
370451
}
371452
r.postPrompt()
372453
wantGit = initGit == "yes"

pkg/tui/views/deploycancel.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func CancelDeploy(ctx context.Context, input DeployCancelInput) (string, error)
3333
if err != nil {
3434
return "", fmt.Errorf("failed to cancel deploy: %w", err)
3535
}
36-
return fmt.Sprintf("Deploy %s successfully cancelled", input.DeployID), nil
36+
return fmt.Sprintf("Deploy %s successfully canceled", input.DeployID), nil
3737
}
3838

3939
func RequireConfirmationForCancelDeploy(ctx context.Context, input DeployCancelInput) (string, error) {

pkg/tui/views/jobcancel.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func CancelJob(ctx context.Context, input JobCancelInput) (string, error) {
3434
if err != nil {
3535
return "", fmt.Errorf("failed to cancel job: %w", err)
3636
}
37-
return fmt.Sprintf("Job %s successfully cancelled", input.JobID), nil
37+
return fmt.Sprintf("Job %s successfully canceled", input.JobID), nil
3838
}
3939

4040
func RequireConfirmationForCancelJob(ctx context.Context, input JobCancelInput) (string, error) {

0 commit comments

Comments
 (0)