> ## Documentation Index
> Fetch the complete documentation index at: https://docs.erlc.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Lists and Text Manipulation Blocks in erlc.dev Studio

> Work with lists and text values in your automations: create and iterate lists, join and split strings, and build reusable custom blocks.

Lists and text manipulation blocks give your automations the ability to work with collections of values and build dynamic string output. Whether you are iterating over a roster of player IDs, joining message parts together, or splitting a command argument string, these blocks cover every common data-wrangling task — without any coding required.

***

## List Blocks

A list is an ordered collection of values that you can build, modify, search, and iterate over inside a single automation run. Lists created with these blocks are ephemeral — they last only for the duration of the run. For persistence across runs, see [Database](/logic/database).

### Creating and Modifying Lists

<CardGroup cols={2}>
  <Card title="erlc_list_empty" icon="rectangle-list">
    Produces a new, empty list with no items. Use it as the starting point before pushing values with `erlc_list_add`.
  </Card>

  <Card title="erlc_list_create" icon="list">
    Creates a list with up to three pre-set items. Connect value blocks to the `ITEM0`, `ITEM1`, and `ITEM2` inputs.
  </Card>

  <Card title="erlc_list_add" icon="circle-plus">
    Appends the value in the `VALUE` input to the list variable named in the `VARIABLE` field. This is a statement block — it mutates the variable in place.
  </Card>

  <Card title="erlc_list_remove" icon="circle-minus">
    Removes the first occurrence of the value in the `VALUE` input from the list variable named in the `VARIABLE` field.
  </Card>
</CardGroup>

### Querying Lists

<CardGroup cols={2}>
  <Card title="erlc_list_contains" icon="magnifying-glass">
    Returns `true` if the `LIST` input contains the `VALUE` input. Returns `false` otherwise.
  </Card>

  <Card title="erlc_list_length" icon="hashtag">
    Returns the number of items in the `LIST` input.
  </Card>

  <Card title="erlc_list_item" icon="hand-pointer">
    Returns the item at position `INDEX` in the `LIST` input. Indices are 1-based.
  </Card>

  <Card title="erlc_list_first" icon="arrow-left-to-line">
    Returns the first item in the `LIST` input.
  </Card>

  <Card title="erlc_list_last" icon="arrow-right-to-line">
    Returns the last item in the `LIST` input.
  </Card>

  <Card title="erlc_list_random" icon="dice">
    Returns a randomly selected item from the `LIST` input.
  </Card>

  <Card title="erlc_list_index_of" icon="location-crosshairs">
    Returns the 1-based position of `VALUE` within `LIST`, or `0` if the value is not found.
  </Card>
</CardGroup>

### Transforming Lists

<CardGroup cols={2}>
  <Card title="erlc_list_join" icon="link">
    Joins all items in the `LIST` input into a single string, separated by the `SEPARATOR` input.
  </Card>

  <Card title="erlc_list_sort" icon="arrow-down-a-z">
    Returns a new sorted copy of the `LIST` input.
  </Card>

  <Card title="erlc_list_reverse" icon="arrow-right-arrow-left">
    Returns a new reversed copy of the `LIST` input.
  </Card>

  <Card title="erlc_list_unique" icon="filter">
    Returns a new copy of the `LIST` input with duplicate values removed.
  </Card>

  <Card title="erlc_list_slice" icon="scissors">
    Returns a sub-list from the `LIST` input beginning at position `START` and ending at position `END` (inclusive, 1-based).
  </Card>

  <Card title="erlc_for_each" icon="rotate">
    Iterates over every item in the `LIST` input. Each item is stored in the variable named by the `VARIABLE` field, and the `DO` body runs once per item.
  </Card>
</CardGroup>

***

## Saved List Blocks

Saved lists are persistent named lists stored on the server. Unlike in-run lists, saved lists survive between automation runs and are shared across all your automations. They are read-only from these blocks — use the [Database blocks](/logic/database) to write saved list data.

<CardGroup cols={2}>
  <Card title="erlc_saved_list_contains" icon="database">
    Returns `true` if the saved list named in the `LIST` field contains the value provided in the `VALUE` input.
  </Card>

  <Card title="erlc_saved_list_item" icon="database">
    Returns the item at the 1-based position provided in the `INDEX` input from the saved list named in the `LIST` field.
  </Card>
</CardGroup>

<Note>
  Saved lists use the same underlying named-set storage as the Database blocks. The `LIST` field value corresponds to a set name. Read [Persistent Database Storage](/logic/database) to understand how sets and positions work.
</Note>

***

## Text Blocks

