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 {
|
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) {
|
||||||
|
@ -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 {
|
||||||
|
2
cobra.go
2
cobra.go
@ -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] {
|
||||||
|
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,
|
// 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 {
|
||||||
|
@ -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.
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user