
# `commands`

Client commands typed in chat behind the client prefix (`.` by default). A scripted command
behaves like a built-in one: it appears in `.help`, completes in the chat box and shows its
usage hint while you type.

```lua
commands.register({
    name = "ping",
    description = "Prints your latency",
    execute = function(ctx)
        ctx:info(server.ping() .. " ms")
    end,
})
```

| Function | Does |
|----------|------|
| `commands.register(desc)` | Registers a command and returns a handle |
| `commands.prefix()` | The prefix in effect, e.g. `"."` |
| `commands.run(line)` | Runs a client command as if typed, with or without the prefix |

Commands aimed at the **server** go through [`chat.command`](chat.md) instead.

## The descriptor

| Field | Meaning |
|-------|---------|
| `name` | Command name, no prefix and no spaces. Required |
| `execute` | `function(ctx, args)`. Required |
| `aliases` | Extra names it answers to |
| `description` | The line `.help` lists it with. Defaults to the script file name |
| `usage` | Detail lines shown by `.help <name>` |
| `params` | Argument hints shown in the chat box while typing |
| `hidden` | Keeps it out of `.help` and completion |
| `complete` | `function(ctx, args) -> string[]` |

Registering a name or alias another command already owns raises an error, so a script cannot
shadow `.help` or another script's command.

## Arguments

`args` holds the words after the command name, with quoted sections kept together
(`.warp "spawn area"` is one argument). Everything arrives as a string; use `tonumber` when
you need a number.

```lua
commands.register({
    name = "warp",
    params = {
        { name = "name" },
        { name = "distance", type = "number", optional = true },
    },
    execute = function(ctx, args)
        if #args == 0 then
            ctx:error("usage: " .. ctx.prefix .. "warp <name>")
            return
        end
        ctx:success(("warping to %s"):format(args[1]))
    end,
})
```

`params` only shapes the hint the chat box shows (`<name: string> [distance: number]`).
`type` is a label, not a parser, so validate values yourself.

## Replying

`ctx` carries the prefix in effect, the alias the player typed (`ctx.label`) and the raw line
after the prefix (`ctx.raw`), plus four output channels:

| Call | Prints |
|------|--------|
| `ctx:respond(msg)` | A [text component](text.md) or string, as an indented line |
| `ctx:info(text)` | Grey `kawaki »` line |
| `ctx:success(text)` | Green `kawaki »` line |
| `ctx:error(text)` | Red `kawaki »` line |

## Completion

`complete` runs on every keystroke with the arguments typed so far. The last one is the word
being completed, empty right after a space, so `#args` is its position. Return every
candidate and the client filters by what is already typed: candidates containing it anywhere
are kept, those starting with it listed first.

```lua
commands.register({
    name = "tp",
    params = { { name = "player" } },
    execute = function(ctx, args)
        chat.command("tp " .. (args[1] or ""))
    end,
    complete = function(ctx, args)
        if #args ~= 1 then return {} end
        local names = {}
        for _, entry in ipairs(server.tablist.entries() or {}) do
            names[#names + 1] = entry.name
        end
        return names
    end,
})
```

## Lifetime

A command belongs to the script that registered it: saving the file re-registers it, deleting
the file removes it. To drop one earlier, keep the handle:

```lua
local cmd = commands.register({
    name = "debug",
    hidden = true,
    execute = function(ctx) ctx:info("still here") end,
})

cmd:unregister()
```

`cmd:usage()` returns the usage line with the current prefix, useful in a bad-argument reply.

Errors from `execute` land in chat with the `lua »` prefix like any script error. An error
inside `complete` is reported once, then that completer goes quiet.
