# UI

This chapter documents the UI styling helpers and spinner API.

**Availability:** REPL + Script

## `gsh.ui.styles`

Text styling helpers for colored and formatted output.

### Available Styles

| Method                        | Description               |
| ----------------------------- | ------------------------- |
| `gsh.ui.styles.primary(text)` | Primary color (yellow)    |
| `gsh.ui.styles.success(text)` | Success indicator (green) |
| `gsh.ui.styles.error(text)`   | Error indicator (red)     |
| `gsh.ui.styles.dim(text)`     | Dimmed/secondary text     |
| `gsh.ui.styles.bold(text)`    | Bold text                 |
| `gsh.ui.styles.italic(text)`  | Italic text               |

### Basic Usage

```gsh
print(gsh.ui.styles.primary("Welcome to gsh!"))
print(gsh.ui.styles.success("✓ Operation completed"))
print(gsh.ui.styles.error("✗ Something went wrong"))
print(gsh.ui.styles.dim("(secondary information)"))
```

### Combining Styles

Nest style calls to combine effects:

```gsh
# Bold and primary color
message = gsh.ui.styles.bold(gsh.ui.styles.primary("Important"))
print(message)

# Dim and italic
note = gsh.ui.styles.dim(gsh.ui.styles.italic("Note: this is optional"))
print(note)
```

### Common Patterns

**Status Messages:**

```gsh
tool showStatus(success, message) {
    if (success) {
        print(gsh.ui.styles.success("✓ " + message))
    } else {
        print(gsh.ui.styles.error("✗ " + message))
    }
}
```

**Headers:**

```gsh
tool printHeader(text) {
    print(gsh.ui.styles.bold(gsh.ui.styles.primary(text)))
    print(gsh.ui.styles.dim("─".repeat(text.length())))
}
```

**Inline Emphasis:**

```gsh
print("The answer is " + gsh.ui.styles.bold("42"))
print("See " + gsh.ui.styles.primary("docs/README.md") + " for details")
```

## `gsh.ui.spinner`

Loading spinner API for long-running operations.

### Methods

| Method                               | Description            |
| ------------------------------------ | ---------------------- |
| `gsh.ui.spinner.start(message, id)`  | Start a spinner        |
| `gsh.ui.spinner.stop(id)`            | Stop a spinner         |
| `gsh.ui.spinner.update(id, message)` | Update spinner message |

### Basic Usage

```gsh
gsh.ui.spinner.start("Loading...", "my-spinner")
# ... do work ...
gsh.ui.spinner.stop("my-spinner")
```

### Complete Example

```gsh
tool processFiles() {
    gsh.ui.spinner.start("Processing files...", "file-spinner")

    # Simulate work
    exec("sleep 2")

    gsh.ui.spinner.stop("file-spinner")
    print(gsh.ui.styles.success("Done!"))
}

processFiles()
```

### Updating Messages

Update the spinner message without stopping it:

```gsh
tool multiStepProcess() {
    gsh.ui.spinner.start("Starting...", "process")

    exec("sleep 1")
    gsh.ui.spinner.update("process", "Step 1/3: Downloading...")

    exec("sleep 1")
    gsh.ui.spinner.update("process", "Step 2/3: Processing...")

    exec("sleep 1")
    gsh.ui.spinner.update("process", "Step 3/3: Finalizing...")

    exec("sleep 1")
    gsh.ui.spinner.stop("process")
    print("Complete!")
}
```

### Multiple Spinners

Use different IDs to manage multiple spinners:

```gsh
tool parallelTasks() {
    gsh.ui.spinner.start("Downloading...", "download")
    gsh.ui.spinner.start("Processing...", "process")

    exec("sleep 1")
    gsh.ui.spinner.stop("download")
    print("Download complete")

    exec("sleep 1")
    gsh.ui.spinner.stop("process")
    print("Processing complete")
}
```

> **Note:** gsh renders one spinner at a time, automatically managing which to display based on status and recency.

## Best Practices

### Styling

1. **Don't overuse color** - Too much makes output hard to read
2. **Be consistent** - Use the same colors for the same types of information
3. **Test in different terminals** - Colors may render differently
4. **Don't rely on color alone** - Include text/symbols for meaning

### Spinners

1. **Use for long operations** - Only show spinners if operation takes > 500ms
2. **Give meaningful messages** - Help users understand what's happening
3. **Always stop spinners** - Use try/catch to ensure cleanup
4. **Use unique IDs** - Avoid ID collisions between spinners

## Accessibility

1. **Include text with symbols** - Don't rely on color alone (e.g., "✓ Success" not just green text)
2. **Avoid red/green only** - Consider colorblind users
3. **Use bold/italic as alternatives** - When color isn't essential
4. **Maintain high contrast** - Ensure styled text remains readable

---

**← Back to [SDK Reference](README.md)**
