Hwylterm
see also these utility modules:
| module | description |
|---|---|
| hwylcli | macro to generate CLI's styled by bbansi and with parsing parseopt3 |
| chooser | simple scrolling multi-item selecter |
| logging | wrapper for std/logging with styling |
bbansi
BB-style markup for ANSI terminal colors and styles.
Basic Markup Syntax
Wrap text in [style]...[/style] tags:
[bold]hello[/bold] [red]error[/red] [bold red]warning[/]
- [/style] — close a specific style
- [/] — close the most recently opened style
- [reset] — reset all active styles
Available Styles
Text styles
| Markup | Abbreviation | Effect |
|---|---|---|
| bold | b | bold |
| italic | i | italic |
| underline | u | underline |
| faint | dim/faint | |
| blink | blinking | |
| reverse | reverse video | |
| strike | ~~strikethrough~~ | |
| conceal | hidden |
Colors
Named xterm colors: black, red, green, yellow, blue, magenta, cyan, white, plus bright variants (brightred, brightblue, etc.).
Hex colors:
[#ff8800]orange text[/]
256-color palette:
[color(42)]text[/]
Background colors
Use the on keyword to set a background color:
[red on blue]text[/] [on yellow]text[/]
Combined styles
Multiple styles can be combined in a single tag:
[bold red]error[/] [bold italic underline]important[/]
Rendering to string
Parse markup into a BbString:
let s = bb("[bold]hello[/bold]")
Apply a style to a plain string:
let s = bb("hello", "bold red")
Render a BbString to an ANSI string using the global console:
echo $bb("[green]ok[/]")
Write to the global hwylConsole file (a wrapper around hwylConsole.file.write):
hecho bb("[bold]hello[/]"), " world"
Format strings with BB markup using bbfmt:
let name = "world" hecho $bbfmt"[bold]hello {name}[/]"
Escaping
| Input | Output |
|---|---|
| [[ | [ |
| \\ | \ |
Use bbEscape to programmatically escape a string before embedding it in markup:
let userInput = bbEscape(untrustedText) hecho $bb("[bold]" & userInput & "[/bold]")
Text Operations on BbString
All operations preserve styling:
# Truncate to N visible characters let t = bb("[bold]hello world[/]").truncate(5) # Word-wrap at N columns let w = bb("[red]long text...[/]").wrapWords(40) # Right-align / left-align (pad with spaces) let r = bb("[blue]hi[/]").align(10) let l = bb("[blue]hi[/]").alignLeft(10) # Concatenate let a = bb("[red]foo[/]") & bb("[blue]bar[/]") # Side-by-side horizontal concatenation let h = hconcat(bb("left\ncol"), bb("right\ncol")) # Join a seq of BbStrings let parts = @[bb("[red]a[/]"), bb("[green]b[/]")] let joined = parts.join(bb(", "))
Environment / Color Mode
| Variable | Effect |
|---|---|
| NO_COLOR | Disables all color output |
| HWYLTERM_FORCE_COLOR | Forces color on (even in pipes) |
| HWYLTERM_FORCE_MARKUP | Outputs BB markup instead of ANSI codes |
Compile-time flags (checked before environment variables):
| Flag | Effect |
|---|---|
| -d:bbansiOn | Forces color on |
| -d:bbansiOff | Forces color off |
| -d:bbansiNoColor | Disables color (strips styles, keeps text) |
| -d:bbMarkup | Outputs BB markup instead of ANSI codes |
confirm
Prompt the user for a yes/no answer on stderr. Returns true for y/yes and false for n/no (case-insensitive). Reprompts on any other input.
import hwylterm/confirm if confirm("Delete all files?"): echo "deleting..." else: echo "aborted"
spin
Animated terminal spinner backed by a background thread. The simplest usage is the withSpinner template, which starts the spinner, runs a block, then stops it automatically.
import std/os import hwylterm/spin withSpinner("loading..."): sleep 2000
Use spinner.setText inside the block to update the message while running:
import std/os import hwylterm/spin withSpinner("step 1"): sleep 500 spinner.setText("step 2") sleep 500 spinner.setText("done") sleep 500
To pick a specific spinner style, use the with template:
import std/os import hwylterm/spin Moon.with("loading..."): sleep 2000
See spinners: SpinnerKind for all available styles.
progress
Progress bar iterator that wraps a sequence and renders a bar as items are consumed. It runs inside a withSpinner/useSpinner context so the bar animates smoothly.
import std/os import hwylterm/progress let items = (1..20).toSeq() for item in progress(items): sleep 100
Segments
By default the bar renders only the bar itself. Pass segments to newProgress to add a fraction counter or percentage:
import std/os import hwylterm/progress var pb = newProgress(segments = @[Bar, Fraction, Percent]) for item in pb.progress((1..20).toSeq()): sleep 100
See progress: ProgressSegment for all options (Bar, Fraction, Percent).
With an existing spinner
If you already have a Spinny from the spin module, pass it to progress to share the spinner:
import std/os import hwylterm/[spin, progress] withSpinner("processing"): for item in progress(spinner, (1..20).toSeq()): sleep 100
Exports
-
BbString, bbEscape, toAnsiCode, bbMarkup, bbfmt, BbMode, join, $, alignLeft, wrapWordsBbMarkup, hecho, echo, toAnsiCode, repeat, bb, bb, hconcat, &, setHwylConsole, bb, toAnsiCode, align, wrapWords, bb, hconcat, &, len, truncate, add, bbEscape, &, add, BbSpan, toString, stripAnsi, setHwylConsoleFile, join, newConsole, bb, hwylConsole, splitLines, [], confirm, inc, newProgress, progress, Progress, progress, progress, progress, ProgressStyle, ProgressSegment, useSpinner, defaultSpinnerKind, with, newSpinny, setSymbol, withSpinner, echo, withSpinner, running, start, Spinner, with, newSpinny, setSymbolColor, Spinny, setText, makeSpinner, newSpinny, withSpinner, Spinners, stop, SpinnerKind