
# Text

Constructors return a text handle. Styling methods mutate it and return it, so calls chain:

```lua
local msg = text.empty()
    :append(text.literal("[wiki] "):color("gold"))
    :append(text.literal("diamond ore"):color(0x55FFFF):underlined()
        :open_url("https://minecraft.wiki/w/Diamond_Ore")
        :hover_text("Click to open the wiki"))
chat.print(msg)
```

Text handles are snapshots, unlike the live handles elsewhere in the API. Wrapping game text
(`e:display_name()`, `item:tooltip()`) copies it, and appending one handle to another appends
a copy, so later edits never reach what you already built or printed.

`tostring(t)` gives the plain string, and `..` joins handles and strings into a new component.

## Constructors

| Function | Builds |
|----------|--------|
| `text.literal(s)` | Fixed text |
| `text.empty()` | Empty root, so a root style cannot bleed into the children |
| `text.translatable(key, ...)` | Translatable key; extra args fill `%s` (strings, numbers, booleans, handles) |
| `text.translatable_fallback(key, fb, ...)` | Same, showing `fb` when the key is missing |
| `text.keybind(key)` | The key bound to an action, e.g. `text.keybind("key.jump")` |
| `text.legacy(s[, alt_char])` | Parses `§` codes; pass `"&"` to accept `&` codes too |
| `text.from_json(json)` | JSON text format, raises on invalid input |

## Styling

| Method | Effect |
|--------|--------|
| `:append(text_or_string)` | Appends a child component |
| `:color(c)` | `0xRRGGBB`, a name like `"red"`, or `"#RRGGBB"` |
| `:shadow_color(argb)` | Shadow color, `0xAARRGGBB` |
| `:bold(b?)`, `:italic(b?)`, `:underlined(b?)` | No argument means `true` |
| `:strikethrough(b?)`, `:obfuscated(b?)` | `obfuscated` is `§k` |
| `:font(id)` | Font, e.g. `"minecraft:alt"` |
| `:insertion(s)` | Text inserted into chat on shift-click |
| `:formatting(...)` | Formattings by name: `"red"`, `"bold"`, `"underline"`, `"reset"`, … |

## Click and hover

| Method | On click or hover |
|--------|-------------------|
| `:run_command(cmd)` | Runs a command, leading `/` included |
| `:suggest_command(cmd)` | Puts it in the chat box |
| `:open_url(url)` | Opens a URL |
| `:copy_to_clipboard(s)` | Copies a string |
| `:change_page(n)` | Book page, meaningful only inside books |
| `:hover_text(text_or_str)` | Text tooltip |
| `:hover_item(item)` | [Item](item.md) tooltip |
| `:hover_entity(entity)` | [Entity](entity.md) tooltip |

Click and hover work only where the game renders real chat lines (`chat.print`, server chat).
The HUD canvas draws plain strings, so use `:string()` there.

## Reading

| Method | Returns |
|--------|---------|
| `:string()` | Plain string of the whole tree |
| `:truncated(n)` | Plain string capped at `n` characters |
| `:kind()` | `"literal"`, `"translatable"`, `"keybind"` or `"other"` |
| `:literal()` | Own literal string without siblings, or `nil` |
| `:key()` | Translation key or keybind name, or `nil` |
| `:siblings()` | Child snapshots |
| `:style()` | `{color, color_name, shadow_color, bold, italic, underlined, strikethrough, obfuscated, insertion, font, click, hover}` |
| `:copy()` | Deep copy |
| `:to_json()` | JSON text format, or `nil` on failure |

Game text arrives as snapshots too: `e:name_text()`, `e:display_name()`, `e:custom_name()`,
`item:name_text()`, `item:formatted_name()`, `item:hover_text()`, `item:tooltip()`, and
`name_text` on effect entries.

## Display

A handle (or a plain string) goes to [`chat.print`](chat.md), [`hud.actionbar`](chat.md#hud),
`hud.title` and `hud.subtitle`. Server chat (`chat.say`, `chat.command`) takes plain strings
only.

```lua
local held = player:held_item()
for _, line in ipairs(held:tooltip()) do
    print(line:string())
end

hud.actionbar(text.legacy("&6gold &r/ &b&laqua bold", "&"))
```
