Nothing needed building for the dark code panel: MdCodeBlock.qml already
provides a rounded secondaryBackground panel, a header naming the
language, a Copy button with "Copied!" feedback, and horizontal scroll.
The language string is the only missing piece, and it is also what turns
on highlighting. syntax::highlight resolves it with
definitionForName(language) and then definitionForFileName("file." +
language), so `bash` and `ts` colour correctly while an unrecognised
string such as `terminal` still renders a label but produces no
highlighting at all.
Two changes:
- The default prompt now requires a language on every fence, and forbids
leaving commands inline in a sentence or padding them with a leading $,
so commands stay copy-pasteable.
- code.ts labels fences the model left bare. It is deliberately
conservative, because a wrong label is worse than none: it claims bash
only on a clear shell signal, json only when the body actually parses,
ts only on TypeScript-specific syntax, and leaves plain JavaScript
alone rather than guessing.
Verified by rendering a probe with four fences and reading the result:
```bash -> "bash" label, "git" coloured
``` -> no label, no colouring
```ts -> "ts" label, const/number/length coloured
```terminal -> "terminal" label, no colouring
`bash` is used over `terminal` for shell commands precisely because
`terminal` costs the colouring.
Also fixes an index bug in labelCodeFences found by its own test: the
unlabelled branch pushed the wrong line back, duplicating code instead of
preserving the opening fence.
typecheck, eslint, 156 tests and vici build all pass.