sigoden/argc

Feature request: default subcommand

CGamesPlay opened this issue · 5 comments

Hi @sigoden, continuing to love using argc for all of my shell scripts. One pattern that I see coming up sometimes is a desire for a "default subcommand". Basically, I have a script called "backup", and I want it to... perform a backup. But I also want to add subcommands, like "backup verify" or "backup restore". With the current system, I can't do this, because the main command is completely masked by the presence of subcommands.

So the feature request is for the ability to designate a subcommand as a "default" one. Something like this:

#!/usr/bin/env bash

# @cmd
# @default_subcommand
backup() { :; }

# @cmd
restore() { :; }

eval "$(argc --argc-eval "$0" "$@")"

This script could be invoked as argc; argc backup; argc restore. Now, this behavior would cause ambiguity with positional arguments. For example, if the backup subcommand accepted arguments, should argc $PARAM be an error, or invoke argc backup $PARAM? What if $PARAM was restore? So, in order for a subcommand to be eligible as a default subcommand, it cannot accept any positional arguments.

Ideally this feature would also work with nested subcommands in the same way, so e.g. with 3 subcommands backup; backup::incremental; backup::full I could designate backup::incremental as the default for the backup command (which again could be the default subcommand for the overall script).

It would be nice if the shell completion also understood when a command was the default and showed arguments for that subcommand when there wasn't one given.

Thanks again for the consideration. Loving the activity on this project!

use main function.

# @cmd
backup() { :; }

# @cmd
restore() { :; }


main() {
  backup
}

eval "$(argc --argc-eval "$0" "$@")"
# @cmd
backup() { :; }

# @cmd
backup::incremental() { :; }

# @cmd
backup::full() { :; }

backup::main() {
  backup::incremental
}

eval "$(argc --argc-eval "$0" "$@")"

Amazing. Works like a charm.

One quirk I found while playing with it is that the main command really only works if it doesn't take arguments/options/flags. If you need any of these, you have to specify the main function as a separate @cmd. It can still be invoked using the parent command, but you can't pass any parameters to it when you invoke it this way. Example: in the following, argc; argc main --incremental both work, but argc --incremental does not.

# @cmd
restore() { :; }

# @cmd
# @option --incremental
main() { :; }

eval "$(argc --argc-eval "$0" "$@")"

It would be nice to be able to use the normal @option/@flag with the main function without using @cmd, like this:

# @cmd
restore() { :; }

# @option --incremental
main() { :; }

eval "$(argc --argc-eval "$0" "$@")"

Again, allowing @arg invites ambiguity, so maybe that one should be disabled.

After pr #150, main fn can accept arguments/options/flags.

# @flag --incremental

# @cmd
restore() { :; }

main() { :; }

eval "$(argc --argc-eval "$0" "$@")"

#296 implements the feature.