Safe Text
Before this: Taking Text Apart, Rich Text
Next steps: Chat Commands
Parts that use this: Obstacle Course, Whack-a-Light, Card Table
A player picks their own display name, and a name can contain anything, including tags. When a circuit shows that name, the game reads those tags as formatting. This lesson shows the problem, then fixes it with the two helpers in the lessons’ starter library.
Contents
switch Enabled -> chip safe
chip text -> decal Text
Code
import { escape } from "sanitize"
const TRICKY = '<size="96"><color="ff0000">Sam'
@left in safe: bool
let shown = if safe then escape(TRICKY) else TRICKY
@right out text = "Guest: ${shown}<br>Welcome!"
TRICKY stands in for a player whose display name is
<size="96"><color="ff0000">Sam. The switch picks whether the sign shows it
as it is, or after escape.
escape replaces every < with <. That is the standard way to write a
< that is not the start of a tag: the game shows it as a plain <, so the
tag appears as text instead of being obeyed.
With the switch off, what does the word Welcome! look like? With it on?
Run
- Compile the chip and paste it in-game. Place a Switch and a brick with a Text Decal.
- Wire the Switch’s Enabled to
safe, andtextto the Text Decal’s Text. - With the switch off, the name’s tags take over:
Samand everything after it,Welcome!included, is huge and red. - Flip the switch on. The sign shows the name exactly as it was typed, tags
and all, and
Welcome!looks normal.
Under the Hood
Open the chip. escape added one Replace in String gate, which searches
for < and puts < in its place. A Select chooses between the
escaped and the raw text, and a Format String builds the sign.
The library is a file named sanitize.ws, and
import { escape } from "sanitize" brings in one helper from it. This is the
whole file:
// Escape markup in a display name before showing it. A `mod`, so each use is a single gate.
mod escape(text: string) -> string {
return text.Replace("<", "<")
}
// Clean free-form player input: trim, cap the length, then escape.
// Capping first keeps the cut from landing inside an `<`.
fn sanitize(raw: string, maxLen: int = 24) -> string {
return raw.Trim().Substring(0, maxLen).Replace("<", "<")
}
escapeis amod. A mod is copied into every place that uses it, so eachescape(...)becomes one Replace in String gate right there.sanitizeis afn. A function is built once, on its own small board, and each place that uses it gets a Function Call gate that runs it.maxLen: int = 24gives the second input a default, sosanitize(name)meanssanitize(name, 24).
Use it: a guest sign
sanitize is for text that must also fit a space. It trims spaces from the
ends, keeps at most maxLen characters, then escapes what is left. This
sign keeps the last guest’s name short enough for a narrow sign, and greets
the guest by their full name in chat:
import { escape, sanitize } from "sanitize"
const SIGN_WIDTH = 12
@left in room: zone
var guest: string = "Nobody yet"
@right out text = '<size="32">Last guest:<br><b>${guest.Value}</>'
on ZoneEntered(zone = room) -> (character) {
let name = character.GetDisplayName()
guest = sanitize(name, SIGN_WIDTH)
character.ShowChatMessage("Welcome, ${escape(name)}!")
}
Wire an Attached Zone’s Zone Ref to room and text to a Text
Decal’s Text, then walk into the zone.
The cap comes before the escape because escaping turns one < into four
characters. If the cut came after, it could land in the middle of an <
and leave a broken piece such as &l at the end of the sign. Cutting first
means every < that survives the cut is escaped whole. The cost is that the
result can be longer than maxLen when the name contains <.
Which one to use:
escape(text)when the whole text should be shown, such as a name in a chat line.sanitize(text, maxLen)when the text must fit, such as a sign, a label or one row of a list.
Modify
- Change
SIGN_WIDTHto 4 and walk in again. Only the start of your name fits. - Run your sign through the switch test: replace
namewithTRICKYfrom the first example in thesanitizecall, and check that the sign shows the tags as text. - Greet the guest in chat by the first word of their name only, with
Split(" ")from Taking Text Apart. Split the raw name first, then escape the word you show: escaping is always the last step before text is displayed.
Make
Make a sign that lists the last three guests, one per line, newest first.
Keep three vars, move each one down a line when someone new walks in, and
sanitize every name before it is stored.
zone "Zone Ref" -> chip room
chip text -> decal Text
Good to Know
- Every place that shows text reads tags, chat included, so a name in a chat line can restyle that line too. Escape any text a player chose before you show it, wherever it goes.
escapeonly changes<. Text without a<comes out unchanged.
Next: Matching Text.