Documentation
¶
Overview ¶
Package highlight turns Go source code into syntax-highlighted output built from go-mx components.
It is independent of the shadcn and other higher-level packages: it depends only on the root mx package and the html element helpers, so it can be used on its own or composed into any go-mx markup, including the shadcn UI.
Highlighting works in two steps, the way an editor does:
TokenizeGo splits source into a flat list of [Token]s, each tagged with a semantic TokenClass (keyword, string, comment, ...). It uses the standard library go/scanner, so it has no third-party dependencies and is lenient about syntactically invalid input. The concatenation of all token texts reproduces the input byte-for-byte.
A Highlighter turns those tokens into output. Two backends share the same tokens and configuration. Highlighter.Component and Highlighter.HTML emit the highlighted markup, built through mx/html components: every highlighted token becomes a <span class="hl-CLASS"> and the rest render as plain escaped text. Highlighter.GoSource instead emits Go source code that, using the html package, builds that same markup; it is a generator, not an echo of the input, so feeding it "func main() {}" returns a tree of html.Pre(...) calls.
Colors live in a separate Theme that emits a CSS stylesheet, so the same HTML works with any theme. Use LightTheme or DarkTheme, or build your own.
import "github.com/ungerik/go-mx/highlight"
block := highlight.Component(src) // *mx.Element: <pre><code>…</code></pre>
code := highlight.GoSource(src) // string: html.Pre(...) Go source
style := highlight.LightTheme.StyleElement("") // <style>…</style>
Render the markup with a non-indenting writer (the default mx.NewCheckedWriter); an indenting writer would inject whitespace between the spans and corrupt the code layout inside <pre>.
Index ¶
- Constants
- Variables
- func Component(src string) *mx.Element
- func GoSource(src string) string
- func HTML(src string) (string, error)
- func Inline(src string) *mx.Element
- type Highlighter
- func (h *Highlighter) BlockClass() string
- func (h *Highlighter) Component(src string) *mx.Element
- func (h *Highlighter) Components(tokens []Token) mx.Components
- func (h *Highlighter) GoSource(src string) string
- func (h *Highlighter) HTML(src string) (string, error)
- func (h *Highlighter) Inline(src string) *mx.Element
- type Style
- type Theme
- type Token
- type TokenClass
Constants ¶
const DefaultPrefix = "hl-"
DefaultPrefix is prepended to every token CSS class name. Trimmed of its trailing "-" it also names the <pre> block ("hl").
Variables ¶
var DarkTheme = Theme{ Name: "dark", Background: "#0d1117", Foreground: "#c9d1d9", Styles: map[TokenClass]Style{ ClassKeyword: {Color: "#ff7b72"}, ClassType: {Color: "#d2a8ff"}, ClassFunction: {Color: "#d2a8ff"}, ClassBuiltin: {Color: "#ffa657"}, ClassConstant: {Color: "#79c0ff"}, ClassString: {Color: "#a5d6ff"}, ClassNumber: {Color: "#79c0ff"}, ClassComment: {Color: "#8b949e", Italic: true}, ClassOperator: {Color: "#ff7b72"}, ClassPunctuation: {Color: "#c9d1d9"}, ClassIdent: {Color: "#c9d1d9"}, }, }
DarkTheme is a dark, GitHub-like color scheme.
var Default = &Highlighter{}
Default is the zero-value Highlighter used by the package-level functions.
var DefaultHighlighted = map[TokenClass]bool{ ClassKeyword: true, ClassType: true, ClassFunction: true, ClassBuiltin: true, ClassConstant: true, ClassString: true, ClassNumber: true, ClassComment: true, }
DefaultHighlighted is the set of token classes wrapped in a <span> by a zero-value Highlighter. Operators, punctuation and plain identifiers render as text, which keeps the markup small and matches how editors like GitHub's highlight Go.
var LightTheme = Theme{ Name: "light", Background: "#f6f8fa", Foreground: "#24292e", Styles: map[TokenClass]Style{ ClassKeyword: {Color: "#d73a49"}, ClassType: {Color: "#6f42c1"}, ClassFunction: {Color: "#6f42c1"}, ClassBuiltin: {Color: "#e36209"}, ClassConstant: {Color: "#005cc5"}, ClassString: {Color: "#032f62"}, ClassNumber: {Color: "#005cc5"}, ClassComment: {Color: "#6a737d", Italic: true}, ClassOperator: {Color: "#d73a49"}, ClassPunctuation: {Color: "#24292e"}, ClassIdent: {Color: "#24292e"}, }, }
LightTheme is a light, GitHub-like color scheme.
Functions ¶
func Component ¶
Component highlights Go source with the Default highlighter. See Highlighter.Component.
func GoSource ¶
GoSource highlights Go source with the Default highlighter. See Highlighter.GoSource.
func HTML ¶
HTML highlights Go source with the Default highlighter. See Highlighter.HTML.
Types ¶
type Highlighter ¶
type Highlighter struct {
// Prefix is prepended to every token CSS class name. It conventionally
// ends with "-". An empty Prefix means [DefaultPrefix].
Prefix string
// Highlighted selects which token classes are wrapped in a <span>; every
// other class renders as plain text. A nil map means [DefaultHighlighted].
Highlighted map[TokenClass]bool
}
Highlighter holds the rendering configuration shared by both output backends. The zero value is ready to use and is exposed as Default.
func (*Highlighter) BlockClass ¶
func (h *Highlighter) BlockClass() string
BlockClass is the class name put on the <pre> block, derived from the prefix by trimming a trailing "-" (so DefaultPrefix "hl-" yields "hl").
func (*Highlighter) Component ¶
func (h *Highlighter) Component(src string) *mx.Element
Component highlights Go source and returns it as a <pre class="hl"><code>…</code></pre> block element.
func (*Highlighter) Components ¶
func (h *Highlighter) Components(tokens []Token) mx.Components
Components turns tokens into a sequence of mx components: a <span class="PREFIX+CLASS"> for every highlighted token and plain escaped text for everything else. Use it to place highlighted code inside a custom wrapper; Highlighter.Component and Highlighter.Inline wrap it for you.
func (*Highlighter) GoSource ¶
func (h *Highlighter) GoSource(src string) string
GoSource highlights Go source and returns, instead of HTML, the Go source code that builds that highlighted markup with the html package. It is a generator: the returned code is not the input echoed back but a tree of html.Pre / html.Code / html.Span calls.
For the input
func main() {}
it returns roughly
html.Pre(html.Class("hl"),
html.Code(
html.Span(html.Class("hl-keyword"), "func"),
" ",
html.Span(html.Class("hl-function"), "main"),
html.Span(html.Class("hl-punctuation"), "()"),
" ",
html.Span(html.Class("hl-punctuation"), "{}"),
),
)
The result is gofmt-formatted. If the generated expression somehow fails to format, the unformatted but valid expression is returned instead.
func (*Highlighter) HTML ¶
func (h *Highlighter) HTML(src string) (string, error)
HTML highlights Go source and renders it directly to an HTML string using a non-indenting mx.CheckedWriter, so the code layout inside <pre> is preserved exactly.
type Style ¶
Style is the appearance of one TokenClass in a Theme.
type Theme ¶
type Theme struct {
Name string // human-readable theme name
Background string // <pre> background-color, "" to inherit
Foreground string // <pre> base text color, "" to inherit
Styles map[TokenClass]Style
}
Theme maps token classes to colors and provides the CSS to render them. The HTML produced by a Highlighter is theme-independent, so the same markup can be styled by any theme that uses the same class prefix.
func (Theme) CSS ¶
CSS renders the theme as a CSS stylesheet for the given class prefix (pass DefaultPrefix or "" to match the default Highlighter). It emits one rule for the <pre> block and one rule per styled token class, in deterministic order.
func (Theme) StyleElement ¶
StyleElement returns the theme's CSS wrapped in a <style> element, ready to place in a document <head>. It uses the given prefix; pass DefaultPrefix or "" to match the default Highlighter.
type Token ¶
type Token struct {
Class TokenClass
Text string
}
Token is a single classified slice of the source. The concatenation of the Text of every token returned by TokenizeGo equals the original source.
func TokenizeGo ¶
TokenizeGo splits Go source into classified [Token]s. It never returns an error: invalid input is scanned as far as possible and any unrecognized bytes are emitted as plain text, so the result always reproduces src exactly when the token texts are concatenated.
type TokenClass ¶
type TokenClass string
TokenClass is the semantic category of a token. It is also used, with the Highlighter prefix, as the CSS class name of a highlighted token's <span>.
const ( // ClassPlain is the zero value: text that is not highlighted (whitespace // and, by default, identifiers, operators and punctuation). ClassPlain TokenClass = "" // ClassKeyword is a Go keyword such as if, for, func or package. ClassKeyword TokenClass = "keyword" // ClassType is a predeclared type such as int, string or error. ClassType TokenClass = "type" // ClassFunction is a called or declared function/method name. ClassFunction TokenClass = "function" // ClassBuiltin is a predeclared function such as make, len or append. ClassBuiltin TokenClass = "builtin" // ClassConstant is a predeclared value such as true, false, nil or iota. ClassConstant TokenClass = "constant" // ClassString is a string or rune literal. ClassString TokenClass = "string" // ClassNumber is an integer, float or imaginary literal. ClassNumber TokenClass = "number" // ClassComment is a line or block comment. ClassComment TokenClass = "comment" // ClassOperator is an operator such as +, :=, == or <-. ClassOperator TokenClass = "operator" // ClassPunctuation is a delimiter such as a parenthesis, brace, comma, dot or colon. ClassPunctuation TokenClass = "punctuation" // ClassIdent is any other identifier. ClassIdent TokenClass = "ident" )