a rounded panel on Theme.secondaryBackground (the dark background)
a header showing the fence's language, plus a Copy button with "Copied!" feedback
syntax colouring, in the theme's mono font, with horizontal scroll
The only missing piece was the language string on the fence.
Why the label matters more than it looks
Vicinae resolves the language with KSyntaxHighlighting:
autodef=repo.definitionForName(language);if(!def.isValid())def=repo.definitionForFileName(QStringLiteral("file.")+language);if(!def.isValid())returnwrapPre(code.toHtmlEscaped());// label shows, no colouring
So ts resolves through file.ts and bash through its definition name, while an unrecognised string still renders a label but produces no highlighting at all. A wrong label is worse than none.
Changes
The default prompt now requires a language on every fence, forbids leaving code inline in a sentence, and forbids padding commands with a leading $ so they stay copy-pasteable.
code.ts labels fences the model left bare. Deliberately conservative: 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
I injected a probe with four fences and read the result back:
Fence
Label
Colouring
```bash
bash
✅git coloured
bare ```
none
❌ plain white
```ts
ts
✅const / number / length coloured
```terminal
terminal
❌ plain white
On terminal: it renders the label you asked for, but costs the colouring, because there is no such KSyntaxHighlighting definition. I used bash for shell content so you get both. If you would rather have the word terminal than the colours, it is a one-line change in code.ts.
I also skipped the ~ / > prompt prefix idea: it would become part of the block content, so the Copy button would hand you a command with a prompt character stuck to the front.
Bug found and fixed
labelCodeFences had an index error in its unlabelled branch — it pushed the wrong line back, duplicating code instead of preserving the opening fence. Caught by its own test before shipping.
Verification
tsc --noEmit clean, eslint . clean
156 tests passing across 11 files (was 130 across 10); new code.test.ts covers inference and fence rewriting
vici build succeeds
## The good news: Vicinae already does this
Nothing needed building. `MdCodeBlock.qml` renders:
- a rounded panel on `Theme.secondaryBackground` (the dark background)
- a header showing the fence's language, plus a **Copy** button with "Copied!" feedback
- syntax colouring, in the theme's mono font, with horizontal scroll
The only missing piece was the **language string** on the fence.
## Why the label matters more than it looks
Vicinae resolves the language with KSyntaxHighlighting:
```cpp
auto def = repo.definitionForName(language);
if (!def.isValid()) def = repo.definitionForFileName(QStringLiteral("file.") + language);
if (!def.isValid()) return wrapPre(code.toHtmlEscaped()); // label shows, no colouring
```
So `ts` resolves through `file.ts` and `bash` through its definition name, while an unrecognised string still renders a label but produces **no highlighting at all**. A wrong label is worse than none.
## Changes
- **The default prompt** now requires a language on every fence, forbids leaving code inline in a sentence, and forbids padding commands with a leading `$` so they stay copy-pasteable.
- **`code.ts`** labels fences the model left bare. Deliberately conservative: 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
I injected a probe with four fences and read the result back:
| Fence | Label | Colouring |
| --- | --- | --- |
| ` ```bash ` | `bash` | ✅ `git` coloured |
| bare ` ``` ` | none | ❌ plain white |
| ` ```ts ` | `ts` | ✅ `const` / `number` / `length` coloured |
| ` ```terminal ` | `terminal` | ❌ plain white |
**On `terminal`:** it renders the label you asked for, but costs the colouring, because there is no such KSyntaxHighlighting definition. I used `bash` for shell content so you get both. If you would rather have the word `terminal` than the colours, it is a one-line change in `code.ts`.
I also skipped the `~` / `>` prompt prefix idea: it would become part of the block content, so the Copy button would hand you a command with a prompt character stuck to the front.
## Bug found and fixed
`labelCodeFences` had an index error in its unlabelled branch — it pushed the wrong line back, duplicating code instead of preserving the opening fence. Caught by its own test before shipping.
## Verification
- `tsc --noEmit` clean, `eslint .` clean
- **156 tests passing** across 11 files (was 130 across 10); new `code.test.ts` covers inference and fence rewriting
- `vici build` succeeds
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.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
The good news: Vicinae already does this
Nothing needed building.
MdCodeBlock.qmlrenders:Theme.secondaryBackground(the dark background)The only missing piece was the language string on the fence.
Why the label matters more than it looks
Vicinae resolves the language with KSyntaxHighlighting:
So
tsresolves throughfile.tsandbashthrough its definition name, while an unrecognised string still renders a label but produces no highlighting at all. A wrong label is worse than none.Changes
$so they stay copy-pasteable.code.tslabels fences the model left bare. Deliberately conservative: it claimsbashonly on a clear shell signal,jsononly when the body actually parses,tsonly on TypeScript-specific syntax, and leaves plain JavaScript alone rather than guessing.Verified by rendering
I injected a probe with four fences and read the result back:
```bashbashgitcoloured``````tstsconst/number/lengthcoloured```terminalterminalOn
terminal: it renders the label you asked for, but costs the colouring, because there is no such KSyntaxHighlighting definition. I usedbashfor shell content so you get both. If you would rather have the wordterminalthan the colours, it is a one-line change incode.ts.I also skipped the
~/>prompt prefix idea: it would become part of the block content, so the Copy button would hand you a command with a prompt character stuck to the front.Bug found and fixed
labelCodeFenceshad an index error in its unlabelled branch — it pushed the wrong line back, duplicating code instead of preserving the opening fence. Caught by its own test before shipping.Verification
tsc --noEmitclean,eslint .cleancode.test.tscovers inference and fence rewritingvici buildsucceedsNothing 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.