diff --git a/go.mod b/go.mod index 70de088..1fcd9a0 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/spf13/afero v1.9.3 github.com/spf13/viper v1.15.0 github.com/valyala/fasthttp v1.44.0 + golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 ) require ( diff --git a/go.sum b/go.sum index b01c57d..2778dc7 100644 --- a/go.sum +++ b/go.sum @@ -337,6 +337,7 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/heffalump/markov.go b/heffalump/markov.go index 211406d..ca522ab 100644 --- a/heffalump/markov.go +++ b/heffalump/markov.go @@ -5,7 +5,6 @@ import ( "io" "math/rand" "strings" - "time" "unicode" "unicode/utf8" @@ -15,7 +14,6 @@ import ( var DefaultMarkovMap MarkovMap func init() { - rand.Seed(time.Now().UnixNano()) // DefaultMarkovMap is a Markov chain based on src. src, err := squish.UnpackStr(srcGz) if err != nil { diff --git a/internal/config/arguments.go b/internal/config/arguments.go index 33d8b60..89fe1fd 100644 --- a/internal/config/arguments.go +++ b/internal/config/arguments.go @@ -1,44 +1,33 @@ package config -import "os" - -var usage = []string{ - "\n" + Title + " v" + Version + " Usage\n", - "-c - Specify config file", - "--nocolor - disable color and banner ", - "--banner - show banner + version and exit", - "--genconfig - write default config to 'default.toml' then exit", -} - -func printUsage() { - println(usage) - os.Exit(0) -} +import ( + "os" +) var ( forceDebug = false forceTrace = false ) +var argBoolMap = map[string]*bool{ + "--debug": &forceDebug, "-v": &forceDebug, "--trace": &forceTrace, "-vv": &forceTrace, + "--nocolor": &noColorForce, "--banner": &BannerOnly, "--genconfig": &GenConfig, +} + // TODO: should probably just make a proper CLI with flags or something func argParse() { for i, arg := range os.Args { + if t, ok := argBoolMap[arg]; ok { + *t = true + continue + } switch arg { case "-h": - printUsage() - case "--genconfig": - GenConfig = true - case "--debug", "-v": - forceDebug = true - case "--trace", "-vv": - forceTrace = true - case "--nocolor": - noColorForce = true - case "--banner": - BannerOnly = true + CLI.printUsage() case "-c", "--config": - if len(os.Args) <= i-1 { - panic("syntax error! expected file after -c") + if len(os.Args) < i+2 { + println("missing config file after -c/--config") + os.Exit(1) } loadCustomConfig(os.Args[i+1]) default: diff --git a/internal/config/globals.go b/internal/config/globals.go index 80b675a..8d06205 100644 --- a/internal/config/globals.go +++ b/internal/config/globals.go @@ -16,6 +16,7 @@ func init() { for _, v := range info.Settings { binInfo[v.Key] = v.Value } + if gitrev, ok := binInfo["vcs.revision"]; ok && Version == "dev" { Version = gitrev[:7] } diff --git a/internal/config/help.go b/internal/config/help.go new file mode 100644 index 0000000..912104a --- /dev/null +++ b/internal/config/help.go @@ -0,0 +1,123 @@ +package config + +import ( + "io" + "os" + "strings" + + "golang.org/x/term" +) + +type help struct { + title, version string + usage map[int][]string + out io.Writer +} + +var CLI = help{ + title: Title, + version: Version, + usage: map[int][]string{ + 0: {0: "--config", 1: "", 2: "Specify config file"}, + 1: {0: "--nocolor", 1: "disable color and banner"}, + 2: {0: "--banner", 1: "show banner + version and exit"}, + 3: {0: "--genconfig", 1: "write default config to 'default.toml' then exit"}, + 4: {0: "--help", 1: "show this help and exit"}, + }, + out: os.Stdout, +} + +func (cli help) secondColStart(index int) (max int) { + l := cli.firstColEnd() + 2 + if len(cli.usage[index]) > 2 && cli.usage[index][2] != "" { + l -= len(cli.usage[index][1]) + } + if l > max { + max = l + } + return max +} + +func (cli help) firstColEnd() (max int) { + for n := range cli.usage { + l := len(cli.usage[n][0]) + if l > max { + max = l + } + } + return max +} + +func (cli help) stdout(s ...string) { + for _, v := range s { + _, _ = cli.out.Write([]byte(v)) + } +} + +func (cli help) lb(n int) { + for n > 0 { + cli.stdout("\n") + n-- + } +} + +func (cli help) printUsage() { + if !term.IsTerminal(int(os.Stdout.Fd())) { + os.Exit(1) + } + cli.header() + + for n := 0; n < len(cli.usage); n++ { + line := &strings.Builder{} + buf := &strings.Builder{} + usageAt := 1 + tlen := cli.secondColStart(n) + switch { + case cli.usage[n][0] == "": + cli.lb(1) + case cli.usage[n][1] == "": + cli.stdout(cli.usage[n][0]) + cli.lb(2) + case len(cli.usage[n]) > 2 && cli.usage[n][2] != "": + tlen = cli.firstColEnd() - len(cli.usage[n][1]) + usageAt = 2 + fallthrough + default: + buf.WriteString(cli.usage[n][0]) + } + if tlen < 0 { + tlen = 2 + } + tab := strings.Repeat(" ", tlen) + line.WriteString(" ") + if buf.Len() < cli.firstColEnd() { + line.WriteString(strings.Repeat(" ", cli.firstColEnd()-buf.Len())) + } + if usageAt == 2 { + buf.WriteString(strings.Repeat(" ", tlen/2)) + buf.WriteString(cli.usage[n][1]) + } + buf.WriteString(tab) + buf.Write([]byte(" (" + cli.usage[n][usageAt] + ")")) + buf.Write([]byte{'\n'}) + line.Write([]byte(buf.String())) + cli.stdout(line.String()) + } + os.Exit(0) + +} + +func (cli help) header() { + cli.stdout("\n") + s := &strings.Builder{} + s.Write([]byte(cli.title)) + s.Write([]byte(" v[")) + s.Write([]byte(cli.version)) + s.Write([]byte("]")) + tab := cli.firstColEnd() - (s.Len() % 2) + 1 + if tab > 0 { + cli.stdout(strings.Repeat(" ", tab)) + } + cli.stdout(s.String()) + cli.lb(2) +}