Kixunil/configure_me

Subcommands

Opened this issue · 0 comments

Support subcommands like e.g. commit is a subcommand of git.

Example input:

[general]
# global options

# This is a global param - given to program in the form of cmd --foo subcmd
# We could later support cmd subcmd --foo
[[param]]
name = "foo"
type = "String"
# ...

# same as above an be done with switch

# We use subcmd instead of subcommand to keep it reasonably short because it will be repeated
[subcmd.subcmdname.general]
# Only support these two for now, other things available above are mostly non-sensical here
summary = "This command does something"
doc = "Long explanation of what this command is all about..."
# LATER we could also support include = "file-relative-to-current"
# included files should probably only support params and switches

# works exactly the same as in top-level
[[subcmd.subcmdname.param]]
name = "bar"
type = "String"

# switch is supported here as well
# nested subcommand is also supported

The generated code will look something like this:

enum Subcommand {
    Subcmdname(subcmdname::Config),
}

// recursively generates almost the same thing as top-level
mod subcmdname {
    struct Config {
        // no _program_name here, it's pointless
        bar: String,
    }

    // also has raw module like the top-level
    mod raw {
    }
}

Specification parsing code will get subcmd: HashMap<Ident, Subcommand> field.

struct Subcommand {
    global: SubcommandGlobal,
    param: Vec<Param>,
    switch: Vec<Switch>,
}

Difficult stuff:

  • How to parse and process config files for subcommands? Suggestion: don't support in initial impl
  • How to process env vars for config files? Suggestion: don't support in initial impl
  • Should subcommand be inside Config, or outside? The advantage of being outside is it can get global config without self-reference but maybe that's not useful as immutable references will most likely be used?
  • Should we support more straightforward design as clap does? If there are multiple nested subcommands and mid-commmands don't have any options, then avoiding the struct would lead to easier-to-write code, although harder-to-refactor. Maybe instead have Subcmdname { config: subcmdname::Config, subcmd: subcmdname::Subcommand }, then matching code can just ignore empty struct. This obviously implies "outside" for the question about.