rune.trigger
Triggers match server text and run actions. For a task-oriented introduction, see Triggers.
Quick reference
Section titled “Quick reference”rune.trigger.exact(line, action, opts?) -- whole line matches exactlyrune.trigger.starts(prefix, action, opts?) -- line starts with prefixrune.trigger.contains(text, action, opts?) -- line contains textrune.trigger.regex(pattern, action, opts?) -- Go regexp, with capturesAll constructors return a handle and accept
the common options plus gag, raw, on, and
span.
Triggers match complete lines by default. Set on = "prompt" to match
partial lines and GA/EOR prompts instead.
Matching
Section titled “Matching”| Mode | Matches when | Captures |
|---|---|---|
exact |
the whole clean line equals line |
none |
starts |
the line begins with prefix |
none |
contains |
the line contains text |
none |
regex |
the Go regexp matches | capture groups |
Matching runs against the clean (ANSI-stripped) line unless raw = true.
Triggers run in priority order (lower first); a rewrite from one
trigger is what later triggers match against.
rune.trigger.regex
Section titled “rune.trigger.regex”rune.trigger.regex(pattern, action, opts?) -> handlepattern(string) — Go regexp (RE2, not Lua patterns). Validated at registration; a bad pattern raises immediately.action(string | function | nil) — a command string (%1…%nsubstituted from captures), orfunction(matches, ctx).nilis allowed withgag = true.opts(table, optional) — common options plus the options below.
rune.trigger.regex("^(\\w+) tells you: follow me$", function(m) rune.send("follow " .. m[1])end)Actions and return values
Section titled “Actions and return values”A string action is sent as a command. A function action receives
(matches, ctx) — ctx.line is the line object
with :raw() and :clean(). The return value controls the line:
| Return | Effect |
|---|---|
nil |
Line passes through unchanged |
| string | Line is rewritten; later triggers see the new text |
false |
Line is gagged (hidden) |
This table does not apply to multi-line triggers: their actions fire after the collected lines have been displayed, so return values are ignored.
Options
Section titled “Options”Beyond the common options:
| Option | Type | Default | Description |
|---|---|---|---|
gag |
bool | false | Hide the matching line (equivalent to returning false) |
raw |
bool | false | Match against the raw line, ANSI codes included |
on |
string | "output" |
"output" for complete lines or "prompt" for partial lines and GA/EOR prompts |
span |
table | — | Collect a multi-line output message; cannot be combined with on = "prompt" |
Prompt triggers
Section titled “Prompt triggers”Most triggers use on = "output" and run only after a complete line arrives.
Some MUDs send prompts without a newline, so Rune also exposes the partial
line through on = "prompt":
rune.trigger.contains("Username:", "example-user", { on = "prompt", once = true })Each trigger observes exactly one of the two streams:
| Setting | Text it observes |
|---|---|
on = "output" |
Complete server lines. This is the default. |
on = "prompt" |
Partial lines and prompts confirmed by Telnet GA/EOR. |
The same text can pass through both streams over its lifetime. Rune does not
wait on a timer or use a pattern to decide whether a partial line is a
prompt: prompt triggers observe it as it grows (observations can repeat), and
if CR/LF later completes it, the completed line runs through output triggers.
A prompt confirmed by GA/EOR stays with the prompt triggers, as does a
partial line finished by a submission or an accepted send: its latest
observation is committed without ever reaching output triggers. Actions
should be safe to repeat; use once for one-shot work such as login.
Prompt triggers can rewrite or gag the displayed prompt; rewrites chain, so
later prompt triggers match the rewritten text. They cannot use span, and
partial-line observations never alter an open span. Function actions receive
ctx.confirmed, which is true when GA/EOR confirmed the prompt.
Rune finishes the partial line before processing user-submitted input. A game command sent by Lua finishes it only when the connection accepts the send. Failed sends and protocol traffic such as GMCP leave it open. If the partial text was part of an ordinary fragmented line, finishing it commits the visible prefix and later data starts a new line.
Multi-line triggers
Section titled “Multi-line triggers”Server output often spans lines — wrapped chat, score sheets, who
lists, quest logs. A span collects the block: the trigger’s pattern
matches the first line as usual, following lines are appended, and
the action fires once with the whole thing.
-- Terminator-delimited: a wrapped message ending in a color resetrune.trigger.regex("^(\\w+) tells you: (.+)$", function(matches, ctx) forward("[Tell] " .. matches[1] .. ": " .. ctx.text)end, { name = "tells", span = { to = "\\x1b\\[0?m\\s*$", raw = true, max = 8 } })
-- Fixed-count: a block that is always the same number of linesrune.trigger.starts("You have scored", parse_score, { span = { max = 4 } })| Field | Type | Default | Description |
|---|---|---|---|
to |
string | — | Regex for the line that ends the span, inclusive. Validated at registration. Optional: without it the span always runs to max. |
raw |
bool | false | Match to against the raw line — needed when the terminator is an escape code (like a trailing color reset) that stripping removes. Independent of the trigger-level raw, which governs pattern matching. |
max |
number | 8 | Flush after this many lines, first line included. |
In the action, ctx.text is the message text — the pattern’s last
capture (or the whole clean line for the literal modes), with each
continuation line appended, space-joined. ctx.lines holds the
collected line objects, first line
first. matches are the first line’s captures, as usual; a string
action substitutes them and is sent once, at completion.
Behavior:
- Lines display as they arrive, so the action’s return value is
ignored — a span cannot rewrite.
gag = trueis the exception: it hides every collected line as it arrives, first line included. - Collected lines still run through other triggers and hooks. A span sees each line as this trigger would have — including rewrites from higher-priority triggers.
- Partial-line prompt observations leave spans open. A confirmed prompt closes them before prompt hooks and triggers run.
- Finishing the partial line through submission or an accepted game send also closes spans, without running prompt triggers again. Empty prompt boundaries, failed sends, protocol traffic, and sends with no active prompt overlay do not close spans. A prompt a handler gagged to empty text still counts as active, so a later send closes spans even though nothing is visible.
- Connect and disconnect discard spans without firing.
/reloadis itself a submission, so it first finishes the partial line like any other submission, then discards any spans still owned by the old Lua VM. - One open span per trigger: if the pattern matches again mid-span, the previous message fires and a new span starts.
- If the first line also matches
to, the message is complete immediately — single-line messages work with no special casing. onceremoves the trigger after its first completed span.
Managing
Section titled “Managing”Standard registry management applies:
rune.trigger.get/enable/disable/remove(name), .list(), .count(),
.clear(), .remove_group(group) — see
Registries. /triggers lists everything;
/test <line> feeds a fake complete line through the output-trigger
pipeline. It does not exercise prompt triggers.
Related: Triggers guide · rune.alias · rune.regex · rune.hooks