Documentation
¶
Overview ¶
Package htmlterm renders a restricted subset of HTML and CSS to ANSI-styled terminal strings.
It is intended for CLIs, terminal UIs, and text-first applications that need richer formatting than plain text without embedding a browser engine.
The renderer supports HTML fragments or full documents, a focused CSS subset, inherited inline styles, block layout, lists, tables, pseudo-elements, and OSC 8 hyperlinks. Unsupported HTML and CSS are ignored rather than treated as errors. See CSS.md in the repository for the supported surface.
Security ¶
htmlterm is not a browser sandbox or a general-purpose HTML sanitizer. It renders to terminal output, where control sequences can affect display state or create misleading hyperlinks. Input-provided text, CSS string content, generated attribute content, custom markers, and hyperlink URLs are sanitized before output. Renderer-generated ANSI styling and OSC 8 wrappers may still be emitted intentionally.
When rendering attacker-controlled documents, consider setting Options.NoOSC8Links and applying application-level URL and size limits. See SECURITY.md in the repository for the full security policy and threat model.
Index ¶
Examples ¶
Constants ¶
const DefaultStylesheet = render.DefaultStylesheet
DefaultStylesheet is the built-in default stylesheet applied before Options.CSS and Options.Stylesheets. It is exposed so callers can inspect or diff against it when writing overrides.
const ScrollbarGutterWidth = render.ScrollbarGutterWidth
ScrollbarGutterWidth is the fixed column width an overflow-y:scroll element reserves for its scrollbar gutter (see docs/SCROLLING.md). Exposed for callers who pre-render content in a separate Renderer.Render/Document pass outside the scrollable element that will eventually display it, to cache an expensive layout and later splice it into a live pane via cache an expensive layout for Document.SetPreRendered, so that pass can subtract this from its own Width and wrap at the same content width the live pane will actually have. Skipping this produces content wrapped 1 column wider than the live pane's real innerW, which desyncs from that pane's own scrollbar gutter and produces an off-by-one-short scrollbar column on any line that reaches the (wrongly wider) boundary.
const SizeAutomatic = 0
SizeAutomatic is the zero value for Options.Width/Options.Height: track the terminal's current size for that dimension. Plain Renderer.Render/Document have no terminal to query, so it's inert there (behaves like SizeNatural for Height; Width has no natural fallback and is simply left at 0, same as before this constant existed). Loop is what resolves it, in Loop.Run and Document.SetSize, querying the terminal once at startup and again on every SIGWINCH, keeping whichever of Width/Height is SizeAutomatic live for the life of the Loop. It is the zero value deliberately, matching the rest of Options: a caller who never mentions Width/Height and drives rendering through Loop gets automatic sizing without writing anything.
const SizeNatural = -1
SizeNatural, valid for Options.Height only, means "don't constrain height at all": the document renders at whatever line count its content produces, with no clipping or padding (today's behavior, before Height existed). There is no equivalent for Width: wrapping always needs a concrete column count, so a "natural width" isn't a meaningful concept here the way it is for height.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Options ¶
type Options struct {
CSS string // additional stylesheet layered above built-in defaults (DefaultStylesheet)
Stylesheets []string // additional stylesheets, layered above CSS in order, similar to a page's own <link> stylesheets
Width int // terminal column count; affects wrapping, tables, percentage widths
Height int // content-box line count the whole document is clipped/padded to; zero value is SizeAutomatic (see there); SizeNatural (-1) leaves it unconstrained
IgnoreDocumentCSS bool // if true, <style> elements and style= attributes in HTML are ignored
Profile colorprofile.Profile // color profile; zero value (NoTTY) auto-detects from environment
NoOSC8Links bool // if true, OSC 8 hyperlink sequences are not emitted for <a> elements
MaxBlankLines int // if > 0, collapses runs of blank lines to at most this many; <pre> content is not affected
StripHiddenInline bool // if true, elements hidden via their own inline style= (display:none, visibility:hidden, opacity:0, zero height/max-height with overflow:hidden) are removed before rendering; independent of IgnoreDocumentCSS
}
Options configures a Renderer.
type Renderer ¶
type Renderer struct {
// contains filtered or unexported fields
}
Renderer renders HTML+CSS to terminal strings.
A Renderer can be reused for multiple Render calls, including concurrent calls. Per-document state is built fresh for each render.
func New ¶
New parses opts.CSS and returns a Renderer.
Example (CustomCSS) ¶
package main
import (
"fmt"
"log"
"github.com/client9/htmlterm"
)
func main() {
css := `.note { border-left: "│"; padding-left: 1; }`
r, err := htmlterm.New(htmlterm.Options{CSS: css, Width: 24, NoOSC8Links: true})
if err != nil {
log.Fatal(err)
}
out, err := r.Render(`<p class="note">custom CSS</p>`)
if err != nil {
log.Fatal(err)
}
fmt.Print(out)
}
Output: │ custom CSS
Example (UntrustedHTML) ¶
package main
import (
"fmt"
"log"
"github.com/client9/htmlterm"
)
func main() {
r, err := htmlterm.New(htmlterm.Options{
Width: 40,
IgnoreDocumentCSS: true,
NoOSC8Links: true,
})
if err != nil {
log.Fatal(err)
}
out, err := r.Render("<p>\x1b[31mnot red\x1b[0m</p>")
if err != nil {
log.Fatal(err)
}
fmt.Print(out)
}
Output: not red
func (*Renderer) Render ¶
Render parses htmlStr and returns a styled terminal string.
Example ¶
package main
import (
"fmt"
"log"
"github.com/client9/htmlterm"
)
func main() {
r, err := htmlterm.New(htmlterm.Options{Width: 40, NoOSC8Links: true})
if err != nil {
log.Fatal(err)
}
out, err := r.Render(`<p>Hello terminal.</p>`)
if err != nil {
log.Fatal(err)
}
fmt.Print(out)
}
Output: Hello terminal.
Directories
¶
| Path | Synopsis |
|---|---|
|
htmlterm renders HTML to styled terminal output.
|
htmlterm renders HTML to styled terminal output. |
|
gendocs
command
gendocs renders the hand-picked examples in examples.go through the real htmlterm engine and writes docs/examples/: one markdown page per example (title, HTML/CSS input, and the plain-text terminal output, all readable on GitHub as-is), one SVG per example (the same output with color and style, since GitHub strips the style attribute from raw HTML embedded in markdown, so an <img> is the only way color survives being embedded there), one aggregated gallery.html (the same output again, this time as real <span style="..."> HTML for a standalone webpage, where a real browser resolves the CSS itself and GitHub's sanitizer never runs), and an index README.md linking every example page.
|
gendocs renders the hand-picked examples in examples.go through the real htmlterm engine and writes docs/examples/: one markdown page per example (title, HTML/CSS input, and the plain-text terminal output, all readable on GitHub as-is), one SVG per example (the same output with color and style, since GitHub strips the style attribute from raw HTML embedded in markdown, so an <img> is the only way color survives being embedded there), one aggregated gallery.html (the same output again, this time as real <span style="..."> HTML for a standalone webpage, where a real browser resolves the CSS itself and GitHub's sanitizer never runs), and an index README.md linking every example page. |
|
htmlterm-tui
command
htmlterm-tui is a small interactive demo of htmlterm's Loop: it renders a form to the real terminal and lets you drive it with the keyboard and mouse (Tab to move forward, type into the focused field, click a checkbox, Enter or click Submit to submit, Ctrl-C to quit).
|
htmlterm-tui is a small interactive demo of htmlterm's Loop: it renders a form to the real terminal and lets you drive it with the keyboard and mouse (Tab to move forward, type into the focused field, click a checkbox, Enter or click Submit to submit, Ctrl-C to quit). |
|
Package document provides htmlterm's persistent, mutable document API for interactive terminal applications.
|
Package document provides htmlterm's persistent, mutable document API for interactive terminal applications. |
|
internal
|
|
|
ansidecode
Package ansidecode turns the ANSI string htmlterm's Render produces back into structured styled runs, for consumers that aren't a terminal.
|
Package ansidecode turns the ANSI string htmlterm's Render produces back into structured styled runs, for consumers that aren't a terminal. |
|
cssengine
Package cssengine owns htmlterm's CSS parsing, selector matching, and cascade resolution.
|
Package cssengine owns htmlterm's CSS parsing, selector matching, and cascade resolution. |
|
render
Package render owns htmlterm's HTML/CSS layout engine and render-state production.
|
Package render owns htmlterm's HTML/CSS layout engine and render-state production. |
|
textcell
Package textcell measures and manipulates already-rendered terminal text in *cells*, the unit a terminal charges for, rather than in bytes or runes.
|
Package textcell measures and manipulates already-rendered terminal text in *cells*, the unit a terminal charges for, rather than in bytes or runes. |
|
Package tui drives a document.Document interactively against a real terminal via tcell.Screen.
|
Package tui drives a document.Document interactively against a real terminal via tcell.Screen. |