Documentation
¶
Overview ¶
Package gox renders HTML-like templates as ordinary Go values.
In practice, templates are usually authored in `.gox` with HTML expressions or the `elem` form, and GoX compiles that syntax to Elem values.
Common forms:
// Regular Go function returning a template expression.
func Badge(label string) gox.Elem {
return <span class="badge">~(label)</span>
}
// `elem` is shorthand for the same thing.
elem Badge(label string) {
<span class="badge">~(label)</span>
}
// Generated/lowered form using Cursor directly.
func Badge(label string) gox.Elem {
return func(cur gox.Cursor) error {
if err := cur.Init("span"); err != nil {
return err
}
if err := cur.AttrSet("class", "badge"); err != nil {
return err
}
if err := cur.Submit(); err != nil {
return err
}
if err := cur.Text(label); err != nil {
return err
}
return cur.Close()
}
}
Elem renders through Cursor under the hood. Cursor, Attrs, Job, and Printer are the lower-level APIs for custom rendering, stream transforms, and other integrations.
Index ¶
- func NewEscapedWriter(w io.Writer) io.Writer
- func Release(r Releaser)
- type Attr
- type AttrModFunc
- type Attrs
- func (a Attrs) AddMod(m Modify)
- func (a Attrs) ApplyMods(ctx context.Context, tag string) error
- func (a Attrs) Clone() Attrs
- func (a Attrs) Find(name string) (Attr, bool)
- func (a Attrs) Get(name string) Attr
- func (a Attrs) Has(name string) bool
- func (a Attrs) Inherit(attrs Attrs)
- func (a Attrs) List() []Attr
- type Comp
- type Cursor
- func (c Cursor) Any(any any) error
- func (c Cursor) AttrMod(mods ...Modify) error
- func (c Cursor) AttrSet(name string, value any) error
- func (c Cursor) Bytes(data []byte) error
- func (c Cursor) Close() error
- func (c Cursor) Comp(comp Comp) error
- func (c Cursor) CompCtx(ctx context.Context, comp Comp) error
- func (c Cursor) Context() context.Context
- func (c Cursor) Editor(editor Editor) error
- func (c Cursor) Fprint(any any) error
- func (c Cursor) Init(tag string) error
- func (c Cursor) InitContainer() error
- func (c Cursor) InitVoid(tag string) error
- func (c Cursor) Many(many ...any) error
- func (c Cursor) NewID() uint64
- func (c Cursor) Raw(text string) error
- func (c Cursor) Send(job Job) error
- func (c Cursor) Submit() error
- func (c Cursor) Templ(templ Templ) error
- func (c Cursor) TemplCtx(ctx context.Context, templ Templ) error
- func (c Cursor) Text(text string) error
- type Editor
- type EditorComp
- type EditorCompFunc
- type EditorFunc
- type Elem
- type HeadError
- type HeadKind
- type Job
- type JobBytes
- type JobComp
- type JobError
- type JobFprint
- type JobHeadClose
- type JobHeadOpen
- type JobRaw
- type JobTempl
- type JobText
- type Modify
- type Mutate
- type Output
- type OutputError
- type Printer
- type PrinterFunc
- type Proxy
- type ProxyFunc
- type Releaser
- type Templ
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func NewEscapedWriter ¶
NewEscapedWriter returns a writer that applies GoX's HTML escaping rules.
It is useful in custom printers or helpers that need the same escaping behavior as Text, Fprint, and attribute output.
Types ¶
type Attr ¶
type Attr = *attr
Attr is a handle to one attribute entry.
Attr values usually come from Attrs.Get, Attrs.Find, or Attrs.List.
func (Attr) IsSet ¶
IsSet reports whether this attribute should be rendered.
Rules:
- nil Attr => false
- stored value is bool => that bool value (true=set, false=unset)
- otherwise => value != nil
func (Attr) OutputName ¶
OutputName writes only the attribute name to w.
This is a low-level helper for custom rendering pipelines.
func (Attr) OutputValue ¶
OutputValue writes only the attribute value to w.
This is a low-level helper for custom rendering pipelines.
type AttrModFunc ¶
AttrModFunc adapts a function into a Modify.
type Attrs ¶
type Attrs = *attrs
Attrs stores the attributes attached to one element head.
Example:
attrs := gox.NewAttrs()
attrs.Get("class").Set("badge")
attrs.Get("hidden").Set(false)
Attrs keeps entries sorted by name for stable output and binary-search lookups. Names are case-sensitive, so "class" and "Class" are different attributes.
Presence follows these rules:
- nil means unset
- bool is set only when true
- any other non-nil value is set
Attr handles returned by Get, Find, and List point into the owning Attrs. Attrs is not safe for concurrent use.
func (Attrs) ApplyMods ¶
ApplyMods runs all queued modifiers on this attribute set.
Modifiers run in insertion order. If one returns an error, ApplyMods stops immediately. Modifiers that already ran are discarded.
func (Attrs) Clone ¶
Clone returns an independent copy of the attribute set.
Clone copies only attributes that are currently set. The modifier slice is copied too, but modifier values are shared.
func (Attrs) Find ¶
Find returns the set attribute named name.
Find does not create missing entries and returns false for unset ones.
func (Attrs) Get ¶
Get returns the entry for name, creating it when needed.
The returned Attr is a live handle into this Attrs.
func (Attrs) Inherit ¶
Inherit copies all set attributes from attrs into a.
For each attribute in attrs:
- if it is not set (per Attr.IsSet), it is ignored
- otherwise, a.Get(name).Set(value) is performed
Note: because this uses Attr.Set, if the target attribute already has a value and the inherited value implements Mutate, the inherited value may be computed from the target’s previous value.
type Comp ¶
type Comp interface {
Main() Elem
}
Comp is anything that can produce a root Elem.
In practice, most components are written in `.gox` as `elem (T) Main() { ... }`. Elem itself also satisfies Comp, so APIs can accept either components or plain Elem values through one interface. Main may return nil to render nothing.
type Cursor ¶
type Cursor = *cursor
Cursor builds output by streaming Jobs to a Printer.
Most `.gox` users never construct a Cursor directly because generated code does it for them. Reach for Cursor when you need manual rendering, custom editors, or proxy/printer integrations.
Example:
cur := gox.NewCursor(ctx, gox.NewPrinter(w))
_ = cur.Init("span")
_ = cur.AttrSet("class", "badge")
_ = cur.Submit()
_ = cur.Text("New")
_ = cur.Close()
Cursor maintains a stack of active heads to validate nesting and enforce a small state machine:
Regular element lifecycle:
- Init(tag)
- (optional) AttrSet / AttrMod
- Submit() // emits head-open job
- emit children jobs // Text/Comp/Any/etc.
- Close() // emits head-close job
Void element lifecycle:
- InitVoid(tag)
- (optional) AttrSet / AttrMod
- Submit() // emits head-open job; no children and no Close
Container lifecycle:
- InitContainer() // emits container head-open job immediately
- emit children jobs
- Close() // emits container head-close job
Content state ¶
Several methods require the cursor to be in a content state, meaning:
- no element head is active (top-level), OR
- the current element/container head has already been submitted with Submit, and may accept children.
Cursor is not safe for concurrent use.
func NewCursor ¶
NewCursor returns a Cursor that emits jobs to printer.
ctx becomes the default context for jobs created through this cursor. The returned cursor starts at top level, so callers may emit content immediately or begin a new head with Init, InitVoid, or InitContainer.
func (Cursor) Any ¶
Any renders a value using GoX's default dynamic dispatch.
Supported cases include:
- string / []string
- Elem / []Elem
- Comp / []Comp
- Job / []Job
- Editor
- Templ
- []any (treated as a variadic list)
Nil interface values are ignored. Everything else falls back to Fprint.
func (Cursor) AttrMod ¶
AttrMod adds one or more modifiers to the current head.
AttrMod may be used only after Init or InitVoid and before Submit. Modifiers run right before rendering and may inspect, leave unchanged, or mutate the full attribute set.
func (Cursor) AttrSet ¶
AttrSet sets an attribute on the current head.
AttrSet may be used only after Init or InitVoid and before Submit.
func (Cursor) Close ¶
Close closes the current regular or container head.
The current head must already be submitted. Void elements must not be closed.
func (Cursor) Init ¶
Init starts a regular element head.
After Init, callers may set attributes with AttrSet or AttrMod. Child content must wait until Submit succeeds.
func (Cursor) InitContainer ¶
InitContainer starts a synthetic container head and submits it immediately.
Containers do not emit an HTML tag. They group a range of child jobs under a shared head id and must still be closed with Close.
func (Cursor) InitVoid ¶
InitVoid starts a void element head.
Void heads may receive attributes before Submit, but they never accept children and must not be closed.
func (Cursor) Many ¶
Many renders each value in order using Any.
Many is a convenient way to emit mixed values without switching manually.
func (Cursor) NewID ¶
NewID returns a process-unique id for correlating render-time state.
IDs increase monotonically within one cursor.
func (Cursor) Send ¶
Send forwards job directly to the underlying Printer.
Send skips cursor state validation, so callers must preserve any ordering and nesting guarantees they need.
func (Cursor) Submit ¶
Submit emits the current head's opening job.
After Submit, the current head is open for child content and no longer accepts attribute mutation.
type Editor ¶
Editor renders by operating on a Cursor directly.
Use Editor when returning another Elem is not enough and the implementation needs low-level access to cursor methods or custom jobs.
type EditorComp ¶
EditorComp is both a low-level Editor and a regular Comp.
It is useful for values that should plug into component-based APIs while still exposing direct cursor control.
type EditorCompFunc ¶
EditorCompFunc adapts a function into an EditorComp.
It is useful for small helpers that need direct cursor access but should also satisfy component-based APIs.
func (EditorCompFunc) Main ¶
func (e EditorCompFunc) Main() Elem
Main makes EditorCompFunc satisfy Comp by returning it as an Elem.
type EditorFunc ¶
EditorFunc adapts a function into an Editor.
type Elem ¶
Elem is the runtime value produced by GoX template syntax.
In practice, Elem is usually authored in `.gox` as an HTML expression or with the `elem` form.
Example:
var badge gox.Elem = <span class="badge">New</span>
elem Badge(label string) {
<span class="badge">~(label)</span>
}
Generated code lowers Elem to Cursor operations. Elem also implements Comp and templ-style rendering through Render.
type HeadError ¶
type HeadError string
HeadError reports an invalid Cursor state transition.
Examples include emitting child content before Submit or mutating attributes after a head has already been submitted.
type HeadKind ¶
type HeadKind int
HeadKind identifies what kind of head Cursor is building.
The kind controls whether the head emits a real tag and whether it may have children.
const ( // KindContainer is a synthetic head used to group a sequence of jobs without // emitting an actual HTML tag. It is submitted immediately. KindContainer HeadKind = iota // KindRegular is a normal, non-void HTML element. KindRegular // KindVoid is a void/self-closing HTML element (e.g. <input>, <br>, etc.). // Void heads are submitted as an open job and then removed from the stack; // they never accept children and must not be closed. KindVoid )
type Job ¶
type Job interface {
// Context returns the context associated with this job.
Context() context.Context
Output
}
Job is a single render operation emitted by Cursor.
Concrete jobs such as JobHeadOpen, JobText, and JobComp let custom printers observe or transform the stream while still sharing one cancellation context.
type JobBytes ¶
JobBytes writes bytes without escaping.
func NewJobBytes ¶
NewJobBytes returns a pooled JobBytes.
type JobComp ¶
JobComp renders a Comp.
Output calls Comp.Main and, when it returns a non-nil Elem, renders that Elem into the output stream.
func NewJobComp ¶
NewJobComp returns a pooled JobComp.
type JobError ¶
JobError fails rendering with a stored error.
func NewJobError ¶
NewJobError returns a pooled JobError.
type JobFprint ¶
JobFprint formats a value with fmt.Fprint and GoX escaping.
It is the default fallback for values that do not have specialized handling in Cursor.Any.
func NewJobFprint ¶
NewJobFprint returns a pooled JobFprint.
type JobHeadClose ¶
type JobHeadClose struct {
// ID is the head identifier associated with this element/container.
// The opening and closing jobs for the same head share the same ID.
ID uint64
// Kind describes how this head should be rendered (regular/void/container).
Kind HeadKind
// Tag is the element tag name. It must be non-empty for regular heads.
Tag string
// Ctx is the context associated with this job.
Ctx context.Context
}
JobHeadClose writes the closing half of a head.
Regular heads emit `</tag>`. Container heads emit no HTML. Closing a void head is an error.
func NewJobHeadClose ¶
NewJobHeadClose returns a pooled JobHeadClose.
func (*JobHeadClose) Context ¶
func (j *JobHeadClose) Context() context.Context
Context returns the context associated with this job.
func (*JobHeadClose) Output ¶
func (j *JobHeadClose) Output(w io.Writer) error
Output writes the closing tag to w.
Behavior by kind:
- KindContainer: writes nothing and returns nil
- KindVoid: returns an error (void elements cannot be closed)
- KindRegular: requires Tag to be non-empty and writes `</tag>`
type JobHeadOpen ¶
type JobHeadOpen struct {
// ID is the head identifier associated with this element/container.
// The opening and closing jobs for the same head share the same ID.
ID uint64
// Kind describes how this head should be rendered (regular/void/container).
Kind HeadKind
// Tag is the element tag name. It must be non-empty for regular/void heads.
Tag string
// Ctx is the context used for attribute modifiers and downstream render hooks.
Ctx context.Context
// Attrs is the attribute set associated with this head.
Attrs Attrs
}
JobHeadOpen writes the opening half of a head.
Regular and void heads emit `<tag ...>`. Container heads emit no HTML.
func NewJobHeadOpen ¶
func NewJobHeadOpen(ctx context.Context, id uint64, kind HeadKind, tag string, attrs Attrs) *JobHeadOpen
NewJobHeadOpen returns a pooled JobHeadOpen.
The returned job is single-use and is usually sent straight to a Printer.
func (*JobHeadOpen) Context ¶
func (j *JobHeadOpen) Context() context.Context
Context returns the context associated with this job.
type JobRaw ¶
JobRaw writes unescaped text.
type JobTempl ¶
JobTempl renders a templ-compatible value.
func NewJobTempl ¶
NewJobTempl returns a pooled JobTempl.
type JobText ¶
JobText writes escaped text.
func NewJobText ¶
NewJobText returns a pooled JobText.
type Modify ¶
Modify can inspect and mutate an element's full attribute set right before rendering.
Modifiers run in the order they were added. They are one-shot: after ApplyMods succeeds, the queue is cleared.
type Mutate ¶
Mutate computes a new attribute value from the previous one.
Attr.Set detects Mutate values and stores the result of value.Mutate(attributeName, currentValue).
type Output ¶
Output is the low-level write contract implemented by Jobs.
Output is aliased from an internal utility type.
type OutputError ¶
type OutputError string
OutputError reports invalid job state during rendering.
func (OutputError) Error ¶
func (e OutputError) Error() string
type Printer ¶
Printer consumes the Job stream produced during rendering.
The default Printer from NewPrinter writes HTML sequentially to an io.Writer. Custom printers can inspect, buffer, rewrite, or reroute jobs before final output. Printer implementations are not required to be safe for concurrent use unless they document otherwise.
func NewPrinter ¶
NewPrinter returns the default Printer that writes jobs to w in order.
type PrinterFunc ¶
PrinterFunc adapts a function into a Printer.
type Proxy ¶
Proxy wraps an Elem before it is rendered.
Proxies are useful when a subtree needs cross-cutting behavior such as instrumentation, attribute injection, conditional rendering, or rerouting through a custom Printer.
