File: positional.go

package info (click to toggle)
golang-github-willabides-kongplete 0.4.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 160 kB
  • sloc: sh: 40; makefile: 2
file content (92 lines) | stat: -rw-r--r-- 2,193 bytes parent folder | download
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
}