# Commands

There are two different ways of registering functions:

1. `app.default` - Registers an action for when no registered command is provided. This was previously demonstrated in Getting Started.

   A sub-app cannot be registered with `app.default`. If no `default` command is registered, Cyclopts will display the help-page.

2. `app.command` - Registers a function or `App` as a command.

This section will detail how to use the `@app.command` decorator.

## Registering a Command

The `@app.command` decorator adds a command to a Cyclopts application.

    from cyclopts import App

    app = App()

    @app.command
    def fizz(n: int):
        print(f"FIZZ: {n}")

    @app.command
    def buzz(n: int):
        print(f"BUZZ: {n}")

    app()

We can now control which command runs from the CLI:

    $ my-script fizz 3
    FIZZ: 3

    $ my-script buzz 4
    BUZZ: 4

    $ my-script fuzz
    ╭─ Error ────────────────────────────────────────────────────────────────────╮
    │ Unknown command "fuzz". Did you mean "fizz"?                               │
    ╰────────────────────────────────────────────────────────────────────────────╯

## Registering a SubCommand

The `app.command` method can also register another Cyclopts `App` as a command.

    from cyclopts import App

    app = App()
    sub_app = App(name="foo")  # "foo" would be a better variable name than "sub_app".
    # "sub_app" in this example emphasizes the name comes from name="foo".
    app.command(sub_app)  # Registers sub_app to command "foo"
    # Or, as a one-liner:  app.command(sub_app := App(name="foo"))

    @sub_app.command
    def bar(n: int):
        print(f"BAR: {n}")

    # Alternatively, access subapps from app like a dictionary.
    @app["foo"].command
    def baz(n: int):
        print(f"BAZ: {n}")

    app()

    $ my-script foo bar 3
    BAR: 3

    $ my-script foo baz 4
    BAZ: 4

The subcommand may have their own registered `default` action. Cyclopts's command structure is fully recursive.

## Changing Command Name

By default, commands are registered to the python function's name with underscores replaced with hyphens. Any leading or trailing underscores will be stripped. For example, the function `_foo_bar()` will become the command `foo-bar`. This renaming is done because CLI programs generally tend to use hyphens instead of underscores. The name transform can be configured by `App.name_transform`. For example, to make CLI command names be identical to their python function name counterparts, we can configure `App` as follows:

    from cyclopts import App

    app = App(name_transform=lambda s: s)

    @app.command
    def foo_bar():  # will now be "foo_bar" instead of "foo-bar"
        print("running function foo_bar")

    app()

    $ my-script foo_bar
    running function foo_bar

Alternatively, the name can be manually changed in the `@app.command` decorator. Manually set names are not subject to `App.name_transform`.

    from cyclopts import App

    app = App()

    @app.command(name="bar")
    def foo():  # function name will NOT be used.
        print("Hello World!")

    app()

    $ my-script bar
    Hello World!

## Adding Help

There are a few ways to add a help string to a command:

1. If the function has a docstring, the short description will be used as the help string for the command. This is generally the preferred method of providing help strings.

2. If the registered command is a sub app, the sub app's `help` field will be used.

       sub_app = App(name="foo", help="Help text for foo.")
       app.command(sub_app)

3. The `help` field of `@app.command`. If provided, the docstring or subapp help field will not be used.

       from cyclopts import App

       app = App()

       @app.command
       def foo():
           """Help string for foo."""
           pass

       @app.command(help="Help string for bar.")
       def bar():
           """This got overridden."""

       app()

       $ my-script --help
       ╭─ Commands ────────────────────────────────────────────────────────────╮
       │ bar        Help string for bar.                                       │
       │ foo        Help string for foo.                                       │
       │ --help,-h  Display this message and exit.                             │
       │ --version  Display application version.                               │
       ╰───────────────────────────────────────────────────────────────────────╯

## Async

Cyclopts also works with async commands:

    import asyncio
    from cyclopts import App

    app = App()

    @app.command
    async def foo():
        await asyncio.sleep(10)

    app()

## Decorated Function Details

Cyclopts does not modify the decorated function in any way. The returned function is the exact same function being decorated and can be used exactly as if it were not decorated by Cyclopts.