Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 32 additions & 30 deletions confutils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -174,12 +174,14 @@ func isCliSwitch(opt: OptInfo): bool =
opt.kind == CliSwitch or
(opt.kind == Discriminator and opt.isCommand == false)

func isOpt(opt: OptInfo): bool =
opt.isCliSwitch and not opt.isHidden

func hasOpts(cmd: CmdInfo): bool =
for opt in cmd.opts:
if opt.isCliSwitch and not opt.isHidden:
if opt.isOpt:
return true

return false
false

func hasArgs(cmd: CmdInfo): bool =
cmd.opts.len > 0 and cmd.opts[^1].kind == Arg
Expand Down Expand Up @@ -323,9 +325,7 @@ proc describeOptionsList(
appInfo: HelpAppInfo
) =
for opt in cmd.opts:
if opt.kind == Arg or
opt.kind == Discriminator or
opt.isHidden:
if not opt.isOpt:
continue

if opt.separator.len > 0:
Expand Down Expand Up @@ -356,27 +356,18 @@ proc describeOptionsList(

helpOutput "\p"

# TODO: this is not reached: https://github.com/status-im/nim-confutils/issues/39
when false:
if opt.kind == Discriminator:
for i, subCmd in opt.subCmds:
if not subCmd.hasOpts: continue

helpOutput "\pWhen ", styleBright, fgBlue, opt.humaneName, resetStyle, " = ", fgGreen, subCmd.name

if i == opt.defaultSubCmd: helpOutput " (default)"
help.describeOptions subCmd, cmdInvocation, appInfo, conditionalOpts

proc describeOptions(
help: var string,
cmd: CmdInfo,
cmds: openArray[CmdInfo],
cmdInvocation: string,
appInfo: HelpAppInfo,
optionsType = normalOpts,
activeCmds: openArray[CmdInfo] = @[]
optionsType = normalOpts
) =
var hasOpts = cmd.hasOpts
for c in activeCmds:
if cmds.len == 0:
return

var hasOpts = false
for c in cmds:
if c.hasOpts:
hasOpts = true

Expand All @@ -389,26 +380,37 @@ proc describeOptions(
of defaultCmdOpts:
discard

if activeCmds.len > 0:
for c in activeCmds:
describeOptionsList(help, c, appInfo)
else:
describeOptionsList(help, cmd, appInfo)
for c in cmds:
describeOptionsList(help, c, appInfo)

for c in cmds:
for opt in c.opts:
if opt.isOpt and opt.kind == Discriminator:
for i, subCmd in opt.subCmds:
if not subCmd.hasOpts:
continue

helpOutput "\pWhen ", styleBright, fgBlue, opt.humaneName, resetStyle, " = ", fgGreen, subCmd.name

if i == opt.defaultSubCmd:
helpOutput " (default)"
help.describeOptions [subCmd], cmdInvocation, appInfo, conditionalOpts

let cmd = cmds[^1]
let subCmdDiscriminator = cmd.getSubCmdDiscriminator
if subCmdDiscriminator != nil:
let defaultCmdIdx = subCmdDiscriminator.defaultSubCmd
if defaultCmdIdx != -1:
let defaultCmd = subCmdDiscriminator.subCmds[defaultCmdIdx]
help.describeOptions defaultCmd, cmdInvocation, appInfo, defaultCmdOpts
help.describeOptions [defaultCmd], cmdInvocation, appInfo, defaultCmdOpts

helpOutput fgSection, "\pAvailable sub-commands:\p"

for i, subCmd in subCmdDiscriminator.subCmds:
if i != subCmdDiscriminator.defaultSubCmd:
let subCmdInvocation = cmdInvocation & " " & subCmd.name
help.describeInvocation subCmd, subCmdInvocation, appInfo
help.describeOptions subCmd, subCmdInvocation, appInfo
help.describeOptions [subCmd], subCmdInvocation, appInfo

proc showHelp(help: var string,
appInfo: HelpAppInfo,
Expand Down Expand Up @@ -437,7 +439,7 @@ proc showHelp(help: var string,
# Write out the app or script name
helpOutput fgSection, "Usage: \p"
help.describeInvocation cmd, cmdInvocation, appInfo
help.describeOptions cmd, cmdInvocation, appInfo, activeCmds = activeCmds
help.describeOptions activeCmds, cmdInvocation, appInfo
helpOutput "\p"

flushOutputAndQuit QuitSuccess
Expand Down
25 changes: 25 additions & 0 deletions tests/help/snapshots/test_case_opt.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
Usage:

test_case_opt [OPTIONS]... command

The following options are available:

-p, --pre The name of your pre-state (without .ssz) [=pre].

Available sub-commands:

test_case_opt cmdSlotProcessing [OPTIONS]...

The following options are available:

-s, --num-slots The number of slots the pre-state will be advanced by [=1].

test_case_opt cmdBlockProcessing [OPTIONS]...

The following options are available:

--blockProcessingCat block transitions.

When blockProcessingCat = catAttestations, the following additional options are available:

--attestation Attestation filename (without .ssz).
12 changes: 12 additions & 0 deletions tests/help/snapshots/test_case_opt_cmdBlockProcessing.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Usage:

test_case_opt cmdBlockProcessing [OPTIONS]...

The following options are available:

-p, --pre The name of your pre-state (without .ssz) [=pre].
--blockProcessingCat block transitions.

When blockProcessingCat = catAttestations, the following additional options are available:

--attestation Attestation filename (without .ssz).
52 changes: 52 additions & 0 deletions tests/help/test_case_opt.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# confutils
# Copyright (c) 2018-2025 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
# at your option.
# This file may not be copied, modified, or distributed except according to
# those terms.

import ../../confutils

type
StartupCommand* = enum
noCommand
cmdSlotProcessing
cmdBlockProcessing

BlockProcessingCat* = enum
catBlockHeader
catAttestations

ScenarioConf* = object
preState* {.
desc: "The name of your pre-state (without .ssz)"
name: "pre"
abbr: "p"
defaultValue: "pre".}: string
case cmd*{.
command
defaultValue: noCommand }: StartupCommand
of noCommand:
discard
of cmdSlotProcessing:
numSlots* {.
desc: "The number of slots the pre-state will be advanced by"
name: "num-slots"
abbr: "s"
defaultValue: 1.}: uint64
of cmdBlockProcessing:
case blockProcessingCat* {.
desc: "block transitions"
#name: "process-blocks" # Comment this to make it work
implicitlySelectable
required .}: BlockProcessingCat
of catBlockHeader:
discard
of catAttestations:
attestation*{.
desc: "Attestation filename (without .ssz)"
name: "attestation".}: string

let scenario = ScenarioConf.load(termWidth = int.high)
8 changes: 7 additions & 1 deletion tests/test_help.nim
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ suite "test --help":

test "test test_nested_cmd lvl1Cmd1":
cmdTest("test_nested_cmd", "lvl1Cmd1")

test "test test_nested_cmd lvl1Cmd1 lvl2Cmd2":
cmdTest("test_nested_cmd", "lvl1Cmd1 lvl2Cmd2")

test "test test_case_opt":
cmdTest("test_case_opt", "")

test "test test_case_opt cmdBlockProcessing":
cmdTest("test_case_opt", "cmdBlockProcessing")