mirror of https://github.com/spf13/cobra.git
Micro-optimizations (#1957)
* Avoid redundant string splits There likely isn't actually more than once to split in the source strings in these cases, but avoid doing so anyway as we're only interested in the first. * Avoid redundant completion output target evaluations The target is not to be changed while outputting completions, so resolve it only once. * Avoid redundant active help enablement evaluations The enablement state is not to be changed during completion output, so evaluate it only once. * Preallocate some slices and maps with known size * Avoid some unnecessary looping * Use strings.Builder to construct suggestions
This commit is contained in:
parent
283e32d889
commit
3d8ac432bd
4
args.go
4
args.go
|
@ -52,9 +52,9 @@ func OnlyValidArgs(cmd *Command, args []string) error {
|
|||
if len(cmd.ValidArgs) > 0 {
|
||||
// Remove any description that may be included in ValidArgs.
|
||||
// A description is following a tab character.
|
||||
var validArgs []string
|
||||
validArgs := make([]string, 0, len(cmd.ValidArgs))
|
||||
for _, v := range cmd.ValidArgs {
|
||||
validArgs = append(validArgs, strings.Split(v, "\t")[0])
|
||||
validArgs = append(validArgs, strings.SplitN(v, "\t", 2)[0])
|
||||
}
|
||||
for _, v := range args {
|
||||
if !stringInSlice(v, validArgs) {
|
||||
|
|
|
@ -621,7 +621,7 @@ func writeRequiredNouns(buf io.StringWriter, cmd *Command) {
|
|||
for _, value := range cmd.ValidArgs {
|
||||
// Remove any description that may be included following a tab character.
|
||||
// Descriptions are not supported by bash completion.
|
||||
value = strings.Split(value, "\t")[0]
|
||||
value = strings.SplitN(value, "\t", 2)[0]
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(" must_have_one_noun+=(%q)\n", value))
|
||||
}
|
||||
if cmd.ValidArgsFunction != nil {
|
||||
|
|
2
cobra.go
2
cobra.go
|
@ -193,8 +193,6 @@ func ld(s, t string, ignoreCase bool) int {
|
|||
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] {
|
||||
|
|
10
command.go
10
command.go
|
@ -706,7 +706,7 @@ Loop:
|
|||
// This is not a flag or a flag value. Check to see if it matches what we're looking for, and if so,
|
||||
// return the args, excluding the one at this position.
|
||||
if s == x {
|
||||
ret := []string{}
|
||||
ret := make([]string, 0, len(args)-1)
|
||||
ret = append(ret, args[:pos]...)
|
||||
ret = append(ret, args[pos+1:]...)
|
||||
return ret
|
||||
|
@ -754,14 +754,14 @@ func (c *Command) findSuggestions(arg string) string {
|
|||
if c.SuggestionsMinimumDistance <= 0 {
|
||||
c.SuggestionsMinimumDistance = 2
|
||||
}
|
||||
suggestionsString := ""
|
||||
var sb strings.Builder
|
||||
if suggestions := c.SuggestionsFor(arg); len(suggestions) > 0 {
|
||||
suggestionsString += "\n\nDid you mean this?\n"
|
||||
sb.WriteString("\n\nDid you mean this?\n")
|
||||
for _, s := range suggestions {
|
||||
suggestionsString += fmt.Sprintf("\t%v\n", s)
|
||||
_, _ = fmt.Fprintf(&sb, "\t%v\n", s)
|
||||
}
|
||||
}
|
||||
return suggestionsString
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func (c *Command) findNext(next string) *Command {
|
||||
|
|
|
@ -212,23 +212,23 @@ func (c *Command) initCompleteCmd(args []string) {
|
|||
}
|
||||
|
||||
noDescriptions := (cmd.CalledAs() == ShellCompNoDescRequestCmd)
|
||||
noActiveHelp := GetActiveHelpConfig(finalCmd) == activeHelpGlobalDisable
|
||||
out := finalCmd.OutOrStdout()
|
||||
for _, comp := range completions {
|
||||
if GetActiveHelpConfig(finalCmd) == activeHelpGlobalDisable {
|
||||
// Remove all activeHelp entries in this case
|
||||
if strings.HasPrefix(comp, activeHelpMarker) {
|
||||
if noActiveHelp && strings.HasPrefix(comp, activeHelpMarker) {
|
||||
// Remove all activeHelp entries if it's disabled.
|
||||
continue
|
||||
}
|
||||
}
|
||||
if noDescriptions {
|
||||
// Remove any description that may be included following a tab character.
|
||||
comp = strings.Split(comp, "\t")[0]
|
||||
comp = strings.SplitN(comp, "\t", 2)[0]
|
||||
}
|
||||
|
||||
// Make sure we only write the first line to the output.
|
||||
// This is needed if a description contains a linebreak.
|
||||
// Otherwise the shell scripts will interpret the other lines as new flags
|
||||
// and could therefore provide a wrong completion.
|
||||
comp = strings.Split(comp, "\n")[0]
|
||||
comp = strings.SplitN(comp, "\n", 2)[0]
|
||||
|
||||
// Finally trim the completion. This is especially important to get rid
|
||||
// of a trailing tab when there are no description following it.
|
||||
|
@ -237,14 +237,14 @@ func (c *Command) initCompleteCmd(args []string) {
|
|||
// although there is no description).
|
||||
comp = strings.TrimSpace(comp)
|
||||
|
||||
// Print each possible completion to stdout for the completion script to consume.
|
||||
fmt.Fprintln(finalCmd.OutOrStdout(), comp)
|
||||
// Print each possible completion to the output for the completion script to consume.
|
||||
fmt.Fprintln(out, comp)
|
||||
}
|
||||
|
||||
// As the last printout, print the completion directive for the completion script to parse.
|
||||
// The directive integer must be that last character following a single colon (:).
|
||||
// The completion script expects :<directive>
|
||||
fmt.Fprintf(finalCmd.OutOrStdout(), ":%d\n", directive)
|
||||
fmt.Fprintf(out, ":%d\n", directive)
|
||||
|
||||
// Print some helpful info to stderr for the user to understand.
|
||||
// Output from stderr must be ignored by the completion script.
|
||||
|
|
|
@ -130,7 +130,7 @@ func processFlagForGroupAnnotation(flags *flag.FlagSet, pflag *flag.Flag, annota
|
|||
continue
|
||||
}
|
||||
|
||||
groupStatus[group] = map[string]bool{}
|
||||
groupStatus[group] = make(map[string]bool, len(flagnames))
|
||||
for _, name := range flagnames {
|
||||
groupStatus[group][name] = false
|
||||
}
|
||||
|
@ -253,17 +253,17 @@ func (c *Command) enforceFlagGroupsForCompletion() {
|
|||
// If none of the flags of a one-required group are present, we make all the flags
|
||||
// of that group required so that the shell completion suggests them automatically
|
||||
for flagList, flagnameAndStatus := range oneRequiredGroupStatus {
|
||||
set := 0
|
||||
isSet := false
|
||||
|
||||
for _, isSet := range flagnameAndStatus {
|
||||
for _, isSet = range flagnameAndStatus {
|
||||
if isSet {
|
||||
set++
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// None of the flags of the group are set, mark all flags in the group
|
||||
// as required
|
||||
if set == 0 {
|
||||
if !isSet {
|
||||
for _, fName := range strings.Split(flagList, " ") {
|
||||
_ = c.MarkFlagRequired(fName)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue