2022-11-16 10:33:57PM
This commit is contained in:
parent
7d9ace3ae4
commit
052b461b03
3 changed files with 134 additions and 24 deletions
|
|
@ -28,7 +28,7 @@ Subcommands:
|
|||
%[1]s layout [layout name] - Display long help for a particular layout engine
|
||||
|
||||
See more docs and the source code at https://oss.terrastruct.com/d2
|
||||
`, ms.Name, ms.Opts.Help())
|
||||
`, ms.Name, ms.Opts.Defaults())
|
||||
}
|
||||
|
||||
func layoutHelp(ctx context.Context, ms *xmain.State) error {
|
||||
|
|
|
|||
45
lib/xmain/flag_helpers.go
Normal file
45
lib/xmain/flag_helpers.go
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
// flag_helpers.go are private functions from pflag/flag.go
|
||||
package xmain
|
||||
|
||||
import "strings"
|
||||
|
||||
func wrap(i, w int, s string) string {
|
||||
if w == 0 {
|
||||
return strings.Replace(s, "\n", "\n"+strings.Repeat(" ", i), -1)
|
||||
}
|
||||
wrap := w - i
|
||||
var r, l string
|
||||
if wrap < 24 {
|
||||
i = 16
|
||||
wrap = w - i
|
||||
r += "\n" + strings.Repeat(" ", i)
|
||||
}
|
||||
if wrap < 24 {
|
||||
return strings.Replace(s, "\n", r, -1)
|
||||
}
|
||||
slop := 5
|
||||
wrap = wrap - slop
|
||||
l, s = wrapN(wrap, slop, s)
|
||||
r = r + strings.Replace(l, "\n", "\n"+strings.Repeat(" ", i), -1)
|
||||
for s != "" {
|
||||
var t string
|
||||
t, s = wrapN(wrap, slop, s)
|
||||
r = r + "\n" + strings.Repeat(" ", i) + strings.Replace(t, "\n", "\n"+strings.Repeat(" ", i), -1)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func wrapN(i, slop int, s string) (string, string) {
|
||||
if i+slop > len(s) {
|
||||
return s, ""
|
||||
}
|
||||
w := strings.LastIndexAny(s[:i], " \t\n")
|
||||
if w <= 0 {
|
||||
return s, ""
|
||||
}
|
||||
nlPos := strings.LastIndex(s[:i], "\n")
|
||||
if nlPos > 0 && nlPos < w {
|
||||
return s[:nlPos], s[nlPos+1:]
|
||||
}
|
||||
return s[:w], s[w+1:]
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package xmain
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
|
|
@ -17,7 +18,7 @@ type Opts struct {
|
|||
env *xos.Env
|
||||
log *cmdlog.Logger
|
||||
|
||||
registeredEnvs []string
|
||||
flagEnv map[string]string
|
||||
}
|
||||
|
||||
func NewOpts(env *xos.Env, log *cmdlog.Logger, args []string) *Opts {
|
||||
|
|
@ -26,42 +27,106 @@ func NewOpts(env *xos.Env, log *cmdlog.Logger, args []string) *Opts {
|
|||
flags.Usage = func() {}
|
||||
flags.SetOutput(io.Discard)
|
||||
return &Opts{
|
||||
Args: args,
|
||||
Flags: flags,
|
||||
env: env,
|
||||
log: log,
|
||||
Args: args,
|
||||
Flags: flags,
|
||||
env: env,
|
||||
log: log,
|
||||
flagEnv: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Opts) Help() string {
|
||||
b := &strings.Builder{}
|
||||
o.Flags.SetOutput(b)
|
||||
o.Flags.PrintDefaults()
|
||||
// Mostly copy pasted pasted from pflag.FlagUsagesWrapped
|
||||
// with modifications for env var
|
||||
func (o *Opts) Defaults() string {
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
if len(o.registeredEnvs) > 0 {
|
||||
b.WriteString("\nYou may persistently set the following as environment variables (flags take precedent):\n")
|
||||
for i, e := range o.registeredEnvs {
|
||||
s := fmt.Sprintf("- $%s", e)
|
||||
if i != len(o.registeredEnvs)-1 {
|
||||
s += "\n"
|
||||
}
|
||||
b.WriteString(s)
|
||||
var lines []string
|
||||
|
||||
maxlen := 0
|
||||
maxEnvLen := 0
|
||||
o.Flags.VisitAll(func(flag *pflag.Flag) {
|
||||
if flag.Hidden {
|
||||
return
|
||||
}
|
||||
|
||||
line := ""
|
||||
if flag.Shorthand != "" && flag.ShorthandDeprecated == "" {
|
||||
line = fmt.Sprintf(" -%s, --%s", flag.Shorthand, flag.Name)
|
||||
} else {
|
||||
line = fmt.Sprintf(" --%s", flag.Name)
|
||||
}
|
||||
|
||||
varname, usage := pflag.UnquoteUsage(flag)
|
||||
if varname != "" {
|
||||
line += " " + varname
|
||||
}
|
||||
if flag.NoOptDefVal != "" {
|
||||
switch flag.Value.Type() {
|
||||
case "string":
|
||||
line += fmt.Sprintf("[=\"%s\"]", flag.NoOptDefVal)
|
||||
case "bool":
|
||||
if flag.NoOptDefVal != "true" {
|
||||
line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
|
||||
}
|
||||
case "count":
|
||||
if flag.NoOptDefVal != "+1" {
|
||||
line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
|
||||
}
|
||||
default:
|
||||
line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
|
||||
}
|
||||
}
|
||||
|
||||
line += "\x00"
|
||||
|
||||
if len(line) > maxlen {
|
||||
maxlen = len(line)
|
||||
}
|
||||
|
||||
if e, ok := o.flagEnv[flag.Name]; ok {
|
||||
line += fmt.Sprintf("$%s", e)
|
||||
}
|
||||
|
||||
line += "\x01"
|
||||
|
||||
if len(line) > maxEnvLen {
|
||||
maxEnvLen = len(line)
|
||||
}
|
||||
|
||||
line += usage
|
||||
if flag.Value.Type() == "string" {
|
||||
line += fmt.Sprintf(" (default %q)", flag.DefValue)
|
||||
} else {
|
||||
line += fmt.Sprintf(" (default %s)", flag.DefValue)
|
||||
}
|
||||
if len(flag.Deprecated) != 0 {
|
||||
line += fmt.Sprintf(" (DEPRECATED: %s)", flag.Deprecated)
|
||||
}
|
||||
|
||||
lines = append(lines, line)
|
||||
})
|
||||
|
||||
for _, line := range lines {
|
||||
sidx1 := strings.Index(line, "\x00")
|
||||
sidx2 := strings.Index(line, "\x01")
|
||||
spacing1 := strings.Repeat(" ", maxlen-sidx1)
|
||||
spacing2 := strings.Repeat(" ", (maxEnvLen-maxlen)-sidx2+sidx1)
|
||||
fmt.Fprintln(buf, line[:sidx1], spacing1, line[sidx1+1:sidx2], spacing2, wrap(maxEnvLen+3, 0, line[sidx2+1:]))
|
||||
}
|
||||
|
||||
return b.String()
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func (o *Opts) getEnv(k string) string {
|
||||
func (o *Opts) getEnv(flag, k string) string {
|
||||
if k != "" {
|
||||
o.registeredEnvs = append(o.registeredEnvs, k)
|
||||
o.flagEnv[flag] = k
|
||||
return o.env.Getenv(k)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (o *Opts) Int64(envKey, flag, shortFlag string, defaultVal int64, usage string) (*int64, error) {
|
||||
if env := o.getEnv(envKey); env != "" {
|
||||
if env := o.getEnv(flag, envKey); env != "" {
|
||||
envVal, err := strconv.ParseInt(env, 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(`invalid environment variable %s. Expected int64. Found "%v".`, envKey, envVal)
|
||||
|
|
@ -73,7 +138,7 @@ func (o *Opts) Int64(envKey, flag, shortFlag string, defaultVal int64, usage str
|
|||
}
|
||||
|
||||
func (o *Opts) String(envKey, flag, shortFlag string, defaultVal, usage string) *string {
|
||||
if env := o.getEnv(envKey); env != "" {
|
||||
if env := o.getEnv(flag, envKey); env != "" {
|
||||
defaultVal = env
|
||||
}
|
||||
|
||||
|
|
@ -81,7 +146,7 @@ func (o *Opts) String(envKey, flag, shortFlag string, defaultVal, usage string)
|
|||
}
|
||||
|
||||
func (o *Opts) Bool(envKey, flag, shortFlag string, defaultVal bool, usage string) (*bool, error) {
|
||||
if env := o.getEnv(envKey); env != "" {
|
||||
if env := o.getEnv(flag, envKey); env != "" {
|
||||
if !boolyEnv(env) {
|
||||
return nil, fmt.Errorf(`invalid environment variable %s. Expected bool. Found "%s".`, envKey, env)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue