term
Terminal interaction: capability probes, an interactive picker, and styled output. Renders to stderr; pick raises rather than hanging when there is no terminal.
Naming convention: import the module under its bare name (
import "term"), reach members with a backslash, and call methods incamelCase:term\someMethod.
The examples below are reference-only. term performs real IO (filesystem, process, network, or environment access) that the in-browser playground's sandbox cannot provide, so it is not registered there and its examples have no Run button. Pure-compute modules such as strings and json run their examples live in the page.
Methods
isInteractive
Report whether this run can prompt at all: both standard input and standard error are terminals. Branch on it before calling pick - in CI, behind a pipe, or under a daemon this is false, and pick would raise. It is the one call that makes an interactive step safe to add to a target that also runs unattended.
Signature: term\isInteractive() -> bool - source
Returns: bool
wantsColor
Report whether styled output should be emitted: standard error is a terminal and the environment does not ask for plain text (NO_COLOR, TERM=dumb). colorize already consults this, so a caller needs it only to make a wider rendering choice - a box-drawing table versus a plain one.
Signature: term\wantsColor() -> bool - source
Returns: bool
size
Return the terminal's {width, height} in character cells. Both are 0 when there is no terminal to measure - piped output, no controlling terminal - so check width rather than expecting a raise. Use it to wrap or truncate output to the reader's actual window instead of assuming 80 columns.
Signature: term\size() -> TermSize - source
Returns: map[string]any
Example:
import "std";
import "term";
// width is 0 when there is no terminal to measure, so check it rather than
// catching an error.
final size = term\size();
final width = if (size.width > 0) size.width else 80;
std\print("wrapping to {width} columns");
colorize
Wrap s in the given style and close it again. Returns s UNCHANGED when the output is not a terminal or the environment asked for plain text, so a magusfile never has to guard the call and escape codes cannot leak into a CI log. A style of none is also pass-through, which lets a conditionally-computed style be passed without branching.
Signature: term\colorize(s, style) -> string - source
| Parameter | Type | Optional | Description |
|---|---|---|---|
s |
string |
||
style |
string |
Returns: string
pick
Prompt the reader to choose one of items and return its index. Type to filter (matching every whitespace-separated token), arrow keys or Ctrl-N/Ctrl-P to move, Enter to choose. RAISES when there is no terminal to prompt on - guard with is_interactive - and raises when the reader aborts with ESC, Ctrl-C or Ctrl-D, so a cancel ends the run rather than quietly returning a choice nobody made. Renders to stderr.
Signature: term\pick(items, [prompt], [initial_filter], [initial], [max_rows]) -> int - source
| Parameter | Type | Optional | Description |
|---|---|---|---|
items |
[]string |
||
prompt |
string |
yes | |
initial_filter |
string |
yes | |
initial |
int |
yes | |
max_rows |
int |
yes |
Returns: int
Example:
import "std";
import "term";
// pick RAISES when there is no terminal, so an interactive step that also has to
// run unattended guards on isInteractive and declares its own default. It raises
// again when the reader aborts with ESC or Ctrl-C, which is why the call is
// caught rather than merely guarded: a cancel is not a choice.
final projects = ["console", "docs", "libs/gopherbuzz"];
fun choose() > str {
if (!term\isInteractive()) {
return projects[0];
}
try {
return projects[term\pick(projects, prompt: "project")];
} catch (e) {
return projects[0];
}
}
std\print(term\colorize(choose(), style: term\TermStyle.brightGreen));
notify
Raise a notification into the band magus pins at the bottom of the terminal, where it shows for a few seconds and then disappears on its own. Unlike log.info it does not join the scrolling transcript: it is for something worth GLANCING at during a long run, not for the record. Returns immediately - the message expires on its own clock - and never raises: it is DROPPED when there is no terminal to show it on, or when the band has no room, so a piped or CI run is never given a repainted view it cannot use and no caller has to guard a notification. Log the same fact if it also needs recording. ttl_ms defaults to 5000; a negative ttl_ms pins the notification until newer ones push it out.
Signature: term\notify(message, [level], [ttl_ms]) - source
| Parameter | Type | Optional | Description |
|---|---|---|---|
message |
string |
||
level |
string |
yes | |
ttl_ms |
int |
yes |
Example:
import "term";
// A notification is something to GLANCE at during a long run, not a record of
// it. It is dropped when there is no terminal to show it on, so anything that
// must survive the run goes through log as well.
term\notify("docs regenerated");
// Severity picks the color; the default ttl is 5 seconds.
term\notify("cache stampede on go-build", level: term\LogLevel.warn);
// A longer ttl for something worth reading twice.
term\notify("deploy skipped: no credentials", level: term\LogLevel.error, ttl_ms: 15000);
// A negative ttl keeps it until newer notifications push it out of the band.
term\notify("daemon unreachable", level: term\LogLevel.error, ttl_ms: -1);
clearScreen
Erase the screen and move the cursor home, the repaint a full-screen refresh loop issues before redrawing. Scrollback is preserved, so a reader who scrolls up after the loop ends still sees what came before. A no-op when there is no terminal, so a watch loop needs no guard.
Signature: term\clearScreen() - source