1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
|
package positionalpredictor
import (
"strings"
"github.com/posener/complete"
)
// PositionalPredictor is a predictor for positional arguments
type PositionalPredictor struct {
Predictors []complete.Predictor
ArgFlags []string
BoolFlags []string
IsCumulative bool
}
// Predict implements complete.Predict
func (p *PositionalPredictor) Predict(a complete.Args) []string {
predictor := p.predictor(a)
if predictor == nil {
return []string{}
}
return predictor.Predict(a)
}
func (p *PositionalPredictor) predictor(a complete.Args) complete.Predictor {
position := p.predictorIndex(a)
complete.Log("predicting positional argument(%d)", position)
if p.IsCumulative && position >= len(p.Predictors) {
return p.Predictors[len(p.Predictors)-1]
}
if position < 0 || position > len(p.Predictors)-1 {
return nil
}
return p.Predictors[position]
}
// predictorIndex returns the index in predictors to use. Returns -1 if no predictor should be used.
func (p *PositionalPredictor) predictorIndex(a complete.Args) int {
idx := 0
for i := 0; i < len(a.Completed); i++ {
if !p.nonPredictorPos(a, i) {
idx++
}
}
return idx
}
// nonPredictorPos returns true if the value at this position is either a flag or a flag's argument
func (p *PositionalPredictor) nonPredictorPos(a complete.Args, pos int) bool {
if pos < 0 || pos > len(a.All)-1 {
return false
}
val := a.All[pos]
if p.valIsFlag(val) {
return true
}
if pos == 0 {
return false
}
prev := a.All[pos-1]
return p.nextValueIsFlagArg(prev)
}
// valIsFlag returns true if the value matches a flag from the configuration
func (p *PositionalPredictor) valIsFlag(val string) bool {
val = strings.Split(val, "=")[0]
for _, flag := range p.BoolFlags {
if flag == val {
return true
}
}
for _, flag := range p.ArgFlags {
if flag == val {
return true
}
}
return false
}
// nextValueIsFlagArg returns true if the value matches an ArgFlag and doesn't contain an equal sign.
func (p *PositionalPredictor) nextValueIsFlagArg(val string) bool {
if strings.Contains(val, "=") {
return false
}
for _, flag := range p.ArgFlags {
if flag == val {
return true
}
}
return false
}
|