github.com/toolvox/utilgo@v0.0.5/pkg/cli/lexer/tokenize_flags.go (about) 1 // Package lexer contains [FlagTokenizer] which parses args/actions 2 package lexer 3 4 import ( 5 "strings" 6 7 "github.com/toolvox/utilgo/pkg/sets" 8 "github.com/toolvox/utilgo/pkg/stringutil" 9 ) 10 11 // FlagTokenizer holds the names of the boolean flags and uses them the tokenize the input args into args and actions. 12 // Actions are args that are not flags. 13 // 14 // After calling [FlagTokenizer.TokenizeFlags] the Tokenized and Action fields will be initialized. 15 type FlagTokenizer struct { 16 BooleanFlags sets.TinySet[string] 17 Tokenized map[string]string 18 Actions []string 19 } 20 21 // NewFlagTokenizer creates a new [FlagTokenizer] from a list of boolean flag names 22 func NewFlagTokenizer(booleanFlags ...string) *FlagTokenizer { 23 return &FlagTokenizer{ 24 BooleanFlags: *sets.NewTinySet(booleanFlags...), 25 Tokenized: map[string]string{}, 26 Actions: []string{}, 27 } 28 } 29 30 // TokenizeFlags sorts the args into flags and actions, without parsing the values. 31 func (ft *FlagTokenizer) TokenizeFlags(args []string) { 32 ft.Actions = append(ft.Actions, args[0]) 33 for i := 1; i < len(args); i++ { 34 arg := strings.TrimSpace(args[i]) 35 if len(arg) == 0 { 36 continue 37 } 38 39 // action 40 prefixLen := stringutil.CountPrefix(arg, func(r rune) bool { return r == '-' }) 41 if prefixLen == 0 { 42 ft.Actions = append(ft.Actions, arg) 43 continue 44 } 45 46 arg = arg[prefixLen:] 47 if len(arg) == 0 { 48 continue 49 } 50 51 // -flag= 52 if strings.Contains(arg, "=") { 53 parts := strings.SplitN(arg, "=", 2) 54 arg = parts[0] 55 if len(arg) == 0 { 56 continue 57 } 58 59 val := parts[1] 60 if len(val) == 0 { 61 if ft.BooleanFlags.Contains(arg) { 62 ft.Tokenized[arg] = "false" 63 continue 64 } 65 66 ft.Tokenized[arg] = "" 67 continue 68 } 69 70 ft.Tokenized[arg] = val 71 continue 72 } 73 74 // -flag 75 if ft.BooleanFlags.Contains(arg) { 76 ft.Tokenized[arg] = "true" 77 continue 78 } 79 80 if i+1 == len(args) { 81 ft.Tokenized[arg] = "" 82 continue 83 } 84 85 val := args[i+1] 86 if strings.HasPrefix(val, "-") { 87 ft.Tokenized[arg] = "" 88 continue 89 } 90 91 ft.Tokenized[arg] = val 92 i++ 93 } 94 95 for _, v := range ft.BooleanFlags { 96 if _, ok := ft.Tokenized[v]; !ok { 97 ft.Tokenized[v] = "false" 98 } 99 } 100 }