Skip to main content
Kazari
On this page

Configuration Layers

Understand how Kazari resolves block settings through its three-layer cascade: engine defaults, language defaults, and per-block overrides.

Every code block Kazari renders gets its final settings from a three-layer cascade. Engine defaults establish the baseline, language defaults refine behavior for specific languages, and per-block overrides give each block the final say. Higher layers override lower ones, and omitted values fall through to the layer below.

The cascade

Engine defaults
└─ Language defaults
└─ Per-block overrides (meta string or Options struct)

Kazari resolves five block properties through this cascade:

Property Meta string key Options field Description
Frame frame=code Frame Visual frame style: auto, code, terminal, none
Line numbers showLineNumbers LineNumbers Show or hide the line number gutter
Word wrap wrap Wrap Enable word wrapping for long lines
Preserve indent preserveIndent PreserveIndent Keep leading indentation on wrapped lines
Hanging indent hangingIndent=2 HangingIndent Extra indent (in ch) for continuation lines

Feature toggles like WithCopyButton and WithCollapsible are engine-level only. They do not participate in the cascade and cannot be overridden per block.

Layer 1: Engine defaults

Set during engine construction via functional options passed to kazari.New(). These apply to every code block the engine renders.

Go
engine := kazari.New(
kazari.WithHighlighter(hl),
kazari.WithThemes("github-light", "github-dark"),
kazari.WithLineNumbers(true),
kazari.WithDefaults(kazari.BlockDefaults{
Wrap: true,
Frame: kazari.FrameCode,
}),
)

WithDefaults sets block-level properties for all languages. Individual With* functions like WithLineNumbers modify the same defaults. Both approaches write to the same internal structure, so the last one in the option list wins.

Built-in defaults

When no options are provided, the engine starts with these values:

Property Default
Frame FrameAuto (auto-detect from language)
Line numbers false
Word wrap false
Preserve indent true
Hanging indent 0 (disabled)

These come from DefaultConfig() and apply before any functional options run.

File-based configuration

Engine defaults can also come from a kazari.config.yaml (or .yml or .json) file instead of Go code:

Go
engine := kazari.New(
kazari.WithHighlighter(hl),
kazari.WithConfigDir("."),
)

The config file maps directly to functional options. WithConfigDir searches for a config file and applies its settings as options during engine construction. Options passed after WithConfigDir override the file:

Go
engine := kazari.New(
kazari.WithHighlighter(hl),
kazari.WithConfigDir("."), // loads config file
kazari.WithCopyButton(false), // overrides config file's copyButton
)

See File-Based Config for the full schema and validation rules.

Layer 2: Language defaults

Apply block properties to all blocks of a specific language. Set via WithLanguageDefaults or the languageDefaults key in a config file.

Go
engine := kazari.New(
kazari.WithHighlighter(hl),
kazari.WithLanguageDefaults(map[string]kazari.BlockDefaults{
"bash,sh,zsh": {
Wrap: true,
Frame: kazari.FrameTerminal,
},
"go": {
LineNumbers: true,
},
}),
)

Comma-separated keys apply the same defaults to multiple languages. "bash,sh,zsh" sets all three to use terminal frames with word wrap.

The equivalent in a config file:

YAML
languageDefaults:
"bash,sh,zsh":
wrap: true
frame: "terminal"
"go":
lineNumbers: true

Language defaults override engine defaults for matching blocks. When a code block's language matches a key, all five properties from that entry replace the engine defaults for that block. Non-matching blocks fall through to engine defaults unchanged.

When multiple comma-separated keys could match the same language, keys are sorted alphabetically and the first match wins.

Layer 3: Per-block overrides

Override any cascaded property for a single code block. Two interfaces provide per-block control: the meta string (for Markdown workflows) and the Options struct (for the Go API).

Meta string

The meta string follows the language identifier in a fenced code block:

```go title="main.go" showLineNumbers frame=code {3-5}
func main() {
cfg := loadConfig()
svc := newService(cfg)
svc.Run()
}
```

Cascade-relevant meta string keys:

Key Effect
showLineNumbers Enable line numbers
showLineNumbers=false Disable line numbers
wrap Enable word wrap
preserveIndent Enable preserved indentation on wrapped lines
preserveIndent=false Disable preserved indentation
hangingIndent=2 Set hanging indent to 2ch
frame=code Force editor frame
frame=terminal Force terminal frame
frame=none Remove frame

The meta string also carries non-cascade properties like title, theme, markers ({3-5}), focus lines, and collapse directives. These are per-block only and do not participate in the cascade.

Options struct

When calling engine.Render() directly, use the Options struct:

Go
ln := true
html, err := engine.Render(code, kazari.Options{
Lang: "go",
Title: "main.go",
LineNumbers: &ln,
LineMarkers: []kazari.LineMarker{
{Type: kazari.MarkerMark, Lines: []kazari.Range{{Start: 3, End: 5}}},
},
})

Cascade properties in Options use pointer types (*bool, *int, *Frame). A nil pointer means "use the cascaded value." A non-nil pointer overrides it. This makes the distinction between "not specified" and "explicitly set to the zero value" unambiguous.

Field Type nil behavior
Frame *Frame Use language or engine default
LineNumbers *bool Use language or engine default
Wrap *bool Use language or engine default
PreserveIndent *bool Use language or engine default
HangingIndent *int Use language or engine default
StartLineNumber *int Default: 1

Resolution example

Given this engine setup:

Go
engine := kazari.New(
kazari.WithHighlighter(hl),
kazari.WithDefaults(kazari.BlockDefaults{
LineNumbers: true,
Frame: kazari.FrameCode,
}),
kazari.WithLanguageDefaults(map[string]kazari.BlockDefaults{
"bash,sh": {
Frame: kazari.FrameTerminal,
Wrap: true,
},
}),
)

Three code blocks resolve differently:

Block A (```go)

Property Value Source
Frame FrameCode Engine default
Line numbers true Engine default
Wrap false Built-in default

Block B (```bash)

Property Value Source
Frame FrameTerminal Language default
Line numbers false Language default (replaces engine)
Wrap true Language default

Block C (```bash showLineNumbers frame=none)

Property Value Source
Frame FrameNone Meta string
Line numbers true Meta string
Wrap true Language default

Block C shows all three layers in action: Wrap comes from the language default, Frame and LineNumbers come from the meta string, and the engine defaults are fully overridden.

What does not cascade

Engine-level features are set once during construction and apply uniformly. They cannot be overridden per language or per block.

Feature Option
Copy button WithCopyButton
Fullscreen button WithFullscreenButton
Wrap toggle button WithWrapButton
Theme toggle WithThemeToggle
Language badge WithLanguageBadge
Frame detection WithFrameDetection
File name extraction WithFileNameExtraction
Style reset WithStyleReset
Themed scrollbars WithThemedScrollbars
Content exclusion WithContentExclusion
Minimum contrast WithMinContrast
Collapsible config WithCollapsible
Links WithLinks
File icons WithFileIcons
Mermaid pass-through WithMermaidPassThrough
Terminal comment stripping WithTerminalCommentStripping
Output panel WithOutputPanel

Quick reference

This page explains how the cascade works. For a complete list of every option, config file field, and meta string key in one place, see the Reference section:

  • Configuration Options lists every With* functional option and its corresponding config file field, type, and default value
  • Meta String Syntax lists every key recognized in the fence info string with usage examples
  • File-Based Config covers the full YAML/JSON schema and validation rules
Edit this page

Last updated: