forked from jenkins-x/jx
-
Notifications
You must be signed in to change notification settings - Fork 0
/
suggestions.go
122 lines (109 loc) · 3.26 KB
/
suggestions.go
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package util
import (
"fmt"
"sort"
"strings"
)
const (
DefaultSuggestionsMinimumDistance = 2
)
func InvalidOptionError(option string, value string, err error) error {
return InvalidOptionf(option, value, "%s", err)
}
func InvalidOptionf(option string, value string, message string, a ...interface{}) error {
text := fmt.Sprintf(message, a...)
return fmt.Errorf("Invalid option: --%s %s\n%s", option, value, text)
}
func MissingOption(name string) error {
return fmt.Errorf("Missing option: --%s", name)
}
func InvalidOption(name string, value string, values []string) error {
suggestions := SuggestionsFor(value, values, DefaultSuggestionsMinimumDistance)
if len(suggestions) > 0 {
if len(suggestions) == 1 {
return InvalidOptionf(name, value, "Did you mean: --%s %s", name, suggestions[0])
}
return InvalidOptionf(name, value, "Did you mean one of: %s", strings.Join(suggestions, ", "))
}
sort.Strings(values)
return InvalidOptionf(name, value, "Possible values: %s", strings.Join(values, ", "))
}
func InvalidArg(value string, values []string) error {
suggestions := SuggestionsFor(value, values, DefaultSuggestionsMinimumDistance)
if len(suggestions) > 0 {
if len(suggestions) == 1 {
return InvalidArgf(value, "Did you mean: %s", suggestions[0])
}
return InvalidArgf(value, "Did you mean one of: %s", strings.Join(suggestions, ", "))
}
sort.Strings(values)
return InvalidArgf(value, "Possible values: %s", strings.Join(values, ", "))
}
func InvalidArgError(value string, err error) error {
return InvalidArgf(value, "%s", err)
}
func InvalidArgf(value string, message string, a ...interface{}) error {
text := fmt.Sprintf(message, a...)
return fmt.Errorf("Invalid argument: %s\n%s", value, text)
}
func SuggestionsFor(typedName string, values []string, suggestionsMinimumDistance int, explicitSuggestions ...string) []string {
suggestions := []string{}
for _, value := range values {
levenshteinDistance := ld(typedName, value, true)
suggestByLevenshtein := levenshteinDistance <= suggestionsMinimumDistance
suggestByPrefix := strings.HasPrefix(strings.ToLower(value), strings.ToLower(typedName))
if suggestByLevenshtein || suggestByPrefix {
suggestions = append(suggestions, value)
}
for _, explicitSuggestion := range explicitSuggestions {
if strings.EqualFold(typedName, explicitSuggestion) {
suggestions = append(suggestions, value)
}
}
}
return suggestions
}
// ld compares two strings and returns the levenshtein distance between them.
//
// this was copied from vendor/github.com/spf13/cobra/command.go as its not public
func ld(s, t string, ignoreCase bool) int {
if ignoreCase {
s = strings.ToLower(s)
t = strings.ToLower(t)
}
d := make([][]int, len(s)+1)
for i := range d {
d[i] = make([]int, len(t)+1)
}
for i := range d {
d[i][0] = i
}
for j := range d[0] {
d[0][j] = j
}
for j := 1; j <= len(t); j++ {
for i := 1; i <= len(s); i++ {
if s[i-1] == t[j-1] {
d[i][j] = d[i-1][j-1]
} else {
min := d[i-1][j]
if d[i][j-1] < min {
min = d[i][j-1]
}
if d[i-1][j-1] < min {
min = d[i-1][j-1]
}
d[i][j] = min + 1
}
}
}
return d[len(s)][len(t)]
}
func Contains(arr []string, str string) bool {
for _, a := range arr {
if a == str {
return true
}
}
return false
}