cli/opt-string-map.go
2025-12-11 07:57:48 +01:00

109 lines
2.5 KiB
Go

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
}