Skip to content

Commit

Permalink
Micro-optimizations (#1957)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
scop committed Nov 23, 2023
1 parent 283e32d commit 3d8ac43
Show file tree
Hide file tree
Showing 6 changed files with 23 additions and 25 deletions.
4 changes: 2 additions & 2 deletions args.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion bash_completions.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 0 additions & 2 deletions cobra.go
Original file line number Diff line number Diff line change
Expand Up @@ -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] {
Expand Down
10 changes: 5 additions & 5 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down
20 changes: 10 additions & 10 deletions completions.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
continue
}
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.
Expand All @@ -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.
Expand Down
10 changes: 5 additions & 5 deletions flag_groups.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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)
}
Expand Down

0 comments on commit 3d8ac43

Please sign in to comment.