...
1 package cli
2
3 import (
4 "flag"
5 "strings"
6 )
7
8 type iterativeParser interface {
9 newFlagSet() (*flag.FlagSet, error)
10 useShortOptionHandling() bool
11 }
12
13
14
15
16
17
18
19 func parseIter(set *flag.FlagSet, ip iterativeParser, args []string, shellComplete bool) error {
20 for {
21 err := set.Parse(args)
22 if !ip.useShortOptionHandling() || err == nil {
23 if shellComplete {
24 return nil
25 }
26 return err
27 }
28
29 trimmed, trimErr := flagFromError(err)
30 if trimErr != nil {
31 return err
32 }
33
34
35 argsWereSplit := false
36 for i, arg := range args {
37
38 if name := strings.TrimLeft(arg, "-"); name != trimmed {
39 continue
40 }
41
42
43 shortOpts := splitShortOptions(set, arg)
44 if len(shortOpts) == 1 {
45 return err
46 }
47
48
49
50
51
52 args = append(shortOpts, args[i+1:]...)
53 argsWereSplit = true
54 break
55 }
56
57
58
59 if !argsWereSplit {
60 return err
61 }
62 }
63 }
64
65 const providedButNotDefinedErrMsg = "flag provided but not defined: -"
66
67
68
69 func flagFromError(err error) (string, error) {
70 errStr := err.Error()
71 trimmed := strings.TrimPrefix(errStr, providedButNotDefinedErrMsg)
72 if errStr == trimmed {
73 return "", err
74 }
75 return trimmed, nil
76 }
77
78 func splitShortOptions(set *flag.FlagSet, arg string) []string {
79 shortFlagsExist := func(s string) bool {
80 for _, c := range s[1:] {
81 if f := set.Lookup(string(c)); f == nil {
82 return false
83 }
84 }
85 return true
86 }
87
88 if !isSplittable(arg) || !shortFlagsExist(arg) {
89 return []string{arg}
90 }
91
92 separated := make([]string, 0, len(arg)-1)
93 for _, flagChar := range arg[1:] {
94 separated = append(separated, "-"+string(flagChar))
95 }
96
97 return separated
98 }
99
100 func isSplittable(flagArg string) bool {
101 return strings.HasPrefix(flagArg, "-") && !strings.HasPrefix(flagArg, "--") && len(flagArg) > 2
102 }
103
View as plain text