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:
Ville Skyttä 2023-11-23 19:24:33 +02:00 committed by GitHub
parent 283e32d889
commit 3d8ac432bd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 23 additions and 25 deletions

View file

@ -52,9 +52,9 @@ func OnlyValidArgs(cmd *Command, args []string) error {
if len(cmd.ValidArgs) > 0 { if len(cmd.ValidArgs) > 0 {
// Remove any description that may be included in ValidArgs. // Remove any description that may be included in ValidArgs.
// A description is following a tab character. // A description is following a tab character.
var validArgs []string validArgs := make([]string, 0, len(cmd.ValidArgs))
for _, v := range 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 { for _, v := range args {
if !stringInSlice(v, validArgs) { if !stringInSlice(v, validArgs) {

View file

@ -621,7 +621,7 @@ func writeRequiredNouns(buf io.StringWriter, cmd *Command) {
for _, value := range cmd.ValidArgs { for _, value := range cmd.ValidArgs {
// Remove any description that may be included following a tab character. // Remove any description that may be included following a tab character.
// Descriptions are not supported by bash completion. // 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)) WriteStringAndCheck(buf, fmt.Sprintf(" must_have_one_noun+=(%q)\n", value))
} }
if cmd.ValidArgsFunction != nil { if cmd.ValidArgsFunction != nil {

View file

@ -193,8 +193,6 @@ func ld(s, t string, ignoreCase bool) int {
d := make([][]int, len(s)+1) d := make([][]int, len(s)+1)
for i := range d { for i := range d {
d[i] = make([]int, len(t)+1) d[i] = make([]int, len(t)+1)
}
for i := range d {
d[i][0] = i d[i][0] = i
} }
for j := range d[0] { for j := range d[0] {

View file

@ -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, // 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. // return the args, excluding the one at this position.
if s == x { if s == x {
ret := []string{} ret := make([]string, 0, len(args)-1)
ret = append(ret, args[:pos]...) ret = append(ret, args[:pos]...)
ret = append(ret, args[pos+1:]...) ret = append(ret, args[pos+1:]...)
return ret return ret
@ -754,14 +754,14 @@ func (c *Command) findSuggestions(arg string) string {
if c.SuggestionsMinimumDistance <= 0 { if c.SuggestionsMinimumDistance <= 0 {
c.SuggestionsMinimumDistance = 2 c.SuggestionsMinimumDistance = 2
} }
suggestionsString := "" var sb strings.Builder
if suggestions := c.SuggestionsFor(arg); len(suggestions) > 0 { 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 { 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 { func (c *Command) findNext(next string) *Command {

View file

@ -212,23 +212,23 @@ func (c *Command) initCompleteCmd(args []string) {
} }
noDescriptions := (cmd.CalledAs() == ShellCompNoDescRequestCmd) noDescriptions := (cmd.CalledAs() == ShellCompNoDescRequestCmd)
noActiveHelp := GetActiveHelpConfig(finalCmd) == activeHelpGlobalDisable
out := finalCmd.OutOrStdout()
for _, comp := range completions { for _, comp := range completions {
if GetActiveHelpConfig(finalCmd) == activeHelpGlobalDisable { if noActiveHelp && strings.HasPrefix(comp, activeHelpMarker) {
// Remove all activeHelp entries in this case // Remove all activeHelp entries if it's disabled.
if strings.HasPrefix(comp, activeHelpMarker) { continue
continue
}
} }
if noDescriptions { if noDescriptions {
// Remove any description that may be included following a tab character. // 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. // Make sure we only write the first line to the output.
// This is needed if a description contains a linebreak. // This is needed if a description contains a linebreak.
// Otherwise the shell scripts will interpret the other lines as new flags // Otherwise the shell scripts will interpret the other lines as new flags
// and could therefore provide a wrong completion. // 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 // Finally trim the completion. This is especially important to get rid
// of a trailing tab when there are no description following it. // 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). // although there is no description).
comp = strings.TrimSpace(comp) comp = strings.TrimSpace(comp)
// Print each possible completion to stdout for the completion script to consume. // Print each possible completion to the output for the completion script to consume.
fmt.Fprintln(finalCmd.OutOrStdout(), comp) fmt.Fprintln(out, comp)
} }
// As the last printout, print the completion directive for the completion script to parse. // 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 directive integer must be that last character following a single colon (:).
// The completion script expects :<directive> // 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. // Print some helpful info to stderr for the user to understand.
// Output from stderr must be ignored by the completion script. // Output from stderr must be ignored by the completion script.

View file

@ -130,7 +130,7 @@ func processFlagForGroupAnnotation(flags *flag.FlagSet, pflag *flag.Flag, annota
continue continue
} }
groupStatus[group] = map[string]bool{} groupStatus[group] = make(map[string]bool, len(flagnames))
for _, name := range flagnames { for _, name := range flagnames {
groupStatus[group][name] = false 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 // 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 // of that group required so that the shell completion suggests them automatically
for flagList, flagnameAndStatus := range oneRequiredGroupStatus { for flagList, flagnameAndStatus := range oneRequiredGroupStatus {
set := 0 isSet := false
for _, isSet := range flagnameAndStatus { for _, isSet = range flagnameAndStatus {
if isSet { if isSet {
set++ break
} }
} }
// None of the flags of the group are set, mark all flags in the group // None of the flags of the group are set, mark all flags in the group
// as required // as required
if set == 0 { if !isSet {
for _, fName := range strings.Split(flagList, " ") { for _, fName := range strings.Split(flagList, " ") {
_ = c.MarkFlagRequired(fName) _ = c.MarkFlagRequired(fName)
} }