Interpret flags and operands for completion
This commit is contained in:
62
binding.go
62
binding.go
@@ -4,6 +4,8 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
commandmeta "gitea.maximumdirect.net/eric/CommandKit/internal/commandmeta"
|
||||
)
|
||||
|
||||
// ValueFlag declares a singleton flag with a typed parser, optional default,
|
||||
@@ -255,60 +257,76 @@ func prepareInputWithSpellings[I any](spec CommandSpec[I], flagValues, flagSpell
|
||||
func newBindingIdentity() *bindingIdentity { return &bindingIdentity{marker: 1} }
|
||||
|
||||
func allocateOperands[I any](operands []string, definitions []Argument[I], enforceRequired bool) ([][]string, error) {
|
||||
arguments := make([]commandmeta.Argument, len(definitions))
|
||||
for i, definition := range definitions {
|
||||
arguments[i] = commandmeta.Argument{Name: definition.binding.meta.Name, Min: definition.binding.min, Max: definition.binding.max}
|
||||
}
|
||||
counts, err := allocateOperandCounts(len(operands), arguments, enforceRequired)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
allocated := make([][]string, len(definitions))
|
||||
position := 0
|
||||
for i, count := range counts {
|
||||
allocated[i] = operands[position : position+count]
|
||||
position += count
|
||||
}
|
||||
return allocated, nil
|
||||
}
|
||||
|
||||
func allocateOperandCounts(total int, definitions []commandmeta.Argument, enforceRequired bool) ([]int, error) {
|
||||
for _, argument := range definitions {
|
||||
binding := argument.binding
|
||||
if binding.min < 0 || binding.max < -1 || (binding.max >= 0 && binding.min > binding.max) {
|
||||
return nil, fmt.Errorf("argument %q has invalid bounds %d..%d", binding.meta.Name, binding.min, binding.max)
|
||||
if argument.Min < 0 || argument.Max < -1 || (argument.Max >= 0 && argument.Min > argument.Max) {
|
||||
return nil, fmt.Errorf("argument %q has invalid bounds %d..%d", argument.Name, argument.Min, argument.Max)
|
||||
}
|
||||
}
|
||||
if enforceRequired {
|
||||
minimum := 0
|
||||
for _, argument := range definitions {
|
||||
if argument.binding.min > len(operands)-minimum {
|
||||
if argument.Min > total-minimum {
|
||||
return nil, fmt.Errorf("not enough positional arguments")
|
||||
}
|
||||
minimum += argument.binding.min
|
||||
minimum += argument.Min
|
||||
}
|
||||
}
|
||||
|
||||
suffixMinimum := make([]int, len(definitions)+1)
|
||||
for i := len(definitions) - 1; i >= 0; i-- {
|
||||
minimum := definitions[i].binding.min
|
||||
remaining := len(operands) - suffixMinimum[i+1]
|
||||
minimum := definitions[i].Min
|
||||
remaining := total - suffixMinimum[i+1]
|
||||
if minimum > remaining {
|
||||
suffixMinimum[i] = len(operands)
|
||||
suffixMinimum[i] = total
|
||||
} else {
|
||||
suffixMinimum[i] = suffixMinimum[i+1] + minimum
|
||||
}
|
||||
}
|
||||
|
||||
allocated := make([][]string, len(definitions))
|
||||
counts := make([]int, len(definitions))
|
||||
position := 0
|
||||
for i, argument := range definitions {
|
||||
binding := argument.binding
|
||||
remaining := len(operands) - position
|
||||
remaining := total - position
|
||||
available := remaining - suffixMinimum[i+1]
|
||||
if available < 0 {
|
||||
available = 0
|
||||
}
|
||||
count := available
|
||||
if binding.max >= 0 && count > binding.max {
|
||||
count = binding.max
|
||||
if argument.Max >= 0 && count > argument.Max {
|
||||
count = argument.Max
|
||||
}
|
||||
if !enforceRequired && count < binding.min && remaining > 0 {
|
||||
if !enforceRequired && count < argument.Min && remaining > 0 {
|
||||
count = remaining
|
||||
if binding.max >= 0 && count > binding.max {
|
||||
count = binding.max
|
||||
if argument.Max >= 0 && count > argument.Max {
|
||||
count = argument.Max
|
||||
}
|
||||
}
|
||||
if enforceRequired && count < binding.min {
|
||||
return nil, fmt.Errorf("not enough values for argument %q", binding.meta.Name)
|
||||
if enforceRequired && count < argument.Min {
|
||||
return nil, fmt.Errorf("not enough values for argument %q", argument.Name)
|
||||
}
|
||||
allocated[i] = operands[position : position+count]
|
||||
counts[i] = count
|
||||
position += count
|
||||
}
|
||||
if position < len(operands) {
|
||||
return nil, fmt.Errorf("received %d extra positional arguments", len(operands)-position)
|
||||
if position < total {
|
||||
return nil, fmt.Errorf("received %d extra positional arguments", total-position)
|
||||
}
|
||||
return allocated, nil
|
||||
return counts, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user