From da22fc53caa7980fda3570fd339c046a1b56d6b6 Mon Sep 17 00:00:00 2001 From: chriswalz Date: Sun, 8 Nov 2020 17:51:38 -0500 Subject: [PATCH] add traditonal unix style flags using env variable --- complete.go | 39 ++++++++++++++++++++++++++++----------- complete_test.go | 3 +++ flags_test.go | 18 ++++++++++++++++++ testing.go | 22 +++++++++++++++++++++- 4 files changed, 70 insertions(+), 12 deletions(-) diff --git a/complete.go b/complete.go index 2a4c905..0a29256 100644 --- a/complete.go +++ b/complete.go @@ -60,11 +60,12 @@ var ( // `os.Exit()`. The program name should be provided for installation purposes. func Complete(name string, cmd Completer) { var ( - line = getEnv("COMP_LINE") - point = getEnv("COMP_POINT") - doInstall = getEnv("COMP_INSTALL") == "1" - doUninstall = getEnv("COMP_UNINSTALL") == "1" - yes = getEnv("COMP_YES") == "1" + line = getEnv("COMP_LINE") + point = getEnv("COMP_POINT") + doInstall = getEnv("COMP_INSTALL") == "1" + doUninstall = getEnv("COMP_UNINSTALL") == "1" + yes = getEnv("COMP_YES") == "1" + traditionalUnixStyle = getEnv("COMP_TRADITIONAL_UNIX_STYLE") == "1" ) if doInstall || doUninstall { install.Run(name, doUninstall, yes, out, in) @@ -89,7 +90,7 @@ func Complete(name string, cmd Completer) { args = args[1:] // Run the completion algorithm. - options, err := completer{Completer: cmd, args: args}.complete() + options, err := completer{Completer: cmd, args: args, traditionalUnixStyle: traditionalUnixStyle}.complete() if err != nil { fmt.Fprintln(out, "\n"+err.Error()) } else { @@ -102,8 +103,9 @@ func Complete(name string, cmd Completer) { type completer struct { Completer - args []arg.Arg - stack []Completer + args []arg.Arg + stack []Completer + traditionalUnixStyle bool } // compete command with given before and after text. @@ -217,10 +219,25 @@ func (c completer) suggestFlag(dashes, prefix string) []string { return suggest(dashes, prefix, func(prefix string) []string { var options []string c.iterateStack(func(cmd Completer) { - // Suggest all flags with the given prefix. for _, name := range cmd.FlagList() { - if strings.HasPrefix(name, prefix) { - options = append(options, dashes+name) + if c.traditionalUnixStyle { + // Suggest single dash or double dash flags only with the given prefix. + if len(prefix) == 0 { + if len(name) >= 2 { + options = append(options, "--"+name) + } else { + options = append(options, "-"+name) + } + } else if dashes == "-" && len(name) == 1 && strings.HasPrefix(name, prefix) { + options = append(options, dashes+name) + } else if dashes == "--" && len(name) >= 2 && strings.HasPrefix(name, prefix) { + options = append(options, dashes+name) + } + } else { + // Suggest all flags with the given prefix. + if strings.HasPrefix(name, prefix) { + options = append(options, dashes+name) + } } } }) diff --git a/complete_test.go b/complete_test.go index 3a0809f..99d3234 100644 --- a/complete_test.go +++ b/complete_test.go @@ -168,6 +168,7 @@ func TestComplete(t *testing.T) { shouldPanic bool install string uninstall string + traditionalUnixStyle string }{ {shouldExit: true, line: "cmd", point: "1"}, {shouldExit: false, line: "", point: ""}, @@ -195,6 +196,8 @@ func TestComplete(t *testing.T) { return tt.uninstall case "COMP_YES": return "0" + case "COMP_TRADITIONAL_UNIX_STYLE": + return tt.traditionalUnixStyle default: panic(env) } diff --git a/flags_test.go b/flags_test.go index 374a6cc..72f4ef7 100644 --- a/flags_test.go +++ b/flags_test.go @@ -21,12 +21,30 @@ func TestFlags(t *testing.T) { fs.String("foo-bar", "", "") cmp := FlagSet(fs) + // go style flags Test(t, cmp, "", []string{"-foo", "-bar", "-foo-bar", "-h"}) Test(t, cmp, "-foo", []string{"-foo", "-foo-bar"}) Test(t, cmp, "-foo ", []string{"false"}) Test(t, cmp, "-foo=", []string{"false"}) Test(t, cmp, "-bar ", []string{"-foo", "-bar", "-foo-bar", "-h"}) Test(t, cmp, "-bar=", []string{}) + + // traditional unix style flags + fs = flag.NewFlagSet("test", flag.ExitOnError) + fs.Var(&tr, "f", "") + fs.Var(&fl, "b", "") + fs.Var(&fl, "foo", "") + fs.Var(&fl, "bar", "") + fs.String("foo-bar", "", "") + cmp = FlagSet(fs) + + TestWithTraditionalUnixStyle(t, cmp, "", []string{"-f", "-b", "--foo", "--bar", "--foo-bar", "-h"}) + TestWithTraditionalUnixStyle(t, cmp, "-", []string{"-f", "-b", "--foo", "--bar", "--foo-bar", "-h"}) + TestWithTraditionalUnixStyle(t, cmp, "--foo", []string{"--foo", "--foo-bar"}) + TestWithTraditionalUnixStyle(t, cmp, "--bar", []string{"--bar"}) + TestWithTraditionalUnixStyle(t, cmp, "--bar=", []string{}) + TestWithTraditionalUnixStyle(t, cmp, "--foo ", []string{"false"}) + TestWithTraditionalUnixStyle(t, cmp, "--foo=", []string{"false"}) } type boolValue bool diff --git a/testing.go b/testing.go index 3195660..4251cd7 100644 --- a/testing.go +++ b/testing.go @@ -10,7 +10,7 @@ import ( // Test is a testing helper function for testing bash completion of a given completer. func Test(t *testing.T, cmp Completer, args string, want []string) { t.Helper() - got, err := completer{Completer: cmp, args: arg.Parse(args)}.complete() + got, err := completer{Completer: cmp, args: arg.Parse(args), traditionalUnixStyle: false}.complete() if err != nil { t.Fatal(err) } @@ -27,3 +27,23 @@ func Test(t *testing.T, cmp Completer, args string, want []string) { } } } + +func TestWithTraditionalUnixStyle(t *testing.T, cmp Completer, args string, want []string) { + t.Helper() + got, err := completer{Completer: cmp, args: arg.Parse(args), traditionalUnixStyle: true}.complete() + if err != nil { + t.Fatal(err) + } + sort.Strings(got) + sort.Strings(want) + if len(want) != len(got) { + t.Errorf("got != want: want = %+v, got = %+v", want, got) + return + } + for i := range want { + if want[i] != got[i] { + t.Errorf("got != want: want = %+v, got = %+v", want, got) + return + } + } +} \ No newline at end of file