The `codeEnrichment` feature decorates fenced code blocks with per-line/per-word annotations — diff markers, line highlighting, and word highlighting. It runs as a hast-phase visitor after syntax highlighting, so it operates on the already-tokenized `<span class="line">` output.

:::note[Opt-in feature]

This feature is disabled by default. Enable it with the `codeEnrichment` key in `zfb.config.ts`. It is an object-typed feature, so it must be given an options object (`{}` or fields) — the `true` shorthand is rejected.

:::

:::note[Title bar is a separate, always-on feature]

The filename/title bar shown above a titled fence (`.code-block-container` / `.code-block-title`) comes from a separate, always-on core mechanism — not from `codeEnrichment`. It renders whether or not `codeEnrichment` is enabled. See [Code Title](https://zudo-doc.takazudomodular.com/docs/markdown-features/code-title).

:::

## Configuration

```ts title="zfb.config.ts"
export default defineConfig({
  markdown: {
    features: {
      codeEnrichment: {},
    },
  },
});
```

All three enhancements (diff markers, line highlighting, and word highlighting) are active by default. Disable any individually:

```ts title="zfb.config.ts"
codeEnrichment: {
  diffMarkers: false,
  lineHighlight: true,
  wordHighlight: true,
}
```

## Diff markers

Append `// [!code ++]` or `// [!code --]` comments at line ends. The marker is stripped from the output, and the line receives a `data-line-diff` attribute (`added` or `removed`):

```js title="diff-demo.js"
const unchanged = 1;
const removed = 2; // [!code --]
const added = 3; // [!code ++]
```

Supported comment styles match the language: `//` (JavaScript/TypeScript/Rust), `#` (Python/Ruby/Shell), `--` (SQL/Lua).

## Line highlighting

Add brace-delimited ranges to the fence info-string. Matching lines receive a `data-line-highlight="true"` attribute:

```js title="highlight-demo.js"
const a = 1;
const b = 2;
const c = 3;
const d = 4;
const e = 5;
```

The fence above was authored as:

````md
```js {1,3-5}
const a = 1;
const b = 2;
const c = 3;
const d = 4;
const e = 5;
```
````

Supported range syntax: single numbers (`{3}`), inclusive ranges (`{3-5}`), and combinations (`{1,3-5,8}`).

## Word highlighting

Add whitespace-delimited `/phrase/` expressions to the fence info-string. Every visible occurrence of the phrase in the block is wrapped in a `.highlighted-word` span, preserving syntax-highlighting markup at the match boundaries:

```js title="word-demo.js" /answer/
const answer = 42;
console.log(answer);
```

The fence above was authored as:

````md
```js title="word-demo.js" /answer/
const answer = 42;
console.log(answer);
```
````

Multiple expressions are space-separated (`/first/ /second phrase/`); a literal slash inside a phrase is escaped as `\/` (`/path\/name/`). Malformed or unterminated expressions are silently ignored.

## Copy and wrap buttons

The copy and word-wrap toggle buttons are added by client-side JavaScript at runtime; they are not present in the server-rendered HTML. This runs unconditionally on every highlighted code block — independent of whether `codeEnrichment` is configured. When hydrated, the copy button markup is `button.code-btn.code-btn-copy` containing `svg.code-icon.code-icon-copy`.

Word wrap is a **page-wide** preference, not a per-block one: toggling any wrap button wraps every code block on the page, and the choice is remembered for the browser-tab session (`sessionStorage`, key `zudo-doc-code-wrap`) so it survives a reload. The toggle is only offered on blocks whose content actually overflows — a block that already fits never shows one, whether wrap is on or off.

## Emitted DOM

| Trigger | Emitted element(s) | Class names |
| --- | --- | --- |
| Diff marker line | `<span class="line" data-line-diff="added\|removed">` | `span.line[data-line-diff]` |
| Highlighted line | `<span class="line" data-line-highlight="true">` | `span.line[data-line-highlight]` |
| Word match | wraps the matched visible text | `.highlighted-word` |