Text blocks let you produce, combine, inspect, and transform string values throughout your automations.

### Producing Text

| Block | Input / Field | Output |
| - | - | - |
| `erlc_text_value` | Field `VALUE` | Text literal |
| `text` (Blockly native) | Field `TEXT` | Text literal |

### Combining Text

<CardGroup cols={2}>
  <Card title="erlc_join_values" icon="merge">
    Concatenates the `LEFT` and `RIGHT` inputs into a single string. Chain multiple blocks to join more than two values.
  </Card>

  <Card title="erlc_text_split" icon="scissors">
    Splits the `TEXT` input into a list using the `SEPARATOR` input as the delimiter. Returns a list of strings.
  </Card>
</CardGroup>

### JSON Example — Joining Two Text Values

```json theme={null}
{
  "type": "erlc_join_values",
  "id": "block_join_1",
  "inputs": {
    "LEFT": {
      "block": {
        "type": "erlc_text_value",
        "id": "block_text_left",
        "fields": { "VALUE": "Welcome, " }
      }
    },
    "RIGHT": {
      "block": {
        "type": "erlc_text_value",
        "id": "block_text_right",
        "fields": { "VALUE": "Officer Johnson!" }
      }
    }
  }
}
```

### JSON Example — Splitting a String by a Separator

```json theme={null}
{
  "type": "erlc_text_split",
  "id": "block_split_1",
  "inputs": {
    "TEXT": {
      "block": {
        "type": "erlc_text_value",
        "id": "block_text_src",
        "fields": { "VALUE": "alpha,bravo,charlie" }
      }
    },
    "SEPARATOR": {
      "block": {
        "type": "erlc_text_value",
        "id": "block_text_sep",
        "fields": { "VALUE": "," }
      }
    }
  }
}
```

### Inspecting Text

| Block | Inputs | Output |
| - | - | - |
| `erlc_text_contains` | `TEXT`, `SEARCH` | `true` if `SEARCH` is a substring of `TEXT` |
| `erlc_text_starts` | `TEXT`, `SEARCH` | `true` if `TEXT` starts with `SEARCH` |
| `erlc_text_ends` | `TEXT`, `SEARCH` | `true` if `TEXT` ends with `SEARCH` |
| `erlc_text_length` | `TEXT` | Number of characters |
| `erlc_text_word_count` | `TEXT` | Number of whitespace-delimited words |
| `text_charAt` | `VALUE`, `AT` | Character at position; `WHERE` field: `FROM_START`, `FROM_END`, `FIRST`, `LAST`, `RANDOM` |

### Transforming Text

| Block | Inputs | Output |
| - | - | - |
| `erlc_text_lower` | `TEXT` | Lowercase string |
| `erlc_text_upper` | `TEXT` | Uppercase string |
| `erlc_text_trim` | `TEXT` | String with leading/trailing whitespace removed |
| `erlc_text_replace` | `OLD`, `NEW`, `TEXT` | String with all occurrences of `OLD` replaced by `NEW` |
| `erlc_text_substring` | `START`, `END`, `TEXT` | Sub-string from position `START` to `END` (1-based, inclusive) |
| `erlc_text_url_encode` | `TEXT` | URL-encoded version of the string |
| `erlc_discord_escape` | `TEXT` | Markdown-escaped string safe for Discord messages |

<Tip>
  Use `erlc_discord_escape` whenever you are inserting player-supplied text (such as a username or in-game message) into a Discord message. This prevents special Markdown characters like `*`, `_`, and \`\`\` from accidentally formatting your output.
</Tip>

***

## Custom Reusable Blocks

Custom block definitions let you encapsulate a sequence of blocks and call it by name from anywhere in your workspace — similar to a function or subroutine.

<CardGroup cols={3}>
  <Card title="erlc_custom_block_definition" icon="puzzle-piece">
    Defines a reusable block. Connect a text value to `TITLE` to name it, and build the body in the `BODY` statement input. Use the `EDIT` field to manage the definition.
  </Card>

  <Card title="erlc_custom_block_call" icon="play">
    Calls the custom block whose name matches the value connected to the `TITLE` input. Execution jumps into the definition body and returns when it finishes.
  </Card>

  <Card title="erlc_custom_block_argument" icon="arrow-right-to-bracket">
    Reads an argument passed to the currently executing custom block. Connect a text value to the `NAME` input specifying which argument to retrieve.
  </Card>
</CardGroup>

<Info>
  Custom block definitions are evaluated at the time they are called, not when they are defined. This means you can define a block anywhere on your canvas and call it from any other automation stack.
</Info>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.