# Input Routing Strategies for Text Snippet Expansion in vorssaint-utils: Immediate vs After-Delimiter

> Discover vorssaint-utils input routing strategies: Immediate and After-Delimiter expansion. Learn how to control text snippet expansion timing for efficient text expansion.

- Repository: [vorssaint/vorssaint-utils](https://github.com/vorssaint/vorssaint-utils)
- Tags: internals
- Published: 2026-09-10

---

**vorssaint-utils employs two distinct input routing strategies—Immediate and After-Delimiter—defined by the `TextSnippet.Expansion` enum to control whether snippets expand instantly upon trigger completion or wait for a delimiter character.**

vorssaint-utils is an open-source Swift utility library that provides advanced text snippet expansion capabilities. The engine routes keystrokes through configurable **input routing strategies** that determine exactly when a typed trigger transforms into replacement text. These strategies are implemented in [`Sources/Vorssaint/Services/Snippets/TextSnippetSupport.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/Sources/Vorssaint/Services/Snippets/TextSnippetSupport.swift) and exposed through the `TextSnippet.Expansion` enum.

## Overview of the Two Input Routing Strategies

The expansion behavior is governed by the `TextSnippet.Expansion` enum, which offers two mutually exclusive routing paths:

- **Immediate** – Fires as soon as the last character of the trigger is typed, enabling instant replacements without additional keystrokes.
- **After-Delimiter** – Waits until the user types a delimiter character (`space`, `Tab`, `Return`, or newline) before expanding the snippet while preserving the delimiter in the output.

Both strategies use a rolling buffer mechanism limited to **64 characters** (`bufferLimit = 64`) and prioritize the **longest matching trigger** when multiple snippets share similar prefixes.

## Strategy 1: Immediate Expansion

When a snippet is configured with `.immediate` expansion, the engine monitors every keystroke through `TextSnippetSupport.bufferAppending`. As soon as the buffer ends with a complete trigger sequence, `TextSnippetSupport.match(buffer:expansion:snippets:)` injects the replacement text instantly.

This strategy is ideal for single-character shortcuts or rapid-fire replacements where you want the text to appear the moment you finish typing the trigger.

```swift
let instantSnippet = TextSnippet(
    name: "Instant Email",
    trigger: ";e",
    replacement: "example@domain.com",
    expansion: .immediate,
    enabled: true
)

```

In this example, typing `;e` immediately replaces it with `example@domain.com` without requiring a space or return key.

## Strategy 2: After-Delimiter Expansion

Snippets using `.afterDelimiter` expansion rely on the `TextSnippetSupport.delimiters` set to detect boundary characters. When a delimiter is typed, the engine checks if the preceding buffer content matches any enabled snippet with the `.afterDelimiter` strategy. Upon match, the replacement text is inserted **after** the delimiter, ensuring natural sentence flow.

This approach prevents accidental mid-word expansions and feels more natural for signature blocks or form templates that appear at the end of sentences.

```swift
let delayedSnippet = TextSnippet(
    name: "Signature",
    trigger: ";sig",
    replacement: "Best regards,\nYour Name",
    expansion: .afterDelimiter,
    enabled: true
)

```

Here, typing `;sig` followed by a space expands to `Best regards,\nYour Name ` while keeping the space you typed.

## Buffer Routing and Matching Logic

The routing engine in [`TextSnippetSupport.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/TextSnippetSupport.swift) handles the complexity of buffer management and trigger sanitization:

1. **Buffer Management** – Every keystroke updates a rolling buffer via `TextSnippetSupport.bufferAppending`, capped at 64 characters to prevent excessive memory usage.
2. **Trigger Sanitization** – Triggers are cleaned of whitespace and truncated to `maxTriggerLength = 40` characters using `TextSnippetSupport.sanitizedTrigger`.
3. **Longest Match Wins** – The `TextSnippetSupport.match` function scans enabled snippets and selects the longest trigger that matches the current buffer end.
4. **Delimiter Detection** – When a character exists in `TextSnippetSupport.delimiters`, the engine prioritizes checking `.afterDelimiter` matches before falling back to `.immediate` evaluation.

```swift
// Simplified routing logic from TextSnippetSupport.swift
let buffer = TextSnippetSupport.bufferAppending(currentBuffer, typed: key)

if TextSnippetSupport.delimiters.contains(key) {
    if let snippet = TextSnippetSupport.match(
        buffer: buffer,
        expansion: .afterDelimiter,
        snippets: allSnippets
    ) {
        // Insert replacement after the delimiter
    }
}

if let snippet = TextSnippetSupport.match(
    buffer: buffer,
    expansion: .immediate,
    snippets: allSnippets
) {
    // Insert replacement immediately
}

```

## User Interface and Configuration

Users configure these **input routing strategies** through two primary interface files:

- **[`Sources/Vorssaint/UI/Settings/TextSnippetsSettings.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/Sources/Vorssaint/UI/Settings/TextSnippetsSettings.swift)** – Provides the settings page where users toggle the snippet library and select the `expansion` mode for each entry.
- **[`Sources/Vorssaint/UI/SnippetLibraryView.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/Sources/Vorssaint/UI/SnippetLibraryView.swift)** – Displays the browsable snippet library, including visual indicators of whether a snippet uses Immediate or After-Delimiter routing.

## Summary

- vorssaint-utils implements **two input routing strategies**—Immediate and After-Delimiter—via the `TextSnippet.Expansion` enum.
- **Immediate expansion** fires instantly when the trigger is completed, managed by `TextSnippetSupport.match` with `.immediate` parameter.
- **After-Delimiter expansion** waits for `space`, `Tab`, `Return`, or newline from the `TextSnippetSupport.delimiters` set, preserving the delimiter after expansion.
- The engine maintains a **64-character rolling buffer** and prioritizes the **longest matching trigger** to resolve conflicts.
- Configuration occurs in [`TextSnippetsSettings.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/TextSnippetsSettings.swift) while the core logic resides in [`TextSnippetSupport.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/TextSnippetSupport.swift).

## Frequently Asked Questions

### What is the maximum trigger length supported in vorssaint-utils?

The engine enforces a `maxTriggerLength = 40` characters limit through `TextSnippetSupport.sanitizedTrigger`, automatically truncating longer triggers to prevent buffer overflow and ensure performance.

### How does vorssaint-utils resolve conflicts when multiple triggers match?

The matching algorithm in `TextSnippetSupport.match` implements a "longest trigger wins" policy. If you have both `;email` and `;email2`, typing `;email2` will expand the latter because the engine selects the longest matching sequence from the enabled snippets list.

### Can I customize which characters act as delimiters for After-Delimiter expansion?

The delimiter set is defined as a constant in `TextSnippetSupport.delimiters` and includes `space`, `Tab`, `Return`, and newline characters. To modify these boundaries, you would need to edit the source in [`Sources/Vorssaint/Services/Snippets/TextSnippetSupport.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/Sources/Vorssaint/Services/Snippets/TextSnippetSupport.swift) and rebuild the project.

### Does After-Delimiter mode consume the delimiter character?

No, the delimiter is preserved. When the engine detects a delimiter match, it injects the replacement text after the delimiter character, allowing you to continue typing naturally without losing the whitespace or line break you intended to insert.