@@ -41,7 +41,7 @@ type targetItem struct {
4141 key targetKey
4242
4343 displayName string
44- usage string
44+ args []parse. Arg
4545 synopsis string
4646 aliases []string
4747 isDefault bool
@@ -58,8 +58,8 @@ var nsDefaultSuffix = ":" + strings.ToLower(defaultLabel) //nolint:gochecknoglob
5858//
5959// It is implemented in the Stave binary (not in the generated mainfile) so it can
6060// use Charmbracelet styling without requiring additional dependencies in user projects.
61- func renderTargetList (out io.Writer , binaryName string , info * parse.PkgInfo , filters []string ) error {
62- items := buildTargetItems (binaryName , info )
61+ func renderTargetList (out io.Writer , info * parse.PkgInfo , filters []string ) error {
62+ items := buildTargetItems (info )
6363 items = applyTargetFilters (items , filters )
6464
6565 anyWatch := false
@@ -95,27 +95,47 @@ func renderTargetList(out io.Writer, binaryName string, info *parse.PkgInfo, fil
9595 watchStyle = watchStyle .Foreground (cs .QuotedString ).Reverse (true ).Bold (true )
9696 }
9797
98- renderName := func (name string , isDefault , isWatch bool ) string {
98+ renderName := func (name string , isDefault , isWatch bool , args []parse.Arg ) string {
99+ var sb strings.Builder
99100 if ! colorEnabled {
101+ sb .WriteString (name )
102+ for _ , a := range args {
103+ if strings .TrimSpace (a .Name ) == "" {
104+ continue
105+ }
106+ sb .WriteString (" <" )
107+ sb .WriteString (a .Name )
108+ sb .WriteString (">" )
109+ }
100110 if isWatch {
101- return name + " [W]"
111+ sb . WriteString ( " [W]" )
102112 }
103- return name
113+ return sb . String ()
104114 }
105115
106- var renderedName string
107116 if isDefault {
108117 // Default target is highlighted with a distinct color so it is visually discoverable.
109- renderedName = defaultNameStyle .Render (name )
118+ sb . WriteString ( defaultNameStyle .Render (name ) )
110119 } else {
111120 // Non-default targets use the existing env-driven target color semantics.
112- renderedName = targetStyle .Render (name )
121+ sb .WriteString (targetStyle .Render (name ))
122+ }
123+
124+ for _ , a := range args {
125+ if strings .TrimSpace (a .Name ) == "" {
126+ continue
127+ }
128+ sb .WriteString (" <" )
129+ sb .WriteString (a .Name )
130+ sb .WriteString (">" )
113131 }
114132
115133 if isWatch {
116- renderedName += " " + watchStyle .Render ("[W]" )
134+ sb .WriteString (" " )
135+ sb .WriteString (watchStyle .Render ("[W]" ))
117136 }
118- return renderedName
137+
138+ return sb .String ()
119139 }
120140
121141 // Header
@@ -154,7 +174,7 @@ func renderTargetList(out io.Writer, binaryName string, info *parse.PkgInfo, fil
154174 return nil
155175}
156176
157- func buildTargetItems (binaryName string , info * parse.PkgInfo ) []targetItem {
177+ func buildTargetItems (info * parse.PkgInfo ) []targetItem {
158178 aliasByKey := make (map [targetKey ][]string )
159179 for alias , fn := range info .Aliases {
160180 if fn == nil {
@@ -191,7 +211,7 @@ func buildTargetItems(binaryName string, info *parse.PkgInfo) []targetItem {
191211 items = append (items , targetItem {
192212 key : funcKey ,
193213 displayName : display ,
194- usage : usageFor ( binaryName , display , fn .Args ) ,
214+ args : fn .Args ,
195215 synopsis : fn .Synopsis ,
196216 aliases : aliasByKey [funcKey ],
197217 isDefault : funcKey == defaultKey && fn .Name != "" ,
@@ -219,7 +239,7 @@ func buildTargetItems(binaryName string, info *parse.PkgInfo) []targetItem {
219239 items = append (items , targetItem {
220240 key : funcKey ,
221241 displayName : display ,
222- usage : usageFor ( binaryName , display , fn .Args ) ,
242+ args : fn .Args ,
223243 synopsis : fn .Synopsis ,
224244 aliases : aliasByKey [funcKey ],
225245 isDefault : funcKey == defaultKey && fn .Name != "" ,
@@ -293,7 +313,7 @@ func applyTargetFilters(items []targetItem, filters []string) []targetItem {
293313 out := make ([]targetItem , 0 , len (items ))
294314 for _ , it := range items {
295315 aliases := strings .Join (it .aliases , ", " )
296- if matchAll (strings .Join ([]string {it .displayName , it .usage , it . synopsis , aliases , it .groupName , it .groupMeta }, " " )) {
316+ if matchAll (strings .Join ([]string {it .displayName , it .synopsis , aliases , it .groupName , it .groupMeta }, " " )) {
297317 out = append (out , it )
298318 }
299319 }
@@ -349,15 +369,14 @@ func groupTargets(items []targetItem) targetSections {
349369 switch it .groupKind {
350370 case targetGroupLocal :
351371 if it .isDefault {
352- it .usage = strings .TrimSuffix (it .usage , it .displayName )
353- it .usage += "(" + it .displayName + ")"
372+ it .displayName = "(" + it .displayName + ")"
354373 }
355374
356375 locals = append (locals , it )
357376 case targetGroupNamespace :
358377 if it .key .name == defaultLabel {
359378 it .isDefault = true
360- it .usage = strings .TrimSuffix (it .usage , nsDefaultSuffix )
379+ it .displayName = strings .TrimSuffix (it .displayName , nsDefaultSuffix )
361380 }
362381 nsByName [it .groupName ] = append (nsByName [it .groupName ], it )
363382 case targetGroupImport :
@@ -386,7 +405,7 @@ func writeTable(
386405 out io.Writer ,
387406 headerStyle , subsectionStyle lipgloss.Style ,
388407 group targetGroup ,
389- renderName func (name string , isDefault , isWatch bool ) string ,
408+ renderName func (name string , isDefault , isWatch bool , args []parse. Arg ) string ,
390409 indent string ,
391410) {
392411 if len (group .items ) == 0 {
@@ -404,16 +423,15 @@ func writeTable(
404423
405424 type row struct {
406425 name string
407- usage string
426+ args []parse. Arg
408427 synopsis string
409428 isDefault bool
410429 isWatch bool
411430 }
412431
413432 rows := make ([]row , 0 , len (group .items )+ 1 )
414433 rows = append (rows , row {
415- name : "NAME" ,
416- usage : "USAGE" ,
434+ name : "USAGE" ,
417435 synopsis : "SYNOPSIS" ,
418436 })
419437
@@ -428,22 +446,25 @@ func writeTable(
428446 }
429447 rows = append (rows , row {
430448 name : name ,
431- usage : it .usage ,
449+ args : it .args ,
432450 synopsis : syn ,
433451 isDefault : it .isDefault ,
434452 isWatch : it .isWatch ,
435453 })
436454 }
437455
438456 // Column widths (ANSI-aware via lipgloss.Width).
439- maxName , maxUsage , maxSyn := 0 , 0 , 0
440- for _ , theRow := range rows {
441- name := theRow .name
442- if theRow .isWatch {
443- name += " [W]"
457+ maxUsage , maxSyn := 0 , 0
458+ for i , theRow := range rows {
459+ usage := theRow .name
460+ if i > 0 {
461+ // For data rows, use the non-colored usage string to calculate width
462+ usage = usageFor ("" , theRow .name , theRow .args )
463+ if theRow .isWatch {
464+ usage += " [W]"
465+ }
444466 }
445- maxName = max (maxName , lipgloss .Width (name ))
446- maxUsage = max (maxUsage , lipgloss .Width (theRow .usage ))
467+ maxUsage = max (maxUsage , lipgloss .Width (usage ))
447468 maxSyn = max (maxSyn , lipgloss .Width (theRow .synopsis ))
448469 }
449470
@@ -461,16 +482,15 @@ func writeTable(
461482 // Print header.
462483 h := rows [0 ]
463484 headerLine := strings .Join ([]string {
464- pad (h .name , maxName ),
465- pad (h .usage , maxUsage ),
485+ pad (h .name , maxUsage ),
466486 h .synopsis ,
467487 }, " " )
468488 _ , _ = fmt .Fprintln (out , indent + headerStyle .Render (headerLine ))
469489
470490 // Compute terminal width and synopsis column width for wrapping.
471491 termWidth := detectTermWidth (out )
472492 const gap = 2
473- leftOffset := lipgloss .Width (indent ) + maxName + gap + maxUsage + gap
493+ leftOffset := lipgloss .Width (indent ) + maxUsage + gap
474494 synWidth := termWidth - leftOffset
475495 if synWidth < termWidthFloor {
476496 synWidth = termWidthFloor
@@ -480,15 +500,14 @@ func writeTable(
480500
481501 // Print rows with word-wrapped synopsis using a hanging indent.
482502 for _ , theRow := range rows [1 :] {
483- name := renderName (theRow .name , theRow .isDefault , theRow .isWatch )
503+ usage := renderName (theRow .name , theRow .isDefault , theRow .isWatch , theRow . args )
484504
485505 wrappedSyn := wordwrap .String (theRow .synopsis , synWidth )
486506 // Align continuation lines under the start of the synopsis column.
487507 wrappedSyn = strings .ReplaceAll (wrappedSyn , "\n " , "\n " + spaceLeft )
488508
489509 line := strings .Join ([]string {
490- pad (name , maxName ),
491- pad (theRow .usage , maxUsage ),
510+ pad (usage , maxUsage ),
492511 wrappedSyn ,
493512 }, strings .Repeat (" " , gap ))
494513 _ , _ = fmt .Fprintln (out , indent + line )
0 commit comments