mirror of
https://github.com/daylinmorgan/hwylterm.git
synced 2025-02-23 01:35:50 -06:00
add type metavars to help output
This commit is contained in:
parent
5d7e404d0d
commit
bf542a1470
3 changed files with 78 additions and 71 deletions
|
@ -38,13 +38,13 @@ export parseopt3, sets, bbansi
|
||||||
|
|
||||||
type
|
type
|
||||||
HwylFlagHelp* = tuple[
|
HwylFlagHelp* = tuple[
|
||||||
short, long, description, defaultVal: string; required: bool
|
short, long, description, typeRepr, defaultVal: string; required: bool
|
||||||
]
|
]
|
||||||
HwylSubCmdHelp* = tuple[
|
HwylSubCmdHelp* = tuple[
|
||||||
name, aliases, desc: string
|
name, aliases, desc: string
|
||||||
]
|
]
|
||||||
HwylCliStyleSetting = enum
|
HwylCliStyleSetting = enum
|
||||||
Aliases, Required, Defaults
|
Aliases, Required, Defaults, Types
|
||||||
HwylCliStyles* = object
|
HwylCliStyles* = object
|
||||||
header* = "bold cyan"
|
header* = "bold cyan"
|
||||||
flagShort* = "yellow"
|
flagShort* = "yellow"
|
||||||
|
@ -52,12 +52,13 @@ type
|
||||||
flagDesc* = ""
|
flagDesc* = ""
|
||||||
default* = "faint"
|
default* = "faint"
|
||||||
required* = "red"
|
required* = "red"
|
||||||
cmd* = "bold"
|
subcmd* = "bold"
|
||||||
|
typeRepr = "faint"
|
||||||
minCmdLen* = 8
|
minCmdLen* = 8
|
||||||
settings*: set[HwylCliStyleSetting] = {Aliases, Required, Defaults}
|
settings*: set[HwylCliStyleSetting] = {Aliases, Required, Defaults, Types}
|
||||||
|
|
||||||
HwylCliLengths = object
|
HwylCliLengths = object
|
||||||
subcmd*, subcmdDesc*, shortArg*, longArg*, descArg*, defaultVal*: int
|
subcmd*, subcmdDesc*, shortArg*, longArg*, descArg*, typeRepr*, defaultVal*: int
|
||||||
|
|
||||||
HwylCliHelp* = object
|
HwylCliHelp* = object
|
||||||
header*, footer*, description*, usage*: string
|
header*, footer*, description*, usage*: string
|
||||||
|
@ -92,57 +93,63 @@ func newHwylCliHelp*(
|
||||||
result.flags = @flags
|
result.flags = @flags
|
||||||
result.styles = styles
|
result.styles = styles
|
||||||
result.lengths.subcmd = styles.minCmdLen
|
result.lengths.subcmd = styles.minCmdLen
|
||||||
|
|
||||||
for f in flags:
|
for f in flags:
|
||||||
|
# template?
|
||||||
result.lengths.shortArg = max(result.lengths.shortArg, f.short.len)
|
result.lengths.shortArg = max(result.lengths.shortArg, f.short.len)
|
||||||
result.lengths.longArg = max(result.lengths.longArg, f.long.len)
|
result.lengths.longArg = max(result.lengths.longArg, f.long.len)
|
||||||
result.lengths.descArg = max(result.lengths.descArg, f.description.len)
|
result.lengths.descArg = max(result.lengths.descArg, f.description.len)
|
||||||
|
|
||||||
result.lengths.defaultVal = max(result.lengths.defaultVal, f.defaultVal.len)
|
result.lengths.defaultVal = max(result.lengths.defaultVal, f.defaultVal.len)
|
||||||
|
|
||||||
|
# using "bb" before len.. to squash out the escaped [[
|
||||||
|
result.lengths.typeRepr = max(result.lengths.typeRepr, f.typeRepr.bb.len)
|
||||||
|
|
||||||
for s in result.subcmds:
|
for s in result.subcmds:
|
||||||
result.lengths.subcmd = max(result.lengths.subcmd, s.name.len)
|
result.lengths.subcmd = max(result.lengths.subcmd, s.name.len)
|
||||||
result.lengths.subcmdDesc = max(result.lengths.subcmdDesc, s.desc.len)
|
result.lengths.subcmdDesc = max(result.lengths.subcmdDesc, s.desc.len)
|
||||||
|
|
||||||
|
|
||||||
func render*(cli: HwylCliHelp, f: HwylFlagHelp): string =
|
func render*(cli: HwylCliHelp, f: HwylFlagHelp): string =
|
||||||
result.add " "
|
result.add " "
|
||||||
if f.short != "":
|
if f.short != "":
|
||||||
result.add "[" & cli.styles.flagShort & "]"
|
result.add ("-" & f.short.alignLeft(cli.lengths.shortArg)).bbMarkup(cli.styles.flagShort)
|
||||||
result.add "-" & f.short.alignLeft(cli.lengths.shortArg)
|
|
||||||
result.add "[/" & cli.styles.flagShort & "]"
|
|
||||||
else:
|
else:
|
||||||
result.add " ".repeat(1 + cli.lengths.shortArg)
|
result.add " ".repeat(1 + cli.lengths.shortArg)
|
||||||
|
|
||||||
result.add " "
|
result.add " "
|
||||||
if f.long != "":
|
if f.long != "":
|
||||||
result.add "[" & cli.styles.flagLong & "]"
|
result.add ("--" & f.long.alignLeft(cli.lengths.longArg)).bbMarkup(cli.styles.flagLong)
|
||||||
result.add "--" & f.long.alignLeft(cli.lengths.longArg)
|
|
||||||
result.add "[/" & cli.styles.flagLong & "]"
|
|
||||||
else:
|
else:
|
||||||
result.add " ".repeat(2 + cli.lengths.longArg)
|
result.add " ".repeat(2 + cli.lengths.longArg)
|
||||||
|
|
||||||
|
if Types in cli.styles.settings:
|
||||||
|
result.add " "
|
||||||
|
# BUG alignLeft isn't accounting for these '[['
|
||||||
|
let offset = int(
|
||||||
|
(f.typeRepr.len - f.typeRepr.replace("[[","").len) / 2
|
||||||
|
)
|
||||||
|
result.add f.typeRepr
|
||||||
|
.alignLeft(
|
||||||
|
cli.lengths.typeRepr + offset
|
||||||
|
)
|
||||||
|
.bbMarkup(cli.styles.typeRepr)
|
||||||
|
|
||||||
result.add " "
|
result.add " "
|
||||||
if f.description != "":
|
if f.description != "":
|
||||||
result.add "[" & cli.styles.flagDesc & "]"
|
result.add f.description.bbMarkup(cli.styles.flagDesc)
|
||||||
result.add f.description
|
|
||||||
result.add "[/" & cli.styles.flagDesc & "]"
|
|
||||||
|
|
||||||
if f.defaultVal != "" and Defaults in cli.styles.settings:
|
if f.defaultVal != "" and Defaults in cli.styles.settings:
|
||||||
result.add " "
|
result.add " "
|
||||||
result.add "[" & cli.styles.default & "]"
|
result.add ("(default: " & f.defaultVal & ")")
|
||||||
result.add "(" & f.defaultVal & ")"
|
.bbMarkup(cli.styles.default)
|
||||||
result.add "[/" & cli.styles.default & "]"
|
|
||||||
|
|
||||||
if f.required and Required in cli.styles.settings:
|
if f.required and Required in cli.styles.settings:
|
||||||
result.add " "
|
result.add " "
|
||||||
result.add "[" & cli.styles.required & "]"
|
result.add "(required)".bbMarkup(cli.styles.required)
|
||||||
result.add "(required)"
|
|
||||||
result.add "[/" & cli.styles.required & "]"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func render*(cli: HwylCliHelp, subcmd: HwylSubCmdHelp): string =
|
func render*(cli: HwylCliHelp, subcmd: HwylSubCmdHelp): string =
|
||||||
result.add " "
|
result.add " "
|
||||||
result.add "[" & cli.styles.cmd & "]"
|
result.add subcmd.name.alignLeft(cli.lengths.subcmd).bbMarkup(cli.styles.subcmd)
|
||||||
result.add subcmd.name.alignLeft(cli.lengths.subcmd)
|
|
||||||
result.add "[/]"
|
|
||||||
result.add " "
|
result.add " "
|
||||||
result.add subcmd.desc.alignLeft(cli.lengths.subcmdDesc)
|
result.add subcmd.desc.alignLeft(cli.lengths.subcmdDesc)
|
||||||
|
|
||||||
|
@ -154,25 +161,13 @@ template render*(cli: HwylCliHelp): string =
|
||||||
if cli.header != "":
|
if cli.header != "":
|
||||||
parts.add cli.header
|
parts.add cli.header
|
||||||
if cli.usage != "":
|
if cli.usage != "":
|
||||||
var part: string
|
parts.add "usage".bbMarkup(cli.styles.header) & ":\n" & indent(cli.usage, 2 )
|
||||||
part.add "[" & cli.styles.header & "]"
|
|
||||||
part.add "usage[/]:\n"
|
|
||||||
part.add indent(cli.usage, 2 )
|
|
||||||
parts.add part
|
|
||||||
if cli.description != "":
|
if cli.description != "":
|
||||||
parts.add cli.description
|
parts.add cli.description
|
||||||
if cli.subcmds.len > 0:
|
if cli.subcmds.len > 0:
|
||||||
var part: string
|
parts.add "subcommands".bbMarkup(cli.styles.header) & ":\n" & cli.subcmds.mapIt(render(cli,it)).join("\n")
|
||||||
part.add "[" & cli.styles.header & "]"
|
|
||||||
part.add "subcommands[/]:\n"
|
|
||||||
part.add cli.subcmds.mapIt(render(cli,it)).join("\n")
|
|
||||||
parts.add part
|
|
||||||
if cli.flags.len > 0:
|
if cli.flags.len > 0:
|
||||||
var part: string
|
parts.add "flags".bbMarkup(cli.styles.header) & ":\n" & cli.flags.mapIt(render(cli, it)).join("\n")
|
||||||
part.add "[" & cli.styles.header & "]"
|
|
||||||
part.add "flags[/]:\n"
|
|
||||||
part.add cli.flags.mapIt(render(cli, it)).join("\n")
|
|
||||||
parts.add part
|
|
||||||
if cli.footer != "":
|
if cli.footer != "":
|
||||||
parts.add cli.footer
|
parts.add cli.footer
|
||||||
|
|
||||||
|
@ -191,8 +186,21 @@ type
|
||||||
val*: Y
|
val*: Y
|
||||||
KVString* = KV[string, string]
|
KVString* = KV[string, string]
|
||||||
|
|
||||||
|
|
||||||
|
proc `$`*(t: typedesc[KVString]): string =
|
||||||
|
result.add "k(string):v(string)"
|
||||||
|
|
||||||
|
proc `$`*[X,Y](t: typedesc[KV[X, Y]]): string =
|
||||||
|
result.add "k(" & $X & ")"
|
||||||
|
result.add ":"
|
||||||
|
result.add "v(" & $Y & ")"
|
||||||
|
|
||||||
|
proc `$`[X,Y](t: typedesc[seq[KV[X,Y]]]): string =
|
||||||
|
"seq[" & $(KV[X,Y]) & "]"
|
||||||
|
|
||||||
proc `$`(c: Count): string = $c.val
|
proc `$`(c: Count): string = $c.val
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------
|
# ----------------------------------------
|
||||||
|
|
||||||
type
|
type
|
||||||
|
@ -882,7 +890,6 @@ func parseCliBody(body: NimNode, name = "", root = false): CliCfg =
|
||||||
if root:
|
if root:
|
||||||
propagate(result)
|
propagate(result)
|
||||||
|
|
||||||
|
|
||||||
func isBool(f: CliFlag | BuiltinFlag): bool =
|
func isBool(f: CliFlag | BuiltinFlag): bool =
|
||||||
f.typeNode == ident"bool"
|
f.typeNode == ident"bool"
|
||||||
|
|
||||||
|
@ -917,35 +924,44 @@ func flagToTuple(c: CliCfg, f: BuiltinFlag): NimNode =
|
||||||
# under the hood when parsing type/val
|
# under the hood when parsing type/val
|
||||||
|
|
||||||
quote do:
|
quote do:
|
||||||
(`short`, `long`, `help`, bbEscape($`defaultVal`), `required`)
|
(`short`, `long`, `help`, "", bbEscape($`defaultVal`), `required`)
|
||||||
|
|
||||||
|
|
||||||
func flagToTuple(c: CliCfg, f: CliFlag): NimNode =
|
func flagToTuple(c: CliCfg, f: CliFlag): NimNode =
|
||||||
let
|
let
|
||||||
short =
|
short =
|
||||||
if f.short != '\x00': newLit($f.short)
|
if f.short != '\x00': newLit($f.short)
|
||||||
else: newLit("")
|
else: newLit""
|
||||||
long = newLit(f.long)
|
|
||||||
help = f.help
|
|
||||||
|
|
||||||
defaultVal =
|
defaultVal =
|
||||||
if (HideDefault in f.settings) or
|
if (HideDefault in f.settings) or
|
||||||
(HideDefault in c.settings):
|
(HideDefault in c.settings) or
|
||||||
|
f.defaultVal == nil:
|
||||||
newLit""
|
newLit""
|
||||||
else:
|
else:
|
||||||
f.defaultVal or newLit""
|
let val = f.defaultVal
|
||||||
|
quote do:
|
||||||
|
bbEscape($`val`)
|
||||||
|
|
||||||
required = newLit(c.isRequiredFlag(f))
|
required = newLit(c.isRequiredFlag(f))
|
||||||
|
typeNode =
|
||||||
|
if f.isBool: newLit""
|
||||||
|
else:
|
||||||
|
let t = f.typeNode
|
||||||
|
quote do: bbEscape($`t`)
|
||||||
|
|
||||||
|
|
||||||
# BUG: if f.defaultVal is @[] `$` fails
|
# BUG: if f.defaultVal is @[] `$` fails
|
||||||
# but works with `newSeq[T]()`
|
# but works with `newSeq[T]()`
|
||||||
# could replace "defaultVal" with newSeq[T]()
|
# could replace "defaultVal" with newSeq[T]()
|
||||||
# under the hood when parsing type/val
|
# under the hood when parsing type/val
|
||||||
|
|
||||||
result = nnkTupleConstr.newTree(
|
result = nnkTupleConstr.newTree(
|
||||||
short,
|
short,
|
||||||
newLit(f.long),
|
newLit(f.long),
|
||||||
f.help,
|
f.help,
|
||||||
quote do: bbEscape($`defaultVal`),
|
typeNode,
|
||||||
|
defaultVal,
|
||||||
required,
|
required,
|
||||||
)
|
)
|
||||||
# quote do:
|
# quote do:
|
||||||
|
|
|
@ -48,7 +48,7 @@ usage:
|
||||||
positionals first... second third [flags]
|
positionals first... second third [flags]
|
||||||
|
|
||||||
flags:
|
flags:
|
||||||
-h --help show this help
|
-h --help show this help
|
||||||
""",
|
""",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -59,9 +59,9 @@ usage:
|
||||||
flag-settings [flags]
|
flag-settings [flags]
|
||||||
|
|
||||||
flags:
|
flags:
|
||||||
--input flag with default hidden
|
--input string flag with default hidden
|
||||||
--count a count var with default (0)
|
--count Count a count var with default (default: 0)
|
||||||
-h --help show this help
|
-h --help show this help
|
||||||
""",
|
""",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -72,9 +72,9 @@ usage:
|
||||||
setting-hide-default [flags]
|
setting-hide-default [flags]
|
||||||
|
|
||||||
flags:
|
flags:
|
||||||
--input flag with default hidden
|
--input string flag with default hidden
|
||||||
--count a count var with default
|
--count Count a count var with default
|
||||||
-h --help show this help
|
-h --help show this help
|
||||||
""",
|
""",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@ type
|
||||||
Color = enum
|
Color = enum
|
||||||
red, blue, green
|
red, blue, green
|
||||||
|
|
||||||
|
KVColor = KV[string, Color]
|
||||||
|
|
||||||
hwylCli:
|
hwylCli:
|
||||||
name "example"
|
name "example"
|
||||||
V "0.1.0"
|
V "0.1.0"
|
||||||
|
@ -59,7 +61,6 @@ hwylCli:
|
||||||
|
|
||||||
run:
|
run:
|
||||||
echo "hello from `example one` command!"
|
echo "hello from `example one` command!"
|
||||||
echo args
|
|
||||||
echo fmt"{color=}"
|
echo fmt"{color=}"
|
||||||
echo fmt"{verbose=}"
|
echo fmt"{verbose=}"
|
||||||
echo fmt"{config=}"
|
echo fmt"{config=}"
|
||||||
|
@ -71,21 +72,11 @@ hwylCli:
|
||||||
a longer mulitline description that will be visible in the subcommand help
|
a longer mulitline description that will be visible in the subcommand help
|
||||||
and it will automatically be "bb"'ed [bold]this is bold text[/]
|
and it will automatically be "bb"'ed [bold]this is bold text[/]
|
||||||
"""
|
"""
|
||||||
# args first, second
|
|
||||||
# or
|
|
||||||
args:
|
|
||||||
# default type is string
|
|
||||||
# only one 'arg' can be the seq[string]
|
|
||||||
# order matters here
|
|
||||||
# by default string
|
|
||||||
inputs:
|
|
||||||
T int
|
|
||||||
second seq[string]
|
|
||||||
flags:
|
flags:
|
||||||
^something
|
^something
|
||||||
thing:
|
inputs:
|
||||||
T seq[KV[string, Color]]
|
T seq[KVColor]
|
||||||
? "some key value colors"
|
? "some key stuff"
|
||||||
b:
|
b:
|
||||||
T seq[float]
|
T seq[float]
|
||||||
? "multiple floats"
|
? "multiple floats"
|
||||||
|
@ -95,5 +86,5 @@ hwylCli:
|
||||||
* "the value"
|
* "the value"
|
||||||
run:
|
run:
|
||||||
echo "hello from `example b` command"
|
echo "hello from `example b` command"
|
||||||
echo fmt"{thing=}, {b=}, {def=}"
|
echo fmt"{inputs=}, {b=}, {def=}"
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue