package cli import ( "fmt" "strings" ) const ( stringMapTypeName = "map-string" ) type cliOptionStringMap struct { cliOptionBase defaultValue map[string]string targetVar *map[string]string } func (opt *cliOptionStringMap) init() { opt.isArray = true if opt.targetVar != nil { *opt.targetVar = opt.defaultValue } } func (opt *cliOptionStringMap) getTargetVar() (any, string) { var value map[string]string if opt.targetVar != nil { value = *opt.targetVar } return value, stringMapTypeName } func (opt *cliOptionStringMap) getBase() *cliOptionBase { return &opt.cliOptionBase } func MapJoin[T any](m map[string]T, kvSep, itemSep string) string { var sb strings.Builder for key, value := range m { if sb.Len() > 0 { sb.WriteString(itemSep) } fmt.Fprintf(&sb, "%q%s%v", key, kvSep, value) } return sb.String() } func (opt *cliOptionStringMap) requiresValue() bool { return opt.targetVar != nil } func (opt *cliOptionStringMap) getDefaultValue() string { return MapJoin(opt.defaultValue, ",", "=") } func (opt *cliOptionStringMap) getTemplate() string { return opt.makeOptTemplate(true, "key=value") } func (opt *cliOptionStringMap) parse(parser cliParser, argIndex int, valuePtr *string) (skipNextArg bool, err error) { var value string if value, skipNextArg, err = opt.fetchOptionValue(parser, argIndex, valuePtr); err == nil { var boxedValue any if boxedValue, err = opt.getSpecialValue(parser, value, opt.targetVar); err == nil { if opt.targetVar != nil { dict := *opt.targetVar if boxedValue != nil { if val, ok := boxedValue.(map[string]string); ok { dict = val } else { err = errInvalidOptionValue(opt.name, boxedValue, "map of string") } } else { if dict == nil { dict = make(map[string]string) } for value := range strings.SplitSeq(value, ",") { if k, v, sepExists := strings.Cut(value, "="); sepExists { dict[k] = v } else { dict[k] = "" } } } *opt.targetVar = dict } } return } return } func (cli *CliParser) AddStringMapOpt(name, short string, targetVar *map[string]string, defaultValue map[string]string, description string, aliases ...string) OptReference { aliases = cli.checkAlreadyUsedNames(name, short, aliases) opt := &cliOptionStringMap{ cliOptionBase: cliOptionBase{ name: name, shortAlias: short, aliases: aliases, description: description, isArray: true, }, targetVar: targetVar, defaultValue: defaultValue, } cli.options = append(cli.options, opt) return opt }