Skip to content

Commit a3fdfdc

Browse files
committed
Refactor StringArgsDispatcher and SuperStringArgsDispatcher to include baseCommand parameter, streamline command printing, and enhance command completion functionality.
1 parent f9c0059 commit a3fdfdc

File tree

2 files changed

+92
-45
lines changed

2 files changed

+92
-45
lines changed

cli/stringargsdispatcher.go

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@ package cli
33
import (
44
"context"
55
"fmt"
6-
"io"
76
"maps"
87
"reflect"
98
"slices"
10-
"sort"
119
"strings"
1210
"unicode"
1311

@@ -46,14 +44,16 @@ func (f StringArgsCommandLoggerFunc) LogStringArgsCommand(command string, args [
4644
}
4745

4846
type StringArgsDispatcher struct {
49-
comm map[string]*stringArgsCommand
50-
loggers []StringArgsCommandLogger
47+
baseCommand string
48+
comm map[string]*stringArgsCommand
49+
loggers []StringArgsCommandLogger
5150
}
5251

53-
func NewStringArgsDispatcher(loggers ...StringArgsCommandLogger) *StringArgsDispatcher {
52+
func NewStringArgsDispatcher(baseCommand string, loggers ...StringArgsCommandLogger) *StringArgsDispatcher {
5453
return &StringArgsDispatcher{
55-
comm: make(map[string]*stringArgsCommand),
56-
loggers: loggers,
54+
baseCommand: baseCommand,
55+
comm: make(map[string]*stringArgsCommand),
56+
loggers: loggers,
5757
}
5858
}
5959

@@ -159,17 +159,13 @@ func (disp *StringArgsDispatcher) MustDispatchCombinedCommandAndArgs(ctx context
159159
return command
160160
}
161161

162-
func (disp *StringArgsDispatcher) PrintCommands(appName string) {
163-
list := make([]*stringArgsCommand, 0, len(disp.comm))
164-
for _, cmd := range disp.comm {
165-
list = append(list, cmd)
166-
}
167-
sort.Slice(list, func(i, j int) bool {
168-
return list[i].command < list[j].command
162+
func (disp *StringArgsDispatcher) PrintCommands() {
163+
commands := slices.SortedFunc(maps.Values(disp.comm), func(a, b *stringArgsCommand) int {
164+
return strings.Compare(a.command, b.command)
169165
})
170166

171-
for _, cmd := range list {
172-
UsageColor.Printf(" %s %s %s\n", appName, cmd.command, functionArgsString(cmd.commandFunc))
167+
for _, cmd := range commands {
168+
UsageColor.Printf(" %s %s %s\n", disp.baseCommand, cmd.command, functionArgsString(cmd.commandFunc))
173169
if cmd.description != "" {
174170
DescriptionColor.Printf(" %s\n", cmd.description)
175171
}
@@ -189,11 +185,26 @@ func (disp *StringArgsDispatcher) PrintCommands(appName string) {
189185
}
190186
}
191187

192-
func (disp *StringArgsDispatcher) PrintCommandsUsageIntro(appName string, output io.Writer) {
193-
if len(disp.comm) > 0 {
194-
fmt.Fprint(output, "Commands:\n")
195-
disp.PrintCommands(appName)
196-
fmt.Fprint(output, "Flags:\n")
188+
func (disp *StringArgsDispatcher) PrintCommandsUsageIntro() {
189+
if len(disp.comm) == 0 {
190+
return
191+
}
192+
fmt.Println("Commands:")
193+
disp.PrintCommands()
194+
}
195+
196+
func (disp *StringArgsDispatcher) PrintCompletion(args []string) {
197+
prefix := ""
198+
if len(args) > 0 {
199+
prefix = args[0]
200+
}
201+
commands := slices.SortedFunc(maps.Values(disp.comm), func(a, b *stringArgsCommand) int {
202+
return strings.Compare(a.command, b.command)
203+
})
204+
for _, cmd := range commands {
205+
if strings.HasPrefix(cmd.command, prefix) {
206+
fmt.Println(disp.baseCommand, cmd.command)
207+
}
197208
}
198209
}
199210

cli/superstringargsdispatcher.go

Lines changed: 60 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,25 @@ package cli
33
import (
44
"context"
55
"fmt"
6-
"io"
76
"maps"
87
"slices"
98
"sort"
9+
"strings"
1010

1111
"github.com/domonda/go-function"
1212
)
1313

1414
type SuperStringArgsDispatcher struct {
15-
sub map[string]*StringArgsDispatcher
16-
loggers []StringArgsCommandLogger
15+
baseCommand string
16+
sub map[string]*StringArgsDispatcher
17+
loggers []StringArgsCommandLogger
1718
}
1819

19-
func NewSuperStringArgsDispatcher(loggers ...StringArgsCommandLogger) *SuperStringArgsDispatcher {
20+
func NewSuperStringArgsDispatcher(baseCommand string, loggers ...StringArgsCommandLogger) *SuperStringArgsDispatcher {
2021
return &SuperStringArgsDispatcher{
21-
sub: make(map[string]*StringArgsDispatcher),
22-
loggers: loggers,
22+
baseCommand: baseCommand,
23+
sub: make(map[string]*StringArgsDispatcher),
24+
loggers: loggers,
2325
}
2426
}
2527

@@ -32,7 +34,7 @@ func (disp *SuperStringArgsDispatcher) AddSuperCommand(superCommand string) (sub
3234
if _, exists := disp.sub[superCommand]; exists {
3335
return nil, fmt.Errorf("super command already added: '%s'", superCommand)
3436
}
35-
subDisp = NewStringArgsDispatcher(disp.loggers...)
37+
subDisp = NewStringArgsDispatcher(disp.baseCommand, disp.loggers...)
3638
disp.sub[superCommand] = subDisp
3739
return subDisp, nil
3840
}
@@ -160,33 +162,32 @@ func (disp *SuperStringArgsDispatcher) MustDispatchCombinedCommandAndArgs(ctx co
160162
return superCommand, command
161163
}
162164

163-
func (disp *SuperStringArgsDispatcher) PrintCommands(appName string) {
165+
func (disp *SuperStringArgsDispatcher) PrintCommands() {
164166
type superCmd struct {
165167
super string
166168
cmd *stringArgsCommand
167169
}
168-
169-
var list []superCmd
170+
var commands []superCmd
170171
for super, sub := range disp.sub {
171172
for _, cmd := range sub.comm {
172-
list = append(list, superCmd{super: super, cmd: cmd})
173+
commands = append(commands, superCmd{super: super, cmd: cmd})
173174
}
174175
}
175-
sort.Slice(list, func(i, j int) bool {
176-
if list[i].super == list[j].super {
177-
return list[i].cmd.command < list[j].cmd.command
176+
sort.Slice(commands, func(i, j int) bool {
177+
if commands[i].super == commands[j].super {
178+
return commands[i].cmd.command < commands[j].cmd.command
178179
}
179-
return list[i].super < list[j].super
180+
return commands[i].super < commands[j].super
180181
})
181182

182-
for i := range list {
183-
cmd := list[i].cmd
184-
command := list[i].super
183+
for i := range commands {
184+
cmd := commands[i].cmd
185+
command := commands[i].super
185186
if cmd.command != DefaultCommand {
186187
command += " " + cmd.command
187188
}
188189

189-
UsageColor.Printf(" %s %s %s\n", appName, command, functionArgsString(cmd.commandFunc))
190+
UsageColor.Printf(" %s %s %s\n", disp.baseCommand, command, functionArgsString(cmd.commandFunc))
190191
if cmd.description != "" {
191192
DescriptionColor.Printf(" %s\n", cmd.description)
192193
}
@@ -206,10 +207,45 @@ func (disp *SuperStringArgsDispatcher) PrintCommands(appName string) {
206207
}
207208
}
208209

209-
func (disp *SuperStringArgsDispatcher) PrintCommandsUsageIntro(appName string, output io.Writer) {
210-
if len(disp.sub) > 0 {
211-
fmt.Fprint(output, "Commands:\n")
212-
disp.PrintCommands(appName)
213-
// fmt.Fprint(output, "Flags:\n")
210+
func (disp *SuperStringArgsDispatcher) PrintCommandsUsageIntro() {
211+
if len(disp.sub) == 0 {
212+
return
213+
}
214+
fmt.Println("Commands:")
215+
disp.PrintCommands()
216+
}
217+
218+
func (disp *SuperStringArgsDispatcher) PrintCompletion(args []string) {
219+
prefix := ""
220+
if len(args) > 0 {
221+
prefix = args[0]
222+
}
223+
type superCmd struct {
224+
super string
225+
cmd *stringArgsCommand
226+
}
227+
var commands []superCmd
228+
for super, sub := range disp.sub {
229+
for _, cmd := range sub.comm {
230+
commands = append(commands, superCmd{super: super, cmd: cmd})
231+
}
232+
}
233+
sort.Slice(commands, func(i, j int) bool {
234+
if commands[i].super == commands[j].super {
235+
return commands[i].cmd.command < commands[j].cmd.command
236+
}
237+
return commands[i].super < commands[j].super
238+
})
239+
240+
for i := range commands {
241+
cmd := commands[i].cmd
242+
command := commands[i].super
243+
if cmd.command != DefaultCommand {
244+
command += " " + cmd.command
245+
}
246+
// TODO subcommand completion
247+
if strings.HasPrefix(command, prefix) {
248+
fmt.Println(disp.baseCommand, command)
249+
}
214250
}
215251
}

0 commit comments

Comments
 (0)