modify flag inheritance to support individual flags

This commit is contained in:
Daylin Morgan 2024-11-12 14:20:16 -06:00
parent ad57eee373
commit 2a5dce888d
Signed by: daylin
GPG key ID: 950D13E9719334AD
2 changed files with 68 additions and 34 deletions

View file

@ -146,6 +146,12 @@ type
short*: char short*: char
long*: string long*: string
help*: NimNode help*: NimNode
group*: string
Inherit = object
settings: set[CliSetting]
flags: seq[string]
groups: seq[string]
CliCfg = object CliCfg = object
stopWords*: seq[string] stopWords*: seq[string]
@ -160,9 +166,9 @@ type
version*, usage*: NimNode version*, usage*: NimNode
flags*: seq[CliFlag] flags*: seq[CliFlag]
builtinFlags*: seq[BuiltinFlag] builtinFlags*: seq[BuiltinFlag]
flagGroups: Table[string, seq[CliFlag]] flagDefs*: seq[CliFlag]
required*: seq[string] required*: seq[string]
inheritFlags*: seq[string] inherit*: Inherit
root*: bool root*: bool
# some debug procs I use to wrap my ahead aroung the magic of *macro* # some debug procs I use to wrap my ahead aroung the magic of *macro*
@ -252,25 +258,36 @@ func parseCliFlags(cfg: var CliCfg, node: NimNode) =
var group: string var group: string
expectKind node, nnkStmtList expectKind node, nnkStmtList
for n in node: for n in node:
<<< n
var flag: CliFlag var flag: CliFlag
case n.kind case n.kind
of nnkCall, nnkCommand: of nnkCall, nnkCommand:
flag = parseCliFlag(n) flag = parseCliFlag(n)
if group == "": flag.group = group
cfg.flags.add flag cfg.flagDefs.add flag
else:
if group notin cfg.flagGroups: cfg.flagGroups[group] = @[flag]
else: cfg.flagGroups[group].add flag
of nnkBracket: of nnkBracket:
group = n[0].strVal group = n[0].strVal
continue continue
of nnkPrefix: of nnkPrefix:
if n[0].kind != nnkIdent and n[0].strVal != "^": if
n[0].kind != nnkIdent or
n[0].strVal != "^" or
n.len != 2 or
n[1].kind notin [nnkBracket, nnkIdent, nnkStrLit]:
error "unexpected node in flags: " & $n.kind error "unexpected node in flags: " & $n.kind
expectKind n[1], nnkBracket
cfg.inheritFlags.add n[1][0].strVal case n[1].kind
of nnkBracket:
cfg.inherit.groups.add n[1][0].strVal
# cfg.inheritFlags.add n[1][0].strVal
of nnkIdent, nnkStrLit:
cfg.inherit.flags.add n[1].strval
else: bad(n, "flag") else: bad(n, "flag")
else: bad(n, "flag")
cfg.flags = cfg.flagDefs.filterIt(it.group in ["", "global"])
func parseCliSetting(s: string): CliSetting = func parseCliSetting(s: string): CliSetting =
try: parseEnum[CliSetting](s) try: parseEnum[CliSetting](s)
except: error "unknown cli setting: " & s except: error "unknown cli setting: " & s
@ -332,24 +349,40 @@ func sliceStmts(node: NimNode): seq[
start = i + 1 start = i + 1
func addInheritedFlags(child: var CliCfg, parent: CliCfg, self = false) = func inheritFrom(child: var CliCfg, parent: CliCfg) =
let names = child.flags.mapIt(it.name) ## inherit settings from parent command
var groups: seq[string] var
if not self: pflags: Table[string, CliFlag]
groups.add child.inheritFlags pgroups: Table[string, seq[CliFlag]]
flags: seq[string]
groups: seq[string]
# autoinherit the "global" flags flags &= child.inherit.flags
if "global" in parent.flagGroups: groups &= child.inherit.groups
for f in parent.flagDefs:
pflags[f.name] = f
if f.group in pgroups:
pgroups[f.group].add f
else:
pgroups[f.group] = @[f]
if "global" in pgroups:
groups.add "global" groups.add "global"
for f in flags:
if f notin pflags:
error "expected parent command to define flag: " & f
else:
child.flags.add pflags[f]
for g in groups: for g in groups:
if g notin parent.flagGroups: if g notin pgroups:
debugEcho parent.flagGroups.keys().toSeq() error "expected parent command to define flag group " & g
error "expected flag group: " & g & " to exist in parent command" else:
for f in parent.flagGroups[g]: child.flags &= pgroups[g]
if f.name in names:
error "global flag " & f.name & " conflicts with command flag"
child.flags.add f
func parseCliSubcommands(cfg: var CliCfg, node: NimNode) = func parseCliSubcommands(cfg: var CliCfg, node: NimNode) =
expectKind node[1], nnkStmtList expectKind node[1], nnkStmtList
@ -359,7 +392,7 @@ func parseCliSubcommands(cfg: var CliCfg, node: NimNode) =
nnkStmtList.newTree(node[1][s]), cfg.name & " " & name nnkStmtList.newTree(node[1][s]), cfg.name & " " & name
) )
subCfg.subName = name subCfg.subName = name
subCfg.addInheritedFlags(cfg) subCfg.inheritFrom(cfg)
cfg.subcommands.add subCfg cfg.subcommands.add subCfg
func parseHiddenFlags(cfg: var CliCfg, node: NimNode) = func parseHiddenFlags(cfg: var CliCfg, node: NimNode) =
@ -454,8 +487,6 @@ func parseCliBody(body: NimNode, name = "", root = false): CliCfg =
sub.pre = result.preSub sub.pre = result.preSub
sub.post = result.postSub sub.post = result.postSub
result.addInheritedFlags(result, self = true)
if result.name == "": if result.name == "":
error "missing required option: name" error "missing required option: name"

View file

@ -16,8 +16,10 @@ hwylCli:
yes: yes:
T bool T bool
? "set flag to yes" ? "set flag to yes"
[config] [shared]
confiG: something:
? "some flag only needed in one subcommand"
config:
T seq[string] T seq[string]
? "path to config file" ? "path to config file"
* @["config.yml"] * @["config.yml"]
@ -31,7 +33,7 @@ hwylCli:
the first subcommand the first subcommand
this command features both an enum flag and a Count flag this command features both an enum flag and a Count flag
it also inherits the `[[config]` flag group it also inherits the `[[shared]` flag group
""" """
flags: flags:
@ -42,7 +44,7 @@ hwylCli:
T Count T Count
? "a count flag" ? "a count flag"
- v - v
^[config] ^[shared]
run: run:
echo "hello from `example one` command!" echo "hello from `example one` command!"
echo args echo args
@ -58,6 +60,7 @@ hwylCli:
and it will automatically be "bb"'ed [bold]this is bold text[/] and it will automatically be "bb"'ed [bold]this is bold text[/]
""" """
flags: flags:
^something
auto: auto:
- a - a
? "some help" ? "some help"