Skip to content

Subcommands#

You can nest commands. Let's take git for example

git has a command called stash. When you execute git stash, it stashes all the changes. But stash has further commands like, git stash pop, git stash list, etc.

Let's mimic the same behavior using CommandDotNet:

Subcommand as a property#

[Command(Description = "Fake git application")]
public class Program
{
    static int Main(string[] args) => AppRunner.Run(args);
    public static AppRunner AppRunner =>
        new AppRunner<Program>().UseNameCasing(Case.KebabCase);

    // Properties decorated with the [Subcommand] attribute will be subcommands of the host
    [Subcommand]
    public Stash Stash { get; set; }

    [Command(Description = "Commits all staged changes")]
    public void Commit(IConsole console, [Option('m', null)] string? commitMessage)
    {
        console.WriteLine("Commit successful");
    }
}

[Command(Description = "Stashes all changes when executed without any arguments")]
[Subcommand]
public class Stash
{
    [DefaultCommand]
    public void StashImpl(IConsole console)
    {
        console.WriteLine("changes stashed");
    }

    [Command(Description = "Applies last stashed changes")]
    public void Pop(IConsole console)
    {
        console.WriteLine("stash popped");
    }

    [Command(Description = "Lists all stashed changes")]
    public void List(IConsole console)
    {
        console.WriteLine("here's the list of stash");
    }
}
snippet source | anchor

Notice the Stash property decorated with the [SubCommand] attribute.

The help will generate as:

$ git.exe -h
Fake git application

Usage: git.exe [command]

Commands:

  commit  Commits all staged changes
  stash   Stashes all changes when executed without any arguments

Use "git.exe [command] --help" for more information about a command.
snippet source | anchor

Here's how the interaction looks like:

$ git.exe commit -m "some refactoring"
Commit successful
snippet source | anchor

$ git.exe stash
changes stashed
snippet source | anchor

$ git.exe stash -h
Stashes all changes when executed without any arguments

Usage: git.exe stash [command]

Commands:

  list  Lists all stashed changes
  pop   Applies last stashed changes

Use "git.exe stash [command] --help" for more information about a command.
snippet source | anchor

$ git.exe stash pop
stash popped
snippet source | anchor

Tip

See Nullable Reference Types for avoiding "Non-nullable property is uninitialized" warnings for subcommand properties

Subcommand as a nested class#

The same git stash command could be modelled as a nested class.

[Command(Description = "Fake git application")]
public class Program
{
    static int Main(string[] args) => AppRunner.Run(args);
    public static AppRunner AppRunner =>
        new AppRunner<Program>()
            .UseNameCasing(Case.KebabCase);

    [Command(Description = "Commits all staged changes")]
    public void Commit(IConsole console, [Option('m')] string? commitMessage)
    {
        console.WriteLine("Commit successful");
    }

    [Command(Description = "Stashes all changes when executed without any arguments")]
    [Subcommand]
    public class Stash
    {
        [DefaultCommand]
        public void StashImpl(IConsole console)
        {
            console.WriteLine("changes stashed");
        }

        [Command(Description = "Applies last stashed changes")]
        public void Pop(IConsole console)
        {
            console.WriteLine("stash popped");
        }

        [Command(Description = "Lists all stashed changes")]
        public void List(IConsole console)
        {
            console.WriteLine("here's the list of stash");
        }
    }
}
snippet source | anchor