Ejemplo n.º 1
0
// suggestTargets suggests the targets in the given package that might be misspellings of
// the requested one.
func suggestTargets(pkg *core.Package, label, dependor core.BuildLabel) string {
	r := []rune(label.Name)
	options := make(suggestions, 0, len(pkg.Targets))
	for t := range pkg.Targets {
		distance := levenshtein.DistanceForStrings(r, []rune(t), levenshtein.DefaultOptions)
		if distance <= maxSuggestionDistance {
			options = append(options, suggestion{name: t, dist: distance})
		}
	}
	if len(options) == 0 {
		return ""
	}
	sort.Sort(options)
	// Obviously there's now more code to pretty-print the suggestions than to do the calculation...
	msg := "\nMaybe you meant "
	for i, o := range options {
		if i > 0 {
			if i < len(options)-1 {
				msg += ", "
			} else {
				msg += " or "
			}
		}
		if pkg.Name == dependor.PackageName {
			msg += ":" + o.name
		} else {
			msg += fmt.Sprintf("//%s:%s", pkg.Name, o.name)
		}
	}
	return msg + " ?" // Leave a space so you can select them without getting the question mark
}
Ejemplo n.º 2
0
// FindNearestCommand heuristically finds a Command the user wanted to type but
// failed to type correctly.
func FindNearestCommand(a Application, name string) *Command {
	commands := map[string]*Command{}
	for _, c := range a.GetCommands() {
		commands[c.Name()] = c
	}
	if c, ok := commands[name]; ok {
		return c
	}

	// Search for unique prefix.
	withPrefix := []*Command{}
	for n, c := range commands {
		if strings.HasPrefix(n, name) {
			withPrefix = append(withPrefix, c)
		}
	}
	if len(withPrefix) == 1 {
		return withPrefix[0]
	}

	// Search for case insensitivity.
	withPrefix = []*Command{}
	lowName := strings.ToLower(name)
	for n, c := range commands {
		if strings.HasPrefix(strings.ToLower(n), lowName) {
			withPrefix = append(withPrefix, c)
		}
	}
	if len(withPrefix) == 1 {
		return withPrefix[0]
	}

	// Calculate the levenshtein distance and take the closest one.
	closestD := 1000
	var closestC *Command
	secondD := 1000
	for n, c := range commands {
		dist := levenshtein.DistanceForStrings([]rune(n), []rune(name), levenshtein.DefaultOptions)
		if dist < closestD {
			secondD = closestD
			closestD = dist
			closestC = c
		} else if dist < secondD {
			secondD = dist
		}
	}
	if closestD > 3 {
		// Not similar enough. Don't be a fool and run a random command.
		return nil
	}
	if (secondD - closestD) < 3 {
		// Too ambiguous.
		return nil
	}
	return closestC
}
Ejemplo n.º 3
0
func findDev(d Chadevs, name string) (Dev, bool) {
	cleanedname := strings.ToUpper(strings.TrimSpace(name))
	distance := int(^uint(0) >> 1) // initialize to "infinity"
	idx := 0
	for i := 0; i < devsCount(d); i++ {
		cleaneddev := strings.ToUpper(d.Devs[i].Name)
		if cleanedname == cleaneddev {
			return d.Devs[i], true
		}
		newdistance := levenshtein.DistanceForStrings([]rune(cleanedname), []rune(cleaneddev), levenshtein.DefaultOptions)
		if newdistance < distance {
			distance = newdistance
			idx = i
		}
	}

	return d.Devs[idx], false
}
Ejemplo n.º 4
0
func searchGroups(g Groups, n string) Group {
	distance := int(^uint(0) >> 1) // nitialize to "infinity"
	var idx int
	n = strings.ToUpper(strings.TrimSpace(n))

	for i := 0; i < len(g.Group); i++ {
		cleanGroup := strings.ToUpper(strings.TrimSpace(g.Group[i].Name))
		if n == cleanGroup {
			return g.Group[i]
		}

		newdistance := levenshtein.DistanceForStrings([]rune(n), []rune(cleanGroup), levenshtein.DefaultOptions)
		if newdistance < distance {
			distance = newdistance
			idx = i
		}
	}

	return g.Group[idx]
}
Ejemplo n.º 5
0
func suggestUnknownCmd(args []string, root *cmds.Command) []string {
	arg := args[0]
	var suggestions []string
	sortableSuggestions := make(suggestionSlice, 0)
	var sFinal []string
	const MIN_LEVENSHTEIN = 3

	var options levenshtein.Options = levenshtein.Options{
		InsCost: 1,
		DelCost: 3,
		SubCost: 2,
		Matches: func(sourceCharacter rune, targetCharacter rune) bool {
			return sourceCharacter == targetCharacter
		},
	}

	// Start with a simple strings.Contains check
	for name, _ := range root.Subcommands {
		if strings.Contains(arg, name) {
			suggestions = append(suggestions, name)
		}
	}

	// If the string compare returns a match, return
	if len(suggestions) > 0 {
		return suggestions
	}

	for name, _ := range root.Subcommands {
		lev := levenshtein.DistanceForStrings([]rune(arg), []rune(name), options)
		if lev <= MIN_LEVENSHTEIN {
			sortableSuggestions = append(sortableSuggestions, &suggestion{name, lev})
		}
	}
	sort.Sort(sortableSuggestions)

	for _, j := range sortableSuggestions {
		sFinal = append(sFinal, j.cmd)
	}
	return sFinal
}