aboutsummaryrefslogtreecommitdiff
path: root/v_windows/v/vlib/v/util/suggestions.v
blob: e1c35ea9c2d4d6f1da63f31223976f3ea24a568a (plain)
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
module util

import strings

struct Possibility {
	value  string
	svalue string
mut:
	similarity f32
}

struct Suggestion {
mut:
	known   []Possibility
	wanted  string
	swanted string
}

pub fn new_suggestion(wanted string, possibilities []string) Suggestion {
	mut s := Suggestion{
		wanted: wanted
		swanted: short_module_name(wanted)
	}
	s.add_many(possibilities)
	s.sort()
	return s
}

pub fn (mut s Suggestion) add(val string) {
	if val in [s.wanted, s.swanted] {
		return
	}
	sval := short_module_name(val)
	if sval in [s.wanted, s.swanted] {
		return
	}
	// round to 3 decimal places to avoid float comparison issues
	similarity := f32(int(strings.dice_coefficient(s.swanted, sval) * 1000)) / 1000
	s.known << Possibility{
		value: val
		svalue: sval
		similarity: similarity
	}
}

pub fn (mut s Suggestion) add_many(many []string) {
	for x in many {
		s.add(x)
	}
}

pub fn (mut s Suggestion) sort() {
	s.known.sort(a.similarity < b.similarity)
}

pub fn (s Suggestion) say(msg string) string {
	mut res := msg
	mut found := false
	if s.known.len > 0 {
		top_posibility := s.known.last()
		if top_posibility.similarity > 0.5 {
			val := top_posibility.value
			if !val.starts_with('[]') {
				res += '.\nDid you mean `$val`?'
				found = true
			}
		}
	}
	if !found {
		if s.known.len > 0 {
			mut values := s.known.map('`$it.svalue`')
			values.sort()
			if values.len == 1 {
				res += '.\n1 possibility: ${values[0]}.'
			} else if values.len < 25 {
				// it is hard to read/use too many suggestions
				res += '.\n$values.len possibilities: ' + values.join(', ') + '.'
			}
		}
	}
	return res
}

pub fn short_module_name(name string) string {
	if !name.contains('.') {
		return name
	}
	vals := name.split('.')
	if vals.len < 2 {
		return name
	}
	mname := vals[vals.len - 2]
	symname := vals[vals.len - 1]
	return '${mname}.$symname'
}