Strings
Strings are immutable UTF-8 text values.
Shape supports these literal forms:
"..."simple string"""..."""triple-quoted multiline stringf"..."formatted string with interpolationf"""..."""formatted multiline stringf$"..."/f$"""..."""sigil-formatted strings (${expr})f#"..."/f#"""..."""sigil-formatted strings (#{expr})
Quick Examples
Section titled “Quick Examples”let a = "hello";let b = """ line 1 line 2 """;let c = f"name={name}";let d = f""" name={name} score={score} """;let e = f$"""{"name": ${user.name}}""";let f = f#"run #{command}";Simple Strings ("...")
Section titled “Simple Strings ("...")”let s = "plain text";let escaped = "quote: \" | newline: \n | tab: \t";Supported escape sequences:
| Escape | Character |
|---|---|
\" | Double quote |
\\ | Backslash |
\n | Newline |
\t | Tab |
\r | Carriage return |
\{ | Literal { (in f-strings) |
\} | Literal } (in f-strings) |
\$ | Literal $ (in f$-strings) |
\# | Literal # (in f#-strings) |
Only the escape sequences listed above are recognized. Unknown escape sequences
like \q or \a produce a compile-time error. Use \\ for a literal backslash.
Use {{ / }} only in formatted strings. In plain strings they are just characters.
Triple-Quoted Strings ("""...""")
Section titled “Triple-Quoted Strings ("""...""")”Triple strings are designed for readable multiline source with clean runtime text.
Dedent + edge-line trimming rules
Section titled “Dedent + edge-line trimming rules”When parsing """...""" (and f"""..."""), Shape does this:
- Normalizes line endings to
\n. - If the line immediately after opening
"""is whitespace-only, it is removed. - If the line immediately before closing
"""is whitespace-only, it is removed. - Computes common indentation across non-empty lines.
- Removes that common indentation from each non-empty line.
- Preserves relative indentation and internal blank lines.
Example:
let s = """ this is a multiline """;Runtime value:
thisisamultilineRelative indentation is preserved:
let readme = """ this is a multiline string. -it should indent -but remove the block spaces """;// Runtime value (no leading/trailing newline):// this is// a multiline// string.// -it should indent// -but remove the block spacesInline form (no newline after opening """):
let inline = """a quick multiline""";// => "a quick multiline"Inner quotes are fine as long as they don’t form """:
let quoted = """she said "hello" today""";// => she said "hello" todayEscape sequences in triple strings
Section titled “Escape sequences in triple strings”Triple strings do not process escape sequences. Backslash characters are kept as-is. This makes them ideal for templates, regex, and embedded code:
let pattern = """ (\d+)\n(\w+) """;// => "(\d+)\n(\w+)" (literal backslash-n, not a newline)If you need actual escape processing, use a simple string with \n:
let with_newline = "line1\nline2";// => line1// line2Formatted Strings
Section titled “Formatted Strings”Braces Mode (f"...", f"""...""")
Section titled “Braces Mode (f"...", f"""...""")”Formatted strings interpolate expressions inside {...} and produce a normal string.
let msg = f"name={name}, score={score}";let report = f""" user={user.name} total={total} """;Interpolation is a general language feature (not limited to print(...)).
let label = f"{name}:{category}";let key = f"acct/{account_id}/items/{name}";let payload = { text: f"item id={id}" };Escaping braces:
Use doubled braces for literal braces:
let s = f"literal braces: {{value}}";// => "literal braces: {value}"A lone } is invalid in formatted strings. Use }} for a literal close brace.
Sigil Modes (f$..., f#...)
Section titled “Sigil Modes (f$..., f#...)”Sigil modes are designed for templates that contain many literal {} pairs (JSON, config, codegen).
f$"..."uses${expr}interpolation.f#"..."uses#{expr}interpolation.- Plain
{and}are treated as normal text in sigil modes.
let json = f$"""{"name": ${user.name}, "id": ${user.id}}""";let shell = f#"echo #{path}";To render a literal opener sequence, double the sigil:
- In
f$, write$${for literal${. - In
f#, write##{for literal#{.
Expression behavior
Section titled “Expression behavior”- Each
{expr}is parsed as a Shape expression. - Empty expressions are invalid.
- Unclosed interpolation is invalid.
- Nested braces inside expressions are supported by expression parsing.
Typed format specs
Section titled “Typed format specs”Formatted interpolation uses typed specs after ::
fixed(N)for numeric precisiontable(...)for table rendering options
let p = 12.3456let s = f"p={p:fixed(2)}"// s == "p=12.35"Table format options are typed keys and enum-like values (not stringly settings):
let out = f"{rows:table(max_rows=20, align=right, precision=2, border=on)}"Supported table(...) keys:
| Key | Values | Default | Description |
|---|---|---|---|
max_rows | <int> | unlimited | Maximum rows to display |
align | left, center, right | left | Column alignment |
precision | <int> | full | Decimal places for numbers |
color | default, red, green, yellow, blue, magenta, cyan, white | default | Color hint for output |
border | on, off | on | Draw table borders |
Color example:
let gains = results.filter(|r| r.score > 0)let report = f"{gains:table(color=green, precision=2, border=off)}"Colors are renderer hints. The CLI maps them to ANSI terminal codes; other renderers (HTML, plain text) may map them differently or ignore them.
Formatting behavior
Section titled “Formatting behavior”Interpolated values use the same runtime formatting path as print(...) and trait-based display.
Unicode
Section titled “Unicode”Strings are Unicode-safe values.
let text = "Hello 世界 👋";let len = text.length;Methods
Section titled “Methods”Common string methods:
lengthsplit(sep)join(sep)(on vectors)contains(substr)substring(start, end?)toUpperCase()toLowerCase()trim()replace(old, new)
Snake_case aliases are also available for these methods:
to_upper_case()(alias fortoUpperCase())to_lower_case()(alias fortoLowerCase())trim_start()(alias fortrimStart())trim_end()(alias fortrimEnd())
Examples:
let csv = "Alice,Bob,Charlie";let items = csv.split(",");let normalized = " HELLO ".trim().toLowerCase();let sentence = ["hello", "shape"].join(" ");LSP Support
Section titled “LSP Support”Inside formatted-string interpolation (f"...{expr}..."):
- completion context is expression-aware (for example, property completion after
user.) - completion and hover are available for typed format specs after
: - semantic highlighting includes tokens for the expression portion
Performance Notes
Section titled “Performance Notes”- Strings are immutable.
- Prefer formatted strings over long
+chains for readability. - For very large loop-built text, collect fragments and
join(...)once.
Content Strings
Section titled “Content Strings”While f-strings produce plain strings with interpolation, content strings (c"...") produce structured ContentNode values that support styling and structured rendering.
Content strings use the same interpolation modes as f-strings:
c"Hello {name}"— brace interpolationc$"Hello ${name}"— dollar-sign interpolationc#"Hello #{name}"— hash interpolation
Content strings additionally support inline styling:
print(c"{price: fg(green), fixed(2)}") // green number with 2 decimalsprint(c"Alert: {msg: fg(red), bold}") // red bold textFor full documentation on content strings, styling, tables, and charts, see the Content chapter.